From abfd26bb700d93a92da6a04703b0187d4acaaeb5 Mon Sep 17 00:00:00 2001 From: Tomas <tomasysh@gmail.com> Date: 星期三, 22 十二月 2021 10:13:02 +0800 Subject: [PATCH] refactor: move ts folder to shared folder --- PAMapp/pages/login/index.vue | 334 ++++++++++++++++++++++++++++++++++++------------------- 1 files changed, 216 insertions(+), 118 deletions(-) diff --git a/PAMapp/pages/login/index.vue b/PAMapp/pages/login/index.vue index 84e02bd..8e60407 100644 --- a/PAMapp/pages/login/index.vue +++ b/PAMapp/pages/login/index.vue @@ -17,7 +17,7 @@ </div> <div class="pam-inputs mb-10"> - <div class="pt-10" v-show="connectDevice === 'MOBILE'"> + <div class="pam-input-position pt-10" v-show="connectDevice === 'MOBILE'"> <input class="pam-input" :class="{ @@ -27,12 +27,17 @@ placeholder="隢撓�����Ⅳ" :disabled="showPhoneOtpCodeField" > + <i + class="icon-close" + v-if="onPhoneVerifyStep !== 'APPLY_OTP'" + @click="deleteOtpInfo('MOBILE')" + ></i> <div class="error mt-5 mb-5"> <span v-show="!phoneValid">����Ⅳ�撘�炊</span> </div> </div> - <div class="pt-10" v-show="connectDevice === 'EMAIL'"> + <div class="pam-input-position pt-10" v-show="connectDevice === 'EMAIL'"> <input class="pam-input" :class="{ @@ -42,6 +47,11 @@ placeholder="隢撓� Email ���" :disabled="showEmailVerifyField" > + <i + class="icon-close" + v-if="showEmailVerifyField" + @click="deleteOtpInfo('EMAIL')" + ></i> <div class="error mt-5 mb-5"> <span v-show="!emailValid">Email�撘�炊</span> </div> @@ -147,26 +157,23 @@ </template> </div> - <el-row type="flex" justify="center" class="pam-login-page__action-bar mt-30"> <el-button type="primary" v-if="(connectDevice === 'MOBILE' && onPhoneVerifyStep === 'INPUT_OTP') || (connectDevice === 'EMAIL' && onEmailVerifyResendStatus === 'CAN_RESEND')" - :disabled="isLoginBtnDisabled" + :disabled="isSubmitBtnDisabled" @click="login"> � </el-button> </el-row> - <el-dialog - title="甇∟�雿輻��" - :custom-class="'pam-register-dialog'" - :visible.sync="registerDialogVisable" - :fullscreen="true" - :close-on-click-modal="false" - :show-close="false" - center> - <span> + <PopUpFrame + :isOpen.sync="registerDialogVisible" + :dialogWidth="'90%'" + class="pam-register-dialog" + @closePopUp="isReadContract = false" + > + <div class="subTitle text--center mb-20">甇∟�雿輻��</div> <el-row> <input class="pam-input" @@ -184,12 +191,13 @@ </el-row> <el-row class="pt-10"> <div + v-if="registerDialogVisible" class="mdTxt pam-register-dialog__contract" - @scroll="detectContructReadStatus"> + ref="contract" + @scroll="detectContractReadStatus"> <h3>����犖鞈��鈭��</h3> <p class="mt-10"> - �摰�犖鞈��風瘜��������犖鞈���������� - �銝����� + �摰�犖鞈��風瘜��������犖鞈���������銝����� <p> <p class="mt-10"> @@ -208,13 +216,11 @@ </p> <p class="mt-10"> - �������������平���暑�������銝剛瘞���������犖鞈� - ���� + �������������平���暑�������銝剛瘞���������犖鞈��� </p> <p class="mt-10"> - 鈭���������摰���甈∩誑憭�璆凋�撱��恐撠����誑��隞 - ���������銋����嚗�������犖鞈��� + 鈭���������摰���甈∩誑憭�璆凋�撱��恐撠����誑��隞���������銋����嚗�������犖鞈��� </p> <p class="mt-10"> @@ -248,35 +254,35 @@ </el-row> <el-row class="pt-30"> <div class="pam-agree-radio"> - <label for="agreeControct" class="pam-radio" + <label for="agreeContract" class="pam-radio" :class="{disabled: !isReadContract}"> <input type="radio" - id="agreeControct" - @click="agreeControct = !agreeControct" + id="agreeContract" + @click="agreeContract = !agreeContract" :disabled="!isReadContract" - value="agreeControct"> - <i :class="agreeControct ?'icon-checkbox-1': 'icon-checkbox'"></i>����蒂蝜潛�� + value="agreeContract"> + <i :class="agreeContract ?'icon-checkbox-1': 'icon-checkbox'"></i>����蒂蝜潛�� </label> </div> </el-row> - </span> - <span slot="footer" class="dialog-footer"> - <el-button - type="primary" - :disabled="!name || !agreeControct || !isReadContract" - @click="applyAccount" - >撱箇�撣唾�� - </el-button> - </span> - </el-dialog> + <div class="text--center mt-10"> + <el-button + type="primary" + :disabled="!name || !agreeContract || !isReadContract" + @click="applyAccount" + >撱箇�撣唾�� + </el-button> + </div> + </PopUpFrame> <PopUpFrame class="pam-popUpFrame" - :isOpen.sync="emailOtpConfirmVisable"> + :isOpen.sync="emailOtpConfirmVisable" + > <div class="pam-popUp-title text--center">撌脣������</div> <div class="pam-popUp-title text--center">{{email}}</div> <div class="pam-popUp-title text--center">隢��摮隞嗡蒂摰������</div> - <div class="pam-popUp-confirm-bolck pam-paragraph"> + <div class="pam-popUp-confirm-bolck mt-30"> <div class="text--center"> <el-button type="primary" @@ -287,29 +293,37 @@ </PopUpFrame> <PopUpFrame class="pam-popUpFrame" - :isOpen.sync="registerSuccessConfirmVisable"> + :isOpen.sync="registerSuccessConfirmVisable" + @closePopUp="confirmApplySuccess" + > <div class="pam-popUp-title text--center"> 甇∟�����������垣閰g�“���誑�����{ connectDevice === 'MOBILE' ? '����Ⅳ' : 'Email'}}���蝜� </div> - <div class="pam-popUp-confirm-bolck pam-paragraph"> + <div class="pam-popUp-txt text--center mb-10 mt-5" + >�撠�歲��...{{autoRedirectCounter}}蝘�</div> + <div class="pam-popUp-confirm-bolck mt-30"> <div class="text--center"> <el-button type="primary" - @click="confirmApplySuccess" + @click="registerSuccessConfirmVisable = false" >������</el-button> </div> </div> </PopUpFrame> <PopUpFrame class="pam-popUpFrame" - :isOpen.sync="phoneSuccessConfirmVisable"> - <div class="pam-popUp-title text--center mb-50" + :isOpen.sync="phoneSuccessConfirmVisable" + @closePopUp="confirmApplySuccess" + > + <div class="pam-popUp-title text--center" >甇∟�������</div> - <div class="pam-popUp-confirm-bolck pam-paragraph"> + <div class="pam-popUp-txt text--center mb-30 mt-5 xsTxt" + >�撠�歲��...{{autoRedirectCounter}}蝘�</div> + <div class="pam-popUp-confirm-bolck mt-30"> <div class="text--center"> <el-button type="primary" - @click="confirmApplySuccess" + @click="phoneSuccessConfirmVisable = false" >������</el-button> </div> </div> @@ -320,9 +334,15 @@ <script lang="ts"> import { namespace } from 'nuxt-property-decorator'; -import { Vue, Component } from 'vue-property-decorator'; -import { LoginRequest, LoginVerify, loginVerify, OtpInfo, register, RegisterInfo, sendOtp } from '~/assets/ts/api/consultant'; -import { Role } from '~/assets/ts/models/enum/Role'; +import { Vue, Component, Ref } from 'vue-property-decorator'; +import ErrorMessageBox from '~/shared/errorService'; +import { OtpErrorCode } from '~/shared/models/enum/otpErrorCode'; +import { Role } from '~/shared/models/enum/role'; +import { LoginRequest } from '~/shared/models/loginRequest.model'; +import { LoginVerify } from '~/shared/models/loginVerify.model'; +import { OtpInfo } from '~/shared/models/otpInfo.model'; +import { RegisterInfo } from '~/shared/models/registerInfo'; +import loginService from '~/shared/services/login.service'; const roleStorage = namespace('localStorage'); @@ -330,37 +350,44 @@ export default class Login extends Vue { @roleStorage.Mutation storageIdToken!: (token:string) => void; @roleStorage.Mutation storageRole!: (role:string) => void; + @Ref('contract') readonly contract!: any; connectDevice: 'MOBILE' | 'EMAIL' = 'MOBILE'; phoneNumber = ''; otpCode = ''; onPhoneVerifyStep: 'APPLY_OTP' | 'INPUT_OTP' | 'SUBMIT_OTP' = 'APPLY_OTP'; - otpCounterSec = 900; + otpCounterSec = 300; otpResendCounter = 30; otpInterval: any; phoneOtpInfo!: OtpInfo; email = ''; onEmailVerifyResendStatus: 'APPLY_OTP' | 'CAN_RESEND' = 'APPLY_OTP'; - emailCounterSec = 900; + emailCounterSec = 300; emailResendCounter = 30; emailOtpCode = ''; emailResendInterval: any; emailOtpInfo!: OtpInfo; + autoRedirectCounter = 3; + autoRedirectInterval: any; + name = ''; - agreeControct = false; + agreeContract = false; isReadContract = false; phoneSuccessConfirmVisable = false; emailOtpConfirmVisable = false; - registerDialogVisable = false; + registerDialogVisible = false; registerSuccessConfirmVisable = false; applyAccount_onAction = false; + previousPath = ''; + + ///////////////////////////////////////////////////// mounted() { const phoneOtpTime = localStorage.getItem('phoneOtpTime'); const emailOtpTime = localStorage.getItem('emailOtpTime'); @@ -374,7 +401,23 @@ } } - detectContructReadStatus(event: any): void { + beforeRouteEnter (to, from, next) { + next(vm => { + console.log(from.path, 'beforeRouteEnter'); + vm.previousPath = from.path; + }) + } + + destroyed() { + this.removeOtpTime(); + clearInterval(this.otpInterval); + clearInterval(this.emailResendInterval); + clearInterval(this.autoRedirectInterval); + } + + ////////////////////////////////////////////////////////// + + detectContractReadStatus(event: any): void { const scrollTop = Math.round(event.target.scrollTop); const height = event.target.scrollHeight - event.target.clientHeight; if (Math.floor(scrollTop/10) === (Math.floor(height/10))) { @@ -382,16 +425,22 @@ } }; + get isSubmitBtnDisabled(): boolean { + return this.connectDevice === 'MOBILE' + ? (!this.otpCode || !this.phoneNumber || !this.phoneValid || !this.otpCounterSec) + : (!this.emailOtpCode || !this.email || !this.emailValid || !this.emailCounterSec) + } + get phoneCounter() { let min = Math.floor(this.otpCounterSec / 60); let sec = Math.floor(this.otpCounterSec % 60); - return `${min < 10 ? '0' + min : min} : ${sec < 10 ? '0' + sec : sec}`; + return `${min < 10 ? '0' + min : min}:${sec < 10 ? '0' + sec : sec}`; } get emailOtpCounter() { let min = Math.floor(this.emailCounterSec / 60); let sec = Math.floor(this.emailCounterSec % 60); - return `${min < 10 ? '0' + min : min} : ${sec < 10 ? '0' + sec : sec}`; + return `${min < 10 ? '0' + min : min}:${sec < 10 ? '0' + sec : sec}`; } get showPhoneOtpCodeField(): boolean { @@ -412,38 +461,41 @@ return this.email ? rule.test(this.email) : true; } - get isLoginBtnDisabled() { - return this.connectDevice === 'MOBILE' - ? (!this.otpCode || !this.phoneNumber || !this.phoneValid || !this.otpCounterSec) - : (!this.emailOtpCode || !this.email || !this.emailValid || !this.emailCounterSec) - } - applyOtpVerification(type: string): void { const isMobile = this.connectDevice === 'MOBILE'; const loginInfo: LoginRequest = { loginType: isMobile ? 'SMS' : 'EMAIL', account: isMobile ? this.phoneNumber : this.email, } - sendOtp(loginInfo).then(otpInfo => { + loginService.sendOtp(loginInfo).then(otpInfo => { if (otpInfo.success) { this.storageOtpTime(type, otpInfo); this.startOtpSetting(type); this.startOtpCount(type); + } else { + const errorMsg = OtpErrorCode[otpInfo.failCode] ? OtpErrorCode[otpInfo.failCode]:'OTP蝟餌絞�隤�'; + ErrorMessageBox(errorMsg); } }); }; resentOtp(type: string) { - if (type === 'MOBILE') { - clearInterval(this.otpInterval); - this.otpResendCounter = 30; - this.otpCounterSec = 900; - } else { - clearInterval(this.emailResendInterval); - this.emailResendCounter = 30; - this.emailCounterSec = 900; - } + this.resetOtpSetting(type); this.applyOtpVerification(type); + } + + deleteOtpInfo(type: string) { + this.resetOtpSetting(type); + if (type === 'MOBILE') { + this.onPhoneVerifyStep = 'APPLY_OTP'; + this.phoneNumber = ''; + this.otpCode = ''; + } else { + this.onEmailVerifyResendStatus = 'APPLY_OTP'; + this.email = ''; + this.emailOtpCode = ''; + } + this.removeOtpTime(); } applyAccount(): void { @@ -454,10 +506,11 @@ this.applyAccount_onAction = true; const registerInfo = this.setRegisterInfo(); - register(registerInfo).then(res => { - this.storageIdToken(res.data.id_token); + loginService.register(registerInfo).then(res => { + this.storageIdToken(res.id_token); this.storageRole(Role.USER); this.storagePhoneOrEmail(registerInfo); + this.autoRedirect(); this.registerSuccessConfirmVisable = true; }).catch(() => { this.applyAccount_onAction = false; @@ -467,28 +520,62 @@ confirmApplySuccess(): void { this.phoneSuccessConfirmVisable = false; this.registerSuccessConfirmVisable = false; - this.$router.go(-1); + this.redirect(); } login() { const login: LoginVerify = this.setLoginInfo(); this.removeOtpTime(); - loginVerify(login).then(res => { - this.storageIdToken(res.data.id_token); + loginService.loginVerify(login).then(res => { + this.storageIdToken(res.id_token); this.storageRole(Role.USER); this.phoneSuccessConfirmVisable = true; + this.autoRedirect(); this.storagePhoneOrEmail(this.setRegisterInfo()); }).catch(error => { - if (error.response.status === 401) { - this.registerDialogVisable = true; - } - }) + this.checkHttpErrorStatus(error); + }); } - destroyed() { - this.removeOtpTime(); - clearInterval(this.otpInterval); - clearInterval(this.emailResendInterval); + + ////////////////////////////////////////////////////////////////// + private checkHttpErrorStatus(error:any):void{ + switch (error.response.status) { + case 401: + const errorMsg = OtpErrorCode[error.response?.data?.detail] ? OtpErrorCode[error.response?.data?.detail]:'OTP蝟餌絞�隤�'; + ErrorMessageBox(errorMsg); + break; + case 403: + this.registerDialogVisible = true; + setTimeout(() => { + const isScrollBarNeedless = this.contract.scrollHeight <= this.contract.clientHeight; + if (isScrollBarNeedless) { + this.isReadContract = true; + } + }, 1000); + break; + default: + ErrorMessageBox('',error); + break; + } + } + + private autoRedirect() { + this.autoRedirectInterval = setInterval(() => { + this.autoRedirectCounter -= 1; + + if (this.autoRedirectCounter === 0) { + clearInterval(this.autoRedirectInterval); + this.redirect(); + } + }, 1000) + } + + private redirect() { + const backToPrevious = ['questionnaire', 'myConsultantList']; + const find = backToPrevious.findIndex(item => this.previousPath.includes(item)); + console.log(this.previousPath, find, 'redirect'); + find > -1 ? this.$router.go(-1) : this.$router.push('/'); } private phoneDiffTime(parseOtpTime: any) { @@ -525,6 +612,18 @@ const currentTime = new Date().getTime(); const storageTime = new Date(parseOtpTime).getTime(); return Math.floor((currentTime - storageTime) / 1000); + } + + private resetOtpSetting(type: string) { + if (type === 'MOBILE') { + clearInterval(this.otpInterval); + this.otpResendCounter = 30; + this.otpCounterSec = 300; + } else { + clearInterval(this.emailResendInterval); + this.emailResendCounter = 30; + this.emailCounterSec = 300; + } } private setOtpInfo(parseOtpTime) { @@ -628,6 +727,9 @@ display: flex; flex: 1; align-items: flex-end; + @include desktop { + margin-bottom: 30px; + } } } @@ -648,17 +750,21 @@ } } - .pam-register-dialog__contract { - $DEVICE_EXTRA_HEIGHT: 42px; - $ALIGN_PADDING: 60px; - $TOP_CONTENT_HEIGHT: 186px; - $BOTTOM_CONTENT_HEIGHT: 131px; - max-height: calc(100vh - $DEVICE_EXTRA_HEIGHT - $ALIGN_PADDING - $TOP_CONTENT_HEIGHT - $BOTTOM_CONTENT_HEIGHT); - overflow-y: scroll; - border-radius: 6px; - border: 1px solid #707070; - padding: 20px; +.pam-register-dialog__contract { + $DEVICE_EXTRA_HEIGHT: 80px; + $ALIGN_PADDING: 60px; + $TOP_CONTENT_HEIGHT: 211px; + $BOTTOM_CONTENT_HEIGHT: 141px; + // text-align:start; + max-height: calc(100vh - $DEVICE_EXTRA_HEIGHT - $ALIGN_PADDING - $TOP_CONTENT_HEIGHT - $BOTTOM_CONTENT_HEIGHT); + overflow-y: scroll; + border-radius: 6px; + border: 1px solid #707070; + padding: 20px; + @include desktop { + height: 335px; } +} .pam-radio { color: $PRIMARY_RED; @@ -672,31 +778,6 @@ i { font-size: 27px; padding-right: 5px; - } - } - - .pam-register-dialog { - padding: 30px 20px; - display: flex; - flex-direction: column; - border-radius: 0; - &.el-dialog { - border-radius: 0; - } - .el-dialog__header { - padding: 0; - margin-bottom: 30px; - .el-dialog__title { - @extend .subTitle; - } - } - .el-dialog__body { - flex: 1; - padding: 0; - margin-bottom: 30px; - } - .el-dialog__footer { - padding: 0 !important; } } @@ -715,7 +796,24 @@ font-size: 20px; line-height: 27px; } + + .pam-popUp-txt { + font-size: 18px; + color: $MID_GREY; + } + .disabled { color: #A7A8AA; } + + .pam-input-position { + position: relative; + .icon-close { + cursor: pointer; + position: absolute; + right: 15px; + top: 28px; + font-size: 16px; + } + } </style> -- Gitblit v1.8.0