mirror of
https://github.com/pure-admin/pure-admin-thin.git
synced 2025-04-24 23:47:17 +08:00
perf: 登录
This commit is contained in:
parent
52ab1f8a33
commit
cdac80a1c2
@ -82,7 +82,7 @@ login:
|
||||
verifyCodeSixReg: Please enter a 6-digit verify code
|
||||
phoneReg: Please enter the phone
|
||||
phoneCorrectReg: Please enter the correct phone number format
|
||||
passwordRuleReg: The password format should be any combination of 8-18 digits
|
||||
passwordRuleReg: The password format should be any combination of 5-12 digits
|
||||
passwordSureReg: Please enter confirm password
|
||||
passwordDifferentReg: The two passwords do not match!
|
||||
passwordUpdateReg: Password has been updated
|
||||
|
@ -82,7 +82,7 @@ login:
|
||||
verifyCodeSixReg: 请输入6位数字验证码
|
||||
phoneReg: 请输入手机号码
|
||||
phoneCorrectReg: 请输入正确的手机号码格式
|
||||
passwordRuleReg: 密码格式应为8-18位数字、字母、符号的任意两种组合
|
||||
passwordRuleReg: 密码格式应为5-12位数字、字母、符号的任意两种组合
|
||||
passwordSureReg: 请输入确认密码
|
||||
passwordDifferentReg: 两次密码不一致!
|
||||
passwordUpdateReg: 修改密码成功
|
||||
|
@ -14,7 +14,6 @@ export default defineFakeRoute([
|
||||
// 一个用户可能有多个角色
|
||||
roles: ["admin"],
|
||||
accessToken: "eyJhbGciOiJIUzUxMiJ9.admin",
|
||||
refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh",
|
||||
expires: "2030/10/30 00:00:00"
|
||||
}
|
||||
};
|
||||
@ -26,7 +25,6 @@ export default defineFakeRoute([
|
||||
// 一个用户可能有多个角色
|
||||
roles: ["common"],
|
||||
accessToken: "eyJhbGciOiJIUzUxMiJ9.common",
|
||||
refreshToken: "eyJhbGciOiJIUzUxMiJ9.commonRefresh",
|
||||
expires: "2030/10/30 00:00:00"
|
||||
}
|
||||
};
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { defineFakeRoute } from "vite-plugin-fake-server/client";
|
||||
|
||||
// 模拟刷新token接口
|
||||
export default defineFakeRoute([
|
||||
{
|
||||
url: "/refresh-token",
|
||||
method: "post",
|
||||
response: ({ body }) => {
|
||||
if (body.refreshToken) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
accessToken: "eyJhbGciOiJIUzUxMiJ9.newAdmin",
|
||||
refreshToken: "eyJhbGciOiJIUzUxMiJ9.newAdminRefresh",
|
||||
// `expires`选择这种日期格式是为了方便调试,后端直接设置时间戳或许更方便(每次都应该递增)。如果后端返回的是时间戳格式,前端开发请来到这个目录`src/utils/auth.ts`,把第`38`行的代码换成expires = data.expires即可。
|
||||
expires: "2030/10/30 23:59:59"
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
data: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
@ -76,7 +76,8 @@
|
||||
"vue-i18n": "^9.10.1",
|
||||
"vue-router": "^4.3.0",
|
||||
"vue-tippy": "^6.4.1",
|
||||
"vue-types": "^5.1.1"
|
||||
"vue-types": "^5.1.1",
|
||||
"jsencrypt": "^3.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^18.6.1",
|
||||
|
7
pnpm-lock.yaml
generated
7
pnpm-lock.yaml
generated
@ -44,6 +44,9 @@ dependencies:
|
||||
js-cookie:
|
||||
specifier: ^3.0.5
|
||||
version: 3.0.5
|
||||
jsencrypt:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
localforage:
|
||||
specifier: ^1.10.0
|
||||
version: 1.10.0
|
||||
@ -3907,6 +3910,10 @@ packages:
|
||||
argparse: 2.0.1
|
||||
dev: true
|
||||
|
||||
/jsencrypt@3.3.2:
|
||||
resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==}
|
||||
dev: false
|
||||
|
||||
/jsesc@2.5.2:
|
||||
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
|
||||
engines: {node: '>=4'}
|
||||
|
67
src/api/login.ts
Normal file
67
src/api/login.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { http } from "@/utils/http";
|
||||
import { ApiAbstract } from "@/utils/http/ApiAbstract";
|
||||
import { baseUrlAuth } from "./utils";
|
||||
import Cookies from "js-cookie";
|
||||
export class UserResult extends ApiAbstract {
|
||||
declare data: {
|
||||
img: string;
|
||||
uuid: string;
|
||||
};
|
||||
}
|
||||
export interface UserUser {
|
||||
avatarName?: string;
|
||||
avatarPath?: string;
|
||||
createTime?: Date;
|
||||
dept?: any;
|
||||
deptId?: 0;
|
||||
email?: string;
|
||||
enabled?: boolean;
|
||||
gender?: string;
|
||||
id?: Number;
|
||||
isAdmin?: boolean;
|
||||
jobs?: any;
|
||||
nickName?: string;
|
||||
password?: string;
|
||||
phone?: string;
|
||||
roles?: any;
|
||||
updateBy?: string;
|
||||
updateTime?: Date;
|
||||
username?: string;
|
||||
}
|
||||
export interface User {
|
||||
authorities?: any;
|
||||
dataScopes?: any;
|
||||
roles?: any;
|
||||
user?: UserUser;
|
||||
}
|
||||
export class UserLogResult extends ApiAbstract {
|
||||
declare data: {
|
||||
token: string;
|
||||
user: User;
|
||||
username: string;
|
||||
roles: Array<string>;
|
||||
};
|
||||
}
|
||||
|
||||
/** 获取验证码 */
|
||||
export const getCode = () => {
|
||||
return http.request<UserResult>("get", baseUrlAuth("code"));
|
||||
};
|
||||
|
||||
/** 登录 */
|
||||
export const login = (data?: object) => {
|
||||
return http.request<UserLogResult>("post", baseUrlAuth("login"), { data });
|
||||
};
|
||||
/** 获取用户信息 */
|
||||
export const userInfo = () => {
|
||||
return http.request<ApiAbstract>("get", baseUrlAuth("info"), null, {
|
||||
headers: {
|
||||
Authorization: Cookies.get("token")
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** 退出登录 */
|
||||
export const logout = () => {
|
||||
return http.request<UserResult>("delete", baseUrlAuth("logout"));
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
import { http } from "@/utils/http";
|
||||
|
||||
export type UserResult = {
|
||||
success: boolean;
|
||||
data: {
|
||||
/** 用户名 */
|
||||
username: string;
|
||||
/** 当前登陆用户的角色 */
|
||||
roles: Array<string>;
|
||||
/** `token` */
|
||||
accessToken: string;
|
||||
/** 用于调用刷新`accessToken`的接口时所需的`token` */
|
||||
refreshToken: string;
|
||||
/** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
|
||||
expires: Date;
|
||||
};
|
||||
};
|
||||
|
||||
export type RefreshTokenResult = {
|
||||
success: boolean;
|
||||
data: {
|
||||
/** `token` */
|
||||
accessToken: string;
|
||||
/** 用于调用刷新`accessToken`的接口时所需的`token` */
|
||||
refreshToken: string;
|
||||
/** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */
|
||||
expires: Date;
|
||||
};
|
||||
};
|
||||
|
||||
/** 登录 */
|
||||
export const getLogin = (data?: object) => {
|
||||
return http.request<UserResult>("post", "/login", { data });
|
||||
};
|
||||
|
||||
/** 刷新token */
|
||||
export const refreshTokenApi = (data?: object) => {
|
||||
return http.request<RefreshTokenResult>("post", "/refresh-token", { data });
|
||||
};
|
@ -1,85 +1,30 @@
|
||||
import { ref, onMounted } from "vue";
|
||||
import { getCode } from "@/api/login";
|
||||
|
||||
/**
|
||||
* 绘制图形验证码
|
||||
* @param width - 图形宽度
|
||||
* @param height - 图形高度
|
||||
*/
|
||||
export const useImageVerify = (width = 120, height = 40) => {
|
||||
const domRef = ref<HTMLCanvasElement>();
|
||||
export const useImageVerify = () => {
|
||||
const imgCode = ref("");
|
||||
|
||||
function setImgCode(code: string) {
|
||||
imgCode.value = code;
|
||||
}
|
||||
const imgSrc = ref("");
|
||||
|
||||
function getImgCode() {
|
||||
if (!domRef.value) return;
|
||||
imgCode.value = draw(domRef.value, width, height);
|
||||
getCode().then(data => {
|
||||
if (data.status) {
|
||||
imgCode.value = data.data.uuid;
|
||||
imgSrc.value = data.data.img;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getImgCode();
|
||||
});
|
||||
|
||||
return {
|
||||
domRef,
|
||||
imgSrc,
|
||||
imgCode,
|
||||
setImgCode,
|
||||
getImgCode
|
||||
};
|
||||
};
|
||||
|
||||
function randomNum(min: number, max: number) {
|
||||
const num = Math.floor(Math.random() * (max - min) + min);
|
||||
return num;
|
||||
}
|
||||
|
||||
function randomColor(min: number, max: number) {
|
||||
const r = randomNum(min, max);
|
||||
const g = randomNum(min, max);
|
||||
const b = randomNum(min, max);
|
||||
return `rgb(${r},${g},${b})`;
|
||||
}
|
||||
|
||||
function draw(dom: HTMLCanvasElement, width: number, height: number) {
|
||||
let imgCode = "";
|
||||
|
||||
const NUMBER_STRING = "0123456789";
|
||||
|
||||
const ctx = dom.getContext("2d");
|
||||
if (!ctx) return imgCode;
|
||||
|
||||
ctx.fillStyle = randomColor(180, 230);
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
for (let i = 0; i < 4; i += 1) {
|
||||
const text = NUMBER_STRING[randomNum(0, NUMBER_STRING.length)];
|
||||
imgCode += text;
|
||||
const fontSize = randomNum(18, 41);
|
||||
const deg = randomNum(-30, 30);
|
||||
ctx.font = `${fontSize}px Simhei`;
|
||||
ctx.textBaseline = "top";
|
||||
ctx.fillStyle = randomColor(80, 150);
|
||||
ctx.save();
|
||||
ctx.translate(30 * i + 15, 15);
|
||||
ctx.rotate((deg * Math.PI) / 180);
|
||||
ctx.fillText(text, -15 + 5, -15);
|
||||
ctx.restore();
|
||||
}
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(randomNum(0, width), randomNum(0, height));
|
||||
ctx.lineTo(randomNum(0, width), randomNum(0, height));
|
||||
ctx.strokeStyle = randomColor(180, 230);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
for (let i = 0; i < 41; i += 1) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(randomNum(0, width), randomNum(0, height), 1, 0, 2 * Math.PI);
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = randomColor(150, 200);
|
||||
ctx.fill();
|
||||
}
|
||||
return imgCode;
|
||||
}
|
||||
|
@ -20,14 +20,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const { domRef, imgCode, setImgCode, getImgCode } = useImageVerify();
|
||||
const { imgSrc, imgCode, getImgCode } = useImageVerify();
|
||||
|
||||
watch(
|
||||
() => props.code,
|
||||
newValue => {
|
||||
setImgCode(newValue);
|
||||
}
|
||||
);
|
||||
watch(imgCode, newValue => {
|
||||
emit("update:code", newValue);
|
||||
});
|
||||
@ -36,11 +30,10 @@ defineExpose({ getImgCode });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<canvas
|
||||
ref="domRef"
|
||||
width="120"
|
||||
height="40"
|
||||
class="cursor-pointer"
|
||||
<el-image
|
||||
style="width: 120; height: 40"
|
||||
:src="imgSrc"
|
||||
fit="contain"
|
||||
@click="getImgCode"
|
||||
/>
|
||||
</template>
|
||||
|
@ -38,7 +38,6 @@ export type setType = {
|
||||
export type userType = {
|
||||
username?: string;
|
||||
roles?: Array<string>;
|
||||
verifyCode?: string;
|
||||
currentPage?: number;
|
||||
isRemembered?: boolean;
|
||||
loginDay?: number;
|
||||
|
@ -4,10 +4,10 @@ import type { userType } from "./types";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { router, resetRouter } from "@/router";
|
||||
import { storageLocal } from "@pureadmin/utils";
|
||||
import { getLogin, refreshTokenApi } from "@/api/user";
|
||||
import type { UserResult, RefreshTokenResult } from "@/api/user";
|
||||
import { type UserLogResult, login } from "@/api/login";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import { type DataInfo, setToken, removeToken, userKey } from "@/utils/auth";
|
||||
import { encrypt } from "@/utils/rsaEncrypt";
|
||||
|
||||
export const useUserStore = defineStore({
|
||||
id: "pure-user",
|
||||
@ -16,8 +16,6 @@ export const useUserStore = defineStore({
|
||||
username: storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "",
|
||||
// 页面级别权限
|
||||
roles: storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [],
|
||||
// 前端生成的验证码(按实际需求替换)
|
||||
verifyCode: "",
|
||||
// 判断登录页面显示哪个组件(0:登录(默认)、1:手机登录、2:二维码登录、3:注册、4:忘记密码)
|
||||
currentPage: 0,
|
||||
// 是否勾选了登录页的免登录
|
||||
@ -34,10 +32,6 @@ export const useUserStore = defineStore({
|
||||
SET_ROLES(roles: Array<string>) {
|
||||
this.roles = roles;
|
||||
},
|
||||
/** 存储前端生成的验证码 */
|
||||
SET_VERIFYCODE(verifyCode: string) {
|
||||
this.verifyCode = verifyCode;
|
||||
},
|
||||
/** 存储登录页面显示哪个组件 */
|
||||
SET_CURRENTPAGE(value: number) {
|
||||
this.currentPage = value;
|
||||
@ -52,11 +46,23 @@ export const useUserStore = defineStore({
|
||||
},
|
||||
/** 登入 */
|
||||
async loginByUsername(data) {
|
||||
return new Promise<UserResult>((resolve, reject) => {
|
||||
getLogin(data)
|
||||
return new Promise<UserLogResult>((resolve, reject) => {
|
||||
login({
|
||||
username: data.username,
|
||||
password: encrypt(data.password),
|
||||
code: data.code,
|
||||
uuid: data.uuid
|
||||
})
|
||||
.then(data => {
|
||||
if (data) {
|
||||
setToken(data.data);
|
||||
//;
|
||||
setToken({
|
||||
accessToken: data.data.token,
|
||||
username: data.data?.user?.user?.nickName,
|
||||
expires: new Date("2033-03-15T12:00:00Z"),
|
||||
roles: data.data?.user?.roles,
|
||||
user: data.data?.user?.user
|
||||
});
|
||||
resolve(data);
|
||||
}
|
||||
})
|
||||
@ -73,21 +79,6 @@ export const useUserStore = defineStore({
|
||||
useMultiTagsStoreHook().handleTags("equal", [...routerArrays]);
|
||||
resetRouter();
|
||||
router.push("/login");
|
||||
},
|
||||
/** 刷新`token` */
|
||||
async handRefreshToken(data) {
|
||||
return new Promise<RefreshTokenResult>((resolve, reject) => {
|
||||
refreshTokenApi(data)
|
||||
.then(data => {
|
||||
if (data) {
|
||||
setToken(data.data);
|
||||
resolve(data);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -7,12 +7,12 @@ export interface DataInfo<T> {
|
||||
accessToken: string;
|
||||
/** `accessToken`的过期时间(时间戳) */
|
||||
expires: T;
|
||||
/** 用于调用刷新accessToken的接口时所需的token */
|
||||
refreshToken: string;
|
||||
/** 用户名 */
|
||||
username?: string;
|
||||
/** 当前登陆用户的角色 */
|
||||
roles?: Array<string>;
|
||||
/** 当前登陆用户的角色 */
|
||||
user?: any;
|
||||
}
|
||||
|
||||
export const userKey = "user-info";
|
||||
@ -35,13 +35,13 @@ export function getToken(): DataInfo<number> {
|
||||
|
||||
/**
|
||||
* @description 设置`token`以及一些必要信息并采用无感刷新`token`方案
|
||||
* 无感刷新:后端返回`accessToken`(访问接口使用的`token`)、`refreshToken`(用于调用刷新`accessToken`的接口时所需的`token`,`refreshToken`的过期时间(比如30天)应大于`accessToken`的过期时间(比如2小时))、`expires`(`accessToken`的过期时间)
|
||||
* 无感刷新:后端返回`accessToken`(访问接口使用的`token`)(用于调用刷新`accessToken`的接口时所需的`token`,的过期时间(比如30天)应大于`accessToken`的过期时间(比如2小时))、`expires`(`accessToken`的过期时间)
|
||||
* 将`accessToken`、`expires`这两条信息放在key值为authorized-token的cookie里(过期自动销毁)
|
||||
* 将`username`、`roles`、`refreshToken`、`expires`这四条信息放在key值为`user-info`的localStorage里(利用`multipleTabsKey`当浏览器完全关闭后自动销毁)
|
||||
* 将`username`、`roles`、`expires`这四条信息放在key值为`user-info`的localStorage里(利用`multipleTabsKey`当浏览器完全关闭后自动销毁)
|
||||
*/
|
||||
export function setToken(data: DataInfo<Date>) {
|
||||
let expires = 0;
|
||||
const { accessToken, refreshToken } = data;
|
||||
const { accessToken } = data;
|
||||
const { isRemembered, loginDay } = useUserStoreHook();
|
||||
expires = new Date(data.expires).getTime(); // 如果后端直接设置时间戳,将此处代码改为expires = data.expires,然后把上面的DataInfo<Date>改成DataInfo<number>即可
|
||||
const cookieString = JSON.stringify({ accessToken, expires });
|
||||
@ -62,11 +62,15 @@ export function setToken(data: DataInfo<Date>) {
|
||||
: {}
|
||||
);
|
||||
|
||||
function setUserKey(username: string, roles: Array<string>) {
|
||||
function setUserKey(
|
||||
accessToken: string,
|
||||
username: string,
|
||||
roles: Array<string>
|
||||
) {
|
||||
useUserStoreHook().SET_USERNAME(username);
|
||||
useUserStoreHook().SET_ROLES(roles);
|
||||
storageLocal().setItem(userKey, {
|
||||
refreshToken,
|
||||
accessToken,
|
||||
expires,
|
||||
username,
|
||||
roles
|
||||
@ -75,13 +79,13 @@ export function setToken(data: DataInfo<Date>) {
|
||||
|
||||
if (data.username && data.roles) {
|
||||
const { username, roles } = data;
|
||||
setUserKey(username, roles);
|
||||
setUserKey(accessToken, username, roles);
|
||||
} else {
|
||||
const username =
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.username ?? "";
|
||||
const roles =
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [];
|
||||
setUserKey(username, roles);
|
||||
setUserKey(accessToken, username, roles);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,8 @@ import type {
|
||||
import { stringify } from "qs";
|
||||
import NProgress from "../progress";
|
||||
import { getToken, formatToken } from "@/utils/auth";
|
||||
import { message } from "@/utils/message";
|
||||
|
||||
// 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1
|
||||
const defaultConfig: AxiosRequestConfig = {
|
||||
// 请求超时时间
|
||||
@ -91,6 +93,7 @@ class PureHttp {
|
||||
});
|
||||
},
|
||||
error => {
|
||||
message("请求异常!", { type: "error" });
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
@ -116,6 +119,7 @@ class PureHttp {
|
||||
return response.data;
|
||||
},
|
||||
(error: PureHttpError) => {
|
||||
message("服务异常!", { type: "error" });
|
||||
const $error = error;
|
||||
$error.isCancelRequest = Axios.isCancel($error);
|
||||
// 关闭进度条动画
|
||||
|
14
src/utils/rsaEncrypt.ts
Normal file
14
src/utils/rsaEncrypt.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import JSEncrypt from "jsencrypt";
|
||||
// 密钥对生成 http://web.chacuo.net/netrsakeypair
|
||||
const publicKey =
|
||||
"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD\n" +
|
||||
"2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ==";
|
||||
|
||||
// 加密
|
||||
export const encrypt = (txt: string) => {
|
||||
const crypt = new JSEncrypt();
|
||||
// 设置公钥
|
||||
crypt.setPublicKey(publicKey);
|
||||
const enc = crypt.encrypt(txt);
|
||||
return enc; // 对需要加密的数据进行加密
|
||||
};
|
@ -68,9 +68,14 @@ const onLogin = async (formEl: FormInstance | undefined) => {
|
||||
if (valid) {
|
||||
loading.value = true;
|
||||
useUserStoreHook()
|
||||
.loginByUsername({ username: ruleForm.username, password: "admin123" })
|
||||
.loginByUsername({
|
||||
username: ruleForm.username,
|
||||
password: ruleForm.password,
|
||||
code: ruleForm.verifyCode,
|
||||
uuid: imgCode.value
|
||||
})
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
if (res) {
|
||||
// 获取后端路由
|
||||
return initRouter().then(() => {
|
||||
disabled.value = true;
|
||||
@ -85,6 +90,7 @@ const onLogin = async (formEl: FormInstance | undefined) => {
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
} else {
|
||||
loading.value = false;
|
||||
return fields;
|
||||
}
|
||||
});
|
||||
@ -101,9 +107,6 @@ useEventListener(document, "keypress", ({ code }) => {
|
||||
immediateDebounce(ruleFormRef.value);
|
||||
});
|
||||
|
||||
watch(imgCode, value => {
|
||||
useUserStoreHook().SET_VERIFYCODE(value);
|
||||
});
|
||||
watch(checked, bool => {
|
||||
useUserStoreHook().SET_ISREMEMBERED(bool);
|
||||
});
|
||||
|
@ -2,14 +2,13 @@ import { reactive } from "vue";
|
||||
import { isPhone } from "@pureadmin/utils";
|
||||
import type { FormRules } from "element-plus";
|
||||
import { $t, transformI18n } from "@/plugins/i18n";
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
|
||||
/** 6位数字验证码正则 */
|
||||
export const REGEXP_SIX = /^\d{6}$/;
|
||||
|
||||
/** 密码正则(密码格式应为8-18位数字、字母、符号的任意两种组合) */
|
||||
export const REGEXP_PWD =
|
||||
/^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){8,18}$/;
|
||||
/^[0-9a-zA-Z!@#$%^&*()_+\-=\[\]{};':"\\|,.<>/?]{5,12}$/;
|
||||
|
||||
/** 登录校验 */
|
||||
const loginRules = reactive<FormRules>({
|
||||
@ -32,8 +31,6 @@ const loginRules = reactive<FormRules>({
|
||||
validator: (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error(transformI18n($t("login.verifyCodeReg"))));
|
||||
} else if (useUserStoreHook().verifyCode !== value) {
|
||||
callback(new Error(transformI18n($t("login.verifyCodeCorrectReg"))));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
@ -64,8 +61,6 @@ const phoneRules = reactive<FormRules>({
|
||||
validator: (rule, value, callback) => {
|
||||
if (value === "") {
|
||||
callback(new Error(transformI18n($t("login.verifyCodeReg"))));
|
||||
} else if (!REGEXP_SIX.test(value)) {
|
||||
callback(new Error(transformI18n($t("login.verifyCodeSixReg"))));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user