Files
cattleTransportation/pc-cattle-transportation/src/store/permission.js
2025-10-23 17:28:06 +08:00

317 lines
12 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;
console.log('=== 权限store更新 ===', arr);
},
// 强制刷新权限数据
async refreshPermissions() {
console.log('=== 强制刷新权限数据 ===');
this.routeFlag = false; // 重置路由标志,强制重新生成路由
return this.generateRoutes();
},
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).filter(auth => auth); // 过滤掉空权限
console.log('=== 设置用户权限列表 ===', permissionList);
this.setUserPermission(permissionList);
let menuList = data.filter((i) => i.type !== 2);
menuList = menuList.map((item) => {
// 确保 routeUrl 存在且不为空
let routeUrl = item.routeUrl || item.pageUrl || '';
// 规范化路径
routeUrl = normalizeRoutePath(routeUrl);
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);
console.log('=== 路径检查 ===', menuList.map(item => ({ name: item.name, path: item.path })));
// 检查并修复双斜杠路径
const doubleSlashPaths = menuList.filter(item => item.path && item.path.includes('//'));
if (doubleSlashPaths.length > 0) {
console.error('=== 发现双斜杠路径 ===', doubleSlashPaths);
// 修复双斜杠路径
menuList.forEach(item => {
if (item.path && item.path.includes('//')) {
const originalPath = item.path;
item.path = item.path.replace(/\/+/g, '/');
console.warn('修复菜单路径:', originalPath, '->', item.path);
}
});
}
// 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);
}
// 规范化路由路径
function normalizeRoutePath(path) {
if (!path || typeof path !== 'string') {
return '/';
}
// 移除首尾空格
path = path.trim();
// 移除重复的斜杠
path = path.replace(/\/+/g, '/');
// 确保路径以 "/" 开头
if (!path.startsWith('/')) {
path = '/' + path;
}
// 确保路径不为空
if (path === '') {
path = '/';
}
return path;
}
// 安全拼接路径
function joinPaths(parentPath, childPath) {
// 规范化父路径
parentPath = normalizeRoutePath(parentPath);
childPath = normalizeRoutePath(childPath);
// 如果父路径是根路径,直接返回子路径
if (parentPath === '/') {
return childPath;
}
// 如果子路径是根路径,直接返回父路径
if (childPath === '/') {
return parentPath;
}
// 确保父路径不以斜杠结尾,子路径不以斜杠开头
if (parentPath.endsWith('/')) {
parentPath = parentPath.slice(0, -1);
}
if (childPath.startsWith('/')) {
childPath = childPath.slice(1);
}
// 拼接路径
const joinedPath = parentPath + '/' + childPath;
// 再次规范化,确保没有双斜杠
return normalizeRoutePath(joinedPath);
}
// 遍历后台传来的路由字符串,转换为组件对象
// 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 = joinPaths(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 = joinPaths(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;