<template>
|
<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="text--middle">
|
<div class="mdTxt">您指定的聯繫方式</div>
|
<div class="mt-10">
|
<span>手機:</span>
|
<span>{{myRequest.phone}}</span>
|
</div>
|
</div>
|
<div class="mt-30">
|
<div class="datepicker required">
|
<span class="mdTxt">手機連絡的方便時間</span>
|
<PhoneContactTimePicker
|
: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 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="mt-10 ques-header__input-block">
|
<span>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 ml-4"
|
:class="{'is-invalid': !phoneValid}"
|
placeholder="請輸入"
|
maxlength="10"
|
v-model="myRequest.phone">
|
</div>
|
<div class="error mt-5 " style="margin-left:65px">
|
<span v-show="!phoneValid">手機號碼格式有誤</span>
|
</div>
|
</div>
|
<div class="mt-30" v-if="myRequest.phone && phoneValid">
|
<div class="datepicker">
|
<span class="mdTxt">手機連絡的方便時間</span>
|
<PhoneContactTimePicker
|
:scheduleList="myRequest.hopeContactTime"/>
|
</div>
|
</div>
|
</div>
|
</div>
|
<div class="ques-container">
|
<div class="pam-paragraph">
|
<div class="mdTxt">
|
想要詢問的問題
|
<span class="hint text--bold">
|
(可複選)
|
</span>
|
<i class="icon-information text--bold" @click="showDrawer = true"></i>
|
</div>
|
<MultiSelectBtn class="mt-10"
|
:mutiSelect.sync="myRequest.requirement"
|
:options="requirementOptions" />
|
</div>
|
<div class="pam-paragraph">
|
<div class="mdTxt">您的性別</div>
|
<SingleSelectBtn class="mt-10"
|
:singleSelected.sync="myRequest.gender"
|
:options="genderOptions" />
|
</div>
|
<div class="pam-paragraph">
|
<div class="mdTxt">您的年齡</div>
|
<SingleSelectBtn class="mt-10"
|
:singleSelected.sync="myRequest.age"
|
:options="ageRangeOptions" />
|
</div>
|
<div class="pam-paragraph">
|
<CareerSelect :careerSelect.sync="myRequest.job"/>
|
</div>
|
<div class="pam-paragraph ques-footer">
|
<el-button type="primary"
|
:disabled="isDisabledSubmitBtn"
|
@click.native="sentDemand">
|
{{isEditBtn ? '更新' : '送出'}}
|
</el-button>
|
</div>
|
</div>
|
|
<PopUpFrame :isOpen.sync="showDrawer">
|
<div class="qaTextTitle mdTxt">
|
<strong>想要詢問的問題</strong>
|
</div>
|
<div class="qa-dialog">
|
<div v-for="(qaText,index) in quesAboutList" :key="index" >
|
<div class="pt-10">
|
<p class="p bold">{{qaText.title}}</p>
|
<p class="p">{{qaText.content}}</p>
|
</div>
|
</div>
|
</div>
|
<div class="text--center mdTxt mt-10">
|
<el-button type="primary" @click="showDrawer = false">我知道了</el-button>
|
</div>
|
</PopUpFrame>
|
|
<PopUpFrame :isOpen.sync="sendReserve" @update:isOpen="closeReservePopUp">
|
<div class="mdTxt mt-30 sendReserve-txt">預約成功!</div>
|
<div class="mdTxt sendReserve-txt mb-30">您預約的顧問會儘速與您聯絡!</div>
|
<!-- TODO: 未串接 api, 隱藏平台滿意度 -->
|
<!-- <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">
|
送出
|
</el-button> -->
|
<el-button type="primary"
|
@click="closeReservePopUp">
|
我知道了
|
</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, State, Action, Watch, namespace } from 'nuxt-property-decorator';
|
import { getRequestsFromStorage, removeRequestQuestionFromStorage, setRequestsToStorage } from '~/shared/storageRequests';
|
import _ from 'lodash';
|
|
import appointmentService from '~/shared/services/appointment.service';
|
import authService from '~/shared/services/auth.service';
|
import queryConsultantService from '~/shared/services/query-consultant.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';
|
|
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;
|
|
score ="" ;
|
|
genderOptions=[
|
{
|
title:'男性',
|
label:Gender.MALE,
|
},
|
{
|
title:'女性',
|
label:Gender.FEMALE,
|
}
|
];
|
|
requirementOptions=[
|
{
|
title:'健康與保障',
|
label:'健康與保障',
|
},
|
{
|
title:'子女教育',
|
label:'子女教育',
|
},
|
{
|
title:'資產規劃',
|
label:'資產規劃',
|
},
|
{
|
title:'樂活退休',
|
label:'樂活退休',
|
},
|
{
|
title:'保單健檢/規劃',
|
label:'保單健檢/規劃',
|
},
|
{
|
title:'分紅保單',
|
label:'分紅保單',
|
},
|
];
|
|
ageRangeOptions=[
|
{
|
title:'20歲以下',
|
label:'under_20',
|
},
|
{
|
title:'21-30 歲',
|
label:'21-30'
|
},
|
{
|
title:'31-40 歲',
|
label:'31-40'
|
},
|
{
|
title:'41-50 歲',
|
label:'41-50'
|
},
|
{
|
title:'51-60 歲',
|
label:'51-60',
|
},
|
{
|
title:'61-70 歲',
|
label:'61-70',
|
},
|
{
|
title:'71 歲以上',
|
label:'over_71',
|
}
|
];
|
|
quesAboutList = [
|
{
|
title:'健康與保障',
|
content:'唯有把身體照顧好,才是保障幸福之本,不做盲目燃燒的蠟燭,只做綻開的陽光,陪孩子多走一哩路,人生的美正要開展。'
|
},
|
{
|
title:'子女教育',
|
content:'孩子,我們是雙方的導師也是學生,面對未來要並肩作戰,學會勇敢無畏、克服挫折、善於理財,這條路上我們一起學。'
|
},
|
{
|
title:'資產規劃',
|
content:'真正的財富來自嚴謹規劃資產傳承,為人生蓋一堵抵禦財務風險的牆,確保資產穩健成長,替全家族的未來做好萬全準備。'
|
},
|
{
|
title:'樂活退休',
|
content:'拼一輩子,退休後的日子要輕鬆快活,就得提早透過保險商品規劃退休財務,替自己創造穩定收入,為精彩的熟年人生揭開序幕。'
|
},
|
{
|
title:'保單健檢/規劃',
|
content:'全面檢視自己的保障結構是否符合現在或未來的風險移轉需求。'
|
},
|
{
|
title:'分紅保單',
|
content:'分紅保單是兼具「分攤風險」與「紅利共享」特色的保單,具有一定穩定度,讓您可以同時享有壽險保障及紅利!'
|
}
|
];
|
|
myRequest: AppointmentRequests = {
|
phone : this.userInfo?.phone ? this.userInfo.phone : '',
|
email : this.userInfo?.email ? this.userInfo.email : '',
|
contactType : _.isEqual(this.userInfo?.contactType,ContactType.SMS) ? ContactType.PHONE: ContactType.EMAIL,
|
gender : '',
|
age : '',
|
job : '',
|
requirement : [],
|
hopeContactTime: [{
|
selectWeekOptions : [],
|
selectTimesOptions: [],
|
}],
|
agentNo: '',
|
};
|
|
showDrawer= false;
|
sendReserve = false;
|
isEditPopup = false;
|
isEditBtn = false;
|
|
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,
|
hopeContactTime: storageMyRequest.hopeContactTime?.length
|
? storageMyRequest.hopeContactTime
|
: [{
|
selectWeekOptions: [],
|
selectTimesOptions: [],
|
}],
|
};
|
}
|
|
if (storageMyRequirement) {
|
this.myRequest = {
|
...this.myRequest,
|
requirement: storageMyRequirement
|
}
|
removeRequestQuestionFromStorage();
|
}
|
}
|
|
////////////////////////////////////////////////////////////////////////////
|
|
@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;
|
}
|
}
|
}
|
|
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);
|
}
|
|
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;
|
}
|
}
|
|
private getAppointmentId(appointmentInfo) {
|
this.appointmentId = appointmentInfo.id;
|
this.appointmentTime = appointmentInfo.lastModifiedDate
|
? appointmentInfo.lastModifiedDate
|
: appointmentInfo.appointmentDate;
|
}
|
|
////////////////////////////////////////////////////////////////////////////
|
|
sentDemand() {
|
if (this.isEditBtn) {
|
this.editAppointmentDemand();
|
} else {
|
queryConsultantService.addFavoriteConsultant([this.$route.params.agentNo]).then(res => this.sentAppointmentDemand());
|
}
|
}
|
|
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.myRequest.phone && this.phoneValid ? this.getHopeContactTime() :'',
|
agentNo: this.$route.params.agentNo
|
};
|
|
queryConsultantService.appointmentDemand(data).then(res => {
|
this.sendReserve = true;
|
this.myRequest.hopeContactTime = [];
|
setRequestsToStorage(this.myRequest);
|
});
|
}
|
|
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();
|
}
|
|
closeReservePopUp() {
|
this.sendReserve = false;
|
this.$router.push('/')
|
}
|
|
////////////////////////////////////////////////////////////////////////////
|
|
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;
|
}
|
|
//drawer最底下文字樣式
|
.qa-dialog-footer{
|
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 {
|
width: 120px;
|
height:50px;
|
background-color: #ED1B2E;
|
color:#FFFFFF;
|
font-weight: normal;
|
@extend .text--middle ;
|
&.el-button--default {
|
color: $PRIMARY_RED;
|
background-color: #FFFFFF;
|
border-color: $PRIMARY_RED;
|
}
|
&.el-button--primary {
|
background-color: $PRIMARY_RED;
|
border-color: $PRIMARY_RED;
|
}
|
&.is-disabled {
|
color: $PRIMARY_WHITE;
|
background-color: $MID_GREY;
|
border-color: $MID_GREY;
|
border-style: solid;
|
pointer-events: none;
|
}
|
}
|
}
|
|
//詳細問題drawer中間內容空間大小設置
|
.qa-dialog{
|
overflow-y:auto;
|
height: 60vh;
|
margin-top: 20px;
|
}
|
|
//詳細問題drawer主要標題
|
.qaTextTitle{
|
margin-top:30px;
|
display: flex;
|
justify-content: center;
|
}
|
|
.datepicker{
|
display: flex;
|
flex-direction: column;
|
}
|
|
.required {
|
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-header {
|
position: relative;
|
}
|
|
.ques-header__mob-banner {
|
width: 100%;
|
min-height: 80px;
|
background-color: #F8F9FA;
|
background-image: url('~/assets/images/questionnaire/reserve_bg_mob.svg');
|
background-repeat: no-repeat;
|
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: 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;
|
}
|
|
.pam-satisfaction-rate{
|
margin-bottom: 45px;
|
}
|
|
@include desktop{
|
.ques-header{
|
display: flex;
|
justify-content: flex-end;
|
min-height: 460px;
|
background-image: url('~/assets/images/questionnaire/reserve_bg_web.svg');
|
background-repeat: no-repeat;
|
background-size: contain;
|
background-position: bottom;
|
}
|
.ques-header__mob-banner{
|
display: none;
|
}
|
.ques-header__info{
|
margin: 30px 20px;
|
width:500px;
|
min-height: 400px;
|
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
|
-moz-box-sizing: border-box; /* Firefox, other Gecko */
|
box-sizing: border-box;
|
}
|
.ques-container{
|
margin: 0px;
|
}
|
}
|
|
|
</style>
|