2026-01-12 09:19:50 +08:00

1107 lines
32 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>