忘记密码表单校验
Some checks failed
Build And Deploy v3-admin-vite / build-and-deploy (push) Has been cancelled

This commit is contained in:
吕杰刚 2025-05-08 00:43:33 +08:00
parent 158f6fccd9
commit 7c202e3981
3 changed files with 280 additions and 301 deletions

View File

@ -1,34 +1,27 @@
export interface LoginRequestData {
/** admin 或 editor */
username: string
username: string;
/** 密码 */
password: string,
//手机号
// phone: string,
//手机验证码
//mobileCode: string
password: string;
}
export interface phoneLoginRequestData {
//手机号
phone: string,
phone: string;
//手机验证码
mobileCode: string
mobileCode: string;
}
export interface forgetRequestData {
/** admin 或 editor */
// username: string
/** 密码 */
password: string,
password: string;
//确认密码
confirmPassword: string,
confirmPassword: string;
//手机号
phone: string,
phone: string;
//手机验证码
mobileCode: string
mobileCode: string;
}
export type CaptchaResponseData = ApiResponseData<string>
export type CaptchaResponseData = ApiResponseData<string>;
export type LoginResponseData = ApiResponseData<{ token: string }>
export type LoginResponseData = ApiResponseData<{ token: string }>;

View File

@ -23,7 +23,10 @@ const { isFocus, handleBlur, handleFocus } = useFocus();
/** 登录表单元素的引用 */
const loginFormRef = ref<FormInstance | null>(null);
/** 短信验证码登录表单元素的引用 */
const phoneFormRef = ref<FormInstance | null>(null);
/** 短信验证码登录表单元素的引用 */
const forgetFormRef = ref<FormInstance | null>(null);
/** 登录按钮 Loading */
const loading = ref(false);
//
@ -59,20 +62,6 @@ const forgetFormData: forgetRequestData = reactive({
mobileCode: "",
});
// const loginFormRules: FormRules = {
// username: [{ required: true, message: "", trigger: "blur" }],
// password: [
// { required: true, message: "", trigger: "blur" },
// { min: 8, max: 16, message: " 8 16 ", trigger: "blur" },
// ],
// mobileCode: [
// { required: true, message: "", trigger: "blur" },
// ],
// phone: [
// { required: true, message: "", trigger: "blur" },
// { min: 4, max: 4, message: "", trigger: "blur" },
// ],
// };
/** 登录表单校验规则 */
const loginFormRules = reactive<FormRules<LoginRequestData>>({
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
@ -82,7 +71,7 @@ const loginFormRules = reactive<FormRules<LoginRequestData>>({
],
});
/** 登录表单校验规则 */
/** 短信验证码登录登录表单校验规则 */
const phoneFormRules = reactive<FormRules<phoneLoginRequestData>>({
phone: [
{ required: true, message: "请输入手机号", trigger: "blur" },
@ -159,15 +148,14 @@ const forgetFormRules = reactive<FormRules<forgetRequestData>>({
},
],
});
/** 登录 */
async function handleLogin(formEl) {
/** 账号密码登录 */
async function handleUserLogin(formEl) {
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
loading.value = true;
loginApi(loginFormData)
.then(({ data }) => {
console.log(data);
userStore.setToken(data.token);
router.push("/");
})
@ -182,27 +170,54 @@ async function handleLogin(formEl) {
return;
}
});
// loginFormRef.value?.validate((valid) => {
// if (!valid) {
// ElMessage.error("");
// return;
// }
// loading.value = true;
// loginApi(loginFormData)
// .then(({ data }) => {
// console.log(data);
// userStore.setToken(data.token);
// router.push("/");
// })
// .catch(() => {
// loginFormData.password = "";
// })
// .finally(() => {
// loading.value = false;
// });
// });
}
//
async function handlePhoneLogin(formEl) {
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
loading.value = true;
loginApi(forgetFormData)
.then(({ data }) => {
console.log(data);
userStore.setToken(data.token);
router.push("/");
})
.catch(() => {
forgetFormData.mobileCode = "";
})
.finally(() => {
loading.value = false;
});
} else {
ElMessage.error("表单校验不通过");
return;
}
});
}
//
async function submit(formEl) {
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
loading.value = true;
loginApi()
.then(({ data }) => {
userStore.setToken(data.token);
router.push("/");
})
.catch(() => {
phoneFormData.mobileCode = "";
})
.finally(() => {
loading.value = false;
});
} else {
ElMessage.error("表单校验不通过");
return;
}
});
}
// true false
function mobileCode(type: boolean) {
loginMethod.value = type;
@ -242,14 +257,15 @@ watch(isDisabled, (newVal, oldVal) => {
</div>
<div class="title-text">数据运营管理平台</div>
</div>
<div class="content" v-if="!isForgetPwd">
<div class="content">
<el-form
ref="loginFormRef"
:model="loginFormData"
:rules="loginFormRules"
@keyup.enter="handleLogin"
@keyup.enter="handleUserLogin"
v-show="loginMethod && !isForgetPwd"
>
<el-form-item prop="username" v-show="loginMethod">
<el-form-item prop="username">
<el-input
v-model.trim="loginFormData.username"
placeholder="用户名"
@ -259,7 +275,7 @@ watch(isDisabled, (newVal, oldVal) => {
size="large"
/>
</el-form-item>
<el-form-item prop="password" v-show="loginMethod">
<el-form-item prop="password">
<el-input
v-model.trim="loginFormData.password"
placeholder="密码"
@ -272,110 +288,25 @@ watch(isDisabled, (newVal, oldVal) => {
@focus="handleFocus"
/>
</el-form-item>
<el-form
v-show="!loginMethod"
ref="phoneFormRef"
:model="phoneFormData"
:rules="phoneFormRules"
@keyup.enter="handleLogin"
><el-form-item prop="phone">
<el-input
v-model.trim="phoneFormData.phone"
placeholder="手机号"
tabindex="3"
:prefix-icon="Iphone"
size="large"
maxlength="11"
/>
</el-form-item>
<el-form-item prop="mobileCode" v-show="!loginMethod">
<el-input
v-model.trim="phoneFormData.mobileCode"
placeholder="手机验证码"
tabindex="4"
:prefix-icon="Promotion"
size="large"
@blur="handleBlur"
@focus="handleFocus"
maxlength="4"
/>
<button
id="sendCode"
@click="getMobileCode(phoneFormData.mobileCode)"
:disabled="isDisabled"
>
<span v-if="!isDisabled">获取验证码</span>
<span v-if="isDisabled">{{ countdown + " 秒后重试" }}</span>
</button>
</el-form-item></el-form
>
<!-- <el-form-item prop="code">
<el-input
v-model.trim="loginFormData.code"
placeholder="验证码"
type="text"
tabindex="3"
:prefix-icon="Key"
maxlength="7"
size="large"
@blur="handleBlur"
@focus="handleFocus"
>
<template #append>
<el-image :src="codeUrl" draggable="false" @click="createCode">
<template #placeholder>
<el-icon>
<Picture />
</el-icon>
</template>
<template #error>
<el-icon>
<Loading />
</el-icon>
</template>
</el-image>
</template>
</el-input>
</el-form-item> -->
<el-button
v-if="loginMethod"
:loading="loading"
type="primary"
size="large"
@click.prevent="handleLogin(loginFormRef)"
@click.prevent="handleUserLogin(loginFormRef)"
>
</el-button>
</el-form>
<div class="login-btn">
<el-link type="primary" @click="mobileCode(false)" v-if="loginMethod"
>手机验证码登录</el-link
>
<el-link type="primary" @click="mobileCode(true)" v-if="!loginMethod"
>用户名密码登录</el-link
>
<el-link type="primary" @click="forgetPwd()">忘记密码 </el-link>
</div>
</div>
<div class="forget-content" v-if="isForgetPwd">
<el-form
ref="forgetFormRef"
:model="forgetFormData"
:rules="forgetFormRules"
>
<!-- <el-form-item prop="username" v-show="loginMethod">
v-show="!loginMethod && !isForgetPwd"
ref="phoneFormRef"
:model="phoneFormData"
:rules="phoneFormRules"
@keyup.enter="handlePhoneLogin"
><el-form-item prop="phone">
<el-input
v-model.trim="forgetFormData.username"
placeholder="用户名"
type="text"
tabindex="1"
:prefix-icon="User"
size="large"
/>
</el-form-item> -->
<el-form-item prop="phone">
<el-input
v-model.trim="forgetFormData.phone"
v-model.trim="phoneFormData.phone"
placeholder="手机号"
tabindex="3"
:prefix-icon="Iphone"
@ -383,9 +314,9 @@ watch(isDisabled, (newVal, oldVal) => {
maxlength="11"
/>
</el-form-item>
<el-form-item prop="password">
<el-form-item prop="mobileCode" v-show="!loginMethod">
<el-input
v-model.trim="forgetFormData.mobileCode"
v-model.trim="phoneFormData.mobileCode"
placeholder="手机验证码"
tabindex="4"
:prefix-icon="Promotion"
@ -396,7 +327,61 @@ watch(isDisabled, (newVal, oldVal) => {
/>
<button
id="sendCode"
@click="getMobileCode(forgetFormData.mobileCode)"
@click="getMobileCode(phoneFormData.mobileCode)"
:disabled="isDisabled"
>
<span v-if="!isDisabled">获取验证码</span>
<span v-if="isDisabled">{{ countdown + " 秒后重试" }}</span>
</button>
</el-form-item>
<el-button
:loading="loading"
type="primary"
size="large"
@click.prevent="handlePhoneLogin(phoneFormRef)"
>
</el-button>
</el-form>
<div class="login-btn" v-show="!isForgetPwd">
<el-link type="primary" @click="mobileCode(false)" v-if="loginMethod"
>手机验证码登录</el-link
>
<el-link type="primary" @click="mobileCode(true)" v-if="!loginMethod"
>用户名密码登录</el-link
>
<el-link type="primary" @click="forgetPwd()">忘记密码 </el-link>
</div>
<el-form
v-if="isForgetPwd"
ref="forgetFormRef"
:model="forgetFormData"
:rules="forgetFormRules"
>
<el-form-item prop="phone">
<el-input
v-model.trim="forgetFormData.phone"
placeholder="手机号"
tabindex="1"
:prefix-icon="Iphone"
size="large"
maxlength="11"
/>
</el-form-item>
<el-form-item prop="mobileCode">
<el-input
v-model.trim="forgetFormData.mobileCode"
placeholder="手机验证码"
tabindex="2"
:prefix-icon="Promotion"
size="large"
@blur="handleBlur"
@focus="handleFocus"
maxlength="4"
/>
<button
id="sendCode"
@click="getMobileCode(forgetFormData.phone)"
:disabled="isDisabled"
>
<span v-if="!isDisabled">获取验证码</span>
@ -408,7 +393,7 @@ watch(isDisabled, (newVal, oldVal) => {
v-model.trim="forgetFormData.password"
placeholder="密码"
type="password"
tabindex="2"
tabindex="3"
:prefix-icon="Lock"
size="large"
show-password
@ -421,7 +406,7 @@ watch(isDisabled, (newVal, oldVal) => {
v-model.trim="forgetFormData.confirmPassword"
placeholder="确认密码"
type="password"
tabindex="2"
tabindex="4"
:prefix-icon="Check"
size="large"
show-password
@ -429,13 +414,12 @@ watch(isDisabled, (newVal, oldVal) => {
@focus="handleFocus"
/>
</el-form-item>
<el-button
class="forgetLogin"
:loading="loading"
type="primary"
size="large"
@click.prevent="handleLogin"
@click.prevent="submit(forgetFormRef)"
>
</el-button>

View File

@ -1,10 +1,10 @@
import type { RouteRecordRaw } from "vue-router"
import { routerConfig } from "@/router/config"
import { registerNavigationGuard } from "@/router/guard"
import { createRouter } from "vue-router"
import { flatMultiLevelRoutes } from "./helper"
import type { RouteRecordRaw } from "vue-router";
import { routerConfig } from "@/router/config";
import { registerNavigationGuard } from "@/router/guard";
import { createRouter } from "vue-router";
import { flatMultiLevelRoutes } from "./helper";
const Layouts = () => import("@/layouts/index.vue")
const Layouts = () => import("@/layouts/index.vue");
/**
* @name
@ -15,36 +15,36 @@ export const constantRoutes: RouteRecordRaw[] = [
path: "/redirect",
component: Layouts,
meta: {
hidden: true
hidden: true,
},
children: [
{
path: ":path(.*)",
component: () => import("@/pages/redirect/index.vue")
}
]
component: () => import("@/pages/redirect/index.vue"),
},
],
},
{
path: "/403",
component: () => import("@/pages/error/403.vue"),
meta: {
hidden: true
}
hidden: true,
},
},
{
path: "/404",
component: () => import("@/pages/error/404.vue"),
meta: {
hidden: true
hidden: true,
},
alias: "/:pathMatch(.*)*"
alias: "/:pathMatch(.*)*",
},
{
path: "/login",
component: () => import("@/pages/login/index.vue"),
meta: {
hidden: true
}
hidden: true,
},
},
{
path: "/",
@ -58,111 +58,111 @@ export const constantRoutes: RouteRecordRaw[] = [
meta: {
title: "首页",
svgIcon: "dashboard",
affix: true
}
}
]
},
{
path: "/demo",
component: Layouts,
redirect: "/demo/unocss",
name: "Demo",
meta: {
title: "示例集合",
elIcon: "DataBoard"
},
children: [
{
path: "unocss",
component: () => import("@/pages/demo/unocss/index.vue"),
name: "UnoCSS",
meta: {
title: "UnoCSS"
}
},
{
path: "element-plus",
component: () => import("@/pages/demo/element-plus/index.vue"),
name: "ElementPlus",
meta: {
title: "Element Plus",
keepAlive: true
}
},
{
path: "rsgl",
component: () => import("@/pages/demo/rsgl/rsgl.vue"),
name: "RSgl",
meta: {
title: "RSgl",
keepAlive: true
}
},
{
path: "vxe-table",
component: () => import("@/pages/demo/vxe-table/index.vue"),
name: "VxeTable",
meta: {
title: "Vxe Table",
keepAlive: true
}
},
{
path: "level2",
component: () => import("@/pages/demo/level2/index.vue"),
redirect: "/demo/level2/level3",
name: "Level2",
meta: {
title: "二级路由",
alwaysShow: true
affix: true,
},
children: [
{
path: "level3",
component: () => import("@/pages/demo/level2/level3/index.vue"),
name: "Level3",
meta: {
title: "三级路由",
keepAlive: true
}
}
]
}
]
},
{
path: "/link",
meta: {
title: "文档链接",
elIcon: "Link"
},
children: [
{
path: "https://juejin.cn/post/7445151895121543209",
component: () => {},
name: "Link1",
meta: {
title: "中文文档"
}
},
{
path: "https://juejin.cn/column/7207659644487139387",
component: () => {},
name: "Link2",
meta: {
title: "新手教程"
}
}
]
],
},
// {
// path: "/demo",
// component: Layouts,
// redirect: "/demo/unocss",
// name: "Demo",
// meta: {
// title: "示例集合",
// elIcon: "DataBoard"
// },
// children: [
// {
// path: "unocss",
// component: () => import("@/pages/demo/unocss/index.vue"),
// name: "UnoCSS",
// meta: {
// title: "UnoCSS"
// }
// },
// {
// path: "element-plus",
// component: () => import("@/pages/demo/element-plus/index.vue"),
// name: "ElementPlus",
// meta: {
// title: "Element Plus",
// keepAlive: true
// }
// },
// {
// path: "rsgl",
// component: () => import("@/pages/demo/rsgl/rsgl.vue"),
// name: "RSgl",
// meta: {
// title: "RSgl",
// keepAlive: true
// }
// },
// {
// path: "vxe-table",
// component: () => import("@/pages/demo/vxe-table/index.vue"),
// name: "VxeTable",
// meta: {
// title: "Vxe Table",
// keepAlive: true
// }
// },
// {
// path: "level2",
// component: () => import("@/pages/demo/level2/index.vue"),
// redirect: "/demo/level2/level3",
// name: "Level2",
// meta: {
// title: "二级路由",
// alwaysShow: true
// },
// children: [
// {
// path: "level3",
// component: () => import("@/pages/demo/level2/level3/index.vue"),
// name: "Level3",
// meta: {
// title: "三级路由",
// keepAlive: true
// }
// }
// ]
// }
// ]
// },
// {
// path: "/link",
// meta: {
// title: "文档链接",
// elIcon: "Link"
// },
// children: [
// {
// path: "https://juejin.cn/post/7445151895121543209",
// component: () => {},
// name: "Link1",
// meta: {
// title: "中文文档"
// }
// },
// {
// path: "https://juejin.cn/column/7207659644487139387",
// component: () => {},
// name: "Link2",
// meta: {
// title: "新手教程"
// }
// }
// ]
// },
{
path: "/diceke",
component: Layouts,
redirect: "/diceke",
meta: {
title: "地测科",
elIcon: "Link"
elIcon: "Link",
},
children: [
{
@ -170,36 +170,36 @@ export const constantRoutes: RouteRecordRaw[] = [
component: () => import("@/pages/demo/diceke/shovel.vue"),
name: "shovel",
meta: {
title: "电铲维护"
}
title: "电铲维护",
},
},
{
path: "plateArea",
component: () => import("@/pages/demo/diceke/PlateArea.vue"),
name: "plateArea",
meta: {
title: "平盘维护"
}
title: "平盘维护",
},
},
{
path: "dicekeMiningrecord",
component: () => import("@/pages/demo/diceke/DicekeMiningrecord.vue"),
name: "dicekeMiningrecord",
meta: {
title: "Mo品味报表"
}
title: "Mo品味报表",
},
},
{
path: "dicekePrecipitation",
component: () => import("@/pages/demo/diceke/Precipitation.vue"),
name: "dicekePrecipitation",
meta: {
title: "降水量报表"
}
}
]
}
]
title: "降水量报表",
},
},
],
},
];
/**
* @name
@ -217,7 +217,7 @@ export const dynamicRoutes: RouteRecordRaw[] = [
elIcon: "Lock",
// 可以在根路由中设置角色
roles: ["admin", "editor"],
alwaysShow: true
alwaysShow: true,
},
children: [
{
@ -227,8 +227,8 @@ export const dynamicRoutes: RouteRecordRaw[] = [
meta: {
title: "页面级",
// 或者在子路由中设置角色
roles: ["admin"]
}
roles: ["admin"],
},
},
{
path: "button-level",
@ -237,34 +237,36 @@ export const dynamicRoutes: RouteRecordRaw[] = [
meta: {
title: "按钮级",
// 如果未设置角色,则表示:该页面不需要权限,但会继承根路由的角色
roles: undefined
}
}
]
}
]
roles: undefined,
},
},
],
},
];
/** 路由实例 */
export const router = createRouter({
history: routerConfig.history,
routes: routerConfig.thirdLevelRouteCache ? flatMultiLevelRoutes(constantRoutes) : constantRoutes
})
routes: routerConfig.thirdLevelRouteCache
? flatMultiLevelRoutes(constantRoutes)
: constantRoutes,
});
/** 重置路由 */
export function resetRouter() {
try {
// 注意:所有动态路由路由必须带有 Name 属性,否则可能会不能完全重置干净
router.getRoutes().forEach((route) => {
const { name, meta } = route
const { name, meta } = route;
if (name && meta.roles?.length) {
router.hasRoute(name) && router.removeRoute(name)
router.hasRoute(name) && router.removeRoute(name);
}
})
});
} catch {
// 强制刷新浏览器也行,只是交互体验不是很好
location.reload()
location.reload();
}
}
// 注册路由导航守卫
registerNavigationGuard(router)
registerNavigationGuard(router);