From b4d6944076f1df6eedaae35c4c2a7072fe988e8a Mon Sep 17 00:00:00 2001 From: Tomas <tomasysh@gmail.com> Date: 星期二, 30 四月 2024 15:34:02 +0800 Subject: [PATCH] update: package-lock.json --- PAMapp/components/Client/ClientCard.vue | 347 ++++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 219 insertions(+), 128 deletions(-) diff --git a/PAMapp/components/Client/ClientCard.vue b/PAMapp/components/Client/ClientCard.vue index 6d7e821..5889940 100644 --- a/PAMapp/components/Client/ClientCard.vue +++ b/PAMapp/components/Client/ClientCard.vue @@ -6,7 +6,7 @@ class="rowStyle cursor--pointer" justify="space-between" :class="{'new': newAppointment }" - @click.native="viewDetail" + @click.native="viewAppointmentDetail" > <div class="test"> <div class="unread" v-if="isReserved"> @@ -14,9 +14,23 @@ </div> <div class="pl-10"> - <div class="smTxt_bold name">{{ client.name }}</div> - <div class="my-10 xsTxt">������</div> - <div class="professionals"> + <div class="smTxt_bold name">{{ client.name || 'NO NAME' }}</div> + <div v-if="client.communicateStatus === contactStatus.RESERVED" class="my-10 xsTxt">������</div> + <div + class="xsTxt mb-10 mt-10" + v-else-if="client.communicateStatus === contactStatus.CONTACTED"> + 蝝赤蝝���� + </div> + <div + class="xsTxt mb-10 mt-10" + v-else> + 皛踵�漲 + <span v-if="client.satisfactionScore" class="xsTxt text--primary"> + <UiReviewScore :score="client.satisfactionScore"></UiReviewScore> + </span> + <span v-else class="xsTxt text--mid_grey">�憛�</span> + </div> + <div class="professionals mb-10" v-if="client.communicateStatus === contactStatus.RESERVED"> <template v-if="client.requirement"> <span v-for="(item, index) in requirements" @@ -30,7 +44,7 @@ </template> </div> <AppointmentProgress - :currentStep="'contacted'" + :currentStep="client.communicateStatus" ></AppointmentProgress> </div> </div> @@ -40,7 +54,6 @@ ></el-avatar> <div class="satisfaction" v-if="!hideReviews"> <template v-if="client.satisfactionScore"> - TODO:���遛��漲 <i class="icon-star pam-icon icon--yellow satisfaction"></i> <span>{{client.satisfactionScore}}</span> </template> @@ -51,13 +64,26 @@ </el-col> --> <div class="flex-column contactInfo" :xs="4" :sm="6"> - <!-- <div - class="smTxt_bold fix-chrome-click--issue" - :class="{'unread-txt': reservedTxt === '�霈�', 'read-txt': reservedTxt !== '�霈�'}" - >{{ reservedTxt }}</div> --> - <div class="invite-msg smTxt_bold"> - ���赤� + + <div + class="invite-msg smTxt_bold" + @click.stop="showAddInterviewDialog" + v-if="client.communicateStatus === contactStatus.RESERVED"> + ���赤� </div> + <div + class="invite-msg smTxt_bold" + @click.stop="navigateToCloseAppointment" + v-else-if="client.communicateStatus === contactStatus.CONTACTED"> + 蝯�� + </div> + <!-- <div + class="invite-msg smTxt_bold" + @click.stop="inviteReview" + v-else-if="!client.satisfactionScore"> + ��遛��漲 + </div> --> + <div class="date xsTxt text--black" >{{ date }}</div> @@ -68,9 +94,9 @@ </el-row> <Ui-Dialog - :isVisible.sync="isVisibleDialog" + :isVisible.sync="isShowInformDialog" :width="dialogWidth" - @closeDialog="closeDialog" + @closeDialog="closeInformDialog" class="pam-myDemand-dialog" > <h5 class="subTitle text--center mb-30" @@ -92,7 +118,8 @@ <p>�批嚗�<span>{{gender}}</span></p> <p>撟湧翩嚗�<span>{{client.age | toAgeLabel }}</span></p> <p>�璆哨��<span>{{client.job}}</span></p> - <p>��瘙��<span>{{client.requirement.split(',').join('��')}}</span></p> + <p>隢株岷�撘��<span>{{client.consultationMethod | toConsultationMethod }}</span></p> + <p>��瘙��<span>{{ client.requirement ? client.requirement.split(',').join('��') : '--' }}</span></p> <p v-for="(item, index) in hopeContactTime" :key="index" >��蝯⊥�挾{{index + 1 | formatNumber}}嚗�<span>{{ item | formatHopeContactTime}}</span></p> @@ -128,20 +155,35 @@ <el-button @click="markAppointment">璅酉�撌脤��蝯�</el-button> </div> </Ui-Dialog> + + <InterviewMsg + :client="client" + :isVisible.sync="isShowAddInterviewDialog"> + </InterviewMsg> + <PopUpFrame :isOpen.sync="isShowInviteReviewDialog"> + <div class="text--middle invite-review"> + <div class="mb-30 mt-10">撌脩�遛��漲</div> + <div class="text--primary text--middle cursor--pointer text--underline" @click="isShowInviteReviewDialog = false" :size="'250px'">������</div> + </div> + </PopUpFrame> </div> </template> <script lang="ts"> -import { Vue, Component, Prop, Action, namespace, Watch } from 'nuxt-property-decorator'; +import { Vue, Component, Prop, namespace, Watch } from 'nuxt-property-decorator'; import appointmentService from '~/shared/services/appointment.service'; +import myConsultantService from '~/shared/services/my-consultant.service'; import UtilsService from '~/shared/services/utils.service'; import { hideReviews } from '~/shared/const/hide-reviews'; -import { AppointmentMemoInfo, ClientInfo } from '~/shared/models/client.model'; -import myConsultantService from '~/shared/services/my-consultant.service'; import { ElRow } from 'element-ui/types/row'; +import { Appointment, AppointmentMemoInfo } from '~/shared/models/appointment.model'; +import { ContactStatus } from '~/shared/models/enum/contact-status'; +import reviewsService from '~/shared/services/reviews.service'; -const localStorage = namespace('localStorage'); +const appointmentStore = namespace('appointment.store'); +const localStorage = namespace('localStorage'); + @Component({ filters: { formatNumber(index: number) { @@ -162,26 +204,39 @@ } }) export default class ClientList extends Vue { - @Action - updateMyAppointment!: (data: ClientInfo) => void; - @Prop() - client!: ClientInfo; + client!: Appointment; + + @appointmentStore.Action + updateMyAppointmentList!: (data: Appointment) => void; + + @appointmentStore.Action + getAppointmentDetail!: (appointmentId: number) => Promise<Appointment>; + + @appointmentStore.Action + updateAppointmentDetail!: (id: number) => Appointment; + + @appointmentStore.Getter + appointmentProgress!: ContactStatus; @localStorage.Mutation storageClearAppointmentIdFromMsg!: () => void; - isVisibleDialog = false; - dialogWidth = ''; - hideReviews = hideReviews; + contactStatus = ContactStatus; - isEdit = false; + dialogWidth = ''; + hideReviews = hideReviews; + isEdit = false; + isShowAddInterviewDialog = false; + isShowInformDialog = false; + isShowInviteReviewDialog = false; + memo = ''; + memoInfo: AppointmentMemoInfo = { appointmentId: 0, - content: '', - id: 0 - } - memo = ''; + content : '', + id : 0 + }; ////////////////////////////////////////////////////////////////////// @@ -204,63 +259,30 @@ ////////////////////////////////////////////////////////////////////// - viewDetail(): void { - this.$router.push(`/appointment/${this.client.id}`); - } - - get newAppointment(): boolean { - return !this.client.consultantViewTime - && this.client.communicateStatus === 'reserved'; - } - - get isReserved() { - return this.client.communicateStatus === 'reserved'; - } - - get isRead() { - return !!this.client.consultantReadTime; - } - - get requirements() { - return this.client.requirement.split(','); - } - - get gender() { - if (this.client.gender) { - return this.client.gender === 'male' ? '���' : '憟單��'; + viewAppointmentDetail(): void { + this.getAppointmentDetail(this.client.id).then((_) => { + const unread = !this.client.consultantReadTime; + if (unread) { + this.readAppointment(); } - return ''; + this.$router.push(`/appointment/${this.client.id}`); + }); } - get hopeContactTime() { - const contactList = this.client.hopeContactTime.split("'").map(item => item.slice(0, item.length)); - return contactList.filter(item => !!item && item !== ",") + showAddInterviewDialog(): void { + this.isShowAddInterviewDialog = true; } - get reservedTxt(): string { - if (this.isReserved) { - return this.client.consultantReadTime ? '撌脰�' : '�霈�'; - } else { - return '撌脰蝯�' - } + navigateToCloseAppointment(): void { + this.getAppointmentDetail(this.client.id).then((_) => { + this.$router.push(`/appointment/${this.client.id}/close`); + }); } - get displayTime(): string { - if (this.isReserved) { - return this.client.appointmentDate; - } else { - return this.client.lastModifiedDate; - } - } - - get time() { - const formatDate = (this.$options.filters as any).formatDate(this.displayTime); - return formatDate.split(' ')[1] - } - - get date() { - const formatDate = (this.$options.filters as any).formatDate(this.displayTime); - return formatDate.split(' ')[0]; + inviteReview(): void { + reviewsService.sendSatisfactionToClient(this.client.id).then(res => { + this.isShowInviteReviewDialog = true ; + }) } openDetail() { @@ -268,28 +290,40 @@ (this.$refs.clientCardRef as any).$el.classList.add('currentShowStyle'); }, 0) this.dialogWidth = UtilsService.isMobileDevice() ? '80%' : ''; - this.isVisibleDialog = true; + this.isShowInformDialog = true; } markAppointment() { myConsultantService.markAsContact(this.client.id).then(data => { - this.updateMyAppointment(data); - this.isVisibleDialog = false; + this.updateMyAppointmentList(data); + this.isShowInformDialog = false; }) } - closeDialog(): void { - const unread = !this.client.consultantReadTime; - if (unread) { - appointmentService.recordRead(this.client.id).then((_) => { - const updatedClient = {...this.client}; - updatedClient.consultantReadTime = new Date().toString(); - this.updateMyAppointment(updatedClient); - }); - }; + closeInformDialog(): void { + this.readAppointment(); this.isEdit = false; this.clearAppointmentIdFromMsg(); } + + private async readAppointment(): Promise<void> { + try { + const response = await appointmentService.recordRead(this.client.id); + if (response !== null) { + const updatedClient = { ...this.client }; + updatedClient.consultantReadTime = new Date().toString(); + this.updateMyAppointmentList(updatedClient); + this.updateAppointmentDetail(this.client.id); + } else { + throw new Error('appointmentService.recordRead returned null-like value.'); + } + } catch (error) { + console.error('An error occurred while reading appointment:', error); + // �隞亙甇方���隤斗����身�� + throw error; + } + } + private clearAppointmentIdFromMsg() { this.storageClearAppointmentIdFromMsg(); @@ -345,54 +379,113 @@ this.memo = this.memoInfo.content; } + get newAppointment(): boolean { + return !this.client.consultantViewTime + && this.client.communicateStatus === 'reserved'; + } + + get isReserved() { + return this.client.communicateStatus === 'reserved'; + } + + get isRead() { + return !!this.client.consultantReadTime; + } + + get requirements() { + return this.client.requirement ? this.client.requirement.split(',') : []; + } + + get gender() { + if (this.client.gender) { + return this.client.gender === 'male' ? '���' : '憟單��'; + } + return ''; + } + + get hopeContactTime() { + const contactList = this.client.hopeContactTime.split("'").map(item => item.slice(0, item.length)); + return contactList.filter(item => !!item && item !== ",") + } + + get reservedTxt(): string { + if (this.isReserved) { + return this.client.consultantReadTime ? '撌脰�' : '�霈�'; + } else { + return '撌脰蝯�' + } + } + + get displayTime(): string { + if (this.isReserved) { + return this.client.appointmentDate; + } else { + return this.client.lastModifiedDate; + } + } + + get date() { + const formatDate = (this.$options.filters as any).formatDate(this.displayTime); + return formatDate.split(' ')[0]; + } + + get time() { + const formatDate = (this.$options.filters as any).formatDate(this.displayTime); + return formatDate.split(' ')[1] + } + } </script> <style lang="scss" scoped> .rowStyle { - padding: 10px 15px 10px 5px; background-color: $PRIMARY_WHITE; - margin-bottom: 10px; - display: flex; - justify-content: space-between; - + border-left : solid 4px transparent; + display : flex; + justify-content : space-between; + margin-bottom : 10px; + padding : 10px 15px 10px 5px; transition: background-color 0.5s; &.new { - border-left: solid 4px $YELLOW; + border-color: $YELLOW; } &.currentShowStyle { background-color: rgba(236, 195, 178, 0.5); - transition: background-color 0.5s; + transition : background-color 0.5s; } .unread { align-self: center; .circle { - width: 10px; - height: 10px; - border-radius: 50%; background-color: $PRIMARY_RED; - margin: auto; + border-radius : 50%; + height : 10px; + margin : auto; + width : 10px; } } .satisfaction { - font-size: 12px; + font-size : 12px; font-weight: bold; - margin-top: 5px; + margin-top : 5px; .unfilled { + color : $MID_GREY; font-weight: lighter; - color: $MID_GREY; } } .professionals { - overflow: hidden; - white-space: nowrap; + overflow : hidden; text-overflow: ellipsis; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; .professionalsTxt { - font-size: 12px; + font-size : 12px; margin-right: 5px; + + } .noProfessionalsTxt { - color: $PRUDENTIAL_GREY; + color : $PRUDENTIAL_GREY; font-weight: lighter; } } @@ -410,24 +503,23 @@ } } .flex-column { - display: flex; - flex-direction: column; + display : flex; + flex-direction : column; justify-content: space-between; } .dialogTxt { - font-size: 20px; - overflow-y:scroll; + font-size : 20px; max-height: 25vh; + overflow-y: scroll; @include desktop { height: 400px; } } .memoTitleStyle { - display: flex; - flex-direction: row; + display : flex; + flex-direction : row; justify-content: space-between; - - .edit { + .edit { align-self: flex-end; } } @@ -438,14 +530,13 @@ display: flex; } .invite-msg{ - color: #ED1B2E; - border-bottom: 1px solid #ED1B2E; - width: 97px; + width: 96px; + color: $PRIMARY_RED; + @extend .text--underline; } - .line{ - height: 4px; - width: 10px; - background-color: $PRUDENTIAL_GREY; - - } + .invite-review{ + align-items : center; + display : flex; + flex-direction: column; + } </style> -- Gitblit v1.8.0