update: TODO#132858 顧問經由簡訊或mail 點擊 url 查看客戶預約清單
| | |
| | | <div> |
| | | <el-row |
| | | type="flex" |
| | | ref="clientCardRef" |
| | | class="rowStyle cursor--pointer" |
| | | justify="space-between" |
| | | :class="{'new': newAppointment }" |
| | |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { Vue, Component, Prop, Action } from 'nuxt-property-decorator'; |
| | | import { Vue, Component, Prop, Action, namespace, Watch } from 'nuxt-property-decorator'; |
| | | |
| | | import appointmentService from '~/shared/services/appointment.service'; |
| | | import UtilsService from '~/shared/services/utils.service'; |
| | | import { hideReviews } from '~/shared/const/hide-reviews'; |
| | | import { ClientInfo } from '~/shared/models/client.model'; |
| | | import myConsultantService from '~/shared/services/my-consultant.service'; |
| | | import { ElRow } from 'element-ui/types/row'; |
| | | |
| | | |
| | | const localStorage = namespace('localStorage'); |
| | | @Component({ |
| | | filters: { |
| | | formatNumber(index: number) { |
| | |
| | | }) |
| | | export default class ClientList extends Vue { |
| | | @Action |
| | | updateMyAppointment!: (data: ClientInfo) => void |
| | | |
| | | @Action |
| | | storeConsultantList!: () => void; |
| | | updateMyAppointment!: (data: ClientInfo) => void; |
| | | |
| | | @Prop() |
| | | client!: ClientInfo; |
| | | |
| | | @localStorage.Mutation |
| | | storageClearAppointmentIdFromMsg!: () => void; |
| | | |
| | | isVisibleDialog = false; |
| | | dialogWidth = ''; |
| | | hideReviews = hideReviews; |
| | | |
| | | ////////////////////////////////////////////////////////////////////// |
| | | |
| | | @Watch('$route', {immediate: true}) |
| | | onRouteChange() { |
| | | const appointmentIdFromMsg = this.$route.query.appointmentId; |
| | | if (appointmentIdFromMsg && +appointmentIdFromMsg === this.client.id) { |
| | | this.openDetail(); |
| | | } |
| | | } |
| | | |
| | | ////////////////////////////////////////////////////////////////////// |
| | | |
| | |
| | | } |
| | | |
| | | openDetail() { |
| | | setTimeout(() => { |
| | | (this.$refs.clientCardRef as any).$el.classList.add('currentShowStyle'); |
| | | }, 0) |
| | | |
| | | this.dialogWidth = UtilsService.isMobileDevice() ? '80%' : ''; |
| | | this.isVisibleDialog = true; |
| | | } |
| | |
| | | updatedClient.consultantReadTime = new Date().toString(); |
| | | this.updateMyAppointment(updatedClient); |
| | | }); |
| | | } |
| | | }; |
| | | this.clearAppointmentIdFromMsg(); |
| | | } |
| | | |
| | | private clearAppointmentIdFromMsg() { |
| | | this.storageClearAppointmentIdFromMsg(); |
| | | this.$router.push({query: {}}); |
| | | setTimeout(() => { |
| | | (this.$refs.clientCardRef as ElRow).$el.classList.remove('currentShowStyle') |
| | | },1000) |
| | | } |
| | | |
| | | } |
| | |
| | | margin-bottom: 10px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | transition: background-color 0.5s; |
| | | |
| | | &.new { |
| | | border-left: solid 4px $YELLOW; |
| | | } |
| | | |
| | | &.currentShowStyle { |
| | | background-color: rgba(236, 195, 178, 0.5); |
| | | transition: background-color 0.5s; |
| | | } |
| | | |
| | | .unread { |
| | | align-self: center; |
| | | |
| | |
| | | <template> |
| | | <el-pagination |
| | | :current-page.sync="currentPage" |
| | | :current-page.sync="syncCurrentPage" |
| | | layout="prev, pager, next" |
| | | :total="totalList.length" |
| | | :page-size="pageSize" |
| | |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { Vue, Component, Prop, Emit, Watch } from 'nuxt-property-decorator'; |
| | | import { Vue, Component, Prop, Emit, Watch, PropSync } from 'nuxt-property-decorator'; |
| | | import { Consultant } from '~/shared/models/consultant.model'; |
| | | |
| | | @Component |
| | |
| | | totalList!: Consultant[]; |
| | | |
| | | @Prop({default: 5}) pageSize!: number; |
| | | currentPage = 1; |
| | | @PropSync('currentPage', {default: 1}) syncCurrentPage!: number; |
| | | |
| | | pageList: Consultant[] = []; |
| | | |
| | |
| | | @Watch('totalList') |
| | | watchTotalList(newValue: Consultant[]) { |
| | | if (newValue) { |
| | | this.handleCurrentChange(this.currentPage); |
| | | this.handleCurrentChange(this.syncCurrentPage); |
| | | } |
| | | } |
| | | |
| | | ////////////////////////////////////////////////////////////////// |
| | | |
| | | mounted() { |
| | | this.handleCurrentChange(this.currentPage); |
| | | this.handleCurrentChange(this.syncCurrentPage); |
| | | } |
| | | |
| | | ////////////////////////////////////////////////////////////////// |
比對新檔案 |
| | |
| | | import { Middleware } from '@nuxt/types'; |
| | | |
| | | const myAppointment: Middleware = (context) => { |
| | | const appointmentIdFromMsg = context.route.query.appointmentId; |
| | | if (appointmentIdFromMsg) { |
| | | context.store.commit('localStorage/storageAppointmentIdFromMsg', appointmentIdFromMsg); |
| | | }; |
| | | |
| | | const isAdminLogin = context.store.getters['localStorage/isAdminLogin']; |
| | | if (isAdminLogin) { |
| | | if (context.route.name === 'myAppointmentList') { |
| | | context.redirect('/myAppointmentList/appointmentList') |
| | | } |
| | | } else { |
| | | context.redirect('/consultantLogin'); |
| | | } |
| | | } |
| | | |
| | | export default myAppointment |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | <NuxtChild></NuxtChild> |
| | | <NuxtChild keep-alive></NuxtChild> |
| | | |
| | | </div> |
| | | |
| | |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { Vue, Component, State, Action, Watch } from 'nuxt-property-decorator'; |
| | | import { Vue, Component, State, Action, Watch, namespace } from 'nuxt-property-decorator'; |
| | | |
| | | import * as _ from 'lodash'; |
| | | |
| | | import { ClientInfo } from '~/shared/models/client.model'; |
| | | |
| | | const localStorage = namespace('localStorage'); |
| | | |
| | | @Component({ |
| | | layout: 'home', |
| | | middleware: 'myAppointmentMiddleware' |
| | | middleware: 'myAppointment' |
| | | }) |
| | | export default class ClientReservedList extends Vue { |
| | | |
| | |
| | | @Action |
| | | storeMyAppointmentList!: () => Promise<number>; |
| | | |
| | | @localStorage.Mutation |
| | | storageClearAppointmentIdFromMsg!: () => void; |
| | | |
| | | @localStorage.Getter |
| | | currentAppointmentIdFromMsg!: string; |
| | | |
| | | activeTabName : string = 'appointmentList'; |
| | | appointmentList : ClientInfo[] = []; |
| | | clients : ClientInfo[] = []; |
| | |
| | | ////////////////////////////////////////////////////////////////////// |
| | | |
| | | mounted() { |
| | | this.setActivatedTab(); |
| | | this.storeMyAppointmentList(); |
| | | } |
| | | |
| | | private setActivatedTab(): void { |
| | | const routeFullName = this.$route.name; |
| | | if (routeFullName) { |
| | | this.activeTabName = routeFullName.split('-')[1]; |
| | | } |
| | | destroyed() { |
| | | this.storageClearAppointmentIdFromMsg(); |
| | | } |
| | | |
| | | ////////////////////////////////////////////////////////////////////// |
| | |
| | | |
| | | this.appointmentList = this.myAppointmentList |
| | | .filter(item => item.communicateStatus !== 'contacted'); |
| | | |
| | | if (this.currentAppointmentIdFromMsg) { |
| | | this.redirectAppointmentStatus(); |
| | | } |
| | | } |
| | | |
| | | private redirectAppointmentStatus() { |
| | | const currentAppointmentIndex = this.myAppointmentList |
| | | .findIndex(item => item.id === +this.currentAppointmentIdFromMsg); |
| | | if (currentAppointmentIndex > -1) { |
| | | const communicateStatus = this.myAppointmentList[currentAppointmentIndex].communicateStatus; |
| | | const pathName = communicateStatus === 'reserved' ? 'appointmentList' : 'contactedList'; |
| | | this.$router.push( |
| | | { |
| | | path: '/myAppointmentList/' + pathName, |
| | | query: {appointmentId: this.currentAppointmentIdFromMsg} |
| | | } |
| | | ); |
| | | } |
| | | }; |
| | | |
| | | @Watch('newAppointmentSum') |
| | | newAppointmentSumChange(): void { |
| | | this.showNewAppointmentHint = this.newAppointmentSum > 0; |
| | | } |
| | | |
| | | @Watch('$route') |
| | | onRouteChange() { |
| | | const routeFullName = this.$route.name; |
| | | if (routeFullName) { |
| | | this.activeTabName = routeFullName.split('-')[1]; |
| | | } |
| | | } |
| | | |
| | | ////////////////////////////////////////////////////////////////////// |
| | | |
| | | clickTab(path: string): void { |
| | |
| | | |
| | | <UiPagination |
| | | :totalList="filterList" |
| | | :currentPage="currentPage" |
| | | @changePage="changePage" |
| | | ></UiPagination> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { Vue, Component, State, Watch } from 'nuxt-property-decorator'; |
| | | import { Vue, Component, State, Watch, namespace } from 'nuxt-property-decorator'; |
| | | |
| | | import { ClientInfo } from '~/shared/models/client.model'; |
| | | |
| | | const localStorage = namespace('localStorage'); |
| | | @Component |
| | | export default class ClientReservedList extends Vue { |
| | | |
| | | @State('myAppointmentList') |
| | | myAppointmentList!: ClientInfo[]; |
| | | |
| | | @localStorage.Getter |
| | | currentAppointmentIdFromMsg!: string; |
| | | |
| | | appointmentList: ClientInfo[] = []; |
| | | filterList : ClientInfo[] = []; |
| | | keyWord : string = ''; |
| | | pageList : ClientInfo[] = []; |
| | | currentPage : number = 1; |
| | | |
| | | ////////////////////////////////////////////////////////////////////// |
| | | |
| | |
| | | |
| | | this.appointmentList = [...unViewList, ...unreadList, ...readList]; |
| | | this.filterList = this.appointmentList; |
| | | |
| | | this.getCurrentPage(); |
| | | } |
| | | |
| | | private getCurrentPage() { |
| | | const currentIndex = this.filterList |
| | | .findIndex(item => item.id === +this.currentAppointmentIdFromMsg); |
| | | const pageSize = 5; |
| | | if (currentIndex > -1) { |
| | | this.currentPage = Math.ceil((currentIndex + 1) / pageSize); |
| | | } |
| | | } |
| | | |
| | | ////////////////////////////////////////////////////////////////////// |
| | | search(): void { |
| | | this.filterList = this.appointmentList.filter(item => { |
| | | return item.name.match(this.keyWord) || item.requirement.match(this.keyWord) |
| | |
| | | |
| | | <UiPagination |
| | | :totalList="filterList" |
| | | :currentPage="currentPage" |
| | | @changePage="changePage" |
| | | ></UiPagination> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts"> |
| | | import { Vue, Component, Watch, State } from 'nuxt-property-decorator'; |
| | | import { Vue, Component, Watch, State, namespace } from 'nuxt-property-decorator'; |
| | | |
| | | import { ClientInfo } from '~/shared/models/client.model'; |
| | | |
| | | const localStorage = namespace('localStorage'); |
| | | @Component |
| | | export default class ClientContactedList extends Vue { |
| | | |
| | | @State('myAppointmentList') |
| | | myAppointmentList!: ClientInfo[]; |
| | | |
| | | @localStorage.Getter |
| | | currentAppointmentIdFromMsg!: string; |
| | | |
| | | contactedList: ClientInfo[] = []; |
| | | filterList : ClientInfo[] = []; |
| | | keyWord : string = ''; |
| | | pageList : ClientInfo[] = []; |
| | | currentPage : number = 1; |
| | | |
| | | ////////////////////////////////////////////////////////////////////// |
| | | |
| | | mounted() { |
| | | this.onMyAppointmentListChange(); |
| | | } |
| | | |
| | | ////////////////////////////////////////////////////////////////////// |
| | | |
| | | @Watch('myAppointmentList') |
| | | onMyAppointmentListChange() { |
| | |
| | | .map((item) => ({...item, sortTime: new Date(item.contactTime)})) |
| | | .sort((prevItem, nextItem) => +nextItem.sortTime - +prevItem.sortTime); |
| | | this.filterList = this.contactedList; |
| | | |
| | | this.getCurrentPage(); |
| | | } |
| | | |
| | | contactedList: ClientInfo[] = []; |
| | | filterList : ClientInfo[] = []; |
| | | keyWord : string = ''; |
| | | pageList : ClientInfo[] = []; |
| | | |
| | | ////////////////////////////////////////////////////////////////////// |
| | | |
| | | mounted() { |
| | | this.onMyAppointmentListChange(); |
| | | private getCurrentPage() { |
| | | const currentIndex = this.filterList.findIndex(item => item.id === +this.currentAppointmentIdFromMsg); |
| | | const pageSize = 5; |
| | | if (currentIndex > -1) { |
| | | this.currentPage = Math.ceil((currentIndex + 1) / pageSize); |
| | | } |
| | | } |
| | | |
| | | ////////////////////////////////////////////////////////////////////// |
| | |
| | | otherRequirement : string, |
| | | phone : string, |
| | | requirement : string, |
| | | satisfactionScore : number, |
| | | satisfactionScore : number |
| | | } |
| | |
| | | consultant_id = localStorage.getItem('consultant_id'); |
| | | quickFilterSelectedItem = localStorage.getItem('quickFilter'); |
| | | recommendConsultantItem = localStorage.getItem('recommendConsultantItem'); |
| | | appointmentIdFromMsg = localStorage.getItem('appointmentIdFromMsg'); |
| | | |
| | | get idToken(): string|null { |
| | | return this.id_token; |
| | |
| | | return this.currentRole === Role.USER; |
| | | } |
| | | |
| | | |
| | | get currentAppointmentIdFromMsg(): string|null { |
| | | return this.appointmentIdFromMsg; |
| | | } |
| | | |
| | | @Mutation storageIdToken(token: string): void { |
| | | localStorage.setItem('id_token', token); |
| | |
| | | this.recommendConsultantItem = localStorage.getItem('recommendConsultantItem'); |
| | | } |
| | | |
| | | @Mutation storageAppointmentIdFromMsg(id: string) { |
| | | localStorage.setItem('appointmentIdFromMsg', id); |
| | | this.appointmentIdFromMsg = localStorage.getItem('appointmentIdFromMsg'); |
| | | } |
| | | |
| | | @Mutation storageClear(): void { |
| | | localStorage.removeItem('myRequests'); |
| | | localStorage.removeItem('userInfo'); |
| | |
| | | this.recommendConsultantItem = localStorage.getItem('recommendConsultantItem'); |
| | | } |
| | | |
| | | @Mutation storageClearAppointmentIdFromMsg() { |
| | | localStorage.removeItem('appointmentIdFromMsg'); |
| | | this.appointmentIdFromMsg = localStorage.getItem('appointmentIdFromMsg'); |
| | | } |
| | | |
| | | @Action actionStorageClear(): void { |
| | | this.context.commit("storageClear"); |
| | | } |