保誠-保戶業務員媒合平台
Mila
2024-12-25 68a01779c9df1c8b8d68a642204e80c1b3ff896e
PAMapp/pages/consultantLogin/index.vue
@@ -7,9 +7,14 @@
        <div class="position-r mt-10">
          <input type="text"
            v-model="consultantDto.username"
            :disabled="onOTPVerifyStep === 'CAN_RESEND'"
            class="pam-consultant-login__input"
            placeholder="輸入eService帳號">
          <div class="pam-consultant-login__inputIcon text--primary cursor--pointer fix-chrome-click--issue"
          <div v-if="onOTPVerifyStep === 'CAN_RESEND'" class="pam-consultant-login__inputIcon cursor--pointer fix-chrome-click--issue"
            @click="deleteOtpInfo()">
            <i class="icon-close"></i>
          </div>
          <div v-if="onOTPVerifyStep !== 'CAN_RESEND'" class="pam-consultant-login__inputIcon text--primary cursor--pointer fix-chrome-click--issue"
            @click="isRememberChange">
            <i :class="[isRememberUserName ? 'icon-checkbox-1' : 'icon-checkbox','pr-5']"></i>
            記住
@@ -19,20 +24,21 @@
      <div class="pam-paragraph">
        <div class="password-Txt">
          <div class="pam-consultant-login__title ">密碼</div>
          <div class="password-reset" @click="passwordReset">忘記密碼</div>
          <div class="password-reset" @click="resetPassword">忘記密碼</div>
        </div>
        <div class="position-r mt-10">
          <input :type="[ isShowPassword ? 'text' : 'password']"
          <input :type="checkPasswordType ? 'text' : 'password'"
            v-model="consultantDto.password"
            :disabled="onOTPVerifyStep === 'CAN_RESEND'"
            class="pam-consultant-login__input"
            placeholder="輸入eService密碼">
          <div class="pam-consultant-login__inputIcon cursor--pointer fix-chrome-click--issue"
          <div v-if="onOTPVerifyStep !== 'CAN_RESEND'" class="pam-consultant-login__inputIcon cursor--pointer fix-chrome-click--issue"
            @click="isShowPassword = !isShowPassword">
            <i :class="[isShowPassword ? 'icon-eye':'icon-eye-1 fs-25', 'text--primary']"></i>
          </div>
        </div>
      </div>
      <div class="pam-paragraph">
      <div class="pam-paragraph" v-if="onOTPVerifyStep === 'APPLY_OTP'">
        <div class="pam-consultant-login__title">
          <div>驗證碼 <span class="text--dark-blue fs-16">(區分大小寫)</span></div>
          <div class="text--primary fs-16 cursor--pointer fix-chrome-click--issue"
