1107 lines
32 KiB
Vue
1107 lines
32 KiB
Vue
<template>
|
||
<div>
|
||
<a-row :gutter="[16, 16]">
|
||
<a-col :span="24">
|
||
<a-card title="基本设置">
|
||
<div style="margin:0 auto; width: 128px; padding-bottom: 20px;">
|
||
<a-upload v-model:file-list="fileList" name="avatar" list-type="picture-card"
|
||
class="avatar-uploader" :show-upload-list="false"
|
||
action="https://www.mocky.io/v2/5cc8019d300000980a055e76" :before-upload="beforeUpload"
|
||
@change="handleChange">
|
||
<img v-if="imageUrl" :src="imageUrl" alt="avatar" width="100%" height="100%" />
|
||
<div v-else>
|
||
<loading-outlined v-if="loading"></loading-outlined>
|
||
<plus-outlined v-else></plus-outlined>
|
||
<div class="ant-upload-text">Upload</div>
|
||
</div>
|
||
</a-upload>
|
||
</div>
|
||
<div class="info"><span>账户</span><span>17044054908</span></div>
|
||
<div class="info"><span>账户ID</span><span>123456789123456789</span></div>
|
||
<div class="info" style="display: flex;justify-content: space-between;">
|
||
<div>
|
||
<span style="margin-right: 25px;">认证类型</span><span style="color: red;">未实名认证</span>
|
||
</div>
|
||
<div style="color:#1677ff;">前往认证</div>
|
||
</div>
|
||
</a-card>
|
||
</a-col>
|
||
<a-col :span="24">
|
||
<a-card title="安全设置">
|
||
<div class="info" style="display: flex;justify-content: space-between;">
|
||
<div>
|
||
<span style="margin-right: 25px;">手机号</span><span>{{ currentPhone }}</span>
|
||
</div>
|
||
<div style="color:#1677ff;" @click="handleModifyPhone">修改</div>
|
||
</div>
|
||
<div class="info" style="display: flex;justify-content: space-between;">
|
||
<div>
|
||
<span style="margin-right: 25px;">绑定微信</span><span style="color: #666;">未绑定微信</span>
|
||
</div>
|
||
<div style="color:#1677ff;">绑定</div>
|
||
</div>
|
||
<div class="info" style="display: flex;justify-content: space-between;">
|
||
<div>
|
||
<span style="margin-right: 25px;">登录密码</span><span>********</span>
|
||
</div>
|
||
<div style="color:#1677ff;" @click="handleModifyPassword">修改</div>
|
||
</div>
|
||
</a-card>
|
||
</a-col>
|
||
</a-row>
|
||
|
||
<!-- 第一步:身份验证对话框(共用) -->
|
||
<a-modal
|
||
v-model:visible="verifyVisible"
|
||
title="身份验证"
|
||
@ok="handleVerify"
|
||
@cancel="handleCancelVerify"
|
||
:maskClosable="false"
|
||
:width="480"
|
||
:ok-button-props="{ disabled: !isVerificationValid }"
|
||
:confirmLoading="verifying"
|
||
okText="下一步"
|
||
>
|
||
<div class="verify-content">
|
||
<!-- 安全提示 -->
|
||
<div class="security-tip">
|
||
<!-- <div class="security-icon">🔒</div> -->
|
||
<div class="security-text">
|
||
<div class="security-title">为确保账号安全,请您本人操作进行身份验证</div>
|
||
<div class="security-subtitle">我们将向您绑定的手机发送验证码</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 手机号信息 -->
|
||
<div class="phone-info">
|
||
<div class="phone-label">验证手机号</div>
|
||
<div class="phone-number">
|
||
<!-- <span class="phone-icon">📱</span> -->
|
||
<span class="phone-text">{{ maskedPhone }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 验证码输入 -->
|
||
<div class="verification-code">
|
||
<div class="code-label">验证码</div>
|
||
<div class="code-input-group">
|
||
<a-input
|
||
v-model:value="verificationCode"
|
||
placeholder="请输入6位验证码"
|
||
:maxlength="6"
|
||
@input="handleCodeInput"
|
||
class="code-input"
|
||
/>
|
||
<a-button
|
||
type="link"
|
||
@click="sendVerificationCode"
|
||
:disabled="countdown > 0 || sendingCode"
|
||
class="send-code-btn"
|
||
>
|
||
{{ countdownText }}
|
||
</a-button>
|
||
</div>
|
||
<div v-if="codeError" class="code-error">{{ codeError }}</div>
|
||
</div>
|
||
|
||
<!-- 发送状态 -->
|
||
<div v-if="sendStatus" class="send-status" :class="{ 'send-success': sendStatus === '发送成功' }">
|
||
{{ sendStatus }}
|
||
</div>
|
||
</div>
|
||
</a-modal>
|
||
|
||
<!-- 第二步:修改手机号对话框 -->
|
||
<a-modal
|
||
v-model:visible="changePhoneVisible"
|
||
title="修改手机号"
|
||
@ok="handleChangePhone"
|
||
@cancel="handleCancelChangePhone"
|
||
:maskClosable="false"
|
||
:width="480"
|
||
:ok-button-props="{ disabled: !isChangeValid }"
|
||
:confirmLoading="changing"
|
||
>
|
||
<div class="change-phone-content">
|
||
<!-- 安全提示 -->
|
||
<div class="security-tip">
|
||
<!-- <div class="security-icon">🔒</div> -->
|
||
<div class="security-text">
|
||
<div class="security-title">为确保账号安全,请您本人操作进行手机号的修改</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 新手机号输入 -->
|
||
<div class="new-phone-section">
|
||
<div class="input-label">新手机号</div>
|
||
<a-input
|
||
v-model:value="newPhoneNumber"
|
||
placeholder="请输入新手机号"
|
||
:maxlength="11"
|
||
@input="handlePhoneInput"
|
||
class="phone-input"
|
||
/>
|
||
<div v-if="phoneError" class="input-error">{{ phoneError }}</div>
|
||
</div>
|
||
|
||
<!-- 新手机号验证码 -->
|
||
<div class="verification-code">
|
||
<div class="code-label">验证码</div>
|
||
<div class="code-input-group">
|
||
<a-input
|
||
v-model:value="newVerificationCode"
|
||
placeholder="请输入6位验证码"
|
||
:maxlength="6"
|
||
@input="handleNewCodeInput"
|
||
class="code-input"
|
||
/>
|
||
<a-button
|
||
type="link"
|
||
@click="sendNewVerificationCode"
|
||
:disabled="newCountdown > 0 || sendingNewCode"
|
||
class="send-code-btn"
|
||
>
|
||
{{ newCountdownText }}
|
||
</a-button>
|
||
</div>
|
||
<div v-if="newCodeError" class="input-error">{{ newCodeError }}</div>
|
||
</div>
|
||
</div>
|
||
</a-modal>
|
||
|
||
<!-- 修改密码对话框 -->
|
||
<a-modal
|
||
v-model:visible="changePasswordVisible"
|
||
title="修改密码"
|
||
@ok="handleChangePassword"
|
||
@cancel="handleCancelChangePassword"
|
||
:maskClosable="false"
|
||
:width="480"
|
||
:ok-button-props="{ disabled: !isPasswordValid }"
|
||
:confirmLoading="changingPassword"
|
||
>
|
||
<div class="change-password-content">
|
||
<!-- 安全提示 -->
|
||
<div class="security-tip">
|
||
<!-- <div class="security-icon">🔒</div> -->
|
||
<div class="security-text">
|
||
<div class="security-title">为确保账号安全,请设置新的登录密码</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 原密码输入 -->
|
||
<div class="password-section">
|
||
<div class="input-label">原密码</div>
|
||
<a-input-password
|
||
v-model:value="oldPassword"
|
||
placeholder="请输入原密码"
|
||
@input="handleOldPasswordInput"
|
||
class="password-input"
|
||
:visibilityToggle="true"
|
||
/>
|
||
<div v-if="oldPasswordError" class="input-error">{{ oldPasswordError }}</div>
|
||
</div>
|
||
|
||
<!-- 新密码输入 -->
|
||
<div class="password-section">
|
||
<div class="input-label">新密码</div>
|
||
<a-input-password
|
||
v-model:value="newPassword"
|
||
placeholder="请输入新密码(6-20位字符)"
|
||
@input="handleNewPasswordInput"
|
||
class="password-input"
|
||
:visibilityToggle="true"
|
||
/>
|
||
<div v-if="newPasswordError" class="input-error">{{ newPasswordError }}</div>
|
||
<div class="password-tip">
|
||
<div class="tip-item" :class="{ 'valid': passwordStrength.lengthValid }">
|
||
<span class="tip-icon">{{ passwordStrength.lengthValid ? '✓' : '○' }}</span>
|
||
<span>6-20位字符</span>
|
||
</div>
|
||
<div class="tip-item" :class="{ 'valid': passwordStrength.hasLetter }">
|
||
<span class="tip-icon">{{ passwordStrength.hasLetter ? '✓' : '○' }}</span>
|
||
<span>至少包含字母</span>
|
||
</div>
|
||
<div class="tip-item" :class="{ 'valid': passwordStrength.hasNumber }">
|
||
<span class="tip-icon">{{ passwordStrength.hasNumber ? '✓' : '○' }}</span>
|
||
<span>至少包含数字</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 确认密码输入 -->
|
||
<div class="password-section">
|
||
<div class="input-label">确认密码</div>
|
||
<a-input-password
|
||
v-model:value="confirmPassword"
|
||
placeholder="请再次输入新密码"
|
||
@input="handleConfirmPasswordInput"
|
||
class="password-input"
|
||
:visibilityToggle="true"
|
||
/>
|
||
<div v-if="confirmPasswordError" class="input-error">{{ confirmPasswordError }}</div>
|
||
</div>
|
||
</div>
|
||
</a-modal>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, onUnmounted, watch,onBeforeMount } from 'vue';
|
||
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||
import { message, Modal as AModal, Input as AInput, InputPassword as AInputPassword, Button as AButton } from 'ant-design-vue';
|
||
import{certificationInfoApi} from '@/apis/certification';
|
||
|
||
const loading = ref(false);
|
||
const imageUrl = ref<string | null>("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
|
||
const fileList = ref<any[]>([{ url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png' }]);
|
||
const userInfo=ref<any>({})
|
||
const certificationInfo=ref<any>({})
|
||
// 操作类型:修改手机号或修改密码
|
||
const operationType = ref<'phone' | 'password'>('phone');
|
||
|
||
// 第一步:身份验证相关状态(共用)
|
||
const verifyVisible = ref(false);
|
||
const verificationCode = ref('');
|
||
const countdown = ref(0);
|
||
const sendingCode = ref(false);
|
||
const sendStatus = ref('');
|
||
const codeError = ref('');
|
||
const verifying = ref(false);
|
||
|
||
// 第二步:修改手机号相关状态
|
||
const changePhoneVisible = ref(false);
|
||
const newPhoneNumber = ref('');
|
||
const newVerificationCode = ref('');
|
||
const newCountdown = ref(0);
|
||
const sendingNewCode = ref(false);
|
||
const newCodeError = ref('');
|
||
const phoneError = ref('');
|
||
const changing = ref(false);
|
||
|
||
// 修改密码相关状态
|
||
const changePasswordVisible = ref(false);
|
||
const oldPassword = ref('');
|
||
const newPassword = ref('');
|
||
const confirmPassword = ref('');
|
||
const oldPasswordError = ref('');
|
||
const newPasswordError = ref('');
|
||
const confirmPasswordError = ref('');
|
||
const changingPassword = ref(false);
|
||
|
||
// 用户当前绑定的手机号
|
||
const currentPhone = ref('17044054908');
|
||
|
||
// 计算属性
|
||
const maskedPhone = computed(() => {
|
||
const phone = currentPhone.value;
|
||
if (phone.length > 7) {
|
||
return phone.slice(0, 3) + '****' + phone.slice(7);
|
||
}
|
||
return phone;
|
||
});
|
||
|
||
const countdownText = computed(() => {
|
||
if (countdown.value > 0) {
|
||
return `${countdown.value}秒后重试`;
|
||
}
|
||
return '获取验证码';
|
||
});
|
||
|
||
const newCountdownText = computed(() => {
|
||
if (newCountdown.value > 0) {
|
||
return `${newCountdown.value}秒后重试`;
|
||
}
|
||
return '获取验证码';
|
||
});
|
||
|
||
const isVerificationValid = computed(() => {
|
||
return verificationCode.value.length === 6 && /^\d+$/.test(verificationCode.value);
|
||
});
|
||
|
||
const isChangeValid = computed(() => {
|
||
return newPhoneNumber.value.length === 11 &&
|
||
/^1[3-9]\d{9}$/.test(newPhoneNumber.value) &&
|
||
newVerificationCode.value.length === 6 &&
|
||
/^\d+$/.test(newVerificationCode.value);
|
||
});
|
||
|
||
// 密码强度验证
|
||
const passwordStrength = computed(() => {
|
||
const lengthValid = newPassword.value.length >= 6 && newPassword.value.length <= 20;
|
||
const hasLetter = /[a-zA-Z]/.test(newPassword.value);
|
||
const hasNumber = /\d/.test(newPassword.value);
|
||
|
||
return {
|
||
lengthValid,
|
||
hasLetter,
|
||
hasNumber
|
||
};
|
||
});
|
||
|
||
const isPasswordValid = computed(() => {
|
||
const isOldPasswordValid = oldPassword.value.length >= 6;
|
||
const isNewPasswordValid = passwordStrength.value.lengthValid &&
|
||
passwordStrength.value.hasLetter &&
|
||
passwordStrength.value.hasNumber;
|
||
const isConfirmValid = confirmPassword.value === newPassword.value && confirmPassword.value.length > 0;
|
||
|
||
return isOldPasswordValid && isNewPasswordValid && isConfirmValid;
|
||
});
|
||
|
||
// 监听密码输入变化
|
||
watch(newPassword, (newVal) => {
|
||
if (newVal.length > 0 && newVal.length < 6) {
|
||
newPasswordError.value = '密码长度不能少于6位';
|
||
} else if (newVal.length > 20) {
|
||
newPasswordError.value = '密码长度不能超过20位';
|
||
} else {
|
||
newPasswordError.value = '';
|
||
}
|
||
|
||
// 更新确认密码错误提示
|
||
if (confirmPassword.value && confirmPassword.value !== newVal) {
|
||
confirmPasswordError.value = '两次输入的密码不一致';
|
||
} else {
|
||
confirmPasswordError.value = '';
|
||
}
|
||
});
|
||
|
||
watch(confirmPassword, (newVal) => {
|
||
if (newVal && newVal !== newPassword.value) {
|
||
confirmPasswordError.value = '两次输入的密码不一致';
|
||
} else {
|
||
confirmPasswordError.value = '';
|
||
}
|
||
});
|
||
|
||
// 倒计时定时器
|
||
let timer: NodeJS.Timeout | null = null;
|
||
let newTimer: NodeJS.Timeout | null = null;
|
||
|
||
// 清理定时器
|
||
onUnmounted(() => {
|
||
if (timer) {
|
||
clearInterval(timer);
|
||
timer = null;
|
||
}
|
||
if (newTimer) {
|
||
clearInterval(newTimer);
|
||
newTimer = null;
|
||
}
|
||
});
|
||
|
||
const beforeUpload = (file: File) => {
|
||
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
|
||
if (!isJpgOrPng) {
|
||
message.error('只能上传JPG/PNG格式的图片!');
|
||
return false;
|
||
}
|
||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||
if (!isLt2M) {
|
||
message.error('图片大小不能超过2MB!');
|
||
return false;
|
||
}
|
||
return isJpgOrPng && isLt2M;
|
||
};
|
||
|
||
const handleChange = (info: any) => {
|
||
if (info.file.status === 'uploading') {
|
||
loading.value = true;
|
||
return;
|
||
}
|
||
if (info.file.status === 'done') {
|
||
const reader = new FileReader();
|
||
reader.addEventListener('load', () => {
|
||
imageUrl.value = reader.result as string;
|
||
loading.value = false;
|
||
message.success('头像上传成功');
|
||
});
|
||
reader.readAsDataURL(info.file.originFileObj);
|
||
}
|
||
};
|
||
|
||
// 修改手机号按钮点击
|
||
const handleModifyPhone = () => {
|
||
operationType.value = 'phone';
|
||
showPhoneVerifyDialog();
|
||
};
|
||
|
||
// 修改密码按钮点击
|
||
const handleModifyPassword = () => {
|
||
operationType.value = 'password';
|
||
showPhoneVerifyDialog();
|
||
};
|
||
|
||
// 显示身份验证对话框(共用)
|
||
const showPhoneVerifyDialog = () => {
|
||
// 重置验证状态
|
||
verificationCode.value = '';
|
||
codeError.value = '';
|
||
sendStatus.value = '';
|
||
verifyVisible.value = true;
|
||
};
|
||
|
||
// 取消身份验证
|
||
const handleCancelVerify = () => {
|
||
verifyVisible.value = false;
|
||
// 重置倒计时
|
||
if (timer) {
|
||
clearInterval(timer);
|
||
timer = null;
|
||
}
|
||
countdown.value = 0;
|
||
};
|
||
|
||
// 验证码输入处理
|
||
const handleCodeInput = (e: Event) => {
|
||
const target = e.target as HTMLInputElement;
|
||
const value = target.value;
|
||
// 只允许数字
|
||
const numbersOnly = value.replace(/\D/g, '');
|
||
verificationCode.value = numbersOnly.slice(0, 6);
|
||
|
||
// 清除错误提示
|
||
if (codeError.value) {
|
||
codeError.value = '';
|
||
}
|
||
};
|
||
|
||
// 发送当前手机号验证码
|
||
const sendVerificationCode = async () => {
|
||
if (countdown.value > 0 || sendingCode.value) return;
|
||
|
||
sendingCode.value = true;
|
||
sendStatus.value = '发送中...';
|
||
codeError.value = '';
|
||
|
||
try {
|
||
// 模拟API调用
|
||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
|
||
// 假设发送成功
|
||
sendStatus.value = '发送成功';
|
||
countdown.value = 60;
|
||
|
||
// 开始倒计时
|
||
timer = setInterval(() => {
|
||
countdown.value--;
|
||
if (countdown.value <= 0) {
|
||
if (timer) {
|
||
clearInterval(timer);
|
||
timer = null;
|
||
}
|
||
}
|
||
}, 1000);
|
||
|
||
message.success('验证码已发送');
|
||
} catch (error) {
|
||
codeError.value = '发送失败,请稍后重试';
|
||
sendStatus.value = '';
|
||
} finally {
|
||
sendingCode.value = false;
|
||
}
|
||
};
|
||
|
||
// 执行身份验证,成功后根据操作类型跳转到相应的下一步
|
||
const handleVerify = async () => {
|
||
if (!isVerificationValid.value) {
|
||
codeError.value = '请输入有效的6位验证码';
|
||
return;
|
||
}
|
||
|
||
verifying.value = true;
|
||
|
||
try {
|
||
// 模拟API验证
|
||
await new Promise(resolve => setTimeout(resolve, 1500));
|
||
|
||
// 假设验证成功
|
||
message.success('身份验证成功');
|
||
|
||
// 关闭身份验证对话框
|
||
verifyVisible.value = false;
|
||
|
||
// 根据操作类型打开相应的下一步对话框
|
||
if (operationType.value === 'phone') {
|
||
showChangePhoneDialog();
|
||
} else if (operationType.value === 'password') {
|
||
showChangePasswordDialog();
|
||
}
|
||
|
||
} catch (error) {
|
||
codeError.value = '验证码错误,请重新输入';
|
||
verificationCode.value = '';
|
||
} finally {
|
||
verifying.value = false;
|
||
}
|
||
};
|
||
|
||
// 显示修改手机号对话框
|
||
const showChangePhoneDialog = () => {
|
||
// 重置状态
|
||
newPhoneNumber.value = '';
|
||
newVerificationCode.value = '';
|
||
newCodeError.value = '';
|
||
phoneError.value = '';
|
||
changePhoneVisible.value = true;
|
||
};
|
||
|
||
// 取消修改手机号
|
||
const handleCancelChangePhone = () => {
|
||
changePhoneVisible.value = false;
|
||
// 重置倒计时
|
||
if (newTimer) {
|
||
clearInterval(newTimer);
|
||
newTimer = null;
|
||
}
|
||
newCountdown.value = 0;
|
||
};
|
||
|
||
// 新手机号输入处理
|
||
const handlePhoneInput = (e: Event) => {
|
||
const target = e.target as HTMLInputElement;
|
||
const value = target.value;
|
||
// 只允许数字
|
||
const numbersOnly = value.replace(/\D/g, '');
|
||
newPhoneNumber.value = numbersOnly.slice(0, 11);
|
||
|
||
// 清除错误提示
|
||
if (phoneError.value) {
|
||
phoneError.value = '';
|
||
}
|
||
if (newCodeError.value) {
|
||
newCodeError.value = '';
|
||
}
|
||
};
|
||
|
||
// 新验证码输入处理
|
||
const handleNewCodeInput = (e: Event) => {
|
||
const target = e.target as HTMLInputElement;
|
||
const value = target.value;
|
||
// 只允许数字
|
||
const numbersOnly = value.replace(/\D/g, '');
|
||
newVerificationCode.value = numbersOnly.slice(0, 6);
|
||
|
||
// 清除错误提示
|
||
if (newCodeError.value) {
|
||
newCodeError.value = '';
|
||
}
|
||
};
|
||
|
||
// 发送新手机号验证码
|
||
const sendNewVerificationCode = async () => {
|
||
// 验证手机号格式
|
||
if (!newPhoneNumber.value || newPhoneNumber.value.length !== 11) {
|
||
phoneError.value = '请输入11位手机号';
|
||
return;
|
||
}
|
||
|
||
if (!/^1[3-9]\d{9}$/.test(newPhoneNumber.value)) {
|
||
phoneError.value = '请输入正确的手机号格式';
|
||
return;
|
||
}
|
||
|
||
if (newPhoneNumber.value === currentPhone.value) {
|
||
phoneError.value = '新手机号不能与当前手机号相同';
|
||
return;
|
||
}
|
||
|
||
if (newCountdown.value > 0 || sendingNewCode.value) return;
|
||
|
||
sendingNewCode.value = true;
|
||
newCodeError.value = '';
|
||
|
||
try {
|
||
// 模拟API调用
|
||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
|
||
// 假设发送成功
|
||
newCountdown.value = 60;
|
||
|
||
// 开始倒计时
|
||
newTimer = setInterval(() => {
|
||
newCountdown.value--;
|
||
if (newCountdown.value <= 0) {
|
||
if (newTimer) {
|
||
clearInterval(newTimer);
|
||
newTimer = null;
|
||
}
|
||
}
|
||
}, 1000);
|
||
|
||
message.success('验证码已发送到新手机号');
|
||
} catch (error) {
|
||
newCodeError.value = '发送失败,请稍后重试';
|
||
} finally {
|
||
sendingNewCode.value = false;
|
||
}
|
||
};
|
||
|
||
// 执行手机号修改
|
||
const handleChangePhone = async () => {
|
||
if (!isChangeValid.value) {
|
||
// 详细错误提示
|
||
if (!newPhoneNumber.value || newPhoneNumber.value.length !== 11) {
|
||
phoneError.value = '请输入11位手机号';
|
||
return;
|
||
}
|
||
if (!/^1[3-9]\d{9}$/.test(newPhoneNumber.value)) {
|
||
phoneError.value = '请输入正确的手机号格式';
|
||
return;
|
||
}
|
||
if (newPhoneNumber.value === currentPhone.value) {
|
||
phoneError.value = '新手机号不能与当前手机号相同';
|
||
return;
|
||
}
|
||
if (!newVerificationCode.value || newVerificationCode.value.length !== 6) {
|
||
newCodeError.value = '请输入6位验证码';
|
||
return;
|
||
}
|
||
return;
|
||
}
|
||
|
||
changing.value = true;
|
||
|
||
try {
|
||
// 模拟API调用修改手机号
|
||
await new Promise(resolve => setTimeout(resolve, 1500));
|
||
|
||
// 更新当前手机号
|
||
currentPhone.value = newPhoneNumber.value;
|
||
|
||
// 关闭对话框
|
||
changePhoneVisible.value = false;
|
||
|
||
// 重置所有状态
|
||
resetAllStates();
|
||
|
||
message.success('手机号修改成功');
|
||
|
||
} catch (error) {
|
||
newCodeError.value = '修改失败,请稍后重试';
|
||
} finally {
|
||
changing.value = false;
|
||
}
|
||
};
|
||
|
||
// 显示修改密码对话框
|
||
const showChangePasswordDialog = () => {
|
||
// 重置状态
|
||
oldPassword.value = '';
|
||
newPassword.value = '';
|
||
confirmPassword.value = '';
|
||
oldPasswordError.value = '';
|
||
newPasswordError.value = '';
|
||
confirmPasswordError.value = '';
|
||
changePasswordVisible.value = true;
|
||
};
|
||
|
||
// 取消修改密码
|
||
const handleCancelChangePassword = () => {
|
||
changePasswordVisible.value = false;
|
||
};
|
||
|
||
// 原密码输入处理
|
||
const handleOldPasswordInput = (e: Event) => {
|
||
const target = e.target as HTMLInputElement;
|
||
const value = target.value;
|
||
oldPassword.value = value;
|
||
|
||
// 清除错误提示
|
||
if (oldPasswordError.value) {
|
||
oldPasswordError.value = '';
|
||
}
|
||
};
|
||
|
||
// 新密码输入处理
|
||
const handleNewPasswordInput = (e: Event) => {
|
||
const target = e.target as HTMLInputElement;
|
||
const value = target.value;
|
||
newPassword.value = value;
|
||
|
||
// 清除错误提示
|
||
if (newPasswordError.value) {
|
||
newPasswordError.value = '';
|
||
}
|
||
};
|
||
|
||
// 确认密码输入处理
|
||
const handleConfirmPasswordInput = (e: Event) => {
|
||
const target = e.target as HTMLInputElement;
|
||
const value = target.value;
|
||
confirmPassword.value = value;
|
||
|
||
// 清除错误提示
|
||
if (confirmPasswordError.value) {
|
||
confirmPasswordError.value = '';
|
||
}
|
||
};
|
||
|
||
// 执行密码修改
|
||
const handleChangePassword = async () => {
|
||
if (!isPasswordValid.value) {
|
||
// 详细错误提示
|
||
if (!oldPassword.value || oldPassword.value.length < 6) {
|
||
oldPasswordError.value = '请输入原密码';
|
||
return;
|
||
}
|
||
if (!newPassword.value || newPassword.value.length < 6) {
|
||
newPasswordError.value = '请输入新密码';
|
||
return;
|
||
}
|
||
if (!passwordStrength.value.hasLetter || !passwordStrength.value.hasNumber) {
|
||
newPasswordError.value = '密码必须包含字母和数字';
|
||
return;
|
||
}
|
||
if (!confirmPassword.value) {
|
||
confirmPasswordError.value = '请确认密码';
|
||
return;
|
||
}
|
||
if (confirmPassword.value !== newPassword.value) {
|
||
confirmPasswordError.value = '两次输入的密码不一致';
|
||
return;
|
||
}
|
||
return;
|
||
}
|
||
|
||
changingPassword.value = true;
|
||
|
||
try {
|
||
// 模拟API调用修改密码
|
||
await new Promise(resolve => setTimeout(resolve, 1500));
|
||
|
||
// 关闭对话框
|
||
changePasswordVisible.value = false;
|
||
|
||
// 重置所有状态
|
||
resetPasswordStates();
|
||
|
||
message.success('密码修改成功');
|
||
|
||
} catch (error) {
|
||
oldPasswordError.value = '原密码错误或修改失败';
|
||
} finally {
|
||
changingPassword.value = false;
|
||
}
|
||
};
|
||
|
||
// 重置所有状态
|
||
const resetAllStates = () => {
|
||
// 身份验证状态重置
|
||
verificationCode.value = '';
|
||
codeError.value = '';
|
||
sendStatus.value = '';
|
||
if (timer) {
|
||
clearInterval(timer);
|
||
timer = null;
|
||
}
|
||
countdown.value = 0;
|
||
|
||
// 修改手机号状态重置
|
||
newPhoneNumber.value = '';
|
||
newVerificationCode.value = '';
|
||
newCodeError.value = '';
|
||
phoneError.value = '';
|
||
if (newTimer) {
|
||
clearInterval(newTimer);
|
||
newTimer = null;
|
||
}
|
||
newCountdown.value = 0;
|
||
};
|
||
|
||
// 重置密码相关状态
|
||
const resetPasswordStates = () => {
|
||
oldPassword.value = '';
|
||
newPassword.value = '';
|
||
confirmPassword.value = '';
|
||
oldPasswordError.value = '';
|
||
newPasswordError.value = '';
|
||
confirmPasswordError.value = '';
|
||
};
|
||
const getCertificationInfo = async () => {
|
||
try {
|
||
const res=await certificationInfoApi();
|
||
certificationInfo.value=res;
|
||
} catch (error) {
|
||
message.error('获取认证信息失败');
|
||
}
|
||
};
|
||
onBeforeMount(()=>{
|
||
const userInfoStr = localStorage.getItem('userInfo');
|
||
if (userInfoStr) {
|
||
userInfo.value=JSON.parse(userInfoStr);
|
||
if(userInfo.value.certificationStatus==='CERTIFICATION_PASSED'){
|
||
getCertificationInfo();
|
||
}
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.avatar-uploader .ant-upload {
|
||
width: 128px;
|
||
height: 128px;
|
||
border-radius: 50% !important;
|
||
overflow: hidden;
|
||
border: none !important;
|
||
background: none !important;
|
||
}
|
||
|
||
.avatar-uploader img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.ant-upload-select-picture-card i {
|
||
font-size: 32px;
|
||
color: #999;
|
||
}
|
||
|
||
.ant-upload-select-picture-card .ant-upload-text {
|
||
margin-top: 8px;
|
||
color: #666;
|
||
}
|
||
|
||
.info {
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
padding: 10px 20px;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
|
||
span:first-child {
|
||
width: 80px;
|
||
}
|
||
|
||
div[style*="color:#1677ff"] {
|
||
cursor: pointer;
|
||
transition: color 0.3s;
|
||
|
||
&:hover {
|
||
color: #0958d9;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 身份验证对话框样式 */
|
||
.verify-content {
|
||
padding: 8px 0;
|
||
}
|
||
|
||
.security-tip {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 12px;
|
||
margin-bottom: 24px;
|
||
padding: 16px;
|
||
background: #f6f9ff;
|
||
border-radius: 8px;
|
||
border: 1px solid #e6f0ff;
|
||
}
|
||
|
||
.security-icon {
|
||
font-size: 20px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.security-text {
|
||
flex: 1;
|
||
}
|
||
|
||
.security-title {
|
||
color: #1890ff;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.security-subtitle {
|
||
color: #595959;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.phone-info {
|
||
margin-bottom: 24px;
|
||
padding: 16px;
|
||
background: #fafafa;
|
||
border-radius: 6px;
|
||
border: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.phone-label {
|
||
color: #595959;
|
||
font-size: 13px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.phone-number {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.phone-icon {
|
||
font-size: 16px;
|
||
}
|
||
|
||
.phone-text {
|
||
color: #262626;
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.verification-code {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.code-label {
|
||
color: #262626;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.code-input-group {
|
||
display: flex;
|
||
gap: 12px;
|
||
align-items: center;
|
||
}
|
||
|
||
.code-input {
|
||
flex: 1;
|
||
}
|
||
|
||
:deep(.code-input .ant-input) {
|
||
height: 40px;
|
||
font-size: 14px;
|
||
letter-spacing: 2px;
|
||
}
|
||
|
||
.send-code-btn {
|
||
width: 100px;
|
||
height: 40px;
|
||
padding: 0;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.send-code-btn:disabled {
|
||
color: #bfbfbf;
|
||
}
|
||
|
||
.code-error {
|
||
color: #ff4d4f;
|
||
font-size: 12px;
|
||
margin-top: 4px;
|
||
min-height: 20px;
|
||
}
|
||
|
||
.send-status {
|
||
color: #595959;
|
||
font-size: 12px;
|
||
text-align: center;
|
||
margin-top: 8px;
|
||
min-height: 20px;
|
||
}
|
||
|
||
.send-success {
|
||
color: #52c41a;
|
||
}
|
||
|
||
/* 修改手机号对话框样式 */
|
||
.change-phone-content {
|
||
padding: 8px 0;
|
||
}
|
||
|
||
.new-phone-section {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.input-label {
|
||
color: #262626;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.phone-input {
|
||
width: 100%;
|
||
}
|
||
|
||
:deep(.phone-input .ant-input) {
|
||
height: 40px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.input-error {
|
||
color: #ff4d4f;
|
||
font-size: 12px;
|
||
margin-top: 4px;
|
||
min-height: 20px;
|
||
}
|
||
|
||
/* 修改密码对话框样式 */
|
||
.change-password-content {
|
||
padding: 8px 0;
|
||
}
|
||
|
||
.password-section {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.password-input {
|
||
width: 100%;
|
||
}
|
||
|
||
:deep(.password-input .ant-input) {
|
||
height: 40px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.password-tip {
|
||
margin-top: 8px;
|
||
padding: 8px 12px;
|
||
background: #fafafa;
|
||
border-radius: 4px;
|
||
border: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.tip-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
font-size: 12px;
|
||
color: #8c8c8c;
|
||
margin-bottom: 4px;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
&.valid {
|
||
color: #52c41a;
|
||
}
|
||
}
|
||
|
||
.tip-icon {
|
||
font-size: 10px;
|
||
width: 14px;
|
||
height: 14px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 响应式 */
|
||
@media (max-width: 768px) {
|
||
.code-input-group {
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
|
||
.send-code-btn {
|
||
width: 100%;
|
||
}
|
||
}
|
||
</style> |