From cfd8c1b9f5acce841d118d951458565d16ba5719 Mon Sep 17 00:00:00 2001
From: 劉鈞霖 <benson@gmail.com>
Date: 星期三, 24 十一月 2021 14:59:46 +0800
Subject: [PATCH] Merge branch 'master' of ssh://dev.pollex.com.tw:29418/pcalife/PAM

---
 PAMapp/pages/login/index.vue |  421 +++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 297 insertions(+), 124 deletions(-)

diff --git a/PAMapp/pages/login/index.vue b/PAMapp/pages/login/index.vue
index 39bb3ea..0b33aac 100644
--- a/PAMapp/pages/login/index.vue
+++ b/PAMapp/pages/login/index.vue
@@ -1,104 +1,129 @@
 <template>
     <div class="pam-login-page">
-      <div class="text--middle">��</div>
+        <div class='mb-30'>
+          <div class="mdTxt">���撘�</div>
+          <div class="pam-field-title__hint mt-5 mb-10"
+          >憿批���誑甇廾{connectDevice === 'MOBILE' ? '����Ⅳ' : 'Email'}}�銝餉���垣閰Z蝜急撘�</div>
 
-      <div class="pam-paragraph">
-        <div class="mdTxt">
-        撽�撘�<small class="pam-field-title__hint pl-10">(憿批��誑�����撘��蝜�)</small>
-        </div>
-        <div class="pam-tags">
-          <el-row type="flex" class="pt-10">
-            <el-button
-              :class="{ 'active': connectDevice === 'MOBILE'}"
-              @click="connectDevice = 'MOBILE'">����Ⅳ</el-button>
-            <el-button
-              :class="{ 'active': connectDevice === 'EMAIL'}"
-              @click="connectDevice = 'EMAIL'">Email</el-button>
-          </el-row>
-
-        </div>
-          <el-row type="flex" class="pt-10" v-show="connectDevice === 'MOBILE'">
-            <input
-              class="pam-input"
-              :class="{
-                'is-invalid': !phoneNumber
-              }"
-              v-model="phoneNumber"
-              placeholder="隢撓�����Ⅳ"
-              >
-          </el-row>
-
-          <el-row class="pt-10" v-show="connectDevice === 'EMAIL'">
-            <input
-              class="pam-input"
-              :class="{
-                'is-invalid': !phoneNumber
-              }"
-              v-model="email"
-              placeholder="隢撓� Email ���"
-              >
-          </el-row>
-
-          <div class="pt-30" v-show="showPhoneOtpCodeField">
-            <el-row type="flex" justify="space-between">
-                <div class="mdTxt">頛詨撽�Ⅳ</div>
-                <div class="otp-count-timer">
-                  13:50
-                </div>
+          <div class="pam-tags">
+            <el-row type="flex" class="pt-30">
+              <el-button
+                :class="{ 'active': connectDevice === 'MOBILE'}"
+                @click="connectDevice = 'MOBILE'">����Ⅳ</el-button>
+              <el-button
+                :class="{ 'active': connectDevice === 'EMAIL'}"
+                @click="connectDevice = 'EMAIL'">Email</el-button>
             </el-row>
+          </div>
 
-            <el-row class="pt-10">
+          <div class="pam-inputs mb-10">
+            <div class="pt-10" v-show="connectDevice === 'MOBILE'">
+              <input
+                  class="pam-input"
+                  :class="{
+                    'is-invalid': !phoneValid
+                  }"
+                  v-model="phoneNumber"
+                  placeholder="隢撓�����Ⅳ">
+              <div class="error mt-5 mb-5">
+                  <span v-show="!phoneValid">����Ⅳ�撘�炊</span>
+              </div>
+            </div>
+
+            <div class="pt-10" v-show="connectDevice === 'EMAIL'">
               <input
                 class="pam-input"
                 :class="{
-                  'is-invalid': !otpCode
+                  'is-invalid': !emailValid
                 }"