@@ -50,21 +56,82 @@
          </div>
        </div>
      </div>
      <div class="pam-consultant-login__confirmBlock pam-paragraph">
        <button class="pam-consultant-login__confirm cursor--pointer fix-chrome-click--issue"
          @click="sendInfo">送出</button>
      <!--  -->
      <div v-show="onOTPVerifyStep === 'CAN_RESEND'">
        <el-row type="flex" justify="space-between">
            <div class="mdTxt">輸入 OTP 驗證碼</div>
            <div class="otp-count-timer">
              {{counterTime(otpCounterSec)}}
            </div>
        </el-row>
        <el-row>
          <input
            class="pam-consultant-login__input mt-10"
            :class="{
              'is-invalid': !otpCode
            }"
            v-model="otpCode"
            placeholder="請輸入 OTP 驗證碼"
            >
        </el-row>
        <div class="error mt-5 mb-10">
            <span v-show="otpCounterSec === 0">OTP 驗證碼已過期,請重發 OTP 驗證碼</span>
        </div>
        <el-row>
          <el-button
            :disabled="!consultantDto.password || otpResendCounter !== 0 || !consultantDto.username"
            @click="resetOtpSetting()"
            icon="icon-arrow"
          >
            重發 OTP 驗證碼<span
              class="pam-field-title__hint pl-5"
              v-if="otpResendCounter !== 0"
            >({{ otpResendCounter }})</span>
          </el-button>
        </el-row>
      </div>
      <div class="pam-paragraph">
        <el-button v-if="onOTPVerifyStep === 'APPLY_OTP'" icon="icon-arrow"
          :disabled="!consultantDto.username || !consultantDto.password || verificationCode.length !== 4"
            @click="applyOtpVerification">
            發送 OTP 驗證碼</el-button>
      </div>
       <div class="pam-consultant-login__confirmBlock pam-paragraph"  v-if="onOTPVerifyStep === 'CAN_RESEND'">
        <button class="pam-consultant-login__confirm cursor--pointer fix-chrome-click--issue"
          :disabled="!consultantDto.username || !consultantDto.password || !otpCode || !otpCounterSec"
          @click="sendInfo">送出</button>
        </div>
    </div>
    <PopUpFrame class="pam-popUpFrame"
        :isOpen.sync="otpConfirmVisible"
      >
        <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 mt-30">
          <div class="text--center">
            <el-button
                type="primary"
                @click="otpConfirmVisible = false"
            >我知道了</el-button>
          </div>
        </div>
      </PopUpFrame>
  </div>
</template>
<script lang="ts">
  import { Vue, Component , namespace } from 'nuxt-property-decorator';
  import { Vue, Component , namespace, Watch } from 'nuxt-property-decorator';
  import { AxiosError } from 'axios';
  import { Role } from '~/shared/models/enum/Role';
  import messageBoxService from '~/shared/services/message-box.service';
  import loginService from '~/shared/services/login.service'
import { AgentInfo } from '~/shared/models/agent-info.model';
  import { AgentInfo } from '~/shared/models/agent-info.model';
  const loginStore  = namespace('login.store');
  const roleStorage = namespace('localStorage');
