236 lines
5.2 KiB
Vue
236 lines
5.2 KiB
Vue
<script setup lang="ts">
|
||
import { computed, ref } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { storeToRefs } from 'pinia'
|
||
import { ElMessage } from 'element-plus'
|
||
import { useProfileStore } from '@/stores/modules/profile'
|
||
import { useCountDown } from '@/composables/useCountDown'
|
||
|
||
const router = useRouter()
|
||
const profileStore = useProfileStore()
|
||
const { profile } = storeToRefs(profileStore)
|
||
|
||
const hasPhone = computed(() => Boolean(profile.value?.phone))
|
||
|
||
const phone = ref('')
|
||
const code = ref('')
|
||
|
||
const { seconds, isCounting, start } = useCountDown(60)
|
||
|
||
function onGetCode(): void {
|
||
const target = hasPhone.value ? profile.value?.phone : phone.value
|
||
if (!target) {
|
||
ElMessage.warning('请输入手机号')
|
||
return
|
||
}
|
||
start(60)
|
||
ElMessage.success('验证码已发送')
|
||
}
|
||
|
||
function onSubmit(): void {
|
||
const target = hasPhone.value ? profile.value?.phone : phone.value
|
||
if (!target) {
|
||
ElMessage.warning('请输入手机号')
|
||
return
|
||
}
|
||
if (!code.value) {
|
||
ElMessage.warning('请输入验证码')
|
||
return
|
||
}
|
||
void profileStore.bindPhone(target, code.value).then(() => {
|
||
void router.push('/profile/security')
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div class="bind-phone-page">
|
||
<h2 class="bind-phone-page__title">
|
||
绑定手机号
|
||
</h2>
|
||
|
||
<form class="bind-phone-page__form" @submit.prevent="onSubmit">
|
||
<div class="bind-phone-page__field">
|
||
<label class="bind-phone-page__label">手机号</label>
|
||
<input
|
||
v-if="hasPhone"
|
||
class="bind-phone-page__input bind-phone-page__input--disabled"
|
||
type="text"
|
||
:value="profile?.phone ?? ''"
|
||
readonly
|
||
>
|
||
<input
|
||
v-else
|
||
v-model="phone"
|
||
class="bind-phone-page__input"
|
||
type="text"
|
||
placeholder="请输入手机号"
|
||
maxlength="20"
|
||
>
|
||
</div>
|
||
|
||
<div class="bind-phone-page__field">
|
||
<label class="bind-phone-page__label">验证码</label>
|
||
<div class="bind-phone-page__code">
|
||
<input
|
||
v-model="code"
|
||
class="bind-phone-page__input"
|
||
type="text"
|
||
placeholder="请输入验证码"
|
||
maxlength="6"
|
||
>
|
||
<button
|
||
type="button"
|
||
class="bind-phone-page__get-code"
|
||
:disabled="isCounting"
|
||
@click="onGetCode"
|
||
>
|
||
{{ isCounting ? `${seconds}秒后重获` : '获取验证码' }}
|
||
</button>
|
||
</div>
|
||
<p class="bind-phone-page__hint">
|
||
注:更换新手机号之后,可以用新的手机号充当当前账号登录
|
||
</p>
|
||
</div>
|
||
|
||
<button type="submit" class="bind-phone-page__submit">
|
||
{{ hasPhone ? '验证并换绑' : '验证并绑定' }}
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</template>
|
||
|
||
<style lang="less" scoped>
|
||
.bind-phone-page {
|
||
.flex(column, flex-start, stretch);
|
||
|
||
&__title {
|
||
position: relative;
|
||
padding-left: 14px;
|
||
margin-bottom: 24px;
|
||
font-size: @font-size-base;
|
||
font-weight: 600;
|
||
color: @profile-ink;
|
||
line-height: 20px;
|
||
|
||
&::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0;
|
||
top: 3px;
|
||
width: 4px;
|
||
height: 14px;
|
||
border-radius: 2px;
|
||
background: @primary-strong;
|
||
}
|
||
}
|
||
|
||
&__form {
|
||
width: 860px;
|
||
max-width: 100%;
|
||
}
|
||
|
||
&__field {
|
||
.flex(column, flex-start);
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
&__label {
|
||
margin-bottom: 12px;
|
||
font-size: @font-size-sm;
|
||
font-weight: 500;
|
||
color: @profile-ink;
|
||
line-height: 14px;
|
||
}
|
||
|
||
&__input {
|
||
width: 100%;
|
||
height: 38px;
|
||
padding: 0 14px;
|
||
border: 1px solid @profile-input-border;
|
||
border-radius: @profile-radius;
|
||
background: @white;
|
||
font-size: 13px;
|
||
color: @profile-ink;
|
||
outline: none;
|
||
transition: border-color 0.2s;
|
||
box-sizing: border-box;
|
||
|
||
&:focus {
|
||
border-color: @primary-strong;
|
||
}
|
||
|
||
&::placeholder {
|
||
color: @finance-axis-text;
|
||
}
|
||
|
||
&--disabled {
|
||
border-color: transparent;
|
||
background: @profile-input-disabled-bg;
|
||
color: @finance-muted-text;
|
||
cursor: not-allowed;
|
||
}
|
||
}
|
||
|
||
&__code {
|
||
position: relative;
|
||
width: 100%;
|
||
|
||
.bind-phone-page__input {
|
||
padding-right: 124px;
|
||
}
|
||
}
|
||
|
||
&__get-code {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
width: 107px;
|
||
height: 38px;
|
||
border: 1px solid @primary-strong;
|
||
border-radius: @profile-radius;
|
||
background: @white;
|
||
color: @primary-strong;
|
||
font-size: 13px;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
|
||
&:hover:not(:disabled) {
|
||
background: @primary-strong;
|
||
color: @white;
|
||
}
|
||
|
||
&:disabled {
|
||
border-color: @text-color-disabled;
|
||
color: @text-color-disabled;
|
||
cursor: not-allowed;
|
||
}
|
||
}
|
||
|
||
&__hint {
|
||
margin-top: 8px;
|
||
font-size: @font-size-sm;
|
||
color: @finance-axis-text;
|
||
line-height: 16px;
|
||
}
|
||
|
||
&__submit {
|
||
width: 100%;
|
||
height: 46px;
|
||
margin-top: 2px;
|
||
border: none;
|
||
border-radius: @profile-radius;
|
||
background: @primary-strong;
|
||
color: @white;
|
||
font-size: @font-size-base;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: background 0.2s;
|
||
|
||
&:hover {
|
||
background: darken(@primary-strong, 6%);
|
||
}
|
||
}
|
||
}
|
||
</style>
|