-                v-model="otpCode"
-                placeholder="隢撓�撽�Ⅳ"
+                v-model="email"
+                placeholder="隢撓� Email ���"
+              >
+              <div class="error mt-5 mb-5">
+                  <span v-show="!emailValid">Email�撘�炊</span>
+              </div>
+            </div>
+          </div>
+
+          <!-- mobile 撽�Ⅳ -->
+          <template v-if="connectDevice === 'MOBILE'">
+            <div v-show="showPhoneOtpCodeField">
+              <el-row type="flex" justify="space-between">
+                  <div class="mdTxt">頛詨撽�Ⅳ</div>
+                  <div class="otp-count-timer">
+                    {{otpCounter}}
+                  </div>
+              </el-row>
+
+              <el-row class="mb-30">
+                <input
+                  class="pam-input mt-10"
+                  :class="{
+                    'is-invalid': !otpCode
+                  }"
+                  v-model="otpCode"
+                  placeholder="隢撓�撽�Ⅳ"
+                  >
+              </el-row>
+
+              <el-row>
+                <el-button
+                  :disabled="!phoneNumber || otpResendCounter !== 0 || !phoneValid"
+                  @click="resentOtp('MOBILE')"
+                  icon="icon-arrow"
                 >
+                  ��撽�Ⅳ<span class="pam-field-title__hint pl-5">({{ otpResendCounter }})</span>
+                </el-button>
+              </el-row>
+            </div>
+
+            <el-row>
+              <el-button
+                  v-if="onPhoneVerifyStep === 'APPLY_OTP'"
+                  :disabled="!phoneNumber || !phoneValid"
+                  @click="applyOtpVerification('MOBILE')"
+                  icon="icon-arrow"
+                >
+                  ����Ⅳ
+                </el-button>
             </el-row>
 
-            <el-row class="pt-10">
-              <button
-                class="pam-otp-resend-btn"
-                :class="{'disabled': true}">
-                <i class="icon-arrow"></i>
-                ��撽�Ⅳ({{ otpResendCounter }})
-              </button>
-            </el-row>
-          </div>
+          </template>
 
-          <div v-show="showEmailVerifyField">
-            <el-row class="pt-10">
-              <button
-                class="pam-otp-resend-btn"
-                :class="{'disabled': onEmailVerifyResendStatus === 'CANNOT_RESEND'}">
-                <i class="icon-arrow"></i>
-                ��撽�Ⅳ({{ emailResendCounter }})
-              </button>
+          <!-- email 撽�Ⅳ -->
+          <template v-if="connectDevice === 'EMAIL'">
+            <el-row v-show="showEmailVerifyField">
+              <el-button
+                :disabled="!email || emailResendCounter !== 0 || !emailValid"
+                icon="icon-arrow"
+                @click="resentOtp('EMAIL')"
+              >
+                ��撽�Ⅳ<span class="pam-field-title__hint pl-5">({{ emailResendCounter }})</span>
+              </el-button>
+              <div class="mt-10 smTxt_bold text--primary">! 隢�����mail敺�</div>
             </el-row>
-          </div>
+
+            <el-row v-show="!showEmailVerifyField">
+              <el-button
+                  :disabled="!email || !emailValid"
+                  @click="applyOtpVerification('EMAIL')"
+                  icon="icon-arrow"
+                >
+                  ����Ⅳ
+                </el-button>
+            </el-row>
+          </template>
       </div>
 
-      <el-row type="flex" justify="center" class="pam-login-page__action-bar">
-        <div v-if="connectDevice === 'MOBILE'">
-          <el-button
-            type="primary"
-            v-if="onPhoneVerifyStep === 'APPLY_OTP'"
-            :disabled="!phoneNumber"
-            @click="applyOtpVerification">
-            ����Ⅳ
-          </el-button>
 
-          <el-button
-            type="primary"
-            v-if="connectDevice === 'MOBILE' && onPhoneVerifyStep === 'INPUT_OTP'"
-            :disabled="!otpCode"
-            @click="registerDialogVisable = true">
-            �
-          </el-button>
-        </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'"
+          :disabled="!otpCode || !phoneNumber || !phoneValid"
+          @click="phoneLogin">
+          �
+        </el-button>
       </el-row>
 
       <el-dialog
@@ -213,7 +238,22 @@
       </el-dialog>
 
       <PopUpFrame class="pam-popUpFrame"
-        :isOpen.sync="applySuccessConfirmVisable">
+        :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="text--center">
+            <el-button
+                type="primary"
+                @click="emailOtpConfirmVisable = false"
+            >������</el-button>
+          </div>
+        </div>
+      </PopUpFrame>
+
+      <PopUpFrame class="pam-popUpFrame"
+        :isOpen.sync="registerSuccessConfirmVisable">
           <div class="pam-popUp-title text--center">
             甇∟�����������垣閰g�“���誑�����{ connectDevice === 'MOBILE' ? '����Ⅳ' : 'Email'}}���蝜�
           </div>