@@ -94,12 +161,31 @@
    isShowPassword = false;
    verificationCode='';
    otpConfirmVisible = false;
    otpCode = '';
    onOTPVerifyStep: 'APPLY_OTP' | 'CAN_RESEND' = 'APPLY_OTP';
    otpCounterSec = 50;
    otpResendCounter = 30;
    otpInterval: NodeJS.Timeout | null = null;
    otpIndexKey!: string;
    @Watch('onOTPVerifyStep')
    onOTPVerifyStepChange() {
      if (this.onOTPVerifyStep === 'APPLY_OTP') {
        this.regenerateImgOfVerification();
      }
    }
    ////////////////////////////////////////////////////////////////////
    mounted() {
      this.getInitUserName();
      this.regenerateImgOfVerification();
    };
    destroyed() {
      clearInterval(this.otpInterval ?? undefined);
    }
    private getInitUserName(): void {
      const username = localStorage.getItem('consultantUserName')
@@ -113,14 +199,34 @@
    public regenerateImgOfVerification(): void {
      loginService.getImgOfVerification().then( imgOfBase64 =>
        this.imgSrc = imgOfBase64
      );
      loginService.getImgOfVerification().then( imgOfBase64 =>{
        this.imgSrc = imgOfBase64;
        this.verificationCode = '';
      });
    };
    public isRememberChange():void{
      this.isRememberUserName = !this.isRememberUserName;
      this.storeUserName();
    }
    public applyOtpVerification(type: string): void {
    // TODO: sendOTP
        const otpInfo = {
          indexKey: "string", /** 用於帶入otp認證時 */
          success: true, /** Otp是否有成功發送 */
          failCode: "string",
          failReason: "string",
        }
        if (otpInfo.success) {
          // this.storageOtpTime(type, otpInfo);
          this.startOtpSetting(type);
          this.startOtpCount();
        } else {
          // TODO: otp error
          // const errorMsg = OtpErrorCode[otpInfo.failCode] ? OtpErrorCode[otpInfo.failCode]:'OTP系統錯誤';
          // messageBoxService.showErrorMessage(errorMsg);
        }
    }
    public sendInfo():void{
@@ -133,18 +239,35 @@
      return !!(this.verificationCode && this.consultantDto.username && this.consultantDto.password);
    }
    passwordReset() {
       const uatResetUrl = 'https://eserviceuat.pcalife.com.tw/sso/reset_password/agentInputUserInfo.html?sys=epos'
      const prodResetUrl ='https://www.eservice.pcalife.com.tw/sso/reset_password/agentInputUserInfo.html?sys=epos'
      if (process.env.ENV === 'uat') {
        window.open(uatResetUrl);
      }
      else {
        window.open(prodResetUrl);
      }
    resetPassword() {
        window.open(process.env.CONSULTANT_FORGET_PASSWORD_URL);
    }
    resetOtpSetting() {
      clearInterval(this.otpInterval ?? undefined);
      this.otpResendCounter = 30;
      this.otpCounterSec = 50;
      this.onOTPVerifyStep = 'APPLY_OTP';
      this.otpCode = '';
  }
    counterTime(counterSec) {
      let min = Math.floor(counterSec / 60);
      let sec = Math.floor(counterSec % 60);
      return `${min < 10 ? '0' + min : min}:${sec < 10 ? '0' + sec : sec}`;
    }
    deleteOtpInfo() {
      this.resetOtpSetting();
      this.onOTPVerifyStep = 'APPLY_OTP';
      this.consultantDto.password = '';
      this.consultantDto.username = '';
      this.otpCode = '';
    }
    get checkPasswordType(): boolean {
      return this.onOTPVerifyStep === 'CAN_RESEND' ? false : this.isShowPassword;
    }
    ////////////////////////////////////////////////////////////////////
    private verify():void{
@@ -160,7 +283,7 @@
    }
    private loginWithConsultant(): void {
      loginService.logInToConsultant(this.consultantDto).then(res => {
      loginService.logInToConsultant(this.consultantDto, this.verificationCode).then(res => {
        this.getLoginConsultantDetail(this.consultantDto.username);
        this.storageIdToken(res.data.id_token);
        this.storageRole(Role.ADMIN);
@@ -196,8 +319,27 @@
      this.consultantDto.password = '';
      this.verificationCode = '';
    }
  };
  private startOtpSetting(type: string) {
    this.onOTPVerifyStep = 'CAN_RESEND';
    this.otpConfirmVisible = true;
  }
  private startOtpCount() {
    this.otpInterval = setInterval(() => {
      this.otpCounterSec -= 1;
      if (this.otpResendCounter !== 0) {
        this.otpResendCounter -= 1;
        if (this.otpResendCounter === 0) {
          // this.regenerateImgOfVerification();
        }
      }
      if (this.otpCounterSec === 0 && this.otpInterval) {
        clearInterval(this.otpInterval);
      }
    }, 1000)
  }
};
</script>
<style lang="scss" scoped>
@@ -224,7 +366,11 @@
  .password-reset {
    font-size: 16px ;
    cursor: pointer;
  }
  .pam-popUp-title {
      font-size: 20px;
      line-height: 27px;
  }
  .pam-consultant-login {
@@ -302,7 +448,24 @@
      border-radius: 30px;
      border: 1px solid $LIGHT_GREY;
      background-color: $PRIMARY_RED;
      font-weight: 700;
      &:disabled {
        color: $PRIMARY_WHITE;
        background-color: $MID_GREY;
        border-color: $MID_GREY;
      }
    }
  }
  .pam-field-title__hint {
    @extend .smTxt_bold;
    color: #68737A;
  }
  .error {
    @extend .smTxt_bold;
    @extend .text--primary;
    height: 16px;
  }
</style>