Browse Source

Merge remote-tracking branch 'origin/lihui/feature-20250623144029-金币前端lihui' into lihui/feature-20250623144029-金币前端lihui

# Conflicts:
#	src/views/home.vue
#	src/views/workspace/index.vue
lihui/feature-20250623144029-金币前端lihui
lihui 3 weeks ago
parent
commit
c7114a374e
  1. 84
      src/components/PasswordSuccess.vue
  2. 303
      src/components/changePassword.vue
  3. 2
      src/router/index.js

84
src/components/PasswordSuccess.vue

@ -0,0 +1,84 @@
<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>

303
src/components/changePassword.vue

@ -0,0 +1,303 @@
<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>

2
src/router/index.js

@ -71,6 +71,8 @@ const router = createRouter({
{ path: '/noPermission', name: "noPermission", component: () => import("../views/noPermissionPage.vue") } { path: '/noPermission', name: "noPermission", component: () => import("../views/noPermissionPage.vue") }
] ]
}, },
// 跳转页面
{ path: '/PasswordSuccess', name: "PasswordSuccess.vue", component: () => import("../components/PasswordSuccess.vue") },
] ]

Loading…
Cancel
Save