@@ -227,14 +267,27 @@
           </div>
       </PopUpFrame>
 
-      <el-button class="mt-30" @click="fakeLogin">摰X��</el-button>
+      <PopUpFrame class="pam-popUpFrame"
+        :isOpen.sync="phoneSuccessConfirmVisable">
+          <div class="pam-popUp-title text--center mb-50"
+          >甇∟�������</div>
+          <div class="pam-popUp-confirm-bolck pam-paragraph">
+            <div class="text--center">
+              <el-button
+                  type="primary"
+                  @click="confirmApplySuccess"
+              >������</el-button>
+            </div>
+          </div>
+      </PopUpFrame>
+
     </div>
 </template>
 
 <script lang="ts">
 import { namespace } from 'nuxt-property-decorator';
 import { Vue, Component } from 'vue-property-decorator';
-import { login } from '~/assets/ts/api/consultant';
+import { LoginRequest, loginVerify, OtpInfo, register, RegisterInfo, sendOtp } from '~/assets/ts/api/consultant';
 import { Role } from '~/assets/ts/models/enum/Role';
 
 const roleStorage = namespace('localStorage');
@@ -249,20 +302,33 @@
   phoneNumber = '';
   otpCode = '';
   onPhoneVerifyStep: 'APPLY_OTP' | 'INPUT_OTP' | 'SUBMIT_OTP' = 'APPLY_OTP';
+  otpCounter = '15:00';
   otpResendCounter = 30;
+  otpInterval: any;
+  phoneOtpInfo!: OtpInfo;
 
   email = '';
-  onEmailVerifyResendStatus: 'CAN_RESEND' | 'CANNOT_RESEND' = 'CANNOT_RESEND';
+  onEmailVerifyResendStatus: 'APPLY_OTP' | 'CAN_RESEND' = 'APPLY_OTP';
   emailResendCounter = 30;
+  emailResendInterval: any;
+  emailOtpInfo!: OtpInfo;
 
-  registerDialogVisable = false;
-  applySuccessConfirmVisable = false;
   name = '';
   agreeControct = false;
   isReadContract = false;
 
+  phoneSuccessConfirmVisable = false;
+  emailOtpConfirmVisable = false;
+
+  registerDialogVisable = false;
+  registerSuccessConfirmVisable = false;
+
   detectContructReadStatus(event: any): void {
-    this.isReadContract = Math.round(event.target.scrollTop) === (event.target.scrollHeight - event.target.clientHeight);
+    const scrollTop = Math.round(event.target.scrollTop);
+    const height = event.target.scrollHeight - event.target.clientHeight;
+    if (Math.floor(scrollTop/10) === (Math.floor(height/10))) {
+      this.isReadContract = true;
+    }
   };
 
   get showPhoneOtpCodeField(): boolean {
@@ -270,34 +336,141 @@
   };
 
   get showEmailVerifyField(): boolean {
-    return this.connectDevice === 'EMAIL';
+    return this.connectDevice === 'EMAIL' && this.onEmailVerifyResendStatus !== 'APPLY_OTP';
   };
 
-  applyOtpVerification(): void {
-    this.onPhoneVerifyStep = 'INPUT_OTP';
+  get phoneValid() {
+    const rule = /^09[0-9]{8}$/;
+    return this.phoneNumber ? rule.test(this.phoneNumber) : true;
+  }
+
+  get emailValid() {
+    const rule = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
+    return this.email ? rule.test(this.email) : true;
+  }
+
+  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 => {
+      if (otpInfo.success) {
+        this.startOtpCount(type, otpInfo);
+      }
+    });
   };
