mirror of
https://github.com/bjdgyc/anylink.git
synced 2025-09-09 22:58:26 +08:00
增加密码自助重置功能
This commit is contained in:
13652
web/package-lock.json
generated
Normal file
13652
web/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
99
web/src/pages/reset/ForgotPassword.vue
Normal file
99
web/src/pages/reset/ForgotPassword.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div class="login">
|
||||
<el-card style="width: 550px;">
|
||||
<div class="issuer">VPN账号密码重置申请</div>
|
||||
|
||||
<el-form
|
||||
:model="form"
|
||||
status-icon
|
||||
:rules="rules"
|
||||
ref="form"
|
||||
label-width="120px"
|
||||
class="ruleForm"
|
||||
>
|
||||
<el-form-item label="注册邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="请输入注册邮箱"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="submitForm('form')"
|
||||
>
|
||||
发送重置邮件
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios"; // 移除了 qs 的导入
|
||||
|
||||
export default {
|
||||
name: "ForgotPassword",
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
form: {
|
||||
email: ""
|
||||
},
|
||||
rules: {
|
||||
email: [
|
||||
{ required: true, message: "请输入邮箱地址", trigger: "blur" },
|
||||
{ type: "email", message: "请输入正确的邮箱格式", trigger: "blur" }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
submitForm(formName) {
|
||||
this.$refs[formName].validate(valid => {
|
||||
if (!valid) return false;
|
||||
|
||||
this.loading = true;
|
||||
// 修改后的 POST 请求
|
||||
axios.post("/user/reset/forgotPassword",
|
||||
this.form, // 直接发送对象
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json' // 明确指定 JSON 格式
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(res => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success("重置邮件已发送,请检查您的邮箱");
|
||||
} else {
|
||||
this.$message.error(res.data.msg);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.error("服务暂时不可用");
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 样式保持不变 */
|
||||
.login {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.issuer {
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
color: #409EFF;
|
||||
}
|
||||
</style>
|
169
web/src/pages/reset/ResetPassword.vue
Normal file
169
web/src/pages/reset/ResetPassword.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div class="login">
|
||||
<el-card style="width: 550px;">
|
||||
<div class="issuer">VPN个人账号密码重置</div>
|
||||
<el-form
|
||||
:model="form"
|
||||
status-icon
|
||||
:rules="rules"
|
||||
ref="form"
|
||||
label-width="120px"
|
||||
class="ruleForm"
|
||||
>
|
||||
<el-form-item label="新密码" prop="password">
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="form.password"
|
||||
autocomplete="off"
|
||||
show-password
|
||||
placeholder="请输入新密码,需要大小写并且8位以上"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="确认密码" prop="checkPass">
|
||||
<el-input
|
||||
type="password"
|
||||
v-model="form.checkPass"
|
||||
autocomplete="off"
|
||||
show-password
|
||||
placeholder="请再次输入密码"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="submitForm('form')"
|
||||
>
|
||||
确认重置
|
||||
</el-button>
|
||||
<!-- <el-button @click="$router.push('/login')">返回登录</el-button>-->
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: "ResetPassword",
|
||||
data() {
|
||||
const validatePass = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请输入密码"));
|
||||
} else if (value.length < 8) {
|
||||
callback(new Error("密码长度不能小于8位"));
|
||||
} else if (
|
||||
!/[A-Z]/.test(value) || // 必须包含大写字母
|
||||
!/[a-z]/.test(value) || // 必须包含小写字母
|
||||
!/\d/.test(value) // 必须包含数字
|
||||
) {
|
||||
callback(new Error("密码必须包含大小写字母和数字"));
|
||||
} else {
|
||||
if (this.form.checkPass !== "") {
|
||||
this.$refs.form.validateField("checkPass");
|
||||
}
|
||||
callback();
|
||||
}
|
||||
};
|
||||
const validatePass2 = (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error("请再次输入密码"));
|
||||
} else if (value !== this.form.password) {
|
||||
callback(new Error("两次输入密码不一致!"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
loading: false,
|
||||
form: {
|
||||
password: "",
|
||||
checkPass: "",
|
||||
token: ""
|
||||
},
|
||||
rules: {
|
||||
password: [
|
||||
{ validator: validatePass, trigger: "blur" }
|
||||
],
|
||||
checkPass: [
|
||||
{ validator: validatePass2, trigger: "blur" }
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// 从URL获取token参数
|
||||
this.form.token = this.$route.query.token;
|
||||
if (!this.form.token) {
|
||||
this.$message.error("无效的验证令牌");
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitForm(formName) {
|
||||
this.$refs[formName].validate(valid => {
|
||||
if (!valid) return false;
|
||||
|
||||
this.loading = true;
|
||||
axios.post("/user/reset/resetPassword",
|
||||
{
|
||||
password: this.form.password,
|
||||
token: this.form.token
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(res => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success("密码重置成功,关闭此页面即可!");
|
||||
this.form.password = "";
|
||||
this.form.checkPass = "";
|
||||
} else {
|
||||
this.$message.error(res.data.msg || "重置失败");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
let message = "服务暂时不可用";
|
||||
if (error.response) {
|
||||
switch (error.response.status) {
|
||||
case 401:
|
||||
message = "验证令牌已过期";
|
||||
break;
|
||||
case 400:
|
||||
message = "无效的请求参数";
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.$message.error(message);
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 保持相同样式 */
|
||||
.login {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.issuer {
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
color: #409EFF;
|
||||
}
|
||||
</style>
|
@@ -7,6 +7,8 @@ Vue.use(VueRouter)
|
||||
|
||||
const routes = [
|
||||
{ path: '/login', component: () => import('@/pages/Login') },
|
||||
{path: '/forgotPassword', component: () => import('@/pages/reset/ForgotPassword')},
|
||||
{path: '/resetPassword', component: () => import('@/pages/reset/ResetPassword')},
|
||||
{
|
||||
path: '/admin',
|
||||
component: () => import('@/layout/Layout'),
|
||||
@@ -47,6 +49,11 @@ router.beforeEach((to, from, next) => {
|
||||
|
||||
console.log("beforeEach", from.path, to.path, token)
|
||||
// console.log(from)
|
||||
// 无论认证状态都允许访问重置页
|
||||
if (to.path === '/forgotPassword' || to.path === '/resetPassword') {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
// 没有token,全都跳转到login
|
||||
if (!token) {
|
||||
|
Reference in New Issue
Block a user