From 201a97a7379561b24c0699aa6f094711059b7ac5 Mon Sep 17 00:00:00 2001 From: Tomas <tomasysh@gmail.com> Date: 星期二, 01 三月 2022 14:16:53 +0800 Subject: [PATCH] fix#136100: [ 客戶端 ] 登入逾時問題 - 進行預約 跳出逾時登入的異常 --- PAMapp/pages/questionnaire/_agentNo.vue | 581 +++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 410 insertions(+), 171 deletions(-) diff --git a/PAMapp/pages/questionnaire/_agentNo.vue b/PAMapp/pages/questionnaire/_agentNo.vue index d746e44..bf703e4 100644 --- a/PAMapp/pages/questionnaire/_agentNo.vue +++ b/PAMapp/pages/questionnaire/_agentNo.vue @@ -1,10 +1,12 @@ <template> - <div class="ques-page--reset"> + <div class="ques-page--reset" v-if="isUserLogin"> <div class="ques-header"> <div class="ques-header__mob-banner"></div> - <div class="ques-header__info" v-if="myRequest.contactType==='phone'"> + <div + class="ques-header__info" + v-if="myRequest.contactType==='phone'"> <div class="text--middle"> - <div class="mdTxt">雿���蝜急撘�</div> + <div class="mdTxt">�����蝜急撘�</div> <div class="mt-10"> <span>�����</span> <span>{{myRequest.phone}}</span> @@ -14,32 +16,36 @@ <div class="datepicker required"> <span class="mdTxt">�����蝯∠�靘踵���</span> <PhoneContactTimePicker - :scheduleList.sync="myRequest.hopeContactTime"/> + :scheduleList="myRequest.hopeContactTime"/> </div> </div> <div class="mt-30"> <div class="mdTxt">�隞��蝜急撘�</div> <div class="ques-header__input-block"> <span>Email嚗�</span> - <input class="ques-header__input" + <input class="ques-header__input break" + :class="{ 'is-invalid': !emailValid}" placeholder="隢撓�" v-model="myRequest.email"> + </div> + <div class="error mt-5 mb-5" style="margin-left:65px"> + <span v-show="!emailValid">Email�撘�炊</span> </div> </div> </div> <div class="ques-header__info" v-else> <div class="text--middle"> - <div class="mdTxt">雿���蝜急撘�</div> + <div class="mdTxt">�����蝜急撘�</div> <div class="mt-10 ques-header__input-block"> <span>Email嚗�</span> - <span>{{myRequest.email}}</span> + <span class=" break">{{myRequest.email}}</span> </div> </div> <div class="mt-30"> <div class="mdTxt">�隞��蝜急撘�</div> <div class="ques-header__input-block"> - <span>�����</span> - <input class="ques-header__input" + <span>���� : </span> + <input class="ques-header__input ml-4" :class="{'is-invalid': !phoneValid}" placeholder="隢撓�" maxlength="10" @@ -49,11 +55,11 @@ <span v-show="!phoneValid">����Ⅳ�撘�炊</span> </div> </div> - <div class="mt-30" v-if="checkPhoneLength&&phoneValid"> + <div class="mt-30" v-if="myRequest.phone && phoneValid"> <div class="datepicker"> <span class="mdTxt">�����蝯∠�靘踵���</span> <PhoneContactTimePicker - :scheduleList.sync="myRequest.hopeContactTime"/> + :scheduleList="myRequest.hopeContactTime"/> </div> </div> </div> @@ -78,7 +84,7 @@ :options="genderOptions" /> </div> <div class="pam-paragraph"> - <div class="mdTxt">撟湧翩</div> + <div class="mdTxt">���僑朣�</div> <SingleSelectBtn class="mt-10" :singleSelected.sync="myRequest.age" :options="ageRangeOptions" /> @@ -88,14 +94,14 @@ </div> <div class="pam-paragraph ques-footer"> <el-button type="primary" - :disabled="isRequiredByInit || !phoneValid" + :disabled="isDisabledSubmitBtn" @click.native="sentDemand"> - � + {{isEditBtn ? '��' : '�'}} </el-button> </div> </div> - <PopUpFrame :isOpen.sync="showDrawer" :drawerSize=" '95%' "> + <PopUpFrame :isOpen.sync="showDrawer"> <div class="qaTextTitle mdTxt"> <strong>�閬岷������</strong> </div> @@ -113,27 +119,77 @@ </PopUpFrame> <PopUpFrame :isOpen.sync="sendReserve" @update:isOpen="closeReservePopUp"> - <div class="text--middle mt-30 sendReserve-txt">�����������憿批���</div> - <div class="text--middle sendReserve-txt">�����蝯∴��</div> + <div class="mdTxt mt-30 sendReserve-txt">�������</div> + <div class="mdTxt sendReserve-txt mb-30">�����“�������蝯∴��</div> + <div class="pam-app-review mb-10"> + <div class="mdTxt mb-10">撠 + <span class="mdTxt text--primary text--bold ">������</span> + 撟喳��擃���� + </div> + <div class="mdTxt">�蝯虫�嗾憿��嚗�</div> + </div> + <el-rate v-model="score" class="pam-satisfaction-rate fix-chrome-click--issue"></el-rate> <div class="text--center mdTxt"> + <el-button @click="closeReservePopUp">����</el-button> <el-button type="primary" - @click="closeReservePopUp"> - ������ + @click="reviewPlatform"> + � </el-button> </div> + </PopUpFrame> + + <PopUpFrame :isOpen.sync="isEditPopup"> + <div class="text--middle text--center mb-10">撌脫 + <span class="bold">{{appointmentTime | formatDate}}</span> + �脰�����</div> + <div class="text--middle text--center mb-30">��蝜潛�楊頛荔��</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 'vue-property-decorator'; - import { addFavoriteConsultant, appointmentDemand, AppointmentParams, AppointmentRequests ,RegisterInfo } from '~/assets/ts/api/consultant'; - import { getRequestsFromStorage, setRequestsToStorage } from '~/assets/ts/storageRequests'; - import { Gender } from '~/assets/ts/models/enum/Gender'; - import { ContactType } from '~/assets/ts/models/enum/ContactType'; - import _ from 'lodash'; +import { Vue, Component, State, Action, Watch, namespace } from 'nuxt-property-decorator'; +import { getRequestsFromStorage, removeRequestQuestionFromStorage, setRequestsToStorage } from '~/shared/storageRequests'; +import _ from 'lodash'; + +import accountSettingService from '~/shared/services/account-setting.service'; +import appointmentService from '~/shared/services/appointment.service'; +import authService from '~/shared/services/auth.service'; +import queryConsultantService from '~/shared/services/query-consultant.service'; +import reviewsService from '~/shared/services/reviews.service'; +import { Consultant } from '~/shared/models/consultant.model'; +import { ContactType } from '~/shared/models/enum/ContactType'; +import { Gender } from '~/shared/models/enum/Gender'; +import { RegisterInfo } from '~/shared/models/registerInfo'; +import { AppointmentParams, AppointmentRequests } from '~/shared/models/appointment.model'; +import { UserSetting } from '~/shared/models/account.model'; +import { SatisfactionType } from '~/shared/models/enum/satisfaction-type'; +import { UserReviewParams } from '~/shared/models/reviews.model'; + + const roleStorage = namespace('localStorage'); @Component export default class Questionnaire extends Vue { + @State('myConsultantList') + myConsultantList!: Consultant[]; + + @Action + storeConsultantList!: () => Promise<number>; + + @roleStorage.Getter + isUserLogin!:boolean; + + @roleStorage.State + recommendConsultantItem!:string; + + @roleStorage.Mutation + storageUserInfo!: (params: RegisterInfo) => void; + + score = 0; + genderOptions=[ { title:'���', @@ -144,6 +200,7 @@ label:Gender.FEMALE, } ]; + requirementOptions=[ { title:'�摨瑁����', @@ -166,10 +223,11 @@ label:'靽�瑼�/閬��', }, { - title:'��������', - label:'��������', + title:'����', + label:'����', }, ]; + ageRangeOptions=[ { title:'20甇脖誑銝�', @@ -188,10 +246,6 @@ label:'41-50' }, { - title:'46-55 甇�', - label:'46-55', - }, - { title:'51-60 甇�', label:'51-60', }, @@ -204,104 +258,243 @@ label:'over_71', } ]; + quesAboutList = [ - { - title:'�摨瑁����', - content:'蝒���������敺����犖��振摨剜����������������������靘��' - }, - { - title:'摮戊��', - content:'������嚗������� ���摮戊雿�����暑�������' - }, - { - title:'鞈閬��', - content:'�鞎∪�痊隞餃�������雲������������風嚗鈭箇����撥�����' - }, - { - title:'璅暑��隡�', - content:'��靽�������嚗��暑����車������犖�����挾���暑��閬��' - }, - { - title:'靽�瑼�/閬��', - content:'��瑼Z�撌梁������蝚血����靘�◢�蝘餉��瘙�������������銝��' - }, - { - title:'��靽', - content:'���漲��������翰�祟�敺����雿�憿批����脰�������蝯行�����潘��隞乩������“������潦��' - } + { + title:'�摨瑁����', + content:'����澈擃憿批末嚗�靽�兢蝳�嚗��������嚗��飩������摮拙��粥銝��頝荔�犖����迤閬����' + }, + { + title:'摮戊��', + content:'摮拙���������葦銋摮貊��撠靘�蒂�雿嚗飛���������������瓷嚗��楝銝���韏瑕飛��' + }, + { + title:'鞈閬��', + content:'��迤��瓷撖��雓寡�����嚗鈭箇�����蝳西瓷��◢�����Ⅱ靽�蝛拙��嚗�摰嗆��靘�末��皞���' + }, + { + title:'璅暑��隡�', + content:'�銝�頛拙����隡��摮���翰瘣鳴�停敺�����������隡瓷����撌勗�帘摰�嚗蝎曉蔗���僑鈭箇�������' + }, + { + title:'靽�瑼�/閬��', + content:'��瑼Z�撌梁������蝚血����靘�◢�蝘餉��瘙��' + }, + { + title:'����', + content:'���������憸券�����鈭怒�����嚗���摰帘摰漲嚗��隞亙��澈��ˊ�靽���嚗�' + } ]; - myRequest= { - phone:this.userInfo?.phone ? this.userInfo.phone :'', - email:this.userInfo?.email ? this.userInfo.email :'', - contactType:_.includes(this.userInfo.contactType,ContactType.SMS) ? ContactType.PHONE : ContactType.EMAIL , - gender: '', - age: '', - job: '', - requirement: [], + + myRequest: AppointmentRequests = { + name : '', + phone : '', + email : '', + contactType : _.isEqual(this.userInfo?.contactType,ContactType.SMS) ? ContactType.PHONE: ContactType.EMAIL, + gender : '', + age : '', + job : '', + requirement : [], hopeContactTime: [{ - selectWeekOptions:[], - selectTimesOptions:[], + selectWeekOptions : [], + selectTimesOptions: [], }], - agentNo:this.$route.params.agentNo, + agentNo: '', }; showDrawer= false; sendReserve = false; + isEditPopup = false; + isEditBtn = false; - mounted() { + appointmentId = 0; + appointmentTime = ''; + + //////////////////////////////////////////////////////////////////////////// + + beforeRouteEnter(to: any, from: any, next: any) { + next(vm => { + const isUserLogin = authService.isUserLogin(); + if (from.name === 'login' && !isUserLogin) { + vm.$router.go(-1); + return; + } + + if (!isUserLogin) { + vm.$router.push('/login'); + } + }) + } + + mounted(): void { + if (authService.isUserLogin()) { + this.storeConsultantList(); + }; + this.setMyRequest(); + } + + private setMyRequest(): void { const storageMyRequest = getRequestsFromStorage(); + const storageMyRequirement = this.recommendConsultantItem ? JSON.parse(this.recommendConsultantItem).requirements:[]; + if (storageMyRequest) { - this.myRequest = storageMyRequest; + this.myRequest = { + ...storageMyRequest, + hopeContactTime: storageMyRequest.hopeContactTime?.length + ? storageMyRequest.hopeContactTime + : [{ + selectWeekOptions: [], + selectTimesOptions: [], + }], + }; + } + + if (storageMyRequirement) { + this.myRequest = { + ...this.myRequest, + requirement: storageMyRequirement + } + removeRequestQuestionFromStorage(); + } + + if (authService.isUserLogin()) { + accountSettingService.getUserAccountSetting().then((contactTypeDetail) => { + this.myRequest = { + ...this.myRequest, + ...contactTypeDetail + } + }) + } + + + } + + //////////////////////////////////////////////////////////////////////////// + + @Watch('myConsultantList') + onMyConsultantListChange() { + if (authService.isUserLogin() && this.myConsultantList.length > 0) { + const editAppointment = this.getLatestReserved(this.$route.params.agentNo); + + if (editAppointment && editAppointment.agentNo) { + this.myRequest = JSON.parse(JSON.stringify(editAppointment)); + if (!this.$route.query || this.$route.query.edit !== 'true') { + this.isEditPopup = true; + } + this.isEditBtn = true; + } } } - get phoneValid():boolean{ - const rule = /^09[0-9]{8}$/; - return this.myRequest.phone ? rule.test(this.myRequest.phone) : true; - } - get userInfo():RegisterInfo{ - const initUserInfo = JSON.parse(localStorage.getItem('userInfo')); - return initUserInfo; + + 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 === 'reserved') + .map((reversedAppointment) => ( + { ...reversedAppointment, + sortDate: new Date(reversedAppointment.appointmentDate) + })) + .sort((preAppointment, nextAppointment) => +nextAppointment.sortDate - +preAppointment.sortDate)[0] + : null; + return this.getReservedData(appointmentInfo); } - get isMainContractPhoneByLocalStorage():boolean{ - return true; + private getReservedData(appointmentInfo) { + if (appointmentInfo) { + const hopeContactTime = appointmentInfo!.hopeContactTime.split("'") + .filter(item => item && item !== ','); + this.getAppointmentId(appointmentInfo); + + return { + ...appointmentInfo, + hopeContactTime: hopeContactTime.map(item => { + const info = item.split('��'); + return { + selectWeekOptions: info[0].split(','), + selectTimesOptions: info[1].split(',') + } + }), + requirement: appointmentInfo.requirement.split(',') + } + } else { + return null; + } } - get isRequiredByInit():boolean{ - return _.includes(this.myRequest.contactType,ContactType.PHONE) - ? !this.isHopeContactTimeDone() - :false; + private getAppointmentId(appointmentInfo) { + this.appointmentId = appointmentInfo.id; + this.appointmentTime = appointmentInfo.lastModifiedDate + ? appointmentInfo.lastModifiedDate + : appointmentInfo.appointmentDate; } - get checkPhoneLength():boolean{ - return _.isEqual(this.myRequest.phone.length,10); - } - private isHopeContactTimeDone():boolean{ - return this.myRequest.hopeContactTime[0].selectWeekOptions.length >0 && this.myRequest.hopeContactTime[0].selectTimesOptions.length >0; - } - + + //////////////////////////////////////////////////////////////////////////// sentDemand() { - addFavoriteConsultant([this.myRequest.agentNo]).then(res => this.sentAppointmentDemand()); + if (this.isEditBtn) { + this.editAppointmentDemand(); + } else { + queryConsultantService.addFavoriteConsultant([{ agentNo: this.$route.params.agentNo, createdTime: new Date().toISOString()}]).then(res => this.sentAppointmentDemand()); + } + const editSettingInfo: UserSetting = { + name: this.myRequest.name, + phone: this.myRequest.phone, + email: this.myRequest.email, + } + + accountSettingService.updateAccountSetting(editSettingInfo).then((_) => { + this.storageUserInfo(this.userInfo); + }); + } + + private editAppointmentDemand() { + 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 + } + appointmentService.editAppointment(info).then(res => { + this.sendReserve = true; + this.myRequest.hopeContactTime = []; + setRequestsToStorage(this.myRequest); + }); } private sentAppointmentDemand() { - const data: AppointmentParams = { ...this.myRequest, requirement: _.map(this.myRequest.requirement,o=>o).toString(), - hopeContactTime:this.phoneValid&&this.checkPhoneLength ? this.getHopeContactTime() :'', + hopeContactTime: this.myRequest.phone && this.phoneValid ? this.getHopeContactTime() :'', + agentNo: this.$route.params.agentNo }; - appointmentDemand(data).then(res => { + queryConsultantService.appointmentDemand(data).then(res => { this.sendReserve = true; + this.myRequest.hopeContactTime = []; + this.appointmentId = res['id']; setRequestsToStorage(this.myRequest); }); } - getHopeContactTime() { - return this.myRequest.hopeContactTime.map(i => { + private getHopeContactTime() { + const selectedHopeContactTime = this.myRequest.hopeContactTime.filter((i) => i.selectWeekOptions?.length && i.selectTimesOptions?.length); + return selectedHopeContactTime.map(i => { return `'${i.selectWeekOptions}��${i.selectTimesOptions}'`} ).toString(); + } + + reviewPlatform(): void { + const reviewPlatformParams: UserReviewParams = { + appointmentId: this.appointmentId, + score: this.score, + type: SatisfactionType.SYSTEM + }; + reviewsService.reviewPlatform(reviewPlatformParams).then((_) => { + this.closeReservePopUp(); + }); } closeReservePopUp() { @@ -309,37 +502,64 @@ this.$router.push('/') } - } + //////////////////////////////////////////////////////////////////////////// - export interface SelectedQuestion { - name: string; - selected: boolean; + get phoneValid(): boolean { + const rule = /^09[0-9]{8}$/; + return this.myRequest.phone + ? rule.test(this.myRequest.phone) && _.isEqual(this.myRequest.phone.length,10) + : true; + } + + get emailValid() { + const rule = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; + return this.myRequest.email ? rule.test(this.myRequest.email) : true; + } + + get userInfo(): RegisterInfo { + const initUserInfo = JSON.parse(localStorage.getItem('userInfo')!); + return initUserInfo; + } + + get isDisabledSubmitBtn(): boolean { + return _.includes(this.myRequest.contactType,ContactType.PHONE) + ? !this.isHopeContactTimeDone() || !this.emailValid + : !this.phoneValid; + } + + private isHopeContactTimeDone():boolean{ + return this.myRequest.hopeContactTime[0]?.selectWeekOptions.length >0 && this.myRequest.hopeContactTime[0]?.selectTimesOptions.length >0; + } + } </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; } +//drawer��摨���見撘� .qa-dialog-footer{ - display: flex; - justify-content: center; - margin-bottom: 81px; - color: #ED1B2E; - cursor: pointer; -}//drawer��摨���見撘� - + display: flex; + justify-content: center; + margin-bottom: 81px; + color: #ED1B2E; + cursor: pointer; +} +.error { + color:$PRIMARY_RED +} +//����見撘���� .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; @@ -362,47 +582,50 @@ border-style: solid; pointer-events: none; } - } -}//����見撘���� + } +} +//閰喟敦���rawer銝剝�摰寧征��之撠身蝵� .qa-dialog{ - overflow-y:auto; - height: 500px; - margin-top: 20px; -}//閰喟敦���rawer銝剝�摰寧征��之撠身蝵� + overflow-y:auto; + height: 60vh; + margin-top: 20px; +} +//閰喟敦���rawer銝餉���� .qaTextTitle{ - margin-top:30px; - display: flex; - justify-content: center; -}//閰喟敦���rawer銝餉���� - -.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); + } +} +.break{ + word-break: break-all; + line-height: 1.2; +} +.ques-page--reset.pam-page-container { + margin: 0px auto; } -.ques-page--reset.pam-page-container{ - margin: 0px auto; +.ques-header { + position: relative; } -.ques-header{ - position: relative; -} -.ques-header__mob-banner{ + +.ques-header__mob-banner { width: 100%; min-height: 80px; background-color: #F8F9FA; @@ -411,40 +634,54 @@ background-size: cover; 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-header__input-block { + display: flex; + align-items: center; + @extend .text--middle,.mt-10 ; + .ques-header__input{ + &.is-invalid{ + border: 1px 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; + } + } + .ml-4{ + margin-left: 4px; + } + .ques-container { + position: relative; + margin: 0px 20px; + } + +.pam-app-review{ + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; } -.ques-container{ - position: relative; - margin: 0px 20px; +.pam-satisfaction-rate{ + margin-bottom: 45px; } - -@include desktop{ + @include desktop{ .ques-header{ display: flex; justify-content: flex-end; @@ -470,4 +707,6 @@ } } + </style> + -- Gitblit v1.8.0