+
+  resentOtp(type: string) {
+    if (type === 'MOBILE') {
+      clearInterval(this.otpInterval);
+      this.otpResendCounter = 30;
+      this.otpCounter = '15:00';
+      this.startPhoneCounter();
+    } else {
+      this.emailResendCounter = 30;
+      this.startEmailCounter();
+      this.emailOtpConfirmVisable = true;
+    }
+  }
+
+  private startOtpCount(type: string, otpInfo) {
+    type === 'MOBILE' ? this.phoneOtpInfo = otpInfo : this.emailOtpInfo = otpInfo;
+    if (type === 'MOBILE') {
+        this.onPhoneVerifyStep = 'INPUT_OTP';
+        this.startPhoneCounter();
+      } else {
+        this.onEmailVerifyResendStatus = 'CAN_RESEND';
+        this.startEmailCounter();
+        this.emailOtpConfirmVisable = true;
+      }
+  }
+
+  private startEmailCounter() {
+    this.emailResendInterval = setInterval(() => {
+      this.emailResendCounter -= 1;
+      if (this.emailResendCounter === 0) {
+        clearInterval(this.emailResendInterval)
+      }
+    }, 1000)
+  }
+
+  private startPhoneCounter() {
+    const minCount = this.otpCounter.split(':');
+    let secCount = (+minCount[0] * 60) + (+minCount[1]);
+    let min = 0;
+    let sec = 0;
+    this.otpInterval = setInterval(() => {
+      secCount -= 1;
+      min = Math.floor(secCount/60);
+      sec = Math.floor(secCount%60);
+      this.otpCounter = `${min < 10 ? '0' + min : min}:${sec < 10 ? '0' + sec : sec}`;
+
+      if (this.otpResendCounter !== 0) {
+        this.otpResendCounter -= 1;
+      }
+
+      if (secCount === 0) {
+        clearInterval(this.otpInterval)
+      }
+    }, 1000)
+  }
+
+  private setRegisterInfo(): RegisterInfo {
+    return this.connectDevice === 'MOBILE'
+      ? {
+          phone: this.phoneNumber,
+          indexKey: this.phoneOtpInfo.indexKey,
+          otpCode: this.otpCode,
+          name: this.name,
+          contactType: 'SMS'
+        }
+      : {
+          email: this.email,
+          indexKey: this.emailOtpInfo.indexKey,
+          otpCode: this.otpCode,
+          name: this.name,
+          contactType: 'EMAIL'
+        }
+  }
 
   applyAccount(): void {
-    this.applySuccessConfirmVisable = true;
-    console.log('apply new account!')
+    const registerInfo = this.setRegisterInfo();
+    register(registerInfo).then(res => {
+      this.storageIdToken(res.data.id_token);
+      this.storageRole(Role.USER);
+      this.registerSuccessConfirmVisable = true;
+    })
   };
 
   confirmApplySuccess(): void {
-    this.applySuccessConfirmVisable = false
+    this.phoneSuccessConfirmVisable = false;
+    this.registerSuccessConfirmVisable = false;
+    this.$router.go(-1);
   }
 
-  // TODO: ��TP隤����� ���蝙�
-   fakeLogin() {
-        const user = {
-            username: 'user',
-            password: 'user',
-        }
-        login(user).then((res) => {
-            this.storageIdToken(res.data.id_token);
-            this.storageRole(Role.USER);
-            this.$router.go(-1);
-        })
-  };
+  phoneLogin() {
+    const login = {
+      account: this.phoneNumber,
+      indexKey: this.phoneOtpInfo.indexKey,
+      otpCode: this.otpCode
+    }
+    loginVerify(login).then(res => {
+      this.storageIdToken(res.data.id_token);
+      this.storageRole(Role.USER);
+      this.phoneSuccessConfirmVisable = true;
+    }).catch(error => {
+      if (error.response.status === 401) {
+        this.registerDialogVisable = true;
+      }
+    })
+  }
+
+  destroyed() {
+    clearInterval(this.otpInterval);
+    clearInterval(this.emailResendInterval);
+  }
 
 }
 </script>
@@ -319,8 +492,7 @@
   width: calc(100% - 36px);
   border-radius: 10px !important;
   padding: 12px 18px !important;
-  border-width: 1px;
-  outline: none;
+  border:1px solid #CCCCCC;
   @extend .text--middle;
   &::placeholder {
     color: $PRUDENTIAL_GREY;
@@ -328,19 +500,6 @@
   &.is-invalid {
     border: 1px solid $PRIMARY_RED !important;
     border-radius: 20px;
-  }
-}
-
-.pam-otp-resend-btn {
-  background: transparent;
-  border: none;
-  color: $PRIMARY_RED;
-  font-weight: bold;
-  i {
-    margin-right: 10px;
-  }
-  &.disabled {
-    color: $LIGHT_GREY;
   }
 }
 
@@ -396,4 +555,18 @@
   }
 }
 
+.pam-field-title__hint {
+  @extend .smTxt_bold;
+  color: #68737A;
+}
+
+.error {
+  @extend .smTxt_bold;
+  @extend .text--primary;
+  height: 16px;
+}
+
+.pam-popUp-title {
+  line-height: 24px;
+}
 </style>

--
Gitblit v1.8.0