Commit 6fdb8357 authored by 张毅辰's avatar 张毅辰

路由更改提交

parent 4f7ec01e
......@@ -37,8 +37,8 @@ export function loginApi({
*/
export function logoutApi() {
return request({
url: "/api/v1/auth/logout",
method: "delete",
url: "/logout",
method: "post",
});
}
......
import request from "@/utils/request";
import { AxiosPromise } from "axios";
import { UserForm, UserInfo, UserPageVO, UserQuery } from "./types";
import { User, UserForm, UserInfo, UserPageVO, UserQuery } from "./types";
/**
* 登录成功后获取用户信息(昵称、头像、权限集合和角色集合)
*/
export function getUserInfoApi(): AxiosPromise<UserInfo> {
export function getUserInfoApi() {
return request({
url: "/api/v1/users/me",
url: "/system/user/getInfo",
method: "get",
});
}
......
export interface User {
/**
* 用户名称
*/
username?: string;
/**
* 用户特殊标志
*/
specialTag?: string;
/**
* 用户头像地址
*/
avatar?: any;
}
/**
* 登录用户信息
*/
export interface UserInfo {
/**
* 用户id
*/
userId?: number;
/**
* 用户名称
*/
username?: string;
/**
* 用户昵称
*/
nickname?: string;
/**
* 用户头像地址
*/
avatar?: string;
/**
* token
*/
token: string | null;
/**
* 用户角色
*/
roles: string[];
perms: string[];
/**
* 用户权限
*/
permissions: string[];
/**
* 用户特殊标志
*/
specialTag?: string;
/**
* 用户数据
*/
user?: User | undefined;
menus?: [];
}
/**
......
......@@ -7,7 +7,7 @@ import { Directive, DirectiveBinding } from "vue";
export const hasPerm: Directive = {
mounted(el: HTMLElement, binding: DirectiveBinding) {
// 「超级管理员」拥有所有的按钮权限
const { roles, perms } = useUserStoreHook().user;
const { roles, permissions } = useUserStoreHook().user;
if (roles.includes("ROOT")) {
return true;
}
......@@ -16,7 +16,7 @@ export const hasPerm: Directive = {
if (value) {
const requiredPerms = value; // DOM绑定需要的按钮权限标识
const hasPerm = perms?.some((perm) => {
const hasPerm = permissions?.some((perm) => {
return requiredPerms.includes(perm);
});
......
import router from "@/router";
import { useUserStoreHook } from "@/store/modules/user";
import { usePermissionStoreHook } from "@/store/modules/permission";
import { getToken } from "@/utils/auth";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
NProgress.configure({ showSpinner: false }); // 进度条
const userStore = useUserStoreHook();
const permissionStore = usePermissionStoreHook();
// 白名单路由
......@@ -14,14 +16,12 @@ const whiteList = ["/login"];
router.beforeEach(async (to, from, next) => {
NProgress.start();
const hasToken = localStorage.getItem("accessToken");
if (hasToken) {
if (getToken()) {
if (to.path === "/login") {
// 如果已登录,跳转首页
next({ path: "/" });
next();
NProgress.done();
} else {
const userStore = useUserStoreHook();
const hasRoles = userStore.user.roles && userStore.user.roles.length > 0;
if (hasRoles) {
// 未匹配到任何路由,跳转404
......@@ -32,12 +32,24 @@ router.beforeEach(async (to, from, next) => {
}
} else {
try {
const { roles } = await userStore.getUserInfo();
const accessRoutes = await permissionStore.generateRoutes(roles);
const { roles, permissions, menus, user } =
await userStore.getUserInfo();
if (permissions && permissions.length > 0) {
const accessRoutes = await userStore.generateRoutes();
// const accessRoutes = await permissionStore.generateRoutes(roles);
console.log(accessRoutes);
accessRoutes.forEach((route) => {
console.log(route);
router.addRoute(route);
});
next({ ...to, replace: true });
} else {
userStore.logout().then((_) => {
console.log("用户无权限2");
alert("用户无权限");
next(`/login`);
});
}
} catch (error) {
// 移除 token 并跳转登录页
await userStore.resetToken();
......
......@@ -42,12 +42,12 @@ export const constantRoutes: RouteRecordRaw[] = [
},
},
{
path: "401",
path: "/401",
component: () => import("@/views/error-page/401.vue"),
meta: { hidden: true },
},
{
path: "404",
path: "/404",
component: () => import("@/views/error-page/404.vue"),
meta: { hidden: true },
},
......@@ -58,7 +58,8 @@ export const constantRoutes: RouteRecordRaw[] = [
// {
// path: "/external-link",
// component: Layout,
// children: [ {
// children: [
// {
// component: () => import("@/views/external-link/index.vue"),
// path: "https://www.cnblogs.com/haoxianrui/",
// meta: { title: "外部链接", icon: "link" },
......
import { RouteRecordRaw } from "vue-router";
import { defineStore } from "pinia";
import { loginApi, logoutApi } from "@/api/auth";
import { getUserInfoApi } from "@/api/user";
import { resetRouter } from "@/router";
import { constantRoutes, resetRouter } from "@/router";
import { store } from "@/store";
import { LoginData } from "@/api/auth/types";
import { UserInfo } from "@/api/user/types";
import { useStorage } from "@vueuse/core";
import { setToken } from "@/utils/auth";
import { getToken, setToken } from "@/utils/auth";
import { ref } from "vue";
import { listRoutes } from "@/api/menu";
const Layout = () => import("@/layout/index.vue");
const modules = import.meta.glob("../../views/**/**.vue");
export const useUserStore = defineStore("user", () => {
const user: UserInfo = {
const user = reactive<UserInfo>({
token: getToken(),
username: "",
avatar: "",
roles: [],
perms: [],
};
const token = useStorage("accessToken", "");
permissions: [],
specialTag: "",
});
const menus = ref<RouteRecordRaw[]>([]);
function setRoutes(newRoutes: RouteRecordRaw[]) {
menus.value = constantRoutes.concat(newRoutes);
}
/**
* 登录
*
......@@ -30,7 +41,7 @@ export const useUserStore = defineStore("user", () => {
loginApi(loginData)
.then((response) => {
setToken(response.data);
token.value = response.data; // Bearer eyJhbGciOiJIUzI1NiJ9.xxx.xxx
user.token = response.data; // Bearer eyJhbGciOiJIUzI1NiJ9.xxx.xxx
resolve();
})
.catch((error) => {
......@@ -44,15 +55,17 @@ export const useUserStore = defineStore("user", () => {
return new Promise<UserInfo>((resolve, reject) => {
getUserInfoApi()
.then(({ data }) => {
if (!data) {
reject("Verification failed, please Login again.");
return;
}
if (!data.roles || data.roles.length <= 0) {
reject("getUserInfo: roles must be a non-null array!");
return;
if (data.roles.length > 0) {
user.roles = data.roles;
} else {
user.roles = ["ROLE_DEFAULT"];
}
Object.assign(user, { ...data });
user.roles = data.roles;
user.permissions = data.permissions;
user.username = data.user?.username;
user.specialTag = data.user?.specialTag;
user.avatar = data.user?.avatar;
menus.value = data.menus;
resolve(data);
})
.catch((error) => {
......@@ -66,7 +79,7 @@ export const useUserStore = defineStore("user", () => {
return new Promise<void>((resolve, reject) => {
logoutApi()
.then(() => {
token.value = "";
user.token = "";
location.reload(); // 清空路由
resolve();
})
......@@ -79,19 +92,68 @@ export const useUserStore = defineStore("user", () => {
// remove token
function resetToken() {
return new Promise<void>((resolve) => {
token.value = "";
user.token = "";
resetRouter();
resolve();
});
}
/**
* 生成动态路由
*
* @returns
*/
function generateRoutes() {
return new Promise<RouteRecordRaw[]>((resolve, reject) => {
// 接口获取所有路由
if (menus.value.length > 0) {
// 根据角色获取有访问权限的路由
const accessedRoutes = filterAsyncRoutes(menus.value);
console.log(accessedRoutes);
setRoutes(accessedRoutes);
resolve(accessedRoutes);
} else {
reject();
}
});
}
function loadView(view: any) {
// return () => import(`@/views/${view}.vue`);
const path = modules[`../../views/${view}.vue`];
return path;
}
/**
* 递归过滤有权限的异步(动态)路由
*
* @param routes 接口返回的异步(动态)路由
* @param roles 用户角色集合
* @returns 返回用户有权限的异步(动态)路由
*/
function filterAsyncRoutes(routes: RouteRecordRaw[]) {
return routes.filter((route) => {
if (route.component) {
// Layout组件特殊处理
if (route.component?.toString() === "Layout") {
route.component = Layout;
} else {
route.component = loadView(route.component);
}
}
if (route.children != null && route.children && route.children.length) {
route.children = filterAsyncRoutes(route.children);
}
return true;
});
}
return {
token,
user,
login,
getUserInfo,
logout,
resetToken,
generateRoutes,
};
});
......
const TokenKey = "token";
const emailKey = "email";
export function getToken() {
export function getToken(): string | null {
return localStorage.getItem(TokenKey) || sessionStorage.getItem(TokenKey);
}
......
......@@ -57,7 +57,7 @@ function connectWebSocket() {
stompClient = Stomp.over(socket);
stompClient.connect(
{ Authorization: userStore.token },
{ Authorization: userStore.user.token },
() => {
isConnected.value = true;
messages.value.push({
......
......@@ -345,6 +345,7 @@ function successLogin() {
.then(() => {
const query: LocationQuery = route.query;
const redirect = (query.redirect as LocationQueryValue) ?? "/";
//
const otherQueryParams = Object.keys(query).reduce(
(acc: any, cur: string) => {
if (cur !== "redirect") {
......@@ -354,7 +355,7 @@ function successLogin() {
},
{}
);
router.push({ path: redirect, query: otherQueryParams });
router.push({ path: "/system/user", query: otherQueryParams });
})
.catch(() => {
// 验证失败,重新生成验证码
......@@ -444,9 +445,6 @@ onMounted(() => {
}
}
.my_btn {
position: relative;
width: 100%;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment