Add ResetPassword Page.

hikari
PeterAlbus 1 year ago
parent 53680f5f78
commit 251b7a0266

@ -1,7 +1,8 @@
import { createRouter, createWebHashHistory } from "vue-router"; import { createRouter, createWebHashHistory } from "vue-router";
import Nprogress from 'nprogress'; import Nprogress from "nprogress";
import { useUserStore } from "@/stores/user"; import { useUserStore } from "@/stores/user";
import { isLogin } from "@/services/userApi"; import { isLogin } from "@/services/userApi";
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
routes: [ routes: [
@ -9,182 +10,191 @@ const router = createRouter({
path: "/", path: "/",
name: "home", name: "home",
component: () => import("../views/Home.vue"), component: () => import("../views/Home.vue"),
meta:{ meta: {
title:'主页——PeterAlbus的博客', title: "主页——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue,个人博客', keywords: "PeterAlbus,Vue,个人博客",
description:'PeterAlbus的博客主页' description: "PeterAlbus的博客主页"
} }
} }
}, },
{ {
path: '/login', path: "/login",
name: 'Login', name: "Login",
component: () => import("../views/Login.vue"), component: () => import("../views/user/Login.vue"),
meta:{ meta: {
title:'登录——PeterAlbus的博客', title: "登录——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue', keywords: "PeterAlbus,Vue",
description:'PeterAlbus的博客登录页' description: "PeterAlbus的博客登录页"
} }
} }
}, },
{ {
path: '/register', path: "/register",
name: 'Register', name: "Register",
component: () => import("../views/Register.vue"), component: () => import("../views/user/Register.vue"),
meta:{ meta: {
title:'注册——PeterAlbus的博客', title: "注册——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue', keywords: "PeterAlbus,Vue",
description:'PeterAlbus的博客注册页' description: "PeterAlbus的博客注册页"
} }
} }
}, },
{ {
path: '/userCenter', path: "/userCenter",
name: 'UserCenter', name: "UserCenter",
component: () => import("../views/UserCenter.vue"), component: () => import("../views/user/UserCenter.vue"),
meta:{ meta: {
title:'用户中心——PeterAlbus的博客', title: "用户中心——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue', keywords: "PeterAlbus,Vue",
description:'PeterAlbus的博客用户中心' description: "PeterAlbus的博客用户中心"
} }
} }
}, },
{ {
path: '/blog', path: "/blog",
name: 'Blog', name: "Blog",
component: () => import("../views/Blog.vue"), component: () => import("../views/blog/Blog.vue"),
meta:{ meta: {
title:'博文——PeterAlbus的博客', title: "博文——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue', keywords: "PeterAlbus,Vue",
description:'PeterAlbus的博客博文页' description: "PeterAlbus的博客博文页"
} }
} }
}, },
{ {
path: '/about', path: "/about",
name: 'About', name: "About",
component: () => import("../views/About.vue"), component: () => import("../views/blog/About.vue"),
meta:{ meta: {
title:'关于我——PeterAlbus的博客', title: "关于我——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue', keywords: "PeterAlbus,Vue",
description:'PeterAlbus的个人介绍' description: "PeterAlbus的个人介绍"
} }
} }
}, },
{ {
path: '/document', path: "/document",
name: 'Document', name: "Document",
component: () => import("../views/Document.vue"), component: () => import("../views/blog/Document.vue"),
meta:{ meta: {
title:'归档——PeterAlbus的博客', title: "归档——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue', keywords: "PeterAlbus,Vue",
description:'PeterAlbus的博客归档页' description: "PeterAlbus的博客归档页"
} }
} }
}, },
{ {
path: '/photo', path: "/photo",
name: 'Photo', name: "Photo",
component: () => import("../views/Photo.vue"), component: () => import("../views/photo/Photo.vue"),
meta:{ meta: {
title:'照片墙——PeterAlbus的博客', title: "照片墙——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue', keywords: "PeterAlbus,Vue",
description:'PeterAlbus的照片墙' description: "PeterAlbus的照片墙"
} }
} }
}, },
{ {
path: '/types', path: "/types",
name: 'Types', name: "Types",
component: () => import("../views/Types.vue"), component: () => import("../views/blog/Types.vue"),
meta:{ meta: {
title:'分类查看——PeterAlbus的博客', title: "分类查看——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue', keywords: "PeterAlbus,Vue",
description:'PeterAlbus的博客列表' description: "PeterAlbus的博客列表"
} }
} }
}, },
{ {
path: '/editBlog', path: "/editBlog",
name: 'EditBlog', name: "EditBlog",
component: () => import("../views/EditBlog.vue"), component: () => import("../views/blog/EditBlog.vue"),
meta:{ meta: {
title:'编辑/创建博客——PeterAlbus的博客', title: "编辑/创建博客——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue', keywords: "PeterAlbus,Vue",
description:'PeterAlbus的博客编辑页' description: "PeterAlbus的博客编辑页"
} }
} }
}, },
{ {
path: '/uploadPhoto', path: "/uploadPhoto",
name: 'UploadPhoto', name: "UploadPhoto",
component: () => import("../views/UploadPhoto.vue"), component: () => import("../views/photo/UploadPhoto.vue"),
meta:{ meta: {
title:'上传照片——PeterAlbus的博客', title: "上传照片——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue', keywords: "PeterAlbus,Vue",
description:'PeterAlbus的博客' description: "PeterAlbus的博客"
} }
} }
}, },
{ {
path: '/addFriendLink', path: "/addFriendLink",
name: 'AddFriendLink', name: "AddFriendLink",
component: () => import("../views/AddFriendLink.vue"), component: () => import("../views/user/AddFriendLink.vue"),
meta:{ meta: {
title:'添加友情链接——PeterAlbus的博客', title: "添加友情链接——PeterAlbus的博客",
content:{ content: {
keywords:'PeterAlbus,Vue,个人博客', keywords: "PeterAlbus,Vue,个人博客",
description:'PeterAlbus的博客' description: "PeterAlbus的博客"
}
}
},
{
path: "/resetPassword",
name: "ResetPassword",
component: () => import("../views/user/ResetPassword.vue"),
meta: {
title: "重置密码——PeterAlbus的博客",
content: {
keywords: "PeterAlbus,Vue,个人博客",
description: "PeterAlbus的博客"
} }
} }
} }
], ]
}); });
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
Nprogress.start(); Nprogress.start();
const userStore = useUserStore(); const userStore = useUserStore();
if (userStore.userId===''&&localStorage.getItem("token")) { if (userStore.userId === "" && localStorage.getItem("token")) {
isLogin().then(res => { isLogin().then(res => {
userStore.updateUser(res.data) userStore.updateUser(res.data);
}).catch(err => { }).catch(err => {
console.log(err) console.log(err);
localStorage.removeItem("token") localStorage.removeItem("token");
}) });
} } else if (userStore.userId != "" && !localStorage.getItem("token")) {
else if (userStore.userId!=''&&!localStorage.getItem("token")) { userStore.logout();
userStore.logout() } else if (userStore.userId != "" && localStorage.getItem("token")) {
}
else if (userStore.userId!=''&&localStorage.getItem("token")) {
isLogin().then(res => { isLogin().then(res => {
userStore.updateUser(res.data) userStore.updateUser(res.data);
}).catch(() => { }).catch(() => {
userStore.logout() userStore.logout();
}) });
} }
if((to.name=='Login'||to.name=='Register')&&userStore.userId!='') if ((to.name == "Login" || to.name == "Register") && userStore.userId != "") {
{ next("/userCenter");
next('/userCenter') return;
return
} }
if(to.meta.content) { if (to.meta.content) {
const content = to.meta.content as any const content = to.meta.content as any;
document.querySelector('meta[name="keywords"]')?.setAttribute('content',content.keywords) document.querySelector("meta[name=\"keywords\"]")?.setAttribute("content", content.keywords);
document.querySelector('meta[name="description"]')?.setAttribute('content',content.description) document.querySelector("meta[name=\"description\"]")?.setAttribute("content", content.description);
} }
if(to.meta.title) { if (to.meta.title) {
document.title = to.meta.title as string document.title = to.meta.title as string;
} }
next(); next();
}); });

