2 changed files with 0 additions and 387 deletions
@ -1,84 +0,0 @@ |
|||||
<template> |
|
||||
<div class="success-popup"> |
|
||||
<div class="popup-content"> |
|
||||
<div class="icon"> |
|
||||
<el-icon :size="48" color="#67c23a"> |
|
||||
<SuccessFilled /> |
|
||||
</el-icon> |
|
||||
</div> |
|
||||
<div class="title">修改密码成功!</div> |
|
||||
<div class="desc">系统将在 {{ countdown }} 秒后自动跳转至登录页</div> |
|
||||
<el-button type="primary" @click="immediateJump">立即跳转</el-button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import {ref, onMounted} from 'vue'; |
|
||||
import {ElIcon, ElButton} from 'element-plus'; |
|
||||
import {SuccessFilled} from '@element-plus/icons-vue'; |
|
||||
import {useRouter} from 'vue-router'; |
|
||||
|
|
||||
|
|
||||
const countdown = ref(3); |
|
||||
const router = useRouter(); |
|
||||
|
|
||||
// 倒计时逻辑,自动跳转 |
|
||||
const startCountdown = () => { |
|
||||
const timer = setInterval(() => { |
|
||||
countdown.value--; |
|
||||
if (countdown.value === 0) { |
|
||||
clearInterval(timer); |
|
||||
// 这里可根据实际需求选择刷新跳转还是路由跳转 |
|
||||
// 若需要刷新页面跳转,使用 window.location.href |
|
||||
// window.location.href = '/login'; |
|
||||
router.replace ('/login'); |
|
||||
// 若用路由跳转(路由配置好登录页路径前提下):router.push('/login'); |
|
||||
} |
|
||||
}, 1000); |
|
||||
}; |
|
||||
|
|
||||
const immediateJump = () => { |
|
||||
// window.location.href = '/login'; |
|
||||
// 路由跳转方式: |
|
||||
router.replace ('/login'); |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
startCountdown(); |
|
||||
}); |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.success-popup { |
|
||||
position: fixed; |
|
||||
top: 0; |
|
||||
left: 0; |
|
||||
|
|
||||
background-color: rgba(255, 255, 255, 0.8); |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
z-index: 9999; |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
} |
|
||||
.popup-content { |
|
||||
background: #fff; |
|
||||
padding: 30px; |
|
||||
border-radius: 8px; |
|
||||
text-align: center; |
|
||||
} |
|
||||
.icon { |
|
||||
margin-bottom: 16px; |
|
||||
} |
|
||||
.title { |
|
||||
font-size: 18px; |
|
||||
font-weight: bold; |
|
||||
margin-bottom: 8px; |
|
||||
} |
|
||||
.desc { |
|
||||
margin-bottom: 24px; |
|
||||
color: #999; |
|
||||
} |
|
||||
</style> |
|
@ -1,303 +0,0 @@ |
|||||
<template> |
|
||||
<div class="form-container"> |
|
||||
<el-form |
|
||||
ref="passwdFormRef" |
|
||||
:model="passwd" |
|
||||
:rules="rules" |
|
||||
label-width="100px" |
|
||||
class="password-form" |
|
||||
> |
|
||||
<h3 class="form-title">修改密码</h3> |
|
||||
|
|
||||
<!-- 原密码 --> |
|
||||
<el-form-item prop="oldVal" label="原密码"> |
|
||||
<el-input |
|
||||
v-model.trim="passwd.oldVal" |
|
||||
type="password" |
|
||||
placeholder="请输入原密码" |
|
||||
show-password |
|
||||
/> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<!-- 新密码 --> |
|
||||
<el-form-item prop="newVal" label="新密码"> |
|
||||
<el-input |
|
||||
v-model.trim="passwd.newVal" |
|
||||
type="password" |
|
||||
placeholder="请输入新密码" |
|
||||
show-password |
|
||||
/> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<!-- 重复密码 --> |
|
||||
<el-form-item prop="repeatNewVal" label="重复密码"> |
|
||||
<el-input |
|
||||
v-model.trim="passwd.repeatNewVal" |
|
||||
type="password" |
|
||||
placeholder="请再次输入新密码" |
|
||||
show-password |
|
||||
/> |
|
||||
</el-form-item> |
|
||||
|
|
||||
<!-- 密码规则提示 --> |
|
||||
<div class="rule-tips"> |
|
||||
<div :class="isLengthValid ? 'tip pass' : 'tip neutral'"> |
|
||||
<el-icon> |
|
||||
<component :is="isLengthValid ? SuccessFilled : SuccessFilled"/> |
|
||||
</el-icon> |
|
||||
密码由8-16位数字、字母或符号组成 |
|
||||
</div> |
|
||||
<div :class="isComplexValid ? 'tip pass' : 'tip neutral'"> |
|
||||
<el-icon> |
|
||||
<component :is="isComplexValid ? SuccessFilled : SuccessFilled"/> |
|
||||
</el-icon> |
|
||||
至少含2种以上字符 |
|
||||
</div> |
|
||||
<div v-if="errorMsg" class="tip fail"> |
|
||||
<el-icon> |
|
||||
<CircleCloseFilled/> |
|
||||
</el-icon> |
|
||||
{{ errorMsg }} |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<!-- 按钮 --> |
|
||||
<div class="button-group"> |
|
||||
<el-button |
|
||||
type="primary" |
|
||||
@click="onSubmit" |
|
||||
style="width: 300px" |
|
||||
:loading="loading" |
|
||||
:disabled="!isLengthValid || !isComplexValid" |
|
||||
> |
|
||||
{{ loading ? '修改中...' : '确定' }} |
|
||||
</el-button> |
|
||||
</div> |
|
||||
|
|
||||
</el-form> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import {ref, reactive, computed, watch} from 'vue' |
|
||||
import {CircleCloseFilled, SuccessFilled} from '@element-plus/icons-vue' |
|
||||
import {ElMessage} from "element-plus"; |
|
||||
import API from '@/util/http' |
|
||||
import PasswordSuccess from './PasswordSuccess.vue'; |
|
||||
import router from "@/router/index.js"; |
|
||||
|
|
||||
// 父组件调用 |
|
||||
const emit = defineEmits(['confirm']) |
|
||||
|
|
||||
const passwdFormRef = ref(null) |
|
||||
const passwd = reactive({ |
|
||||
oldVal: '', |
|
||||
newVal: '', |
|
||||
repeatNewVal: '' |
|
||||
}) |
|
||||
const errorMsg = ref('') |
|
||||
|
|
||||
// 实时密码规则校验 |
|
||||
const isLengthValid = computed(() => passwd.newVal.length >= 8 && passwd.newVal.length <= 16) |
|
||||
|
|
||||
const isComplexValid = computed(() => { |
|
||||
const rules = [/\d/, /[a-z]/, /[A-Z]/, /[^a-zA-Z0-9]/] |
|
||||
return rules.filter((r) => r.test(passwd.newVal)).length >= 2 |
|
||||
}) |
|
||||
|
|
||||
watch(() => passwd.newVal, (val) => { |
|
||||
if (val && val === passwd.oldVal) { |
|
||||
errorMsg.value = '新密码不能与旧密码一致' |
|
||||
} else { |
|
||||
errorMsg.value = '' |
|
||||
} |
|
||||
}) |
|
||||
// 提交加载状态 |
|
||||
const loading = ref(false) |
|
||||
// 表单校验规则 |
|
||||
const rules = reactive({ |
|
||||
oldVal: [{required: true, message: '请输入原密码', trigger: 'blur'}], |
|
||||
newVal: [ |
|
||||
{required: true, message: '新密码不能为空', trigger: 'blur'}, |
|
||||
{ |
|
||||
validator: (rule, value, callback) => { |
|
||||
if (value === passwd.oldVal) { |
|
||||
callback(new Error('新密码不能与旧密码一致')) |
|
||||
} else if (value.length < 8 || value.length > 16) { |
|
||||
callback(new Error('长度应在 8 到 16 个字符')) |
|
||||
} else { |
|
||||
const types = [/\d/, /[a-z]/, /[A-Z]/, /[^a-zA-Z0-9]/] |
|
||||
const matchCount = types.filter((r) => r.test(value)).length |
|
||||
if (matchCount < 2) { |
|
||||
callback(new Error('密码至少包含两种类型(数字、字母或符号)')) |
|
||||
} else { |
|
||||
callback() |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
trigger: 'blur' |
|
||||
} |
|
||||
], |
|
||||
repeatNewVal: [ |
|
||||
{required: true, message: '请再次输入新密码', trigger: 'blur'}, |
|
||||
{ |
|
||||
validator: (rule, value, callback) => { |
|
||||
if (value !== passwd.newVal) { |
|
||||
callback(new Error('两次输入密码不一致')) |
|
||||
} else { |
|
||||
callback() |
|
||||
} |
|
||||
}, |
|
||||
trigger: 'blur' |
|
||||
} |
|
||||
] |
|
||||
}) |
|
||||
|
|
||||
// // 修改密码接口调用方法 |
|
||||
// const changePassword = async function () { |
|
||||
// try { |
|
||||
// const params = { |
|
||||
// oldVal: passwd.oldVal, |
|
||||
// newVal: passwd.newVal |
|
||||
// } |
|
||||
// |
|
||||
// const result = await API({url: '/user/changePassword', data: params}) |
|
||||
// console.log('@@@@@@@@@@@修改密码结果:', result) |
|
||||
// if(result.status === 200){ |
|
||||
// // 显示成功弹窗 |
|
||||
// |
|
||||
// ElMessage.success('修改密码成功') |
|
||||
// // 重置表单字段 |
|
||||
// resetFields() |
|
||||
// router.replace ('/PasswordSuccess'); |
|
||||
// }else if(result === 400){ |
|
||||
// //todo 待完善 |
|
||||
// } |
|
||||
// |
|
||||
// } catch (error) { |
|
||||
// console.log('re:', result) |
|
||||
// console.error('修改密码失败', error) |
|
||||
// ElMessage.error('操作失败') |
|
||||
// // 抛出错误让外层捕获,保持finally正常执行 |
|
||||
// throw error |
|
||||
// } |
|
||||
// } |
|
||||
|
|
||||
// 修改密码接口调用方法(模拟始终成功) |
|
||||
const changePassword = async function () { |
|
||||
try { |
|
||||
// 模拟API调用 |
|
||||
const result = { |
|
||||
status: 200, |
|
||||
data: {success: true, message: '密码修改成功'} |
|
||||
}; |
|
||||
|
|
||||
console.log('修改密码结果:', result); |
|
||||
|
|
||||
// 统一处理成功逻辑 |
|
||||
if (result.status === 200 ) { |
|
||||
// 显示成功提示 |
|
||||
ElMessage.success(result.data.message || '修改密码成功'); |
|
||||
|
|
||||
// 重置表单字段 |
|
||||
resetFields(); |
|
||||
|
|
||||
router.replace ('/PasswordSuccess'); |
|
||||
|
|
||||
|
|
||||
return result; |
|
||||
} else { |
|
||||
// 处理API返回但状态非成功的情况 |
|
||||
const errorMsg = result.data.message || '密码修改失败'; |
|
||||
ElMessage.error(errorMsg); |
|
||||
throw new Error(errorMsg); |
|
||||
} |
|
||||
} catch (error) { |
|
||||
// 处理网络错误或API异常 |
|
||||
console.error('修改密码失败:', error); |
|
||||
ElMessage.error(error.message || '操作失败,请重试'); |
|
||||
throw error; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
// 表单提交与重置 |
|
||||
const resetFields = () => { |
|
||||
passwdFormRef.value.resetFields() |
|
||||
errorMsg.value = '' |
|
||||
} |
|
||||
|
|
||||
// 修改提交方法 |
|
||||
const onSubmit = () => { |
|
||||
// 若正在加载中则直接返回,防止重复提交 |
|
||||
if (loading.value) return |
|
||||
|
|
||||
passwdFormRef.value.validate(async (valid) => { |
|
||||
if (valid) { |
|
||||
loading.value = true // 开始加载 |
|
||||
try { |
|
||||
await changePassword() // 调用修改密码接口 |
|
||||
emit('confirm') |
|
||||
} finally { |
|
||||
loading.value = false // 无论成功失败都关闭加载态 |
|
||||
} |
|
||||
} else { |
|
||||
console.log('表单校验失败') |
|
||||
} |
|
||||
|
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.form-container { |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
} |
|
||||
|
|
||||
.password-form { |
|
||||
|
|
||||
border-radius: 8px; |
|
||||
} |
|
||||
|
|
||||
.form-title { |
|
||||
text-align: left; |
|
||||
margin-bottom: 24px; |
|
||||
font-size: 20px; |
|
||||
font-weight: bold; |
|
||||
} |
|
||||
|
|
||||
.button-group { |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
margin-top: 24px; |
|
||||
} |
|
||||
|
|
||||
.rule-tips { |
|
||||
margin-left: 100px; |
|
||||
margin-bottom: 12px; |
|
||||
} |
|
||||
|
|
||||
.tip { |
|
||||
font-size: 14px; |
|
||||
margin: 4px 0; |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
} |
|
||||
|
|
||||
.pass { |
|
||||
color: #67c23a; |
|
||||
} |
|
||||
|
|
||||
.neutral { |
|
||||
color: #999; |
|
||||
} |
|
||||
|
|
||||
.fail { |
|
||||
color: #f56c6c; |
|
||||
} |
|
||||
|
|
||||
.rule-tips .el-icon { |
|
||||
margin-right: 6px; |
|
||||
} |
|
||||
</style> |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue