PAMapp/assets/ts/api/appointment.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/components/Client/ClientCard.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/pages/myAppointmentList.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/pages/myAppointmentList/appointmentList.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/pages/myAppointmentList/contactedList.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/store/index.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 |
PAMapp/assets/ts/api/appointment.ts
@@ -19,6 +19,22 @@ .then(res => res.data) } // 顧問登入顯示新預約單筆數後觸發 export function allAppointmentsView() { const headers = { Authorization: 'Bearer ' + localStorage.getItem('id_token') } return service.post('/consultant/record/allAppointmentsView', undefined, {headers}) } // 讀取預約單時觸發 export function recordRead(appointmentId: number) { const headers = { Authorization: 'Bearer ' + localStorage.getItem('id_token') } return service.post('/appointment/recordRead/' + appointmentId, undefined, {headers}) } export interface ClientInfo { id: number, @@ -35,5 +51,9 @@ appointmentDate: Date, agentNo: string, customerId: number, name: string name: string, consultantViewTime: Date, consultantReadTime: Date, contactTime: Date, satisfactionScore: number } PAMapp/components/Client/ClientCard.vue
@@ -1,18 +1,28 @@ <template> <div> <el-row type="flex" class="rowStyle" @click.native="openDetail"> <el-col :xs="5" :sm="3"> <el-row type="flex" class="rowStyle cursor--pointer" justify="space-between" :class="{'new': !isView && isReserved}" @click.native="openDetail" > <el-col :xs="1" :sm="1" class="unread" align="middle"> <div class="circle" v-if="isReserved && !isRead"></div> </el-col> <el-col :xs="4" :sm="2" align="middle"> <el-avatar :size="50" src="" class="cursor--pointer fix-chrome-click--issue" ></el-avatar> <!-- <div class="satisfaction"> <i class="icon-star pam-icon icon--yellow satisfaction"></i> <span>{{'1'}}</span> </div> --> <div class="satisfaction"> <template v-if="client.satisfactionScore"> <i class="icon-star pam-icon icon--yellow satisfaction"></i> <span>{{client.satisfactionScore}}</span> </template> </div> </el-col> <el-col :xs="14" :sm="15"> <el-col :xs="15" :sm="15" class="pl-10"> <div class="smTxt_bold name">{{client.name}}</div> <div class="message">預約成功</div> <div class="professionals"> @@ -29,33 +39,49 @@ </template> </div> </el-col> <el-col class="flex-column contactInfo" :xs="5" :sm="6"> <div class="smTxt_bold cursor--pointer fix-chrome-click--issue" :class="client.communicateStatus" >{{isReserved ? '已預約' : '已聯絡'}} </div> <div class="date xsTxt text--mid_grey">{{date}}</div> <div class="xsTxt text--mid_grey">{{time}}</div> <el-col 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="date xsTxt text--mid_grey" >{{date}}</div> <div class="xsTxt text--mid_grey" >{{time}}</div> </el-col> </el-row> <Ui-Dialog :isVisible.sync="isVisibleDialog" :width="width" @closeDialog="close" class="pam-myDemand-dialog" > <h5 class="subTitle text--center mb-30" >{{isReserved ? '預約成功' : '已聯絡資訊'}}</h5> <p class="smTxt text-right">{{client.appointmentDate | formatDate}}</p> <p v-if='isReserved' class="smTxt text-right" ><span v-if="isRead">{{client.consultantReadTime | formatDate}}</span> 已讀</p> <p v-if="!isReserved" class="smTxt text-right" >{{client.contactTime | formatDate}} 聯絡</p> <p class="smTxt">{{client.appointmentDate | formatDate}} 預約</p> <div class="dialogTxt"> <p>姓名:{{client.name}}</p> <p>電話:{{client.phone}}</p> <p>Email:{{client.email}}</p> <p>性別:{{gender}}</p> <p>年齡:{{client.age | toAgeLabel }}</p> <p>職業:{{client.job}}</p> <p>需求:{{client.requirement.split(',').join('、')}}</p> <p v-for="(item, index) in hopeContactTime" :key="index">連絡時段{{index + 1 | formatNumber}}:{{ item | formatHopeContactTime}}</p> <p>姓名:<span>{{client.name}}</span></p> <p>電話:<span>{{client.phone}}</span></p> <p>Email:<span>{{client.email}}</span></p> <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 v-for="(item, index) in hopeContactTime" :key="index" >連絡時段{{index + 1 | formatNumber}}:<span>{{ item | formatHopeContactTime}}</span></p> </div> <div class="mt-30 text--center" v-if="isReserved"> <el-button @click="markAppointment">標註為已連絡</el-button> @@ -67,7 +93,7 @@ <script lang="ts"> import { Vue, Component, Prop, Mutation, Action } from 'nuxt-property-decorator'; import { isMobileDevice } from '~/assets/ts/device'; import { ClientInfo, markAsContact } from '~/assets/ts/api/appointment'; import { ClientInfo, markAsContact, recordRead } from '~/assets/ts/api/appointment'; @Component({ filters: { @@ -90,6 +116,7 @@ }) export default class ClientList extends Vue { @Action updateMyAppointment!: (data: ClientInfo) => void @Action storeConsultantList!: () => void; @Prop() client!: ClientInfo; isVisibleDialog = false; @@ -111,18 +138,42 @@ return contactList.filter(item => !!item && item !== ",") } get isReserved() { return this.client.communicateStatus === 'reserved'; } get isRead() { return !!this.client.consultantReadTime; } get isView() { return !!this.client.consultantViewTime; } get reservedTxt() { if (this.isReserved) { return this.client.consultantReadTime ? '已讀' : '未讀'; } else { return '已聯絡' } } get latestUpdateTime() { if (this.isReserved) { return this.client.consultantReadTime ? this.client.consultantReadTime : this.client.appointmentDate; } else { return this.client.contactTime; } } get time() { const formatDate = (this.$options.filters as any).formatDate(this.client.appointmentDate); const formatDate = (this.$options.filters as any).formatDate(this.latestUpdateTime); return formatDate.split(' ')[1] } get date() { const formatDate = (this.$options.filters as any).formatDate(this.client.appointmentDate); return formatDate.split(' ')[0] } get isReserved() { return this.client.communicateStatus === 'reserved'; const formatDate = (this.$options.filters as any).formatDate(this.latestUpdateTime); return formatDate.split(' ')[0]; } openDetail() { @@ -136,7 +187,7 @@ const updatedClient = {...this.client}; updatedClient.communicateStatus = 'contacted'; updatedClient.appointmentDate = new Date(); updatedClient.contactTime = new Date(); this.updateMyAppointment(updatedClient); this.isVisibleDialog = false; @@ -144,16 +195,43 @@ }) } close() { if (!this.client.consultantReadTime) { recordRead(this.client.id).then(res => { const updatedClient = {...this.client}; updatedClient.consultantReadTime = new Date(); this.updateMyAppointment(updatedClient); }); } } } </script> <style lang="scss" scoped> .rowStyle { padding: 10px; padding: 10px 15px 10px 5px; background-color: $PRIMARY_WHITE; margin-bottom: 10px; display: flex; justify-content: space-between; &.new { border-left: solid 4px $YELLOW; } .unread { align-self: center; .circle { width: 10px; height: 10px; border-radius: 50px; background-color: $PRIMARY_RED; margin: auto; } } .satisfaction { font-size: 12px; @@ -189,13 +267,14 @@ } } .reserved { .unread-txt { @extend .text--primary; } .contacted { .read-txt { color: $SKY_BLUE; } } .flex-column { @@ -212,7 +291,6 @@ height: 400px; } } .text-right { text-align: right; PAMapp/pages/myAppointmentList.vue
@@ -21,12 +21,26 @@ <NuxtChild></NuxtChild> </div> <PopUpFrame :isOpen.sync="showNewAppointmentNumber" > <div class="text--center mdTxt"> <p class="mb-50">你有 <span class="text--primary">{{newAppointmentNumber}}</span> 則新的預約</p> <div class="text--center"> <el-button type="primary" @click="showNewAppointmentNumber = false" >我知道了</el-button> </div> </div> </PopUpFrame> </div> </template> <script lang="ts"> import { Vue, Component, State, Action, Watch } from 'nuxt-property-decorator'; import { ClientInfo } from '~/assets/ts/api/appointment'; import { allAppointmentsView, ClientInfo } from '~/assets/ts/api/appointment'; import * as _ from 'lodash'; @Component({ @@ -37,12 +51,20 @@ appointmentList: ClientInfo[] = []; contactedList: ClientInfo[] = []; clients: ClientInfo[] = []; newAppointmentNumber: number = 0; showNewAppointmentNumber = false; @State('myAppointmentList') myAppointmentList!: ClientInfo[]; @Action storeMyAppointmentList!: any; @Action storeMyAppointmentList!: () => Promise<number>; mounted() { this.storeMyAppointmentList(); this.storeMyAppointmentList().then(newDataLength => { this.newAppointmentNumber = newDataLength; if (this.newAppointmentNumber > 0) { this.showNewAppointmentNumber = true; allAppointmentsView().then(res => res); } }); if (this.$route.name) { this.activeTabName = this.$route.name.split('-')[1] @@ -52,11 +74,10 @@ @Watch('myAppointmentList') onMyAppointmentListChange() { this.contactedList = this.myAppointmentList .filter(item => item.communicateStatus === 'contacted') .sort((a, b) => a.appointmentDate > b.appointmentDate ? -1 : 1); .filter(item => item.communicateStatus === 'contacted'); this.appointmentList = this.myAppointmentList .filter(item => item.communicateStatus !== 'contacted') .sort((a, b) => a.appointmentDate > b.appointmentDate ? -1 : 1);; .filter(item => item.communicateStatus !== 'contacted'); } tabClick(path: string) { PAMapp/pages/myAppointmentList/appointmentList.vue
@@ -5,6 +5,7 @@ placeholder="請輸入關鍵字" class="mb-30 pam-clientReserved-input" v-model="keyWord" @keyup.enter.native="search" > <i slot="suffix" class="icon-search search cursor--pointer" @click="search"></i> </el-input> @@ -15,14 +16,14 @@ ></ClientList> <UiPagination :totalList="appointmentList" :totalList="filterList" @changePage="changePage" ></UiPagination> </div> </template> <script lang="ts"> import { Vue, Component, Prop, State, Watch } from 'nuxt-property-decorator'; import { Vue, Component, State, Watch } from 'nuxt-property-decorator'; import { ClientInfo } from '~/assets/ts/api/appointment'; @Component @@ -36,9 +37,16 @@ @Watch('myAppointmentList') onMyAppointmentListChange() { this.appointmentList = this.myAppointmentList .filter(item => item.communicateStatus !== 'contacted') .sort((a, b) => a.appointmentDate > b.appointmentDate ? -1 : 1);; const unreadList = this.myAppointmentList .filter(item => item.communicateStatus !== 'contacted' && !item.consultantReadTime) .sort((a, b) => a.consultantViewTime > b.consultantViewTime ? 1 : -1); const readList = this.myAppointmentList .filter(item => item.communicateStatus !== 'contacted' && item.consultantReadTime) .sort((a, b) => a.consultantReadTime > b.consultantReadTime ? -1 : 1) this.appointmentList = unreadList.concat(readList); this.filterList = this.appointmentList; } mounted() { PAMapp/pages/myAppointmentList/contactedList.vue
@@ -5,6 +5,7 @@ placeholder="請輸入關鍵字" class="mb-30 pam-clientReserved-input" v-model="keyWord" @keyup.enter.native="search" > <i slot="suffix" @@ -19,7 +20,7 @@ ></ClientList> <UiPagination :totalList="contactedList" :totalList="filterList" @changePage="changePage" ></UiPagination> </div> @@ -42,12 +43,11 @@ onMyAppointmentListChange() { this.contactedList = (this.myAppointmentList || []) .filter(item => item.communicateStatus === 'contacted') .sort((a, b) => a.appointmentDate > b.appointmentDate ? -1 : 1); .sort((a, b) => a.contactTime > b.contactTime ? -1 : 1); this.filterList = this.contactedList; } mounted() { console.log('ClientContactedList mounted'); this.onMyAppointmentListChange(); } PAMapp/store/index.ts
@@ -1,5 +1,5 @@ import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators' import { ClientInfo, getMyAppointmentList } from '~/assets/ts/api/appointment'; import { allAppointmentsView, ClientInfo, getMyAppointmentList } from '~/assets/ts/api/appointment'; // import * as consultant from '~/assets/ts/api/consultant'; import { Consultants,recommend,AgentOfStrictQuery, getFavoriteConsultant, addFavoriteConsultant, deleteConsultant, strictQuery } from '~/assets/ts/api/consultant'; import { isLogin } from '~/assets/ts/auth'; @@ -97,9 +97,10 @@ } @Action storeMyAppointmentList() { getMyAppointmentList().then((data) => { this.context.commit('updateMyAppointmentList', data) async storeMyAppointmentList() { return await getMyAppointmentList().then((data) => { this.context.commit('updateMyAppointmentList', data); return data.filter(item => !item.consultantViewTime || item.consultantViewTime === null).length }); }