@ -1,7 +1,7 @@
const env:string=import.meta.env.VITE_APP_ENV const env:string=import.meta.env.VITE_APP_ENV
export const BASE_URL:string|undefined = { export const BASE_URL:string|undefined = {
dev: "https://www.peteralbus.com:8089/", dev: "http://localhost:8089/",
prod: "https://www.peteralbus.com:8089/", prod: "https://www.peteralbus.com:8089/",
test: "https://api.testserver.com/base/url", test: "https://api.testserver.com/base/url",
}[env] }[env]

@ -28,4 +28,10 @@ export const changePhone = (data:object) => http.get(data, userUrl.setPhone);
export const changeMail = (data:object) => http.get(data, userUrl.setMail); export const changeMail = (data:object) => http.get(data, userUrl.setMail);
export const fetchResetPasswordVerifyCode = (account: string, type: string) =>
http.get({ account, type }, userUrl.applyResetPasswordVerifyCode);
export const resetPassword = (data:object) =>
http.get(data, userUrl.resetPassword);

@ -12,8 +12,8 @@
<h2 v-if="!loginByPhone"></h2> <h2 v-if="!loginByPhone"></h2>
<h2 v-if="loginByPhone"></h2> <h2 v-if="loginByPhone"></h2>
<div class="switch"> <div class="switch">
<span v-if="!loginByPhone" @click="loginByPhone=true">使</span> <span v-if="!loginByPhone" @click="loginByPhone=true;loginForm.userPhone=loginForm.userMail">使</span>
<span v-if="loginByPhone" @click="loginByPhone=false">使</span> <span v-if="loginByPhone" @click="loginByPhone=false;loginForm.userMail=loginForm.userPhone">使</span>
</div> </div>
</div> </div>
<el-form <el-form
@ -41,6 +41,7 @@
<el-button plain color="#63a35c">注册</el-button> <el-button plain color="#63a35c">注册</el-button>
</router-link> </router-link>
</div> </div>
<div class="reset_pass"><router-link to="/resetPassword">忘记密码?</router-link></div>
</el-form> </el-form>
</el-col> </el-col>
</el-row> </el-row>
@ -157,4 +158,11 @@ const submitForm = async (formEl: FormInstance | undefined) => {
.switch:hover { .switch:hover {
color: #63a35c; color: #63a35c;
} }
.reset_pass {
margin-top: 10px;
text-align: center;
font-size: 0.8em;
color: #4B6186;
}
</style> </style>

@ -64,8 +64,6 @@
import Banner from "@/components/Banner.vue"; import Banner from "@/components/Banner.vue";
import { computed, reactive, ref } from "vue"; import { computed, reactive, ref } from "vue";
import { ElMessage, ElMessageBox, FormInstance } from "element-plus"; import { ElMessage, ElMessageBox, FormInstance } from "element-plus";
import axios from "axios";
import qs from "qs";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { fetchMailVerifyCode, fetchPhoneVerifyCode, register } from "@/services/userApi"; import { fetchMailVerifyCode, fetchPhoneVerifyCode, register } from "@/services/userApi";

@ -0,0 +1,244 @@
<template>
<Banner title="重置密码"></Banner>
<div class="main-container flex-box">
<div class="form-box">
<el-row style="height: 100%" justify="space-between">
<el-col :sm="12" :xs="0">
<el-image style="width: 100%;height: 100%;border-radius: 5px 0 0 5px;"
src="https://file.peteralbus.com/assets/blog/imgs/photo/DJI_0422.JPG" fit="cover" />
</el-col>
<el-col :sm="12" :xs="24" class="flex-box" style="padding: 20px">
<div style="margin: 0 30px 30px 30px">
<h2 v-if="!resetByPhone"></h2>
<h2 v-if="resetByPhone"></h2>
<div class="switch">
<span v-if="!resetByPhone" @click="resetByPhone=true;resetForm.userPhone=resetForm.userMail">使</span>
<span v-if="resetByPhone" @click="resetByPhone=false;resetForm.userMail=resetForm.userPhone">使</span>
</div>
</div>
<el-form
ref="ruleFormRef"
:model="resetForm"
:rules="rules"
label-width="100px"
class="demo-ruleForm"
size="default"
style="width: 100%;max-width: 400px"
>
<el-form-item label="邮箱" prop="userMail" v-if="!resetByPhone">
<el-input v-model="resetForm.userMail" />
</el-form-item>
<el-form-item label="手机" prop="userPhone" v-if="resetByPhone">
<el-input v-model="resetForm.userPhone" />
</el-form-item>
<el-form-item label="新密码" prop="userPassword">
<el-input v-model="resetForm.userPassword" type="password" />
</el-form-item>
<el-form-item label="确认密码" prop="userConfirmPassword">
<el-input v-model="resetForm.userConfirmPassword" type="password" />
</el-form-item>
<el-form-item label="验证码" prop="userVerifyCode" style="justify-content: space-between!important;">
<el-input v-model="resetForm.userVerifyCode" style="width: 70%" />
<el-button type="primary" class="get_verify_button" :disabled="!canGetVerifyCode"
@click="applyVerifyCode">
{{ verifyText }}
</el-button>
</el-form-item>
<div>
<el-button type="primary" style="color: white"
@click="submitForm(ruleFormRef)" color="#63a35c">重置密码
</el-button>&emsp;
</div>
<div class="go_login">
<router-link to="/login">前往登录</router-link>
</div>
</el-form>
</el-col>
</el-row>
</div>
</div>
</template>
<script setup lang="ts">
import Banner from "@/components/Banner.vue";
import { useRouter } from "vue-router";
import { reactive, ref } from "vue";
import { ElMessage, ElMessageBox, FormInstance } from "element-plus";
import { fetchResetPasswordVerifyCode, resetPassword } from "@/services/userApi";
const router = useRouter();
const ruleFormRef = ref<FormInstance>();
const resetForm = reactive({
userPhone: "",
userMail: "",
userPassword: "",
userConfirmPassword: "",
userVerifyCode: ""
});
const resetByPhone = ref(true);
const verifyText = ref("获取");
let time = 0;
const canGetVerifyCode = ref(true);
const timer = () => {
if (time > 0) {
verifyText.value = time + "s";
time--;
canGetVerifyCode.value = false;
setTimeout(timer, 1000);
} else {
canGetVerifyCode.value = true;
verifyText.value = "发送验证码";
}
};
const validatePass = (rule: any, value: any, callback: any) => {
if (value === "") {
callback(new Error("请输入密码"));
} else {
if (resetForm.userConfirmPassword !== "") {
if (!ruleFormRef.value) return;
ruleFormRef.value.validateField("userConfirmPassword", () => null);
}
callback();
}
};
const validateConfirmPass = (rule: any, value: any, callback: any) => {
if (value === "") {
callback(new Error("请再次输入密码"));
} else if (value !== resetForm.userPassword) {
callback(new Error("输入的两次密码不一致!"));
} else {
callback();
}
};
const validateEmail = (rule: any, value: any, callback: any) => {
if (resetByPhone.value) {
callback();
} else if (!value) {
callback(new Error("请输入邮箱"));
} else if (value.indexOf("@") == -1) {
callback(new Error("请输入正确格式的邮箱"));
} else {
callback();
}
};
const validatePhone = (rule: any, value: any, callback: any) => {
if (!resetByPhone.value) {
callback();
} else if (!value) {
callback(new Error("请输入手机号"));
} else if (!Number(value)) {
callback(new Error("请输入数字"));
} else if (value.length != 11) {
callback(new Error("请输入正确格式的11位手机号"));
} else {
callback();
}
};
const rules = reactive({
userMail: [
{ validator: validateEmail, trigger: "blur" }
],
userPhone: [
{ validator: validatePhone, trigger: "blur" }
],
userVerifyCode: [
{ required: true, message: "请输入验证码", trigger: "change" }
],
userPassword: [
{ validator: validatePass, trigger: "blur" },
{ min: 6, max: 60, message: "密码长度必须在6到60位之间", trigger: "blur" }
],
userConfirmPassword: [
{ validator: validateConfirmPass, trigger: "blur" },
{ min: 6, max: 60, message: "密码长度必须在6到60位之间", trigger: "blur" }
]
});
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
const account = resetByPhone.value ? resetForm.userPhone : resetForm.userMail;
resetPassword({
account,
newPassword: resetForm.userPassword,
verifyCode: resetForm.userVerifyCode
}).then(() => {
ElMessage.success("重置密码成功,请登录!");
router.push("/login")
});
}
});
};
const applyVerifyCode = () => {
const type = resetByPhone.value ? "phone" : "mail";
const account = resetByPhone.value ? resetForm.userPhone : resetForm.userMail;
fetchResetPasswordVerifyCode(account, type).then(() => {
ElMessage.success("验证码已发送");
time = 60 * 10;
timer();
}).catch((err) => {
if (err == "验证码已发送请10分钟后重试") {
ElMessageBox.alert("请求验证码过于频繁,请检查收件箱", "验证码已发送", { confirmButtonText: "确认" });
} else if (err == "该账号尚未注册") {
ElMessageBox.alert("该账号尚未注册,请检查", "未注册", { confirmButtonText: "确认" });
} else {
ElMessageBox.alert("发送失败,请联系管理员或确认账号可用性", "验证码发送失败", { confirmButtonText: "确认" });
}
});
};
</script>
<style scoped>
.form-box {
background-color: white;
width: 75vw;
height: 500px;
box-shadow: 0 3px 8px 6px rgba(7, 17, 27, 0.05);
border-radius: 5px;
}
.form-box:hover {
box-shadow: 0 5px 12px 8px rgba(7, 17, 27, 0.1);
}
.flex-box {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.switch {
margin: 5px;
cursor: pointer;
color: #4B6186;
font-size: 0.8em;
}
.switch:hover {
color: #63a35c;
}
.go_login {
margin-top: 10px;
text-align: center;
font-size: 0.8em;
color: #4B6186;
}
.get_verify_button {
border-width: 0;
width: 30%;
}
</style>

@ -493,6 +493,7 @@ const userIdentity = computed(() => {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
flex-direction: row;
} }
.user-center-info { .user-center-info {
Loading…
Cancel
Save