From 0806c3ab46e49711e64e4bc793c12753fb5fb000 Mon Sep 17 00:00:00 2001
From: Tomas <tomasysh@gmail.com>
Date: 星期一, 24 一月 2022 16:24:43 +0800
Subject: [PATCH] add#134746: 客戶收到簡訊通知"有過久無回應的顧問",點擊簡訊/email url 後,進入此流程(belong to TODO#134717: [客戶] 取消預約再改選其他顧問(前端))

---
 PAMapp/pages/index.vue                       |  225 ++++++++++++++++++++++++++++++++------------
 PAMapp/components/Client/ClientCard.vue      |    6 -
 PAMapp/store/localStorage.ts                 |   21 ++++
 PAMapp/shared/models/strict-query.model.ts   |   18 +-
 PAMapp/middleware/getUrlQuery.ts             |   12 ++
 PAMapp/assets/scss/utilities/_utilities.scss |    5 +
 6 files changed, 207 insertions(+), 80 deletions(-)

diff --git a/PAMapp/assets/scss/utilities/_utilities.scss b/PAMapp/assets/scss/utilities/_utilities.scss
index 04b3932..ebf13d7 100644
--- a/PAMapp/assets/scss/utilities/_utilities.scss
+++ b/PAMapp/assets/scss/utilities/_utilities.scss
@@ -5,6 +5,10 @@
   margin-bottom: 50px;
 }
 
+.mt-50 {
+  margin-top: 50px;
+}
+
 .mt-30 {
   margin-top: 30px;
 }
@@ -21,6 +25,7 @@
   margin-bottom: 20px;
 }
 
+
 .mt-10 {
   margin-top: 10px;
 }
