235 lines
8.8 KiB
JavaScript
235 lines
8.8 KiB
JavaScript
|
|
import { defineStore } from 'pinia';
|
||
|
|
import auth from '@/plugins/auth';
|
||
|
|
import router, { constantRoutes, dynamicRoutes } from '@/router';
|
||
|
|
import Layout from '@/components/layout/index.vue';
|
||
|
|
import { getUserMenu } from '@/api/sys.js';
|
||
|
|
import { handleTree } from '~/utils/aiotagro.js';
|
||
|
|
|
||
|
|
// 匹配views里面所有的.vue文件
|
||
|
|
const modules = import.meta.glob('./../views/**/*.vue');
|
||
|
|
|
||
|
|
const usePermissionStore = defineStore('permission', {
|
||
|
|
state: () => ({
|
||
|
|
routes: [],
|
||
|
|
addRoutes: [],
|
||
|
|
sidebarRouters: [],
|
||
|
|
routeFlag: false,
|
||
|
|
userPermission: [],
|
||
|
|
}),
|
||
|
|
actions: {
|
||
|
|
setRoutes(routes) {
|
||
|
|
this.addRoutes = routes;
|
||
|
|
this.routes = constantRoutes.concat(routes);
|
||
|
|
},
|
||
|
|
setSidebarRouters(routes, flag) {
|
||
|
|
this.sidebarRouters = routes;
|
||
|
|
this.routeFlag = !!(flag == 200);
|
||
|
|
},
|
||
|
|
setUserPermission(arr) {
|
||
|
|
this.userPermission = arr;
|
||
|
|
},
|
||
|
|
generateRoutes() {
|
||
|
|
return new Promise((resolve) => {
|
||
|
|
// 向后端请求路由数据
|
||
|
|
getUserMenu().then((res) => {
|
||
|
|
const { code, data } = res;
|
||
|
|
console.log('=== 权限路由生成 ===', { code, data });
|
||
|
|
|
||
|
|
const btnList = data.filter((i) => i.type === 2);
|
||
|
|
const permissionList = btnList.map((i) => i.authority);
|
||
|
|
this.setUserPermission(permissionList);
|
||
|
|
|
||
|
|
let menuList = data.filter((i) => i.type !== 2);
|
||
|
|
menuList = menuList.map((item) => {
|
||
|
|
// 确保 routeUrl 存在且不为空
|
||
|
|
const routeUrl = item.routeUrl || item.pageUrl || '';
|
||
|
|
|
||
|
|
return {
|
||
|
|
id: item.id,
|
||
|
|
parentId: item.parentId,
|
||
|
|
// eslint-disable-next-line no-use-before-define
|
||
|
|
name: capitalizeFirstLetter(routeUrl),
|
||
|
|
path: routeUrl,
|
||
|
|
component: item.pageUrl,
|
||
|
|
alwaysShow: true,
|
||
|
|
meta: {
|
||
|
|
title: item.name,
|
||
|
|
icon: item.icon,
|
||
|
|
noCache: false,
|
||
|
|
link: null,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
});
|
||
|
|
menuList = handleTree(menuList, 'id', 'parentId');
|
||
|
|
JSON.parse(JSON.stringify(menuList));
|
||
|
|
const sdata = JSON.parse(JSON.stringify(menuList));
|
||
|
|
|
||
|
|
console.log('=== 处理后的菜单列表 ===', menuList);
|
||
|
|
|
||
|
|
// eslint-disable-next-line no-use-before-define
|
||
|
|
const rewriteRoutes = filterAsyncRouter(menuList, false, true);
|
||
|
|
// eslint-disable-next-line no-use-before-define
|
||
|
|
const sidebarRoutes = filterAsyncRouter(sdata);
|
||
|
|
// eslint-disable-next-line no-use-before-define
|
||
|
|
const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
|
||
|
|
|
||
|
|
console.log('=== 最终路由配置 ===', {
|
||
|
|
rewriteRoutes,
|
||
|
|
sidebarRoutes,
|
||
|
|
asyncRoutes
|
||
|
|
});
|
||
|
|
|
||
|
|
asyncRoutes.forEach((route) => {
|
||
|
|
router.addRoute(route);
|
||
|
|
});
|
||
|
|
this.setSidebarRouters(sidebarRoutes, code);
|
||
|
|
this.setRoutes(rewriteRoutes);
|
||
|
|
|
||
|
|
resolve(rewriteRoutes);
|
||
|
|
}).catch((error) => {
|
||
|
|
console.error('=== 获取用户菜单失败 ===', error);
|
||
|
|
// 如果获取菜单失败,返回空路由数组
|
||
|
|
this.setSidebarRouters([], 500);
|
||
|
|
this.setRoutes([]);
|
||
|
|
resolve([]);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
},
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
function capitalizeFirstLetter(string) {
|
||
|
|
// 处理 null 或 undefined 值
|
||
|
|
if (!string || typeof string !== 'string') {
|
||
|
|
console.warn('capitalizeFirstLetter: Invalid string input:', string);
|
||
|
|
return 'Unknown';
|
||
|
|
}
|
||
|
|
|
||
|
|
// eslint-disable-next-line no-param-reassign
|
||
|
|
string = string.replace('/', '');
|
||
|
|
return string.charAt(0).toUpperCase() + string.toLowerCase().slice(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 遍历后台传来的路由字符串,转换为组件对象
|
||
|
|
// eslint-disable-next-line no-unused-vars
|
||
|
|
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
|
||
|
|
return asyncRouterMap.filter((route) => {
|
||
|
|
if (type && route.children) {
|
||
|
|
// eslint-disable-next-line no-use-before-define,no-param-reassign
|
||
|
|
route.children = filterChildren(route.children);
|
||
|
|
}
|
||
|
|
if (route.component) {
|
||
|
|
if (route.component === 'Layout') {
|
||
|
|
// eslint-disable-next-line no-param-reassign
|
||
|
|
route.component = Layout;
|
||
|
|
} else if (!route.component) {
|
||
|
|
// eslint-disable-next-line no-param-reassign
|
||
|
|
route.component = Layout;
|
||
|
|
} else {
|
||
|
|
// eslint-disable-next-line no-param-reassign,no-use-before-define
|
||
|
|
route.component = loadView(route.component);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (route.children != null && route.children && route.children.length) {
|
||
|
|
// eslint-disable-next-line no-param-reassign
|
||
|
|
route.children = filterAsyncRouter(route.children, route, type);
|
||
|
|
} else {
|
||
|
|
// eslint-disable-next-line no-param-reassign
|
||
|
|
delete route.children;
|
||
|
|
// eslint-disable-next-line no-param-reassign
|
||
|
|
delete route.redirect;
|
||
|
|
}
|
||
|
|
// eslint-disable-next-line no-param-reassign
|
||
|
|
delete route.id;
|
||
|
|
// eslint-disable-next-line no-param-reassign
|
||
|
|
delete route.parentId;
|
||
|
|
return true;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function filterChildren(childrenMap, lastRouter = false) {
|
||
|
|
let children = [];
|
||
|
|
childrenMap.forEach((el) => {
|
||
|
|
if (el.children && el.children.length) {
|
||
|
|
if (el.component === 'ParentView' && !lastRouter) {
|
||
|
|
el.children.forEach((c) => {
|
||
|
|
// eslint-disable-next-line no-param-reassign
|
||
|
|
c.path = `${el.path}/${c.path}`;
|
||
|
|
if (c.children && c.children.length) {
|
||
|
|
children = children.concat(filterChildren(c.children, c));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
children.push(c);
|
||
|
|
});
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (lastRouter) {
|
||
|
|
// eslint-disable-next-line no-param-reassign
|
||
|
|
el.path = `${lastRouter.path}/${el.path}`;
|
||
|
|
if (el.children && el.children.length) {
|
||
|
|
children = children.concat(filterChildren(el.children, el));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
children = children.concat(el);
|
||
|
|
});
|
||
|
|
return children;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 动态路由遍历,验证是否具备权限
|
||
|
|
export function filterDynamicRoutes(routes) {
|
||
|
|
const res = [];
|
||
|
|
routes.forEach((route) => {
|
||
|
|
if (route.permissions) {
|
||
|
|
if (auth.hasPermiOr(route.permissions)) {
|
||
|
|
res.push(route);
|
||
|
|
}
|
||
|
|
} else if (route.roles) {
|
||
|
|
if (auth.hasRoleOr(route.roles)) {
|
||
|
|
res.push(route);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
export const loadView = (view) => {
|
||
|
|
// 添加默认的视图路径作为后备方案
|
||
|
|
const defaultView = () => import('~/views/entry/details.vue');
|
||
|
|
|
||
|
|
if (!view) {
|
||
|
|
console.warn('loadView: view parameter is empty, using default view');
|
||
|
|
return defaultView;
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log('loadView: Loading view:', view);
|
||
|
|
|
||
|
|
let res;
|
||
|
|
// eslint-disable-next-line guard-for-in,no-restricted-syntax
|
||
|
|
for (const path in modules) {
|
||
|
|
const dir = path.split('views/')[1].split('.vue')[0];
|
||
|
|
if (dir === view) {
|
||
|
|
console.log('loadView: Found matching module:', path);
|
||
|
|
// 使用函数包装导入过程,添加错误处理
|
||
|
|
res = () =>
|
||
|
|
modules[path]().catch((error) => {
|
||
|
|
console.error('Failed to load module:', path, error);
|
||
|
|
// 如果模块加载失败,返回默认视图
|
||
|
|
return import('~/views/entry/details.vue');
|
||
|
|
});
|
||
|
|
break; // 找到匹配的模块后立即退出循环
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 如果没有找到匹配的视图,返回默认视图
|
||
|
|
if (!res) {
|
||
|
|
console.warn('loadView: View not found:', view, 'Available modules:', Object.keys(modules));
|
||
|
|
return defaultView;
|
||
|
|
}
|
||
|
|
|
||
|
|
return res;
|
||
|
|
};
|
||
|
|
|
||
|
|
export default usePermissionStore;
|