PAMapp/components/Appointment/AppointmentClosedInfo.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/components/Client/ClientCard.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/pages/appointment/_appointmentId/close/index.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/pages/appointment/_appointmentId/index.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/pages/myAppointmentList/closedList.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/plugins/filters/appointment-fail-reason.filter.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/shared/const/appointment-fail-reason-list.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/shared/models/appointment.model.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/shared/services/appointment.service.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 |
PAMapp/components/Appointment/AppointmentClosedInfo.vue
¤ñ¹ï·sÀÉ®× @@ -0,0 +1,59 @@ <template> <section class="close-appointment-detail"> <div class="close-appointment-detail-nav"> <div class="mdTxt">çµæ¡æ¹å¼</div> <div class="mdTxt text--primary text--underline cursor--pointer" @click="editAppointmentHasClosed">編輯</div> </div> <span class="mt-10 mb-30">{{ displayClosedType }}</span> <template v-if="appointmentDetail.appointmentClosedInfo.policyholderIdentityId"> <div class="mdTxt mb-10">ä¿æ¶èº«ä»½èåè</div> <div class="mb-30">{{ appointmentDetail.appointmentClosedInfo.policyholderIdentityId }}</div> </template> <template v-if="appointmentDetail.appointmentClosedInfo.planCode"> <div class="mdTxt mb-10">åå代碼Plan Code</div> <div class="mb-30">{{ appointmentDetail.appointmentClosedInfo.planCode }}</div> </template> <template v-if="appointmentDetail.appointmentClosedInfo.closedReason"> <div class="mdTxt mb-10">æªæäº¤åå </div> <div >{{ appointmentDetail.appointmentClosedInfo.closedReason | toFailReasonLabel }}</div> <div v-if="appointmentDetail.appointmentClosedInfo.closedOtherReason" class="mt-10">{{ appointmentDetail.appointmentClosedInfo.closedOtherReason }}</div> <div class="mb-30"></div> </template> <template v-if="appointmentDetail.appointmentClosedInfo.policyEntryDate"> <div class="mdTxt mb-10">é²ä»¶æé</div> <div class="mb-30">{{ appointmentDetail.appointmentClosedInfo.policyEntryDate | formatDate }}</div> </template> <div class="mdTxt mb-10">å註</div> <div>{{ appointmentDetail.appointmentClosedInfo.remark || 'ç¡' }}</div> </section> </template> <script lang="ts"> import { Vue, Component, Prop } from 'nuxt-property-decorator'; import { Appointment } from '~/shared/models/appointment.model'; @Component export default class AppointmentRecordList extends Vue { @Prop() appointmentDetail!: Appointment; ////////////////////////////////////////////////////////////////////// editAppointmentHasClosed(): void{ this.$router.push(`/appointment/${this.appointmentDetail.id}/close`); } } </script> <style lang="scss" scoped> </style> PAMapp/components/Client/ClientCard.vue
@@ -257,6 +257,7 @@ viewAppointmentDetail(): void { this.getAppointmentDetail(this.client.id).then((_) => { this.readAppointment(); this.$router.push(`/appointment/${this.client.id}`); }); } @@ -289,7 +290,13 @@ } closeInformDialog(): void { const unread = !this.client.consultantReadTime; this.readAppointment(); this.isEdit = false; this.clearAppointmentIdFromMsg(); } private readAppointment(): void { const unread = !this.client.consultantReadTime; if (unread) { appointmentService.recordRead(this.client.id).then((_) => { const updatedClient = {...this.client}; @@ -297,8 +304,6 @@ this.updateMyAppointmentList(updatedClient); }); }; this.isEdit = false; this.clearAppointmentIdFromMsg(); } private clearAppointmentIdFromMsg() { PAMapp/pages/appointment/_appointmentId/close/index.vue
@@ -11,7 +11,7 @@ </UiField> </el-row> <template v-if="appointmentCloseInfo.selectCloseOption === 'done'"> <template v-if="appointmentCloseInfo.selectCloseOption === contactStatus.DONE"> <el-row type="flex" class="pam-paragraph" style="flex-direction: column"> @@ -43,18 +43,20 @@ <el-row type="flex" class="pam-paragraph"> <UiField label="é²ä»¶æé" :labelSize="20" class="required"> <DateTimePicker @changeDateTime="appointmentCloseDate = $event"></DateTimePicker> <UiField label="é²ä»¶æé" :labelSize="20"> <DateTimePicker :defaultValue="appointmentCloseInfo.policyEntryDate" @changeDateTime="appointmentCloseInfo.policyEntryDate = $event"></DateTimePicker> </UiField> </el-row> </template> <template v-if="appointmentCloseInfo.selectCloseOption === 'close'"> <template v-if="appointmentCloseInfo.selectCloseOption === contactStatus.CLOSE"> <el-row class="pam-paragraph"> <UiField label="æªæäº¤åå " :labelSize="20" class="required"> </UiField> <div class="appointment-client-detail-close__selectbox"> <div class="appointment-client-detail-close__select-box"> <select class="appointment-client-detail-close__select" name="closedReason" id="closedReason" v-model="appointmentCloseInfo.closedReason"> @@ -64,8 +66,7 @@ </select> <i class="icon-down down-icon"></i> </div> <div style="display: flex" class="mt-10"> <div class="mt-10"> <input v-if="appointmentCloseInfo.closedReason === 'other' || appointmentCloseInfo.closedReason === 'no_suitable_commodity'" @@ -88,16 +89,6 @@ v-model="appointmentCloseInfo.remark" resize="none"> </el-input> <!-- <textarea v-model="appointmentCloseInfo.archivedDate" class="appointment-close__remark" placeholder="è«è¼¸å ¥" name="remark" id="remark" wrap="off" rows="3"> </textarea> --> </UiField> </el-row> @@ -123,9 +114,10 @@ import { namespace } from 'nuxt-property-decorator'; import { Vue, Component } from 'vue-property-decorator'; import { Appointment, ToCloseAppointment, ToDoneAppointment } from '~/shared/models/appointment.model'; import { ContactStatus } from '~/shared/models/enum/contact-status'; import appointmentService from '~/shared/services/appointment.service'; import { appointmentFailReasonList } from '~/shared/const/appointment-fail-reason-list'; import { ContactStatus } from '~/shared/models/enum/contact-status'; const appointmentStore = namespace('appointment.store'); @@ -133,7 +125,10 @@ export default class AppointmentDetailCloseComponent extends Vue { @appointmentStore.Action updateAppointmentDetail!: () => Appointment; updateAppointmentDetail!: (appointmentId: number) => Appointment; @appointmentStore.State('appointmentDetail') appointmentDetail!: Appointment; contactStatus = ContactStatus; @@ -147,58 +142,60 @@ policyEntryDate : this.appointmentCloseDate, policyholderIdentityId: '', remark : '', selectCloseOption : 'done', selectCloseOption : this.contactStatus.DONE, }; closeOptions = [ { title:'æäº¤', label: 'done', label: this.contactStatus.DONE, }, { title:'æªæäº¤', label: 'close', label: this.contactStatus.CLOSE, } ]; appointmentFailReason = [ { key: 'ç¡æ³è¯ç¹«å®¢æ¶', value: 'cannot_to_contact_customer' }, { key: 'å®ç´è«®è©¢', value: 'only_consultation' }, { key: 'ç¡åé©åå', value: 'no_suitable_commodity' }, { key: 'æ ¸ä¿åé¡- 髿³ã財åãè·æ¥', value: 'prohibited_factors' }, { key: 'ç¶æ¿å ç´ ', value: 'economy' }, { key: 'å ¶ä»', value: 'other' }, ]; appointmentFailReason = appointmentFailReasonList; ////////////////////////////////////////////////////////////////////// mounted() { const appointmentId = +this.$route.params.appointmentId; const closedInfo = this.appointmentDetail.appointmentClosedInfo; if (this.appointmentDetail.id === appointmentId && (this.appointmentDetail.communicateStatus === this.contactStatus.DONE || this.appointmentDetail.communicateStatus === this.contactStatus.CLOSE || this.appointmentDetail.communicateStatus === this.contactStatus.CANCEL) ) { this.appointmentCloseInfo = { closedOtherReason : closedInfo?.closedOtherReason, closedReason : closedInfo?.closedReason, planCode : closedInfo?.planCode, policyEntryDate : closedInfo?.policyEntryDate, policyholderIdentityId: closedInfo?.policyholderIdentityId, remark : closedInfo?.remark, selectCloseOption : this.appointmentDetail.communicateStatus === this.contactStatus.DONE ? this.contactStatus.DONE : this.contactStatus.CLOSE }; } } ////////////////////////////////////////////////////////////////////// closeAppointment(): void { const appointmentId = +this.$route.params.appointmentId; if (this.appointmentCloseInfo.selectCloseOption === 'done') { if (this.appointmentCloseInfo.selectCloseOption === this.contactStatus.DONE) { const toDoneAppointment: ToDoneAppointment = { appointmentId : appointmentId, contactStatus : this.contactStatus.DONE, planCode : this.appointmentCloseInfo.planCode, policyEntryDate : this.appointmentCloseInfo.policyEntryDate, policyholderIdentityId: this.appointmentCloseInfo.policyholderIdentityId, remark : this.appointmentCloseInfo.remark, } appointmentService.closeAppointment(toDoneAppointment).then((res) => res); appointmentService.closeAppointment(toDoneAppointment).then((_) => this.updateAppointmentDetail(appointmentId)); this.isShowSuccessAlert = true; } else { const toCloseAppointment: ToCloseAppointment = { @@ -208,7 +205,7 @@ contactStatus : this.contactStatus.CLOSE, remark : this.appointmentCloseInfo.remark, } appointmentService.closeAppointment(toCloseAppointment).then((res) => res); appointmentService.closeAppointment(toCloseAppointment).then((_) => this.updateAppointmentDetail(appointmentId)); this.isShowSuccessAlert = true; } } @@ -224,11 +221,12 @@ policyholderIdentityId, planCode, closedReason, closedOtherReason closedOtherReason, remark } = this.appointmentCloseInfo; // this.appointmentCloseInfo.policyEntryDate ä¸¦æ²æè¾¦æ³åå¼å° this.appointmentCloseDate if (selectCloseOption === 'done') { return !policyholderIdentityId || !this.identityIdValid || !planCode || !this.appointmentCloseDate if (selectCloseOption === this.contactStatus.DONE) { return !policyholderIdentityId || !this.identityIdValid || !planCode || !this.appointmentCloseInfo.policyEntryDate || !remark } else if (closedReason === 'other' || closedReason === 'no_suitable_commodity') { return !closedOtherReason } @@ -261,7 +259,7 @@ border-color: $PRIMARY_RED !important; } } .appointment-client-detail-close__selectbox { .appointment-client-detail-close__select-box { position: relative; & .appointment-client-detail-close__select{ PAMapp/pages/appointment/_appointmentId/index.vue
@@ -31,15 +31,22 @@ </div> <div class="client-detail-demand mt-10"> <div class="client-detail-demand__demand-list"> <div class="client-detail-demand__demand-list mb-10"> <div class="client-detail-demand__demand-list-label">éæ±</div> <div>{{ appointmentDetail.requirement }}</div> <div class="client-detail-demand__demand-list-content">{{ appointmentDetail.requirement }}</div> </div> <div class="client-detail-demand__hope-contact-time"> <div class="client-detail-demand__demand-list"> <div class="client-detail-demand__demand-list-label">è¯çµ¡<br />ææ®µ</div> <div>ææä¸ 17:00 ~ 19:00</div> <!-- TODO: å¤çè¯çµ¡ææ®µå¦ä½åç¾ && è·çåé¡ [Tomas. 2021/1/12] --> <!-- <div>{{ appointmentDetail.hopeContactTime }}</div> --> <div class="client-detail-demand__demand-list-content"> <div v-for="(hopeContactTime, index) in hopeContactTimeList" :key="index" :class="{'mt-10': index > 0, 'pb-10': true, 'hope-contact-time__line': index + 1 < hopeContactTimeList.length }"> <div v-for="(item, index) in getHopeContactTimeContent(hopeContactTime)" :key="index" :class="{'mt-10': index < 0 }"> {{ item }} </div> </div> </div> </div> </div> @@ -54,24 +61,9 @@ </section> <section class="close-appointment-detail" v-if="showWhenAppointmentHasClosed"> <div class="close-appointment-detail-nav"> <div class="mdTxt">çµæ¡æ¹å¼</div> <div class="mdTxt text--primary text--underline cursor--pointer" @click="editAppointmentHasClosed">編輯</div> </div> <span class="mt-10 mb-30">æäº¤</span> <div class="mdTxt mb-10">ä¿æ¶èº«ä»½èåè</div> <div class="mb-30">A123456789</div> <div class="mdTxt mb-10">åå代碼Plan Code</div> <div class="mb-30">8888888</div> <div class="mdTxt mb-10">é²ä»¶æé</div> <div class="mb-30">2021/12/2</div> <div class="mdTxt mb-10">å註</div> <div class="">ç´è¨ª4次ï¼å®¢æ¶å¾åæ¡è寶å¯å¤¢ã</div> </section> <template v-if="showWhenAppointmentHasClosed"> <AppointmentClosedInfo :appointmentDetail="appointmentDetail" /> </template> <InterviewMsg :isVisible.sync="isVisibleDialog" @@ -131,6 +123,28 @@ return this.appointmentDetail.communicateStatus === this.contactStatus.DONE || this.appointmentDetail.communicateStatus === this.contactStatus.CLOSE || this.appointmentDetail.communicateStatus === this.contactStatus.CANCEL; } get displayClosedType(): string { let closedType = 'æäº¤'; switch (this.appointmentDetail.communicateStatus) { case this.contactStatus.CLOSE: closedType = 'æªæäº¤'; break; case this.contactStatus.CANCEL: closedType = 'åæ¶'; break; } return closedType; } get hopeContactTimeList(): any[] { return this.appointmentDetail.hopeContactTime.split("','") } getHopeContactTimeContent(hopeContactTimeString: string): string[] { const result = hopeContactTimeString.replace("'", '').split('ã'); return result; } } </script> @@ -195,9 +209,17 @@ display: flex; } .client-detail-demand__demand-list-label { @extend .mr-10; @extend .mdTxt; @extend .mb-10; @extend .mdTxt; @extend .mr-10; color : $DARK_BLUE; flex-basis: auto; min-width : 40px; } .client-detail-demand__demand-list-content { text-align: justify; text-justify: auto; word-break: break-all; } } .client-detail-action { @@ -219,5 +241,8 @@ justify-content: space-between; flex: 1; } .hope-contact-time__line { border-bottom: 1px solid #CCCCCC; } </style> PAMapp/pages/myAppointmentList/closedList.vue
@@ -34,7 +34,7 @@ </template> <script lang="ts"> import { Vue, Component, Watch, State, namespace } from 'nuxt-property-decorator'; import { Vue, Component, Watch, namespace } from 'nuxt-property-decorator'; import { Appointment } from '~/shared/models/appointment.model'; import { ContactStatus } from '~/shared/models/enum/contact-status'; @@ -52,14 +52,16 @@ @localStorage.Getter currentAppointmentIdFromMsg!: string; closedItemSum = 0; closedList: Appointment[] = []; contactStatus= ContactStatus; currentPage : number = 1; doneItemSum = 0; closedItemSum = 0; currentPage = 1; doneItemSum = 0; itemSum = 0; keyWord = ''; closedList: Appointment[] = []; filterList : Appointment[] = []; itemSum = 0; keyWord : string = ''; pageList : Appointment[] = []; selectedClosedCategory: 'all' | 'done' | 'closed' = 'all'; PAMapp/plugins/filters/appointment-fail-reason.filter.ts
¤ñ¹ï·sÀÉ®× @@ -0,0 +1,16 @@ import Vue from 'vue' import { appointmentFailReasonList } from '~/shared/const/appointment-fail-reason-list'; Vue.filter('toFailReasonLabel', (value: string): string => { if (!value || typeof value !== 'string') { return '--'; }; let failReasonLabel = {}; appointmentFailReasonList.forEach((failReason) => { failReasonLabel[failReason.value] = failReason.key; }); return failReasonLabel[value]; }) PAMapp/shared/const/appointment-fail-reason-list.ts
¤ñ¹ï·sÀÉ®× @@ -0,0 +1,26 @@ export const appointmentFailReasonList = [ { key: 'ç¡æ³è¯ç¹«å®¢æ¶', value: 'cannot_to_contact_customer' }, { key: 'å®ç´è«®è©¢', value: 'only_consultation' }, { key: 'ç¡åé©åå', value: 'no_suitable_commodity' }, { key: 'æ ¸ä¿åé¡- 髿³ã財åãè·æ¥', value: 'prohibited_factors' }, { key: 'ç¶æ¿å ç´ ', value: 'economy' }, { key: 'å ¶ä»', value: 'other' }, ]; PAMapp/shared/models/appointment.model.ts
@@ -14,31 +14,43 @@ } export interface Appointment { age : string; agentNo : string; appointmentDate : string; appointmentMemoList: AppointmentMemoInfo[] communicateStatus : ContactStatus; consultantReadTime : string; consultantViewTime : string; contactTime : string; contactType : string; customerId : number; email : string; gender : string; hopeContactTime : string; id : number; interviewRecordDTOs: InterviewRecord[]; job : string; lastModifiedDate : string; name : string; otherRequirement : string; phone : string; requirement : string; satisfactionScore : number; age : string; agentNo : string; appointmentClosedInfo: AppointmentClosedInfo; appointmentDate : string; appointmentMemoList : AppointmentMemoInfo[] appointmentNoticeLogs: NoticeLogs[]; communicateStatus : ContactStatus; consultantReadTime : string; consultantViewTime : string; contactTime : string; contactType : string; customerId : number; email : string; gender : string; hopeContactTime : string; id : number; interviewRecordDTOs : InterviewRecord[]; job : string; lastModifiedDate : string; name : string; otherRequirement : string; phone : string; requirement : string; satisfactionScore : number; }; export interface AppointmentClosedInfo { appointmentId : number; closedOtherReason : string; closedReason : string; id : number; planCode : string; policyEntryDate : string; policyholderIdentityId: string; remark : string; } export interface AppointmentMemoInfo { appointmentId: number; content : string; PAMapp/shared/services/appointment.service.ts
@@ -55,7 +55,7 @@ return http.delete(`/appointment/memo/${appointmentMemoId}`) } // é ç´å®çµæ¡ // é ç´å®çµæ¡, æ´æ°çµæ¡æç´° async closeAppointment(appointmentInfo: ToDoneAppointment | ToCloseAppointment) { return http.post(`/appointment/close`, appointmentInfo).then((res) => res.data); }