From a7b45caf5b3784f65ba82793d87f5ffb202fca1e Mon Sep 17 00:00:00 2001
From: Tomas <tomasysh@gmail.com>
Date: 星期五, 21 一月 2022 11:42:07 +0800
Subject: [PATCH] update#134555: [顧問] 預約單結案/編輯結案功能串接

---
 PAMapp/shared/const/appointment-fail-reason-list.ts      |   26 +++
 PAMapp/shared/services/appointment.service.ts            |    2 
 PAMapp/pages/myAppointmentList/closedList.vue            |   16 +-
 PAMapp/components/Client/ClientCard.vue                  |   11 +
 PAMapp/components/Appointment/AppointmentClosedInfo.vue  |   59 ++++++++
 PAMapp/shared/models/appointment.model.ts                |   56 ++++---
 PAMapp/plugins/filters/appointment-fail-reason.filter.ts |   16 ++
 PAMapp/pages/appointment/_appointmentId/index.vue        |   77 +++++++---
 PAMapp/pages/appointment/_appointmentId/close/index.vue  |  108 +++++++-------
 9 files changed, 257 insertions(+), 114 deletions(-)

diff --git a/PAMapp/components/Appointment/AppointmentClosedInfo.vue b/PAMapp/components/Appointment/AppointmentClosedInfo.vue
new file mode 100644
index 0000000..8b08adb
--- /dev/null
+++ b/PAMapp/components/Appointment/AppointmentClosedInfo.vue
@@ -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">���誨蝣噗lan 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>
diff --git a/PAMapp/components/Client/ClientCard.vue b/PAMapp/components/Client/ClientCard.vue
index f203dd0..cfe5154 100644
--- a/PAMapp/components/Client/ClientCard.vue
+++ b/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() {
diff --git a/PAMapp/pages/appointment/_appointmentId/close/index.vue b/PAMapp/pages/appointment/_appointmentId/close/index.vue
index 973e48a..956280e 100644
--- a/PAMapp/pages/appointment/_appointmentId/close/index.vue
+++ b/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{
diff --git a/PAMapp/pages/appointment/_appointmentId/index.vue b/PAMapp/pages/appointment/_appointmentId/index.vue
index b4a7da0..54ad105 100644
--- a/PAMapp/pages/appointment/_appointmentId/index.vue
+++ b/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">���誨蝣噗lan 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甈∴�恥�敺�迭��窄�憭U��</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>
diff --git a/PAMapp/pages/myAppointmentList/closedList.vue b/PAMapp/pages/myAppointmentList/closedList.vue
index 9d7957f..b050cab 100644
--- a/PAMapp/pages/myAppointmentList/closedList.vue
+++ b/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';
 
diff --git a/PAMapp/plugins/filters/appointment-fail-reason.filter.ts b/PAMapp/plugins/filters/appointment-fail-reason.filter.ts
new file mode 100644
index 0000000..7df365f
--- /dev/null
+++ b/PAMapp/plugins/filters/appointment-fail-reason.filter.ts
@@ -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];
+})
diff --git a/PAMapp/shared/const/appointment-fail-reason-list.ts b/PAMapp/shared/const/appointment-fail-reason-list.ts
new file mode 100644
index 0000000..3e8f309
--- /dev/null
+++ b/PAMapp/shared/const/appointment-fail-reason-list.ts
@@ -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'
+  },
+];
diff --git a/PAMapp/shared/models/appointment.model.ts b/PAMapp/shared/models/appointment.model.ts
index 3488334..9a66ebe 100644
--- a/PAMapp/shared/models/appointment.model.ts
+++ b/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;
diff --git a/PAMapp/shared/services/appointment.service.ts b/PAMapp/shared/services/appointment.service.ts
index dcba492..9f07fe9 100644
--- a/PAMapp/shared/services/appointment.service.ts
+++ b/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);
   }

--
Gitblit v1.8.0