kboss/f/web-kboss/src/store/modules/permission.js
2025-12-15 17:46:47 +08:00

313 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { asyncRoutes, constantRoutes } from "@/router";
// 获取用户代理字符串
const userAgent = window.navigator.userAgent;
// 判断是否为移动设备
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
// 如果是移动设备,添加移动端首页路由和根路径重定向
if (isMobile) {
console.log("检测到移动设备,添加移动端路由");
// 先添加根路径重定向到移动端首页
constantRoutes.unshift({
path: '/',
redirect: '/h5HomePage',
hidden: true
});
// 添加移动端首页路由
constantRoutes.push({
path: '/h5HomePage',
name: 'H5HomePage',
title: 'H5首页',
component: () => import('@/views/H5/index.vue'),
hidden: true,
redirect: "/h5HomePage/index",
meta: { isMobile: true },
children: [
{
path: "index",
title: 'H5首页',
component: () => import('@/views/H5/official/index.vue'),
meta: {
title: "H5首页",
fullPath: "/h5HomePage/index",
isMobile: true
},
},
{
path: "cloud",
title: '云',
component: () => import('@/views/H5/cloud/index.vue'),
meta: {
title: "云",
fullPath: "/h5HomePage/cloud",
isMobile: true
},
},
{
path: "calculate",
title: '算',
component: () => import('@/views/H5/calculate/index.vue'),
meta: {
title: "算",
fullPath: "/h5HomePage/calculate",
isMobile: true
},
},
{
path: "net",
title: '网',
component: () => import('@/views/H5/net/index.vue'),
meta: {
title: "网",
fullPath: "/h5HomePage/net",
isMobile: true
},
},
{
path: "use",
title: '用',
component: () => import('@/views/H5/use/index.vue'),
meta: {
title: "用",
fullPath: "/h5HomePage/use",
isMobile: true
},
},
]
});
}
// 修复:更全面的路由过滤逻辑
function filterAsyncRoutes(routes, permissions, userRoles = [], deviceType = 'pc') {
const res = [];
// 定义需要客户角色才能访问的路由
const customerOnlyRoutes = [
"/product", "/overview", "/workOrderManagement",
"/unsubscribeManagement", "/informationPerfect",
"/rechargeManagement", "/invoiceManagement"
];
routes.forEach(route => {
// 创建路由副本
const tmpRoute = { ...route };
// 检查当前路由是否在权限列表中
const hasPermission = permissions.some(p => p.path === route.meta?.fullPath);
// 特殊处理:确保"全部产品"和"资源概览"这两个一级路由在客户角色下显示
const isCriticalRoute = route.path === "/product" || route.path === "/overview";
// 检查是否为仅客户可访问的路由
const isCustomerOnlyRoute = customerOnlyRoutes.includes(route.path);
// 如果路由需要客户角色,但用户不是客户,则跳过
if (isCustomerOnlyRoute && !userRoles.includes('客户')) {
return; // 跳过当前路由
}
// 新增:根据设备类型过滤路由
if (deviceType === 'mobile' && !(route.meta?.isMobile || route.meta?.isMobile === true)) {
return; // 移动设备跳过非移动端路由
}
if (deviceType === 'pc' && route.meta?.isMobile === true) {
return; // PC设备跳过移动端路由
}
// 如果当前路由有权限,则加入结果
if (hasPermission) {
res.push(tmpRoute);
}
// 如果是关键路由且用户是客户,也要加入结果
else if (isCriticalRoute && userRoles.includes('客户')) {
res.push(tmpRoute);
}
// 如果没有直接权限,但有子路由,递归处理子路由
else if (tmpRoute.children) {
const filteredChildren = filterAsyncRoutes(tmpRoute.children, permissions, userRoles, deviceType);
if (filteredChildren.length > 0) {
tmpRoute.children = filteredChildren;
res.push(tmpRoute); // 即使父路由本身没有权限,只要有子路由有权限,也要保留父路由
}
}
// 如果当前路由既没有权限,也没有有权限的子路由,则不添加到结果中
});
return res;
}
// 新增:为普通用户添加订单管理和资源管理路由
function addUserRoutes(routes, userType, orgType, userRoles = [], deviceType = 'pc') {
console.log("addUserRoutes - userType:", userType, "orgType:", orgType, "userRoles:", userRoles);
const userRoutes = [];
// 修复:包含 orgType 为 2 和 3 的情况(公司客户和个人客户)
if (userType === 'user' || orgType == 2 || orgType == 3) {
const orderManagementRoute = routes.find(route => route.path === "/orderManagement");
const resourceManagementRoute = routes.find(route => route.path === "/resourceManagement");
// 新增:根据设备类型过滤
if (orderManagementRoute && (deviceType === 'pc' || orderManagementRoute.meta?.isMobile === true)) {
console.log("添加订单管理路由");
userRoutes.push(JSON.parse(JSON.stringify(orderManagementRoute))); // 深拷贝
}
if (resourceManagementRoute && (deviceType === 'pc' || resourceManagementRoute.meta?.isMobile === true)) {
console.log("添加资源管理路由");
userRoutes.push(JSON.parse(JSON.stringify(resourceManagementRoute))); // 深拷贝
}
}
// 新增:为所有用户添加五个新的客户菜单,但只有客户角色才能看到
const newCustomerRoutes = [
routes.find(route => route.path === "/unsubscribeManagement"),
routes.find(route => route.path === "/informationPerfect"),
routes.find(route => route.path === "/rechargeManagement"),
routes.find(route => route.path === "/invoiceManagement"),
routes.find(route => route.path === "/workOrderManagement")
].filter(route => {
// 过滤掉undefined并且只有客户角色才能看到这些路由
return route && userRoles.includes('客户') &&
(deviceType === 'pc' || route.meta?.isMobile === true);
});
console.log("添加新的客户菜单路由:", newCustomerRoutes.map(r => r.path));
userRoutes.push(...newCustomerRoutes);
return userRoutes;
}
const state = {
routes: [],
addRoutes: [],
users: [],
isMobile: isMobile // 保存设备类型状态
};
const mutations = {
SET_ROUTES: (state, routes) => {
console.log("MUTATION SET_ROUTES - received routes:", routes);
state.addRoutes = routes;
sessionStorage.setItem("routes", JSON.stringify(routes));
// 将移动端首页路由也包含在内
state.routes = constantRoutes.concat(routes);
console.log("MUTATION SET_ROUTES - final state.routes:", state.routes);
},
SETUSERS: (state, user) => {
state.users = user;
},
SET_DEVICE_TYPE: (state, isMobile) => {
state.isMobile = isMobile;
}
};
const actions = {
/**
* 生成动态路由
*
* 根据用户类型、组织类型和权限列表生成对应的动态路由配置
* 包含管理员和普通用户的不同路由生成逻辑
*
* @param {Object} context - Vuex上下文对象
* @param {Function} context.commit - 提交mutation的方法
* @param {Object} context.rootState - 根模块的状态
* @param {Object} params - 参数对象
* @param {string} [params.userType] - 用户类型
* @param {number} [params.orgType] - 组织类型
* @param {Array} [params.auths] - 权限列表
* @param {Object} [params.user] - 用户信息对象
* @returns {Promise<Array>} 解析后的动态路由数组
*/
generateRoutes({ commit, rootState, state }, params) {
console.log("ACTION generateRoutes - params:", params);
return new Promise((resolve) => {
let accessedRoutes;
// 从参数或sessionStorage中获取用户类型和组织类型
const userType = params.userType || sessionStorage.getItem('userType') || '';
const orgType = params.orgType || parseInt(sessionStorage.getItem('orgType')) || 0;
// 获取用户角色从store或sessionStorage
const userRoles = rootState.user.roles || JSON.parse(sessionStorage.getItem('roles') || '[]');
console.log("用户角色:", userRoles);
console.log("用户类型:", userType, "orgType:", orgType);
// 确定设备类型
const deviceType = state.isMobile ? 'mobile' : 'pc';
console.log("设备类型:", deviceType);
// 修复:包含 orgType 为 2 和 3 的情况
if (params.user && params.user.includes("admin") && orgType != 2 && orgType != 3) {
// 管理员只显示超级管理员菜单仅PC端
if (deviceType === 'pc') {
accessedRoutes = asyncRoutes.filter(item => item.path === '/superAdministrator');
} else {
accessedRoutes = [];
}
} else {
const auths = params.auths ? JSON.parse(JSON.stringify(params.auths)) : [];
console.log("ACTION generateRoutes - auths:", auths);
if (auths.length) {
// 确保 auths 中的 path 与路由 meta.fullPath 匹配
const paths = auths.map((item) => {
return item.path;
});
console.log("ACTION generateRoutes - paths from auths:", paths);
if (paths.includes("")) {
// 如果权限列表包含空路径,认为用户有所有权限
accessedRoutes = asyncRoutes || [];
} else {
// 使用修复后的过滤函数,传入用户角色和设备类型
accessedRoutes = filterAsyncRoutes(asyncRoutes, auths, userRoles, deviceType);
}
} else {
// 如果没有权限列表,不显示任何动态路由
accessedRoutes = [];
}
// 新增:为普通用户添加订单管理和资源管理路由以及新的五个客户菜单
console.log("为用户添加特定路由");
const userSpecificRoutes = addUserRoutes(asyncRoutes, userType, orgType, userRoles, deviceType);
// 确保不重复添加路由,同时检查角色权限
userSpecificRoutes.forEach(route => {
const isCustomerRoute = [
"/workOrderManagement", "/unsubscribeManagement", "/informationPerfect",
"/rechargeManagement", "/invoiceManagement"
].includes(route.path);
// 如果是客户路由但用户不是客户,则不添加
if (isCustomerRoute && !userRoles.includes('客户')) {
return;
}
if (!accessedRoutes.some(r => r.path === route.path)) {
accessedRoutes.push(route);
}
});
console.log("添加用户特定路由后的accessedRoutes:", accessedRoutes);
}
console.log("ACTION generateRoutes - calculated accessedRoutes:", accessedRoutes);
commit("SET_ROUTES", accessedRoutes);
resolve(accessedRoutes);
});
},
};
export default {
namespaced: true,
state,
mutations,
actions,
};