保誠-保戶業務員媒合平台
HelenHuang
2021-12-08 ea8c5302eb57600b4380e20600d61b1d115a6b53
Merge branch 'master' of https://192.168.0.10:8443/r/pcalife/PAM
修改3個檔案
342 ■■■■ 已變更過的檔案
PAMapp/assets/ts/api/consultant.ts 29 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/Consultant/ConsultantCard.vue 60 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/questionnaire/_agentNo.vue 253 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/ts/api/consultant.ts
@@ -133,6 +133,22 @@
    return service.post('/satisfaction/create', data ,{headers});
}
// 取消預約
export function cancelAppointment(appointment: number) {
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.delete('/appointment/'+appointment ,{headers});
}
// 編輯預約
export function editAppointment(editAppointmentParams: editAppointmentParams) {
    const headers = {
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.put('/appointment', editAppointmentParams, {headers});
}
export interface FastQueryParams {
    gender             : string,
    communicationStyles: string[],
@@ -231,3 +247,16 @@
    appointmentId:number,
    score:number,
}
export interface editAppointmentParams {
    id: number,
    phone: string,
    email: string,
    contactType: string,
    gender: string,
    age: string,
    job: string,
    requirement: string,
    hopeContactTime: string,
    otherRequirement: null
}
PAMapp/components/Consultant/ConsultantCard.vue
@@ -73,7 +73,7 @@
                    >連絡時段{{index + 1 | formatNumber}}:{{ item | formatHopeContactTime }}</p>
                    <div v-if="appointmentDetail.satisfactionScore">
                    <div class="mdTxt mt-10 mb-10">滿意度</div>
                        <el-rate
                        <el-rate
                            :value="appointmentDetail.satisfactionScore"
                            class="pam-myDemand-dialog__rate"
                            disabled>
@@ -81,10 +81,15 @@
                    </div>
                </div>
                <div v-if="agentInfo.contactStatus === 'contacted'
                <div v-if="agentInfo.contactStatus === 'contacted'
                        && !appointmentDetail.satisfactionScore" class="dialogInfo-btn">
                    <el-button type="primary"
                    <el-button type="primary"
                        @click.native="reviewsBtn = true">給予滿意度評分</el-button>
                </div>
                <div v-if="agentInfo.contactStatus === 'reserved'" class="text--center mt-10">
                    <el-button @click="isCancelPopup = true">取消預約</el-button>
                    <el-button @click="edit" type="primary">編輯</el-button>
                </div>
            </div>
        </Ui-Dialog>
@@ -92,23 +97,31 @@
            <div class="mdTxt">
                保險顧問滿意度
                <span class="hint">選取星星</span>
                <div class="dialogInfo-score">
                <div class="dialogInfo-score">
                    <el-rate v-model="inputScore" class="pam-quickFilter-rate"></el-rate>
                </div>
                <div class="dialogInfo-btn">
                    <el-button
                    <el-button
                        type="primary"
                        :disabled="!inputScore"
                        @click="userReviewsConsultants">送出</el-button>
                </div>
            </div>
        </PopUpFrame>
        <PopUpFrame :isOpen.sync="isCancelPopup">
            <div class="text--center mdTxt">是否取消此筆預約?</div>
            <div class="text--center mt-30">
                <el-button @click="isCancelPopup = false">取消</el-button>
                <el-button @click="cancel" type="primary">確定</el-button>
            </div>
        </PopUpFrame>
    </div>
</template>
<script lang="ts">
import { Vue, Component, Prop, Emit, Action, State } from 'nuxt-property-decorator';
import { getAppointmentDetail, UserReviewsConsultantsParams, userReviewsConsultants  } from '~/assets/ts/api/consultant';
import { Vue, Component, Prop, Action } from 'nuxt-property-decorator';
import { getAppointmentDetail, UserReviewsConsultantsParams, userReviewsConsultants, cancelAppointment, AppointmentRequests  } from '~/assets/ts/api/consultant';
import { Consultant, Appointment } from '~/assets/ts/models/consultant.model';
import { isLogin } from '~/assets/ts/auth';
import { isMobileDevice } from '~/assets/ts/device';
@@ -142,7 +155,8 @@
    status = false;
    width: string = '';
    inputScore = 0;
    isCancelPopup = false;
    get latestContactedAppointment(): Appointment | null {
        if (!(this.agentInfo && this.agentInfo.appointments && this.agentInfo.appointments.length)) return null;
        const contactedAppointments: Appointment[] =  this.agentInfo.appointments
@@ -150,7 +164,13 @@
                                                        .sort((preAppointment, nextAppointment) => +nextAppointment.appointmentDate - +preAppointment.appointmentDate);
        return contactedAppointments[0];
    }
    get latestReservedAppointment(): Appointment {
        return this.agentInfo.appointments!
                .filter((appointment) => appointment.communicateStatus !== 'contacted')
                .sort((preAppointment, nextAppointment) => +nextAppointment.appointmentDate - +preAppointment.appointmentDate)[0];
    }
    appointmentDetail: any = {
        age               : '',
        agentNo           : '',
@@ -219,12 +239,9 @@
    }
    openPopUp() {
    const latestReservedAppointment = this.agentInfo.appointments!
                                        .filter((appointment) => appointment.communicateStatus !== 'contacted')
                                        .sort((preAppointment, nextAppointment) => +nextAppointment.appointmentDate - +preAppointment.appointmentDate)[0];
        getAppointmentDetail(this.latestContactedAppointment
                            ? this.latestContactedAppointment.id
                            : latestReservedAppointment.id).then(res => {
        getAppointmentDetail(this.latestContactedAppointment
                            ? this.latestContactedAppointment.id
                            : this.latestReservedAppointment.id).then(res => {
            this.appointmentDetail = {
                ...this.appointmentDetail,
                ...res.data
@@ -255,6 +272,19 @@
            this.storeConsultantList();
        });
    }
    cancel() {
        cancelAppointment(this.latestReservedAppointment.id).then(res => {
            this.storeConsultantList();
            this.isVisibleDialog = false;
            this.isCancelPopup = false;
        });
    }
    edit() {
        this.isVisibleDialog = false;
        this.$router.push({path: `/questionnaire/${this.agentInfo.agentNo}`, query: {'edit': 'true'}});
    }
}
</script>
PAMapp/pages/questionnaire/_agentNo.vue
@@ -92,7 +92,7 @@
        <el-button type="primary"
          :disabled="isDisabledSubmitBtn"
          @click.native="sentDemand">
          送出
          {{isEditBtn ? '更新' : '送出'}}
        </el-button>
      </div>
    </div>
@@ -124,20 +124,32 @@
          </el-button>
        </div>
    </PopUpFrame>
    <PopUpFrame :isOpen.sync="isEditPopup">
      <div class="text--middle mt-30 sendReserve-txt">是否繼續編輯預約單?</div>
      <div class="text--center mdTxt">
        <el-button @click="$router.go(-1)">返回</el-button>
        <el-button @click="isEditPopup = false" type="primary">編輯</el-button>
      </div>
    </PopUpFrame>
  </div>
</template>
<script lang="ts">
  import { Vue, Component } from 'nuxt-property-decorator';
  import { addFavoriteConsultant, appointmentDemand, AppointmentParams, AppointmentRequests ,RegisterInfo } from '~/assets/ts/api/consultant';
  import { getRequestsFromStorage, setRequestsToStorage, getRequestQuestionFromStorage, removeRequestQuestionFromStorage  } from '~/assets/ts/storageRequests';
  import { Gender } from '~/assets/ts/models/enum/Gender';
  import { ContactType } from '~/assets/ts/models/enum/ContactType';
  import _ from 'lodash';
  import { isLogin } from '~/assets/ts/auth';
import { Vue, Component, State, Action, Watch } from 'nuxt-property-decorator';
import { addFavoriteConsultant, appointmentDemand, AppointmentParams, AppointmentRequests ,editAppointment,RegisterInfo } from '~/assets/ts/api/consultant';
import { getRequestQuestionFromStorage, getRequestsFromStorage, removeRequestQuestionFromStorage, setRequestsToStorage } from '~/assets/ts/storageRequests';
import _ from 'lodash';
import { isLogin } from '~/assets/ts/auth';
import { Consultant } from '~/assets/ts/models/consultant.model';
import { ContactType } from '~/assets/ts/models/enum/ContactType';
import { Gender } from '~/assets/ts/models/enum/Gender';
  @Component
  export default class Questionnaire extends Vue {
    @State('myConsultantList') myConsultantList!: Consultant[];
    @Action storeConsultantList!: () => Promise<number>;
    genderOptions=[
      {
        title:'男性',
@@ -255,6 +267,10 @@
    showDrawer= false;
    sendReserve = false;
    isEditPopup = false;
    isEditBtn = false;
    appointmentId = 0;
    beforeRouteEnter(to: any, from: any, next: any) {
      next(vm => {
@@ -267,6 +283,12 @@
          vm.$router.push('/login');
        }
      })
    }
    async fetch() {
      if (isLogin()) {
        await this.storeConsultantList();
      };
    }
    mounted(): void {
@@ -325,7 +347,12 @@
    }
    sentDemand() {
      addFavoriteConsultant([this.$route.params.agentNo]).then(res => this.sentAppointmentDemand());
      if (this.isEditBtn) {
        this.sentEditAppointmentDemand();
      } else {
        addFavoriteConsultant([this.$route.params.agentNo]).then(res => this.sentAppointmentDemand());
      }
    }
    private sentAppointmentDemand() {
@@ -343,6 +370,21 @@
        });
    }
    private sentEditAppointmentDemand() {
      const info = {
          ...this.myRequest,
          requirement: _.map(this.myRequest.requirement,o=>o).toString(),
          hopeContactTime: this.myRequest.phone && this.phoneValid ? this.getHopeContactTime() :'',
          id: this.appointmentId,
          otherRequirement: null
        }
        editAppointment(info).then(res => {
          this.sendReserve = true;
          this.myRequest.hopeContactTime = [];
          setRequestsToStorage(this.myRequest);
        });
    }
    getHopeContactTime() {
        const selectedHopeContactTime = this.myRequest.hopeContactTime.filter((i) => i.selectWeekOptions?.length && i.selectTimesOptions?.length);
        return selectedHopeContactTime.map(i => {
@@ -355,34 +397,99 @@
        this.$router.push('/')
    }
    private getLatestReserved(agentNo) {
      const agentInfo = this.myConsultantList.filter(item => item.agentNo === agentNo);
      const appointmentInfo = agentInfo.length > 0 && agentInfo[0].appointments
        ? agentInfo[0].appointments!
          .filter((appointment) => appointment.communicateStatus !== 'contacted')
          .sort((preAppointment, nextAppointment) => {
              return +nextAppointment.appointmentDate - +preAppointment.appointmentDate
          })[0]
        : null;
      return this.getReservedData(appointmentInfo);
    }
    private getReservedData(appointmentInfo) {
      if (appointmentInfo) {
        const hopeContactTime = appointmentInfo!.hopeContactTime.split("'")
              .filter(item => item && item !== ',');
        this.appointmentId = appointmentInfo.id;
        return {
            age: appointmentInfo.age,
            agentNo: appointmentInfo.agentNo,
            contactType: appointmentInfo.contactType,
            email: appointmentInfo.email || '',
            gender: appointmentInfo.gender,
            hopeContactTime: hopeContactTime.map(item => {
                const info = item.split('、');
                return {
                    selectWeekOptions: info[0].split(','),
                    selectTimesOptions: info[1].split(',')
                }
            }),
            job: appointmentInfo.job,
            phone: appointmentInfo.phone || '',
            requirement: appointmentInfo.requirement.split(',')
          }
      } else {
        return {
          age: '',
          agentNo: '',
          contactType: '',
          email: '',
          gender: '',
          hopeContactTime: [],
          job: '',
          phone: '',
          requirement: []
        }
      }
    }
    @Watch('myConsultantList') onMyConsultantListChange() {
      if (this.isLogin && this.myConsultantList.length > 0) {
          const editAppointment = this.getLatestReserved(this.$route.params.agentNo);
          if (editAppointment.agentNo) {
            this.myRequest = JSON.parse(JSON.stringify(editAppointment));
            if (!this.$route.query || this.$route.query.edit !== 'true') {
              this.isEditPopup = true;
            }
            this.isEditBtn = true;
            return;
          }
      }
    }
  }
</script>
<style lang="scss" scoped>
.sendReserve-txt{
    display: flex;
    justify-content: center;
    margin-top: 10px;
    margin-bottom: 26px;
  display: flex;
  justify-content: center;
  margin-top: 10px;
  margin-bottom: 26px;
}
//drawer最底下文字樣式
.qa-dialog-footer{
    display: flex;
    justify-content: center;
    margin-bottom: 81px;
    color: #ED1B2E;
    cursor: pointer;
  display: flex;
  justify-content: center;
  margin-bottom: 81px;
  color: #ED1B2E;
  cursor: pointer;
}
//送出按鈕樣式與排版
.ques-footer{
    justify-content: center;
    margin: 30px 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    .el-button {
  justify-content: center;
  margin: 30px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  .el-button {
    width: 120px;
    height:50px;
    background-color: #ED1B2E;
@@ -410,43 +517,39 @@
//詳細問題drawer中間內容空間大小設置
.qa-dialog{
    overflow-y:auto;
    height: 500px;
    margin-top: 20px;
  overflow-y:auto;
  height: 500px;
  margin-top: 20px;
}
//詳細問題drawer主要標題
.qaTextTitle{
    margin-top:30px;
    display: flex;
    justify-content: center;
}
.el-button+.el-button{
    margin-left: 0;
  margin-top:30px;
  display: flex;
  justify-content: center;
}
.datepicker{
    display: flex;
    flex-direction: column;
  display: flex;
  flex-direction: column;
}
.required {
    position: relative;
    &::before {
        content: '*';
        position: absolute;
        color: #FF0000;
        transform: translate(-12px, 0);
    }
  position: relative;
  &::before {
      content: '*';
      position: absolute;
      color: #FF0000;
      transform: translate(-12px, 0);
  }
}
.ques-page--reset.pam-page-container {
    margin: 0px auto;
  margin: 0px auto;
}
.ques-header {
    position: relative;
  position: relative;
}
.ques-header__mob-banner {
@@ -459,41 +562,41 @@
  background-position: center;
}
.ques-header__info {
  position: relative;
  padding:30px 20px;
  margin: 0px 20px;
  background-color: #B3E7E3;
  border-radius: 10px;
}
.ques-header__input-block {
  display: flex;
  align-items: center;
  @extend .text--middle,.mt-10 ;
  .ques-header__input{
    &.is-invalid{
      border: 2px solid $PRIMARY_RED !important;
    }
    flex: 1;
    height: 50px;
  .ques-header__info {
    position: relative;
    padding:30px 20px;
    margin: 0px 20px;
    background-color: #B3E7E3;
    border-radius: 10px;
    border: 1px #CCCCCC solid;
    background-color: $PRIMARY_WHITE;
    padding: 15px 10px;
    box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
  }
}
.ques-container {
  position: relative;
  margin: 0px 20px;
}
  .ques-header__input-block {
    display: flex;
    align-items: center;
    @extend .text--middle,.mt-10 ;
    .ques-header__input{
      &.is-invalid{
        border: 2px solid $PRIMARY_RED !important;
      }
      flex: 1;
      height: 50px;
      border-radius: 10px;
      border: 1px #CCCCCC solid;
      background-color: $PRIMARY_WHITE;
      padding: 15px 10px;
      box-sizing: border-box;
      -webkit-box-sizing: border-box;
      -moz-box-sizing: border-box;
    }
  }
  .ques-container {
    position: relative;
    margin: 0px 20px;
  }
@include desktop{
  @include desktop{
  .ques-header{
    display: flex;
    justify-content: flex-end;