改进"侧边栏"权限控制

This commit is contained in:
F。 2025-09-02 18:10:08 +08:00
parent b79fe6cff0
commit 647ed1be83

View File

@ -0,0 +1,200 @@
/*
Copyright (C) 2025 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import React, { useState, useEffect, useContext } from 'react';
import { Navigate } from 'react-router-dom';
import { StatusContext } from '../../context/Status';
import Loading from '../common/ui/Loading';
import { API } from '../../helpers';
/**
* ModuleRoute - 基于功能模块权限的路由保护组件
*
* @param {Object} props
* @param {React.ReactNode} props.children - 要保护的子组件
* @param {string} props.modulePath - 模块权限路径 "admin.channel", "console.token"
* @param {React.ReactNode} props.fallback - 无权限时显示的组件默认跳转到 /forbidden
* @returns {React.ReactNode}
*/
const ModuleRoute = ({ children, modulePath, fallback = <Navigate to="/forbidden" replace /> }) => {
const [hasPermission, setHasPermission] = useState(null);
const [statusState] = useContext(StatusContext);
useEffect(() => {
checkModulePermission();
}, [modulePath, statusState?.status]); // status
const checkModulePermission = async () => {
try {
//
const user = localStorage.getItem('user');
if (!user) {
setHasPermission(false);
return;
}
const userData = JSON.parse(user);
const userRole = userData.role;
//
if (userRole >= 100) {
setHasPermission(true);
return;
}
//
const permission = await checkModulePermissionAPI(modulePath);
// nullstatusloading
if (permission === null) {
setHasPermission(null);
return;
}
setHasPermission(permission);
} catch (error) {
console.error('检查模块权限失败:', error);
// 访
setHasPermission(false);
}
};
const checkModulePermissionAPI = async (modulePath) => {
try {
// 访
if (modulePath === 'console.detail') {
return true;
}
// StatusContext
// statusnull
if (!statusState?.status) {
return null;
}
const user = JSON.parse(localStorage.getItem('user'));
const userRole = user.role;
//
const pathParts = modulePath.split('.');
if (pathParts.length < 2) {
return false;
}
//
if (userRole < 10) {
return await isUserModuleAllowed(modulePath);
}
// -
if (userRole >= 100) {
return true;
}
// -
if (userRole >= 10 && userRole < 100) {
// /api/user/self
try {
const userRes = await API.get('/api/user/self');
if (userRes.data.success && userRes.data.data.sidebar_config) {
const sidebarConfigData = userRes.data.data.sidebar_config;
//
const systemConfig = sidebarConfigData.system || sidebarConfigData;
return checkModulePermissionInConfig(systemConfig, modulePath);
} else {
// 访
return modulePath !== 'admin.setting';
}
} catch (error) {
console.error('获取侧边栏配置失败:', error);
return false;
}
}
return false;
} catch (error) {
console.error('API权限检查失败:', error);
return false;
}
};
const isUserModuleAllowed = async (modulePath) => {
// 访
if (modulePath === 'console.detail') {
return true;
}
//
try {
const userRes = await API.get('/api/user/self');
if (userRes.data.success && userRes.data.data.sidebar_config) {
const sidebarConfigData = userRes.data.data.sidebar_config;
// 使
const finalConfig = sidebarConfigData.final || sidebarConfigData;
return checkModulePermissionInConfig(finalConfig, modulePath);
}
return false;
} catch (error) {
console.error('获取用户权限配置失败:', error);
return false;
}
};
// sidebar_config
const checkModulePermissionInConfig = (sidebarConfig, modulePath) => {
const parts = modulePath.split('.');
if (parts.length !== 2) {
return false;
}
const [sectionKey, moduleKey] = parts;
const section = sidebarConfig[sectionKey];
//
if (!section || !section.enabled) {
return false;
}
//
const moduleValue = section[moduleKey];
//
if (typeof moduleValue === 'boolean') {
return moduleValue === true;
} else if (typeof moduleValue === 'object' && moduleValue !== null) {
// enabled
return moduleValue.enabled === true;
}
return false;
};
//
if (hasPermission === null) {
return <Loading />;
}
//
if (!hasPermission) {
return fallback;
}
//
return children;
};
export default ModuleRoute;