diff --git a/PAMapp/components/Client/ClientCard.vue b/PAMapp/components/Client/ClientCard.vue
index e010af8..0ff9748 100644
--- a/PAMapp/components/Client/ClientCard.vue
+++ b/PAMapp/components/Client/ClientCard.vue
@@ -261,12 +261,6 @@
 
     viewAppointmentDetail(): void {
       this.getAppointmentDetail(this.client.id).then((_) => {
-        // setTimeout(() => {
-        //   const unread = !this.client.consultantReadTime;
-        //   if (unread) {
-        //     this.readAppointment();
-        //   }
-        // }, 0);
         const unread = !this.client.consultantReadTime;
         if (unread) {
           this.readAppointment();
diff --git a/PAMapp/middleware/getUrlQuery.ts b/PAMapp/middleware/getUrlQuery.ts
index 0a6c0ec..5fb2841 100644
--- a/PAMapp/middleware/getUrlQuery.ts
+++ b/PAMapp/middleware/getUrlQuery.ts
@@ -3,7 +3,15 @@
 const getUrlQuery: Middleware = (context) => {
   const currentRouteName = context.route.name;
   const satisfactionIdFromMsg = context.route.query.appointmentId;
+  const queryNotContactAppointmentId = context.route.query.notContactAppointmentId;
   const isUserLogin = context.store.getters['localStorage/isUserLogin'];
+
+  if (currentRouteName === 'index' && queryNotContactAppointmentId) {
+    context.store.commit('localStorage/storageNotContactAppointmentIdFromMsg', queryNotContactAppointmentId);
+    if (!isUserLogin) {
+      context.redirect('/login');
+    }
+  }
 
   if (currentRouteName === 'index' && satisfactionIdFromMsg) {
     context.store.commit('localStorage/storageSatisfactionIdFromMsg', satisfactionIdFromMsg);
@@ -11,6 +19,8 @@
       context.redirect('/login');
     }
   }
+
+
 }
 
-export default getUrlQuery
\ No newline at end of file
+export default getUrlQuery
diff --git a/PAMapp/pages/index.vue b/PAMapp/pages/index.vue
index c237e5e..286c1ff 100644
--- a/PAMapp/pages/index.vue
+++ b/PAMapp/pages/index.vue
@@ -41,10 +41,9 @@
     </div>
 
     <Ui-Dialog
-        :isVisible.sync="isVisibleDialog"
-        :width="width"
+        :isVisible.sync="isShowAppointmentDialog"
+        :width="appointmentDialogWidth"
         class="pam-myDemand-dialog pam-dialog-reserved"
-        @closeDialog="clearSatisfactionId"
       >
         <div v-if="appointmentDetail">
             <h5 class="subTitle text--center mb-30">������</h5>
@@ -73,14 +72,42 @@
 
             <div v-if="notScoreAppointmentYet" class="reserved-btn">
                 <el-button type="primary"
-                    @click.native="reviewsBtn = true">蝯虫�遛��漲閰��</el-button>
+                    @click.native="isShowReviewDialog = true">蝯虫�遛��漲閰��</el-button>
             </div>
         </div>
       </Ui-Dialog>
 
       <PopUpFrame
-        :isOpen.sync="reviewsBtn"
-        @closePopUp="clearSatisfactionId"
+        :isOpen.sync="isShowReAppointmentDialog"
+        @closePopUp="removeUrlQueryParameter('notContactAppointmentId')"
+      >
+          <div class="pam-dialog-review">
+              <div class="mt-30 text--middle" v-if="agentInfo">
+                敺甇������<span class="text--bold">{{ consultantName }}</span>憿批�迤敹�葉嚗������蒂���隞“���
+              </div>
+
+                <el-row
+                  type="flex"
+                  class="mt-50"
+                  justify="center">
+                  <el-button
+                      type="primary"
+                      @click="reAppointment">��������隞“���</el-button>
+                </el-row>
+                <el-row
+                  type="flex"
+                  class="mt-20"
+                  justify="center">
+                  <el-button
+                      class="outline_btn"
+                      @click="cancelAppointment">������</el-button>
+                </el-row>
+          </div>
+      </PopUpFrame>
+
+      <PopUpFrame
+        :isOpen.sync="isShowReviewDialog"
+        @closePopUp="removeUrlQueryParameter('appointmentId')"
       >
           <div class="mdTxt pam-dialog-review">
               靽憿批�遛��漲
@@ -110,11 +137,16 @@
 
 <script lang="ts">
   import { Vue, Component, State, Action, Watch, namespace } from 'nuxt-property-decorator';
+  import { Appointment, AppointmentClosedInfo } from '~/shared/models/appointment.model';
   import { Consultant } from '~/shared/models/consultant.model';
-import { UserReviewsConsultantsParams } from '~/shared/models/reviews.model';
+  import { ContactStatus } from '~/shared/models/enum/contact-status';
+  import { UserReviewsConsultantsParams } from '~/shared/models/reviews.model';
+  import { StrictQueryParams } from '~/shared/models/strict-query.model';
   import appointmentService from '~/shared/services/appointment.service';
-import reviewsService from '~/shared/services/reviews.service';
+  import reviewsService from '~/shared/services/reviews.service';
   import UtilsService from '~/shared/services/utils.service';
+  import myConsultantService from '~/shared/services/my-consultant.service';
+import { AgentInfo } from '~/shared/models/agent-info.model';
 
   const localStorage = namespace('localStorage');
   const roleStorage = namespace('localStorage');
@@ -136,7 +168,8 @@
     @Action
     storeRecommendList!: any;
 
-    @Action storeConsultantList!: any;
+    @Action
+    storeConsultantList!: any;
 
     @localStorage.Mutation
     storageClearQuickFilter!: () => void;
@@ -147,37 +180,55 @@
     @localStorage.Getter
     currentSatisfactionIdFromMsg!: string;
 
+    @localStorage.Getter
+    currentNotContactAppointmentIdFromMsg!: string;
+
     @localStorage.Mutation
     storageClearSatisfactionIdFromMsg!: () => void;
 
+    @localStorage.Mutation
+    storageClearNotContactAppointmentIdFromMsg!: () => void;
+
+    @localStorage.Mutation
+    storageStrickQueryItem!: (strictQueryDto: StrictQueryParams) => void;
+
     consultantList: Consultant[] = [];
 
-    appointmentDetail: any = {
-        age               : '',
-        agentNo           : '',
-        appointmentDate   : '',
-        communicateStatus : '',
-        consultantReadTime: null,
-        consultantViewTime: null,
-        contactTime       : '',
-        contactType       : '',
-        customerId        : 0,
-        email             : '',
-        gender            : '',
-        hopeContactTime   : "",
-        id                : 0,
-        job               : "",
-        lastModifiedDate  : '',
-        name              : '',
-        otherRequirement  : null,
-        phone             : "",
-        requirement       : '',
-        satisfactionScore : 0,
+    appointmentDialogWidth    = '';
+    inputScore                = 0;
+    isShowAppointmentDialog   = false;
+    isShowReAppointmentDialog = false;
+    isShowReviewDialog        = false;
+    consultantName = '';
+    contactStatus = ContactStatus;
+
+    appointmentDetail: Appointment = {
+      age               : '',
+      agentNo           : '',
+      appointmentClosedInfo: {} as AppointmentClosedInfo,
+      appointmentDate   : '',
+      appointmentMemoList: [],
+      appointmentNoticeLogs: [],
+      communicateStatus : this.contactStatus.PICKED,
+      consultantReadTime: '',
+      consultantViewTime: '',
+      contactTime       : '',
+      contactType       : '',
+      customerId        : 0,
+      email             : '',
+      gender            : '',
+      hopeContactTime   : '',
+      interviewRecordDTOs: [],
+      id                : 0,
+      job               : '',
+      lastModifiedDate  : '',
+      name              : '',
+      otherRequirement  : '',
+      phone             : '',
+      requirement       : '',
+      satisfactionScore : 0,
     };
-    isVisibleDialog = false;
-    width = '';
-    reviewsBtn = false;
-    inputScore = 0;
+
     agentInfo: Consultant = {
       agentNo            : '',
       name               : '',
@@ -211,7 +262,7 @@
     }
 
     destroyed() {
-      this.clearSatisfactionId();
+      this.removeUrlQueryParameter();
     }
 
     //////////////////////////////////////////////////////////////////////
@@ -223,36 +274,81 @@
         .map((item) => ({ ...item, formatDate: new Date(item.updateTime || item.createTime)}))
         .sort((preItem, nextItem) => +nextItem.formatDate - +preItem.formatDate);
 
-      if (this.currentSatisfactionIdFromMsg) {
-        this.agentInfo = this.myConsultantList.filter(item => {
-          const satisfactionIdIndex = item.appointments?.findIndex(i => i.id === +this.currentSatisfactionIdFromMsg);
-          return satisfactionIdIndex !== undefined && satisfactionIdIndex > -1;
-        })[0];
-        if (this.agentInfo) {
-          this.openAppointmentInfo();
-        }
+      if (this.currentNotContactAppointmentIdFromMsg) {
+        this.autoOpenAppointmentBy('askReAppointment', +this.currentNotContactAppointmentIdFromMsg);
+        return;
+      }
 
+      if (this.currentSatisfactionIdFromMsg) {
+        this.autoOpenAppointmentBy('inviteReviewConsultant',+this.currentSatisfactionIdFromMsg);
+        this.storageClearSatisfactionIdFromMsg();
+        return;
       }
     }
 
-    private openAppointmentInfo() {
-        appointmentService.getAppointmentDetail(+this.currentSatisfactionIdFromMsg).then(res => {
-            this.appointmentDetail = res;
-            this.width = UtilsService.isMobileDevice() ? '80%' : '';
-            this.isVisibleDialog = true;
-
-            if (this.notScoreAppointmentYet) {
-              setTimeout(() => {
-                this.reviewsBtn = true;
-              }, 500)
-            }
+    private autoOpenAppointmentBy(reason: string, targetAppointmentId: number): void {
+        const setAgentInfo = new Promise((resolve, reject) => {
+          this.agentInfo = this.myConsultantList.filter(item => {
+            const appointmentIndex = item.appointments?.findIndex(i => i.id === targetAppointmentId);
+            return appointmentIndex !== undefined && appointmentIndex > -1;
+          })[0];
+          if (this.agentInfo) {
+            myConsultantService.getConsultantDetail(this.agentInfo.agentNo).then((res) => resolve(res));
+          }
         });
+
+        const setAppointment = new Promise((resolve, reject) => {
+           appointmentService.getAppointmentDetail(targetAppointmentId).then((res) => resolve(res));
+        });
+
+        Promise.all([setAgentInfo, setAppointment]).then((values) => {
+          const agentInfo = values[0] as AgentInfo;
+          const appointmentInfo = values[1] as Appointment;
+          this.consultantName = agentInfo.name;
+          this.appointmentDetail = appointmentInfo;
+          this.appointmentDialogWidth = UtilsService.isMobileDevice() ? '80%' : '';
+          this.isShowAppointmentDialog = true;
+          switch (reason) {
+            case 'inviteReviewConsultant':
+              if (this.notScoreAppointmentYet) {
+                setTimeout(() => {
+                  this.isShowReviewDialog = true;
+                }, 500);
+              }
+              break;
+            case 'askReAppointment':
+              setTimeout(() => {
+                this.isShowReAppointmentDialog = true;
+              }, 500);
+              break;
+          }
+        });
+
     }
 
     //////////////////////////////////////////////////////////////////////
 
     navigateToRoute(path: string): void {
       this.$router.push(path);
+    }
+
+    reAppointment(): void {
+      appointmentService.cancelAppointment(this.appointmentDetail.id).then(() => {
+        const requirements = this.appointmentDetail.requirement.split(',');
+        console.log('requirements', requirements)
+        this.storeConsultantList();
+        this.storageStrickQueryItem({ requirements: requirements });
+        this.storageClearNotContactAppointmentIdFromMsg();
+        this.$router.push('/recommendConsultant');
+      });
+    }
+
+    cancelAppointment(): void {
+      appointmentService.cancelAppointment(this.appointmentDetail.id).then(() => {
+        this.storeConsultantList();
+        this.storageClearNotContactAppointmentIdFromMsg();
+        this.$router.push('');
+      });
     }
 
     userReviewsConsultants() {
@@ -263,21 +359,22 @@
         this.appointmentDetail.satisfactionScore = this.inputScore;
 
         reviewsService.userReviewsConsultants(reviewParams).then((res) => {
-            this.reviewsBtn = false;
+            this.isShowReviewDialog = false;
         });
     }
 
-    clearSatisfactionId() {
-      // NOTE: ���摰�� query parameter [Tomas, 2022/1/24 11:36]
-      // [REF] How to remove a parameter from this.$router.query Nuxt.js? https://reurl.cc/X45aMD
+    removeUrlQueryParameter(targetKey?: string): void {
+        // NOTE: ���摰�� query parameter [Tomas, 2022/1/24 11:36]
+        // [REF] How to remove a parameter from this.$router.query Nuxt.js? https://reurl.cc/X45aMD
         let newRouteQuery = {};
-        Object.keys(this.$route.query).forEach((key) => {
-          if (key !== 'appointmentId') {
-            newRouteQuery[key] = this.$route.query[key]
-          }
-        })
+        if (targetKey) {
+          Object.keys(this.$route.query).forEach((key) => {
+            if (key !== targetKey) {
+              newRouteQuery[key] = this.$route.query[key]
+            }
+          })
+        }
         this.$router.push(newRouteQuery);
-        this.storageClearSatisfactionIdFromMsg();
     }
 
     ///////////////////////////////////////////////////////////////////////////////
diff --git a/PAMapp/shared/models/strict-query.model.ts b/PAMapp/shared/models/strict-query.model.ts
index 59892c1..45a5f31 100644
--- a/PAMapp/shared/models/strict-query.model.ts
+++ b/PAMapp/shared/models/strict-query.model.ts
@@ -1,14 +1,14 @@
 
 export interface StrictQueryParams {
-  gender          : string;
-  avgScore        : number;
-  status          : string;    //phase 1 disable
-  area            : string;
-  requirements    : string[];
-  otherRequirement: string;
-  seniority       : string;
-  popularTags     : string[];
-  otherPopularTags: string;
+  gender?          : string;
+  avgScore?        : number;
+  status?          : string;    //phase 1 disable
+  area?            : string;
+  requirements?    : string[];
+  otherRequirement?: string;
+  seniority?       : string;
+  popularTags?     : string[];
+  otherPopularTags?: string;
 }
 
 export interface AgentOfStrictQuery {
diff --git a/PAMapp/store/localStorage.ts b/PAMapp/store/localStorage.ts
index 9ad38e9..a08b69a 100644
--- a/PAMapp/store/localStorage.ts
+++ b/PAMapp/store/localStorage.ts
@@ -1,6 +1,7 @@
 import { Module, Mutation, VuexModule ,Action } from 'vuex-module-decorators';
 import { Role } from '~/shared/models/enum/Role';
 import { Selected } from '~/shared/models/quick-filter.model';
+import { StrictQueryParams } from '~/shared/models/strict-query.model';
 @Module
 export default class LocalStorage extends VuexModule {
   id_token = localStorage.getItem('id_token');
@@ -10,6 +11,7 @@
   recommendConsultantItem = localStorage.getItem('recommendConsultantItem');
   appointmentIdFromMsg = localStorage.getItem('appointmentIdFromMsg');
   satisfactionIdFromMsg = localStorage.getItem('satisfactionIdFromMsg');
+  notContactAppointmentIdFromMsg = localStorage.getItem('notContactAppointmentIdFromMsg');
 
   get idToken(): string|null {
     return this.id_token;
@@ -41,6 +43,10 @@
 
   get currentSatisfactionIdFromMsg(): string|null {
     return this.satisfactionIdFromMsg;
+  }
+
+  get currentNotContactAppointmentIdFromMsg(): string|null {
+    return this.notContactAppointmentIdFromMsg;
   }
 
   @Mutation storageIdToken(token: string): void {
@@ -78,6 +84,11 @@
     this.satisfactionIdFromMsg = localStorage.getItem('satisfactionIdFromMsg');
   }
 
+  @Mutation storageNotContactAppointmentIdFromMsg(id: string) {
+    localStorage.setItem('notContactAppointmentIdFromMsg', id);
+    this.notContactAppointmentIdFromMsg = id;
+  }
+
   @Mutation storageClear(): void {
     localStorage.removeItem('myRequests');
     localStorage.removeItem('userInfo');
@@ -112,6 +123,16 @@
     this.appointmentIdFromMsg = localStorage.getItem('satisfactionIdFromMsg');
   }
 
+  @Mutation storageClearNotContactAppointmentIdFromMsg() {
+    localStorage.removeItem('notContactAppointmentIdFromMsg');
+    this.appointmentIdFromMsg = localStorage.getItem('notContactAppointmentIdFromMsg');
+  }
+
+  @Mutation storageStrickQueryItem(queryItem: StrictQueryParams): void {
+    localStorage.setItem('recommendConsultantItem', JSON.stringify(queryItem));
+    this.recommendConsultantItem = localStorage.getItem('recommendConsultantItem');
+  }
+
   @Action actionStorageClear(): void {
     this.context.commit("storageClear");
   }

--
Gitblit v1.8.0