Merge branch 'main' of http://139.9.146.228:8083/wd-data/wd-data-web
This commit is contained in:
commit
57c948572b
|
@ -0,0 +1,43 @@
|
|||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
import { formatToken, getToken } from "@/utils/auth";
|
||||
import axios from "axios";
|
||||
export const api = axios.create({
|
||||
// 公共配置
|
||||
baseURL: "",
|
||||
timeout: 15000
|
||||
});
|
||||
|
||||
api.interceptors.request.use(
|
||||
// 在发送请求之前做什么
|
||||
config => {
|
||||
const data = getToken();
|
||||
if (data) {
|
||||
const now = new Date().getTime();
|
||||
const expired = parseInt(data.expires) - now <= 0;
|
||||
if (expired) {
|
||||
useUserStoreHook().logOut();
|
||||
} else {
|
||||
config.headers["Authorization"] = formatToken(data.accessToken);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
// 对请求错误做点什么
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
|
||||
api.interceptors.response.use(
|
||||
// 对响应数据做点什么
|
||||
response => {
|
||||
return response;
|
||||
},
|
||||
);
|
||||
|
||||
function errorHandle(status: number) {
|
||||
switch (status) {
|
||||
case 401:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -12,8 +12,7 @@ import {
|
|||
useDark,
|
||||
debounce,
|
||||
useGlobal,
|
||||
storageLocal,
|
||||
storageSession
|
||||
storageLocal
|
||||
} from "@pureadmin/utils";
|
||||
import { getConfig } from "@/config";
|
||||
import { useRouter } from "vue-router";
|
||||
|
@ -133,7 +132,6 @@ const multiTagsCacheChange = () => {
|
|||
function onReset() {
|
||||
removeToken();
|
||||
storageLocal().clear();
|
||||
storageSession().clear();
|
||||
const { Grey, Weak, MultiTagsCache, EpThemeColor, Layout } = getConfig();
|
||||
useAppStoreHook().setLayout(Layout);
|
||||
setEpThemeColor(EpThemeColor);
|
||||
|
|
|
@ -21,8 +21,8 @@ import {
|
|||
formatTwoStageRoutes,
|
||||
formatFlatteningRoutes
|
||||
} from "./utils";
|
||||
import { buildHierarchyTree } from "@/utils/tree";
|
||||
import { isUrl, openLink, storageSession, isAllEmpty } from "@pureadmin/utils";
|
||||
import {buildHierarchyTree} from "@/utils/tree";
|
||||
import {isUrl, openLink, isAllEmpty, storageLocal} from "@pureadmin/utils";
|
||||
|
||||
import remainingRouter from "./modules/remaining";
|
||||
|
||||
|
@ -108,8 +108,7 @@ router.beforeEach((to: ToRouteType, _from, next) => {
|
|||
handleAliveRoute(to);
|
||||
}
|
||||
}
|
||||
const userInfo = storageSession().getItem<DataInfo<number>>(sessionKey);
|
||||
NProgress.start();
|
||||
const userInfo = storageLocal().getItem<DataInfo<number>>(sessionKey);
|
||||
const externalLink = isUrl(to?.name as string);
|
||||
if (!externalLink) {
|
||||
to.matched.some(item => {
|
||||
|
|
|
@ -13,8 +13,7 @@ import {
|
|||
cloneDeep,
|
||||
isAllEmpty,
|
||||
intersection,
|
||||
storageSession,
|
||||
isIncludeAllChildren
|
||||
isIncludeAllChildren, storageLocal
|
||||
} from "@pureadmin/utils";
|
||||
import { getConfig } from "@/config";
|
||||
import { menuType } from "@/layout/types";
|
||||
|
@ -73,7 +72,7 @@ function filterChildrenTree(data: RouteComponent[]) {
|
|||
}
|
||||
|
||||
/** 判断两个数组彼此是否存在相同值 */
|
||||
function isOneOfArray(a: Array<string>, b: Array<string>) {
|
||||
function isOneOfArray(a: Array<string|number>, b: Array<string|number>) {
|
||||
return Array.isArray(a) && Array.isArray(b)
|
||||
? intersection(a, b).length > 0
|
||||
? true
|
||||
|
@ -84,7 +83,7 @@ function isOneOfArray(a: Array<string>, b: Array<string>) {
|
|||
/** 从sessionStorage里取出当前登陆用户的角色roles,过滤无权限的菜单 */
|
||||
function filterNoPermissionTree(data: RouteComponent[]) {
|
||||
const currentRoles =
|
||||
storageSession().getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
|
||||
storageLocal().getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
|
||||
const newTree = cloneDeep(data).filter((v: any) =>
|
||||
isOneOfArray(v.meta?.roles, currentRoles)
|
||||
);
|
||||
|
@ -150,7 +149,7 @@ function addPathMatch() {
|
|||
}
|
||||
|
||||
/** 处理动态路由(后端返回的路由) */
|
||||
function handleAsyncRoutes(routeList) {
|
||||
export function handleAsyncRoutes(routeList) {
|
||||
if (routeList.length === 0) {
|
||||
usePermissionStoreHook().handleWholeMenus(routeList);
|
||||
} else {
|
||||
|
@ -186,7 +185,7 @@ function initRouter() {
|
|||
if (getConfig()?.CachingAsyncRoutes) {
|
||||
// 开启动态路由缓存本地sessionStorage
|
||||
const key = "async-routes";
|
||||
const asyncRouteList = storageSession().getItem(key) as any;
|
||||
const asyncRouteList = storageLocal().getItem(key) as any;
|
||||
if (asyncRouteList && asyncRouteList?.length > 0) {
|
||||
return new Promise(resolve => {
|
||||
handleAsyncRoutes(asyncRouteList);
|
||||
|
@ -196,7 +195,7 @@ function initRouter() {
|
|||
return new Promise(resolve => {
|
||||
getAsyncRoutes().then(({ data }) => {
|
||||
handleAsyncRoutes(cloneDeep(data));
|
||||
storageSession().setItem(key, data);
|
||||
storageLocal().setItem(key, data);
|
||||
resolve(router);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { store } from "@/store";
|
||||
import { userType } from "./types";
|
||||
import { routerArrays } from "@/layout/types";
|
||||
import { router, resetRouter } from "@/router";
|
||||
import { storageSession } from "@pureadmin/utils";
|
||||
import { getLogin, refreshTokenApi } from "@/api/user";
|
||||
import { UserResult, RefreshTokenResult } from "@/api/user";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import { type DataInfo, setToken, removeToken, sessionKey } from "@/utils/auth";
|
||||
import {defineStore} from "pinia";
|
||||
import {store} from "@/store";
|
||||
import {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 {UserResult, RefreshTokenResult} from "@/api/user";
|
||||
import {useMultiTagsStoreHook} from "@/store/modules/multiTags";
|
||||
import {type DataInfo, setToken, removeToken, sessionKey} from "@/utils/auth";
|
||||
import {http} from "@/utils/http";
|
||||
|
||||
export const useUserStore = defineStore({
|
||||
id: "pure-user",
|
||||
state: (): userType => ({
|
||||
// 用户名
|
||||
username:
|
||||
storageSession().getItem<DataInfo<number>>(sessionKey)?.username ?? "",
|
||||
storageLocal().getItem<DataInfo<number>>(sessionKey)?.username ?? "",
|
||||
// 页面级别权限
|
||||
roles: storageSession().getItem<DataInfo<number>>(sessionKey)?.roles ?? []
|
||||
roles: storageLocal().getItem<DataInfo<number>>(sessionKey)?.roles ?? []
|
||||
}),
|
||||
actions: {
|
||||
/** 存储用户名 */
|
||||
|
@ -42,6 +43,48 @@ export const useUserStore = defineStore({
|
|||
});
|
||||
});
|
||||
},
|
||||
async loginByCode(data) {
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
http
|
||||
.post<any, any>("/wide_data/user/login_by_verify_code", {data})
|
||||
.then(res => {
|
||||
const userInfo = res.user_info;
|
||||
const dataInfo: DataInfo<Date> = {
|
||||
username: userInfo.name,
|
||||
accessToken: res.token,
|
||||
expires: new Date(new Date().getTime() + 60 * 60 * 24 * 3 * 1000),
|
||||
refreshToken: res.token,
|
||||
roles: userInfo.auth_data || []
|
||||
};
|
||||
setToken(dataInfo);
|
||||
resolve(res);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
async refreshToken() {
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
http
|
||||
.post<any, any>("/wide_data/user/refresh_token", {})
|
||||
.then(res => {
|
||||
const userInfo = res.user_info;
|
||||
const dataInfo: DataInfo<Date> = {
|
||||
username: userInfo.name,
|
||||
accessToken: res.token,
|
||||
expires: new Date(new Date().getTime() + 60 * 60 * 24 * 3 * 1000),
|
||||
refreshToken: res.token,
|
||||
roles: userInfo.auth_data || []
|
||||
};
|
||||
setToken(dataInfo);
|
||||
resolve(res);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
},
|
||||
/** 前端登出(不调用接口) */
|
||||
logOut() {
|
||||
this.username = "";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Cookies from "js-cookie";
|
||||
import { storageSession } from "@pureadmin/utils";
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
import {storageLocal} from "@pureadmin/utils";
|
||||
|
||||
export interface DataInfo<T> {
|
||||
/** token */
|
||||
|
@ -23,7 +23,7 @@ export function getToken(): DataInfo<number> {
|
|||
// 此处与`TokenKey`相同,此写法解决初始化时`Cookies`中不存在`TokenKey`报错
|
||||
return Cookies.get(TokenKey)
|
||||
? JSON.parse(Cookies.get(TokenKey))
|
||||
: storageSession().getItem(sessionKey);
|
||||
: storageLocal().getItem(sessionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,7 +47,7 @@ export function setToken(data: DataInfo<Date>) {
|
|||
function setSessionKey(username: string, roles: Array<string>) {
|
||||
useUserStoreHook().SET_USERNAME(username);
|
||||
useUserStoreHook().SET_ROLES(roles);
|
||||
storageSession().setItem(sessionKey, {
|
||||
storageLocal().setItem(sessionKey, {
|
||||
refreshToken,
|
||||
expires,
|
||||
username,
|
||||
|
@ -60,9 +60,9 @@ export function setToken(data: DataInfo<Date>) {
|
|||
setSessionKey(username, roles);
|
||||
} else {
|
||||
const username =
|
||||
storageSession().getItem<DataInfo<number>>(sessionKey)?.username ?? "";
|
||||
storageLocal().getItem<DataInfo<number>>(sessionKey)?.username ?? "";
|
||||
const roles =
|
||||
storageSession().getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
|
||||
storageLocal().getItem<DataInfo<number>>(sessionKey)?.roles ?? [];
|
||||
setSessionKey(username, roles);
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ export function setToken(data: DataInfo<Date>) {
|
|||
/** 删除`token`以及key值为`user-info`的session信息 */
|
||||
export function removeToken() {
|
||||
Cookies.remove(TokenKey);
|
||||
sessionStorage.clear();
|
||||
localStorage.removeItem("user-info");
|
||||
}
|
||||
|
||||
/** 格式化token(jwt格式) */
|
||||
|
|
|
@ -17,8 +17,7 @@ import dayIcon from "@/assets/svg/day.svg?component";
|
|||
import darkIcon from "@/assets/svg/dark.svg?component";
|
||||
import Lock from "@iconify-icons/ri/lock-fill";
|
||||
import User from "@iconify-icons/ri/user-3-fill";
|
||||
import { tr } from "element-plus/es/locale";
|
||||
|
||||
import {api} from "@/api/api";
|
||||
defineOptions({
|
||||
name: "Login"
|
||||
});
|
||||
|
@ -34,47 +33,64 @@ dataThemeChange();
|
|||
const { title } = useNav();
|
||||
|
||||
const ruleForm = reactive({
|
||||
username: "admin",
|
||||
password: "admin123",
|
||||
checked: true
|
||||
account: "",
|
||||
code: ""
|
||||
});
|
||||
|
||||
const onLogin = async (formEl: FormInstance | undefined) => {
|
||||
loading.value = true;
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
useUserStoreHook()
|
||||
.loginByUsername({ username: ruleForm.username, password: "admin123" })
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
// 获取后端路由
|
||||
initRouter().then(() => {
|
||||
router.push(getTopMenu(true).path);
|
||||
message("登录成功", { type: "success" });
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
loading.value = false;
|
||||
return fields;
|
||||
function getLoginVerifyCode() {
|
||||
if (!ruleForm.account) {
|
||||
message("请输入正确的手机号或邮箱", {type: "warning"});
|
||||
return;
|
||||
}
|
||||
});
|
||||
api
|
||||
.post("/wide_data/user/get_login_verify_code", {
|
||||
account: ruleForm.account
|
||||
})
|
||||
.then(res => {
|
||||
message("验证码已发送", {type: "success"});
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
message(e.response.data.detail, {type: "warning"});
|
||||
});
|
||||
}
|
||||
const onLogin = async (formEl: FormInstance | undefined) => {
|
||||
loading.value = true;
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
useUserStoreHook()
|
||||
.loginByCode({account: ruleForm.account, code: ruleForm.code})
|
||||
.then(res => {
|
||||
// 获取后端路由
|
||||
initRouter().then(() => {
|
||||
router.push(getTopMenu(true).path);
|
||||
message("登录成功", {type: "success"});
|
||||
});
|
||||
}).catch(e => {
|
||||
console.log(e);
|
||||
loading.value = false;
|
||||
message(e.response.data.detail, {type: "warning"});
|
||||
});
|
||||
} else {
|
||||
loading.value = false;
|
||||
return fields;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** 使用公共函数,避免`removeEventListener`失效 */
|
||||
function onkeypress({ code }: KeyboardEvent) {
|
||||
if (code === "Enter") {
|
||||
onLogin(ruleFormRef.value);
|
||||
}
|
||||
function onkeypress({code}: KeyboardEvent) {
|
||||
if (code === "Enter") {
|
||||
onLogin(ruleFormRef.value);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.document.addEventListener("keypress", onkeypress);
|
||||
window.document.addEventListener("keypress", onkeypress);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.document.removeEventListener("keypress", onkeypress);
|
||||
window.document.removeEventListener("keypress", onkeypress);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -113,14 +129,14 @@ onBeforeUnmount(() => {
|
|||
{
|
||||
required: true,
|
||||
message: '请输入账号',
|
||||
trigger: 'blur'
|
||||
trigger: 'change'
|
||||
}
|
||||
]"
|
||||
prop="username"
|
||||
prop="account"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
v-model="ruleForm.username"
|
||||
v-model="ruleForm.account"
|
||||
placeholder="账号"
|
||||
:prefix-icon="useRenderIcon(User)"
|
||||
/>
|
||||
|
@ -128,31 +144,45 @@ onBeforeUnmount(() => {
|
|||
</Motion>
|
||||
|
||||
<Motion :delay="150">
|
||||
<el-form-item prop="password">
|
||||
<el-form-item
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入验证码',
|
||||
trigger: 'change'
|
||||
}
|
||||
]"
|
||||
prop="code">
|
||||
<el-input
|
||||
clearable
|
||||
show-password
|
||||
v-model="ruleForm.password"
|
||||
placeholder="密码"
|
||||
v-model="ruleForm.code"
|
||||
placeholder="验证码"
|
||||
:prefix-icon="useRenderIcon(Lock)"
|
||||
/>
|
||||
>
|
||||
<template #append>
|
||||
<div
|
||||
@click="getLoginVerifyCode"
|
||||
style="width: 6rem"
|
||||
class="cursor-pointer active:opacity-70"
|
||||
>
|
||||
发送验证码
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</Motion>
|
||||
<div class="newClass">
|
||||
<el-checkbox v-model="ruleForm.checked">自动登录</el-checkbox>
|
||||
<span>忘记密码</span>
|
||||
</div>
|
||||
<Motion :delay="250">
|
||||
<el-button
|
||||
class="w-full mt-4"
|
||||
size="default"
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="onLogin(ruleFormRef)"
|
||||
>
|
||||
登录
|
||||
</el-button>
|
||||
</Motion>
|
||||
<Motion :delay="250">
|
||||
<el-button
|
||||
class="w-full mt-4"
|
||||
size="default"
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="onLogin(ruleFormRef)"
|
||||
>
|
||||
登录
|
||||
</el-button>
|
||||
</Motion>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { initRouter } from "@/router/utils";
|
||||
import { storageSession } from "@pureadmin/utils";
|
||||
import { storageLocal } from "@pureadmin/utils";
|
||||
import { type CSSProperties, ref, computed } from "vue";
|
||||
import { useUserStoreHook } from "@/store/modules/user";
|
||||
import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
|
@ -34,7 +34,7 @@ function onChange() {
|
|||
.loginByUsername({ username: username.value, password: "admin123" })
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
storageSession().removeItem("async-routes");
|
||||
storageLocal().removeItem("async-routes");
|
||||
usePermissionStoreHook().clearAllCachePage();
|
||||
initRouter();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue