231 lines
5.8 KiB
Vue
231 lines
5.8 KiB
Vue
<template>
|
||
<div class="change-password-container">
|
||
<div class="header">修改密码</div>
|
||
<el-form
|
||
:model="form"
|
||
:rules="rules"
|
||
label-width="120px"
|
||
ref="passwordForm"
|
||
label-position="top"
|
||
status-icon
|
||
>
|
||
<!-- 新密码输入 -->
|
||
<el-form-item label="新密码" prop="newPassword">
|
||
<el-input
|
||
v-model="form.newPassword"
|
||
type="password"
|
||
show-password
|
||
clearable
|
||
placeholder="请输入8-20位包含字母和数字的组合"
|
||
>
|
||
</el-input>
|
||
<!-- 强度指示条 -->
|
||
<div class="strength-indicator" :data-strength="strengthLevel">
|
||
<div class="indicator-bar" :style="barStyle"></div>
|
||
</div>
|
||
</el-form-item>
|
||
<!-- 警告提示 -->
|
||
<el-alert
|
||
title="注意:您是首次登录或被重置密码,为了账号安全,请务必修改密码"
|
||
type="warning"
|
||
:closable="false"
|
||
show-icon
|
||
class="custom-alert"
|
||
/>
|
||
<!-- 确认密码输入 -->
|
||
<el-form-item label="确认新密码" prop="confirmPassword">
|
||
<el-input
|
||
v-model="form.confirmPassword"
|
||
type="password"
|
||
show-password
|
||
clearable
|
||
placeholder="请再次输入新密码"
|
||
></el-input>
|
||
</el-form-item>
|
||
|
||
|
||
|
||
<!-- 提交按钮 -->
|
||
<el-form-item class="submit-btn">
|
||
<el-button
|
||
type="primary"
|
||
@click="submitForm"
|
||
style="width: 100%;"
|
||
:loading="loading"
|
||
>
|
||
{{ loading ? '提交中...' : '确认' }}
|
||
</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from 'vue';
|
||
import { ElMessage } from 'element-plus';
|
||
import { updateUserPassword } from "@/api/system/user";
|
||
const router = useRouter();
|
||
// 表单数据
|
||
const form = ref({
|
||
newPassword: '',
|
||
confirmPassword: ''
|
||
});
|
||
|
||
// 表单引用
|
||
const passwordForm = ref(null);
|
||
|
||
// 加载状态
|
||
const loading = ref(false);
|
||
|
||
// 密码复杂度验证函数
|
||
const validatePassword = (rule, value, callback) => {
|
||
if (!value) {
|
||
return callback(new Error('密码不能为空'));
|
||
}
|
||
if (value.length < 6 || value.length > 20) {
|
||
return callback(new Error('密码长度需在8-20位之间'));
|
||
}
|
||
if (!/[A-Za-z]/.test(value) || !/[0-9]/.test(value)) {
|
||
return callback(new Error('需包含字母和数字组合'));
|
||
}
|
||
callback();
|
||
};
|
||
|
||
// 确认密码验证
|
||
const validateConfirm = (rule, value, callback) => {
|
||
if (value !== form.value.newPassword) {
|
||
callback(new Error('两次输入密码不一致'));
|
||
} else {
|
||
callback();
|
||
}
|
||
};
|
||
|
||
// 表单验证规则
|
||
const rules = {
|
||
newPassword: [
|
||
{ required: true, message: '请输入新密码', trigger: 'change' },
|
||
{ validator: validatePassword, trigger: 'change' }
|
||
],
|
||
confirmPassword: [
|
||
{ required: true, message: '请输入确认密码', trigger: 'change' },
|
||
{ validator: validateConfirm, trigger: 'change' }
|
||
]
|
||
};
|
||
|
||
// 提交处理
|
||
const submitForm = async () => {
|
||
try {
|
||
loading.value = true;
|
||
await passwordForm.value.validate();
|
||
let objForm = {
|
||
password:form.value.newPassword
|
||
}
|
||
// 这里添加实际的API调用
|
||
updateUserPassword(objForm).then(response => {
|
||
|
||
ElMessage.success('密码修改成功,3秒后自动跳转');
|
||
|
||
// 模拟跳转(根据实际需求修改)
|
||
setTimeout(() => {
|
||
router.replace({ path: "/index", query: '' });
|
||
}, 3000);
|
||
});
|
||
|
||
|
||
} catch (error) {
|
||
ElMessage.error(error.message || '提交失败,请检查表单');
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
};
|
||
// 密码强度计算模型 :ml-citation{ref="2,4" data="citationList"}
|
||
const strengthLevel = computed(() => {
|
||
const value = form.value.newPassword;
|
||
if (!value) return 0;
|
||
|
||
let score = 0;
|
||
// 长度检测
|
||
if (value.length >= 6) score++;
|
||
if (value.length >= 12) score++;
|
||
// 字符类型检测
|
||
if (/[A-Za-z]/.test(value)) score++;
|
||
if (/\d/.test(value)) score++;
|
||
if (/[^\w]/.test(value)) score++;
|
||
|
||
return Math.min(Math.floor(score/2), 3);
|
||
});
|
||
|
||
// 进度条动态样式
|
||
const barStyle = computed(() => ({
|
||
width: `${(strengthLevel.value / 3) * 100}%`,
|
||
backgroundColor: ['#ff4d4f', '#faad14', '#52c41a'][strengthLevel.value - 1]
|
||
}));
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.change-password-container {
|
||
width: 100%;
|
||
max-width: 500px;
|
||
margin: 300px auto;
|
||
padding: 30px;
|
||
background: rgba(255, 255, 255, 0.9);
|
||
border-radius: 12px;
|
||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.header {
|
||
font-size: 26px;
|
||
font-weight: 600;
|
||
color: #2c3e50;
|
||
text-align: center;
|
||
margin-bottom: 30px;
|
||
letter-spacing: 2px;
|
||
}
|
||
/* 强度指示条容器 */
|
||
.strength-indicator {
|
||
width: 100%;
|
||
height: 4px;
|
||
background: #f0f0f0;
|
||
border-radius: 2px;
|
||
overflow: hidden;
|
||
margin-top: 8px;
|
||
|
||
.indicator-bar {
|
||
height: 100%;
|
||
transition: all 0.3s ease;
|
||
}
|
||
}
|
||
|
||
.custom-alert {
|
||
margin: 20px 0;
|
||
}
|
||
|
||
.submit-btn {
|
||
margin-top: 30px;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 768px) {
|
||
.change-password-container {
|
||
margin: 20px;
|
||
padding: 20px;
|
||
}
|
||
|
||
.header {
|
||
font-size: 22px;
|
||
}
|
||
}
|
||
|
||
/* 输入框动画效果 */
|
||
:deep(.el-input__inner) {
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
:deep(.el-input__inner:focus) {
|
||
border-color: #409eff;
|
||
box-shadow: 0 0 8px rgba(64, 158, 255, 0.3);
|
||
}
|
||
</style>
|
||
|