PAMapp/assets/scss/vendors/elementUI/_dateTimePicker.scss | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/components/Appointment/AppointmentInterviewList.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/components/DateTimePicker.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/components/Interview/InterviewAdd.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/components/Ui/UiDatePicker.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/components/Ui/UiTimePicker.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/pages/appointment/_appointmentId/index.vue | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/shared/models/appointment.model.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/shared/services/appointment.service.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
PAMapp/store/index.ts | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 |
PAMapp/assets/scss/vendors/elementUI/_dateTimePicker.scss
@@ -52,6 +52,9 @@ td.available:hover { color: $CORAL; } td.today.current span { color: $PRIMARY_WHITE; } } } .el-year-table { PAMapp/components/Appointment/AppointmentInterviewList.vue
@@ -13,27 +13,57 @@ </template> <template v-if="interviewList.length"> <div class="interview--future"> <div v-for="(item, index) in futureList" :key="index + 'feature'" class="interview--future" @click="editInterview(item)" > <div class="record-card"> <div class="record-card-date"> <span class="bold">01/10</span> <span class="mt-5 line-space">09:00</span> <div> <UiDateFormat class="date bold" :date="item.interviewDate" onlyShowSection="DAY" /> </div> <div> <UiDateFormat class="time mt-5 line-space" :date="item.interviewDate" onlyShowSection="TIME" /> </div> </div> <div class="record-card-content"> <span>預計提醒客戶約在公司樓下咖啡廳,推薦熊安心醫療險與防疫保單</span> <span>{{item.content}}</span> </div> </div> </div> <section class="interview--past"> <section class="interview--past" v-for="(item, index) in pastList" :key="index + 'past'" @click="editInterview(item)" > <div class="record-card"> <div class="record-card-date"> <span class="bold">01/08</span> <span class="mt-5 line-space">09:00</span> <div> <UiDateFormat class="date bold" :date="item.interviewDate" onlyShowSection="DAY" /> </div> <div> <UiDateFormat class="time mt-5 line-space" :date="item.interviewDate" onlyShowSection="TIME" /> </div> </div> <div class="record-card-content"> <span>王聰明回信提供電話號碼,去電推薦預約時間</span> <span>{{item.content}}</span> </div> </div> </section> @@ -46,18 +76,49 @@ </template> <script lang="ts"> import { Vue, Component } from 'nuxt-property-decorator'; import { Vue, Component, Prop, Watch, Mutation } from 'nuxt-property-decorator'; import { InterviewRecord } from '~/shared/models/appointment.model'; @Component export default class AppointmentInterviewList extends Vue { @Prop() interviewList!: InterviewRecord[]; interviewList = []; @Mutation updateInterviewRecord!: (data: InterviewRecord) => void; appointmentId!: string; futureList: InterviewRecord[] = []; pastList: InterviewRecord[] = []; ////////////////////////////////////////////////////////////////////// mounted() { this.appointmentId = this.$route.params.appointmentId; } ////////////////////////////////////////////////////////////////////// @Watch('interviewList', {immediate: true}) updateInterviewList() { if (this.interviewList && this.interviewList.length > 0) { this.futureList = this.interviewList .filter(item => new Date(item.interviewDate).getTime() >= new Date().getTime()) this.pastList = this.interviewList .filter(item => new Date(item.interviewDate).getTime() < new Date().getTime()); } } ////////////////////////////////////////////////////////////////////// addInterview(): void { const appointmentId = this.$route.params.appointmentId; this.$router.push(`/appointment/${appointmentId}/interview/new`); this.$router.push(`/appointment/${this.appointmentId}/interview/new`); } editInterview(interviewRecord) { this.updateInterviewRecord(interviewRecord); this.$router.push(`/appointment/${this.appointmentId}/interview/${interviewRecord.id}`); } } PAMapp/components/DateTimePicker.vue
@@ -2,19 +2,28 @@ <template> <div class="dateTime"> <UiDatePicker @changeDate="changeDateTime($event, 'date')"></UiDatePicker> <UiTimePicker @changeTime="changeDateTime($event, 'time')"></UiTimePicker> <UiDatePicker @changeDate="changeDateTime($event, 'date')" :defaultValue="defaultValue" ></UiDatePicker> <UiTimePicker @changeTime="changeDateTime($event, 'time')" :defaultValue="defaultValue" ></UiTimePicker> </div> </template> <script lang="ts"> import { Component, Emit, Vue } from "nuxt-property-decorator"; import { Component, Emit, Prop, Vue } from "nuxt-property-decorator"; @Component export default class DateTimePicker extends Vue { changeDate!: Date; changeTime!: string; @Prop() defaultValue!: string; @Emit('changeDateTime') changeDateTime(event, type) { if (type === 'date') { PAMapp/components/Interview/InterviewAdd.vue
@@ -1,16 +1,38 @@ <template> <div class="edit-appointment-record"> <div class="edit-appointment-record-date"> <span>今天 11:00 建立</span> <span>今天 11:00 更新</span> <div class="edit-appointment-record-date" v-if="interviewId"> <span>{{interviewRecord.createdDate | formatDate}} 建立</span> <span>{{interviewRecord.lastModifiedDate | formatDate}} 更新</span> </div> <div class="mdTxt mb-10">約訪時間</div> <el-row class="mdTxt mb-10"> <el-col :xs="16" :sm="20">約訪時間</el-col> <el-col :xs="8" :sm="4" class="text--right" v-if="interviewId"> <span v-if="!isEdit" class="mr-10 text--primary text--underline cursor--pointer" @click="showCancelPopUp = true" >刪除</span> <span v-if="!isEdit" class="text--primary text--underline cursor--pointer" @click="isEdit = !isEdit" >編輯</span> </el-col> </el-row> <template v-if="!interviewId || isEdit"> <DateTimePicker @changeDateTime="interviewTime = $event" :defaultValue="defaultValue" ></DateTimePicker> </template> <template v-else> <div class="mdTxt lighter mt-20"> {{formatInterviewDate}} </div> </template> <div class="mdTxt mb-10 mt-10">約訪紀錄</div> <div class="mdTxt mb-10 mt-30">約訪紀錄</div> <template v-if="!interviewId || isEdit"> <el-input type="textarea" :rows="5" @@ -19,58 +41,188 @@ v-model="content" > </el-input> <div class="edit-appointment-record-btn"> <el-button>取消</el-button> <el-button :disabled="!interviewTime || !content" @click="createInterviewRecord">確定</el-button> </template> <template v-else> <div class="mdTxt lighter mt-20"> {{content}} </div> </template> <div class="edit-appointment-record-btn" v-if="!interviewId || isEdit"> <el-button @click="cancel">取消</el-button> <el-button :disabled="!interviewTime || !content" @click="saveInterviewRecord" >確定</el-button> </div> <PopUpFrame :isOpen.sync="isConfirmPopup" @closePopUp="closeConfirmPopup"> <div class="text--center mdTxt">新增成功</div> <PopUpFrame :isOpen.sync="showCancelPopUp" @closePopUp="showCancelPopUp = false" > <div class="text--center mdTxt">是否刪除此筆約訪記錄?</div> <div class="text--center mt-30"> <el-button @click="closeConfirmPopup" type="primary">確定</el-button> <el-button @click="showCancelPopUp = false">否</el-button> <el-button @click="deleteInterviewRecord" type="primary">是</el-button> </div> </PopUpFrame> <PopUpFrame :isOpen.sync="showConfirmPopup" @closePopUp="closePopup"> <div class="text--center mdTxt">{{confirmTxt}}!</div> <div class="text--center mt-30"> <el-button @click="closePopup" type="primary">確定</el-button> </div> </PopUpFrame> <PopUpFrame :isOpen.sync="showFutureDateConfirmPopup" @closePopUp="closePopup"> <div class="text--center mdTxt">{{confirmTxt}}!</div> <div class="text--center mdTxt">立即發送約訪通知?</div> <div class="text--center mt-30"> <el-button @click="closePopup">先不發送</el-button> <el-button @click="showInterviewMsgPopup = true" type="primary">傳送約訪通知</el-button> </div> </PopUpFrame> <InterviewMsg :isVisible.sync="showInterviewMsgPopup" @closeDialog="closePopup" ></InterviewMsg> </div> </template> <script lang="ts"> import { AppointmentLog, InterviewRecordInfo } from '~/shared/models/appointment.model'; import { Vue, Component, Prop } from 'nuxt-property-decorator'; import authService from '~/shared/services/auth.service'; import { InterviewRecord, InterviewRecordInfo } from '~/shared/models/appointment.model'; import { Vue, Component, Prop, State, Mutation, Watch, Action } from 'nuxt-property-decorator'; import appointmentService from '~/shared/services/appointment.service'; @Component export default class InterviewAdd extends Vue { @State interviewRecord!: InterviewRecord; @Mutation updateInterviewRecord!: (data: InterviewRecord) => void; @Mutation clearInterviewRecord!: () => void; interviewTime = ''; content = ''; isConfirmPopup = false; // @Prop() // myAppointmentReviewLogList!: AppointmentLog[]; interviewId = ''; appointmentId = ''; confirmTxt: '新增成功' | '編輯成功' | '刪除成功' = '新增成功'; // isUserLogin = false; isEdit = false; ////////////////////////////////////////////////////////////////////// // mounted() { // this.isUserLogin = authService.isUserLogin(); // } showConfirmPopup = false; showCancelPopUp = false; showInterviewMsgPopup = false; showFutureDateConfirmPopup = false; createInterviewRecord() { defaultValue!: Date; //////////////////////////////////////////////////////////////////// mounted() { this.interviewId = this.$route.params.interviewId; this.appointmentId = this.$route.params.appointmentId; const isEditPage = this.interviewId && this.interviewRecord; if (isEditPage) { this.checkInterviewRecord(); } } private checkInterviewRecord() { if (this.interviewRecord.appointmentId !== +this.appointmentId || this.interviewRecord.id !== +this.interviewId) { appointmentService.getAppointmentDetail(+this.appointmentId).then((data) => { const currentInterviewRecord = data.interviewRecordDTOs.filter(item => item.id === +this.interviewId)[0]; this.updateInterviewRecord(currentInterviewRecord); }) } } destroyed() { this.clearInterviewRecord(); } //////////////////////////////////////////////////////////////////// @Watch('interviewRecord', {immediate: true}) watchInterviewRecord() { if (this.interviewRecord && this.interviewRecord.content) { this.content = this.interviewRecord.content; this.defaultValue = new Date(this.interviewRecord.interviewDate); } } //////////////////////////////////////////////////////////////////// saveInterviewRecord() { const interviewRecordInfo: InterviewRecordInfo = { content: this.content, interviewDate: this.interviewTime, appointmentId: +this.$route.params.appointmentId appointmentId: +this.appointmentId }; if (!this.interviewId) { this.createdRecord(interviewRecordInfo); } else { const updateInterviewRecord = { ...interviewRecordInfo, id: +this.interviewId } this.updateRecord(updateInterviewRecord); } } private createdRecord(interviewRecordInfo) { appointmentService.createInterviewRecord(interviewRecordInfo).then(res => { this.isConfirmPopup = true; this.confirmTxt = '新增成功' this.showPopUp(); }); } closeConfirmPopup() { this.isConfirmPopup = false; this.$router.go(-1); private updateRecord(updateInterviewRecord) { appointmentService.updateInterviewRecord(updateInterviewRecord).then(res => { this.confirmTxt = '編輯成功'; this.showPopUp(); }); } private showPopUp() { if (new Date(this.interviewTime).getTime() >= new Date().getTime()) { this.showFutureDateConfirmPopup = true; } else { this.showConfirmPopup = true; } } closePopup() { this.$router.push(`/appointment/${this.appointmentId}`); } deleteInterviewRecord() { appointmentService.deleteInterviewRecord(this.interviewId).then(res => { this.confirmTxt = '刪除成功'; this.showConfirmPopup = true; }); } cancel() { if (this.interviewId) { this.content = this.interviewRecord.content; this.defaultValue = new Date(this.interviewRecord.interviewDate); this.isEdit = false; } else { this.$router.push(`/appointment/${this.appointmentId}`); } } //////////////////////////////////////////////////////////////////// get formatInterviewDate() { const interviewDate = new Date(this.interviewRecord.interviewDate); return `${interviewDate.getFullYear()}/${interviewDate.getMonth() + 1}/${interviewDate.getDate()} ${interviewDate.getHours()}:${interviewDate.getMinutes()}`; } } PAMapp/components/Ui/UiDatePicker.vue
@@ -14,15 +14,26 @@ </template> <script lang="ts"> import { Component, Emit, Vue } from "nuxt-property-decorator"; import { Component, Emit, Prop, Vue, Watch } from "nuxt-property-decorator"; @Component export default class UiDatePicker extends Vue { dateValue = ''; @Prop() defaultValue!: string; @Emit('changeDate') changeDate() { return this.dateValue; } @Watch('defaultValue', {immediate: true}) updateDefault() { if (this.defaultValue) { this.dateValue = this.defaultValue; this.changeDate(); } } } </script> PAMapp/components/Ui/UiTimePicker.vue
@@ -14,7 +14,7 @@ </template> <script lang="ts"> import { Component, Emit, Vue } from "nuxt-property-decorator"; import { Component, Emit, Prop, Vue, Watch } from "nuxt-property-decorator"; @Component export default class UiTimePicker extends Vue { @@ -25,9 +25,22 @@ end: '21:00' } @Prop() defaultValue!: string; @Emit('changeTime') changeTime() { return this.timeValue; } @Watch('defaultValue', {immediate: true}) updateDefault() { if (this.defaultValue) { const hours = new Date(this.defaultValue).getHours(); const minutes = new Date(this.defaultValue).getMinutes(); this.timeValue = `${hours < 10 ? '0' + hours : hours}:${minutes < 10 ? '0' + minutes : minutes}`; this.changeTime(); } } } </script> PAMapp/pages/appointment/_appointmentId/index.vue
@@ -80,7 +80,7 @@ <section class="mt-30"> <AppointmentInterviewList /> <AppointmentInterviewList :interviewList="appointmentDetail.interviewRecordDTOs" /> </section> <section class="mt-30"> PAMapp/shared/models/appointment.model.ts
@@ -74,7 +74,7 @@ gender : string; hopeContactTime : string; id : number; interviewRecordDTOs : string[]; interviewRecordDTOs : InterviewRecord[]; job : string; lastModifiedDate : string; name : string; PAMapp/shared/services/appointment.service.ts
@@ -77,7 +77,7 @@ // 刪除約訪記錄 async deleteInterviewRecord(interviewRecordId) { return http.delete(`/interview_record/'${interviewRecordId}`); return http.delete(`/interview_record/${interviewRecordId}`); } } PAMapp/store/index.ts
@@ -9,8 +9,10 @@ import reviewsService from '~/shared/services/reviews.service'; import { Consultant } from '~/shared/models/consultant.model'; import { Appointment, AppointmentLog } from '~/shared/models/appointment.model'; import { Appointment, AppointmentLog, InterviewRecord } from '~/shared/models/appointment.model'; import { AgentOfStrictQuery } from '~/shared/models/strict-query.model'; import { AgentInfo } from '~/shared/models/agent-info.model'; import { agentCommunicationStyleList } from '~/shared/const/agent-communication-style-list'; @Module export default class Store extends VuexModule { recommendList: Consultant[] = []; @@ -21,6 +23,16 @@ myNewAppointmentSum: number = 0; myAppointmentReviewLogList: AppointmentLog[] = []; interviewRecord: InterviewRecord = { appointmentId : 0, content : '', createdBy : '', createdDate : '', id : 0, interviewDate : '', lastModifiedBy : '', lastModifiedDate: '' } get isUserLogin() { return this.context.getters['localStorage/isUserLogin']; @@ -56,6 +68,25 @@ this.myAppointmentReviewLogList = data; } @Mutation updateInterviewRecord(data: InterviewRecord) { this.interviewRecord = data; } @Mutation clearInterviewRecord() { this.interviewRecord = { appointmentId : 0, content : '', createdBy : '', createdDate : '', id : 0, interviewDate : '', lastModifiedBy : '', lastModifiedDate: '' } } @Action storeRecommendList() { queryConsultantService.getRecommendConsultantList().then(data => {