257 lines
5.5 KiB
Vue
257 lines
5.5 KiB
Vue
<script setup lang="ts">
|
||
import { ref, watch } from 'vue'
|
||
import { ElMessage } from 'element-plus'
|
||
import { AppButton, PasswordStrength, SmsCodeInput } from '@/components'
|
||
|
||
interface Props {
|
||
phone: string
|
||
}
|
||
|
||
const props = defineProps<Props>()
|
||
|
||
const visible = defineModel<boolean>('visible', { default: false })
|
||
|
||
const emit = defineEmits<{
|
||
submit: [payload: { code: string; password: string; confirm: string }]
|
||
}>()
|
||
|
||
const code = ref('')
|
||
const password = ref('')
|
||
const confirm = ref('')
|
||
const agree = ref(false)
|
||
|
||
watch(visible, (open) => {
|
||
if (!open) return
|
||
code.value = ''
|
||
password.value = ''
|
||
confirm.value = ''
|
||
agree.value = false
|
||
})
|
||
|
||
function onGetCode(): void {
|
||
ElMessage.success('验证码已发送')
|
||
}
|
||
|
||
function onSubmit(): void {
|
||
if (!code.value) {
|
||
ElMessage.warning('请输入验证码')
|
||
return
|
||
}
|
||
if (!password.value) {
|
||
ElMessage.warning('请输入新密码')
|
||
return
|
||
}
|
||
if (!agree.value) {
|
||
ElMessage.warning('请先阅读并同意《用户协议》和《隐私政策》')
|
||
return
|
||
}
|
||
emit('submit', {
|
||
code: code.value,
|
||
password: password.value,
|
||
confirm: confirm.value,
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<Teleport to="body">
|
||
<div v-if="visible" class="change-pwd-dialog" @click.self="visible = false">
|
||
<div class="change-pwd-dialog__panel">
|
||
<h3 class="change-pwd-dialog__title">
|
||
修改密码
|
||
</h3>
|
||
|
||
<div class="change-pwd-dialog__field">
|
||
<label class="change-pwd-dialog__label">手机号</label>
|
||
<input
|
||
class="change-pwd-dialog__input"
|
||
type="text"
|
||
:value="props.phone"
|
||
readonly
|
||
>
|
||
</div>
|
||
|
||
<div class="change-pwd-dialog__field">
|
||
<label class="change-pwd-dialog__label">验证码</label>
|
||
<SmsCodeInput v-model:code="code" @get-code="onGetCode" />
|
||
</div>
|
||
|
||
<div class="change-pwd-dialog__field">
|
||
<label class="change-pwd-dialog__label">设置密码</label>
|
||
<input
|
||
v-model="password"
|
||
class="change-pwd-dialog__input"
|
||
type="password"
|
||
placeholder="请输入密码(6-20位)"
|
||
maxlength="20"
|
||
>
|
||
<PasswordStrength :password="password" />
|
||
</div>
|
||
|
||
<div class="change-pwd-dialog__field">
|
||
<label class="change-pwd-dialog__label">确认密码</label>
|
||
<input
|
||
v-model="confirm"
|
||
class="change-pwd-dialog__input"
|
||
type="password"
|
||
placeholder="请再次输入密码"
|
||
maxlength="20"
|
||
@keyup.enter="onSubmit"
|
||
>
|
||
</div>
|
||
|
||
<label class="change-pwd-dialog__agree">
|
||
<input v-model="agree" type="checkbox">
|
||
<span>我已阅读并同意<em>《用户协议》</em>和<em>《隐私政策》</em></span>
|
||
</label>
|
||
|
||
<div class="change-pwd-dialog__footer">
|
||
<AppButton type="default" @click="visible = false">
|
||
取消
|
||
</AppButton>
|
||
<AppButton type="primary" @click="onSubmit">
|
||
确认修改
|
||
</AppButton>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</Teleport>
|
||
</template>
|
||
|
||
<style lang="less" scoped>
|
||
.change-pwd-dialog {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 1000;
|
||
.flex(row, center);
|
||
background: transparent;
|
||
overflow-y: auto;
|
||
|
||
&__panel {
|
||
width: 700px;
|
||
max-width: calc(100vw - 32px);
|
||
max-height: calc(100vh - 48px);
|
||
overflow-y: auto;
|
||
padding: @spacing-base;
|
||
border-radius: @radius-lg;
|
||
background: @white;
|
||
box-shadow: @shadow-lg;
|
||
.flex(column, flex-start);
|
||
gap: @spacing-base;
|
||
.scrollbar();
|
||
}
|
||
|
||
&__title {
|
||
position: relative;
|
||
padding-left: 12px;
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
color: @heading-color;
|
||
line-height: 20px;
|
||
|
||
&::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0;
|
||
top: 3px;
|
||
width: 3px;
|
||
height: 14px;
|
||
border-radius: 2px;
|
||
background: @primary-strong;
|
||
}
|
||
}
|
||
|
||
&__field {
|
||
.flex(column, flex-start);
|
||
gap: @spacing-xs;
|
||
width: 100%;
|
||
}
|
||
|
||
&__label {
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
color: @heading-color;
|
||
}
|
||
|
||
&__input {
|
||
width: 100%;
|
||
height: 32px;
|
||
padding: 0 12px;
|
||
border: 1px solid @profile-input-border;
|
||
border-radius: @profile-radius;
|
||
background: @white;
|
||
font-size: 11px;
|
||
color: @text-color;
|
||
outline: none;
|
||
transition: border-color 0.2s;
|
||
box-sizing: border-box;
|
||
|
||
&:focus {
|
||
border-color: @primary-strong;
|
||
}
|
||
|
||
&::placeholder {
|
||
color: @heading-color;
|
||
}
|
||
|
||
&:read-only {
|
||
color: @text-color;
|
||
cursor: not-allowed;
|
||
}
|
||
}
|
||
|
||
&__agree {
|
||
.flex(row, flex-start, center);
|
||
gap: @spacing-sm;
|
||
font-size: 11px;
|
||
color: @text-color-secondary;
|
||
cursor: pointer;
|
||
|
||
input {
|
||
accent-color: @primary-strong;
|
||
}
|
||
|
||
em {
|
||
font-style: normal;
|
||
color: @primary-strong;
|
||
}
|
||
}
|
||
|
||
&__footer {
|
||
.flex(row, flex-start);
|
||
gap: @spacing-sm;
|
||
width: 100%;
|
||
}
|
||
|
||
.app-button {
|
||
flex: 1;
|
||
height: 36px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
border-radius: @profile-radius;
|
||
}
|
||
|
||
.app-button--primary {
|
||
border-color: @primary-strong;
|
||
background: @primary-strong;
|
||
|
||
&:hover {
|
||
border-color: darken(@primary-strong, 6%);
|
||
background: darken(@primary-strong, 6%);
|
||
}
|
||
}
|
||
|
||
.app-button--default {
|
||
border: none;
|
||
background: @profile-quiet-btn;
|
||
color: @text-color;
|
||
|
||
&:hover {
|
||
border: none;
|
||
background: darken(@profile-quiet-btn, 4%);
|
||
color: @text-color;
|
||
}
|
||
}
|
||
}
|
||
</style>
|