/* 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 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 . For commercial licensing, please contact support@quantumnous.com */ import { useState, useEffect, useMemo, useContext, useRef } from 'react'; import { StatusContext } from '../../context/Status'; import { UserContext } from '../../context/User'; import { API, mergeSelfResponseIntoLocalUser } from '../../helpers'; // 创建一个全局事件系统来同步所有useSidebar实例 const sidebarEventTarget = new EventTarget(); const SIDEBAR_REFRESH_EVENT = 'sidebar-refresh'; // 默认配置(当没有任何角色配置或用户配置时的兜底) export const DEFAULT_SIDEBAR_CONFIG = { chat: { enabled: true, playground: true, chat: true, }, console: { enabled: true, benchmarks: true, detail: true, token: true, log: true, midjourney: true, task: true, 'supplierApply': true, }, personal: { enabled: true, topup: true, personal: true, supplier: true, distributor_center: true, 'supplier-apply': true, 'supplier-channel': true, 'supplier-pricing-settings': true, }, admin: { enabled: true, channel: true, models: true, deployment: true, 'model-heat': true, redemption: true, user: true, 'operation-log': true, subscription: true, setting: true, distributor: true, 'supplier-management': true, 'supplier-application-approval': true, 'supplier-dashboard': true, }, }; const deepClone = (value) => JSON.parse(JSON.stringify(value)); // 将savedConfig合并到DEFAULT_SIDEBAR_CONFIG,确保新增模块有默认值 export const mergeWithDefaults = (savedConfig) => { const merged = deepClone(DEFAULT_SIDEBAR_CONFIG); if (!savedConfig || typeof savedConfig !== 'object') return merged; for (const [sectionKey, sectionConfig] of Object.entries(savedConfig)) { if (!sectionConfig || typeof sectionConfig !== 'object') continue; if (!merged[sectionKey]) { merged[sectionKey] = { ...sectionConfig }; continue; } merged[sectionKey] = { ...merged[sectionKey], ...sectionConfig }; } return merged; }; export const useSidebar = () => { const [statusState] = useContext(StatusContext); const [userState, userDispatch] = useContext(UserContext); const [userConfig, setUserConfig] = useState(null); const [loading, setLoading] = useState(true); const instanceIdRef = useRef(null); const hasLoadedOnceRef = useRef(false); if (!instanceIdRef.current) { const randomPart = Math.random().toString(16).slice(2); instanceIdRef.current = `sidebar-${Date.now()}-${randomPart}`; } // 获取角色级模块配置 const roleModulesConfig = useMemo(() => { if (statusState?.status?.SidebarModulesByRole) { try { return JSON.parse(statusState.status.SidebarModulesByRole); } catch (error) { return {}; } } return {}; }, [statusState?.status?.SidebarModulesByRole]); // 获取当前用户角色 const userRole = userState?.user?.role ?? null; // 基于角色获取基础配置(替代原来的adminConfig) const roleBaseConfig = useMemo(() => { if (userRole != null && roleModulesConfig) { const roleStr = String(userRole); const config = roleModulesConfig[roleStr]; if (config && typeof config === 'object') { return mergeWithDefaults(config); } } return mergeWithDefaults(null); }, [userRole, roleModulesConfig]); // 加载用户配置的通用方法 const loadUserConfig = async ({ withLoading } = {}) => { const shouldShowLoader = typeof withLoading === 'boolean' ? withLoading : !hasLoadedOnceRef.current; try { if (shouldShowLoader) { setLoading(true); } const res = await API.get('/api/user/self'); if (res.data.success && res.data.data) { const payload = res.data.data; if (payload.id != null) { mergeSelfResponseIntoLocalUser(payload, userDispatch); } if (payload.sidebar_modules) { let config; if (typeof payload.sidebar_modules === 'string') { config = JSON.parse(payload.sidebar_modules); } else { config = payload.sidebar_modules; } setUserConfig(config); } else { // 当用户没有配置时,基于角色配置生成默认值 const defaultUserConfig = {}; Object.keys(roleBaseConfig).forEach((sectionKey) => { if (roleBaseConfig[sectionKey]?.enabled) { defaultUserConfig[sectionKey] = { enabled: true }; Object.keys(roleBaseConfig[sectionKey]).forEach((moduleKey) => { if ( moduleKey !== 'enabled' && roleBaseConfig[sectionKey][moduleKey] ) { defaultUserConfig[sectionKey][moduleKey] = true; } }); } }); setUserConfig(defaultUserConfig); } } else { const defaultUserConfig = generateDefaultFromRoleConfig(roleBaseConfig); setUserConfig(defaultUserConfig); } } catch (error) { const defaultUserConfig = generateDefaultFromRoleConfig(roleBaseConfig); setUserConfig(defaultUserConfig); } finally { if (shouldShowLoader) { setLoading(false); } hasLoadedOnceRef.current = true; } }; // 刷新用户配置的方法(供外部调用) const refreshUserConfig = async () => { if (Object.keys(roleBaseConfig).length > 0) { await loadUserConfig({ withLoading: false }); } sidebarEventTarget.dispatchEvent( new CustomEvent(SIDEBAR_REFRESH_EVENT, { detail: { sourceId: instanceIdRef.current, skipLoader: true }, }), ); }; // 加载用户配置 useEffect(() => { if (Object.keys(roleBaseConfig).length > 0) { loadUserConfig(); } }, [roleBaseConfig]); // 监听全局刷新事件 useEffect(() => { const handleRefresh = (event) => { if (event?.detail?.sourceId === instanceIdRef.current) { return; } if (Object.keys(roleBaseConfig).length > 0) { loadUserConfig({ withLoading: event?.detail?.skipLoader ? false : undefined, }); } }; sidebarEventTarget.addEventListener(SIDEBAR_REFRESH_EVENT, handleRefresh); return () => { sidebarEventTarget.removeEventListener( SIDEBAR_REFRESH_EVENT, handleRefresh, ); }; }, [roleBaseConfig]); // 计算最终的显示配置:角色配置(基础) + 用户个人配置(覆盖) const finalConfig = useMemo(() => { const result = {}; if (!roleBaseConfig || Object.keys(roleBaseConfig).length === 0) { return result; } if (!userConfig) { return result; } // 遍历所有区域 Object.keys(roleBaseConfig).forEach((sectionKey) => { const roleSection = roleBaseConfig[sectionKey]; const userSection = userConfig[sectionKey]; // 如果角色配置禁用了整个区域,则该区域不显示 if (!roleSection?.enabled) { result[sectionKey] = { enabled: false }; return; } // 区域级别:用户可以选择隐藏角色允许的区域 const sectionEnabled = userSection ? userSection.enabled !== false : true; result[sectionKey] = { enabled: sectionEnabled }; // 功能级别:只有角色和用户都允许的功能才显示 Object.keys(roleSection).forEach((moduleKey) => { if (moduleKey === 'enabled') return; const roleAllowed = roleSection[moduleKey]; const userAllowed = userSection ? userSection[moduleKey] !== false : true; result[sectionKey][moduleKey] = roleAllowed && userAllowed && sectionEnabled; }); }); return result; }, [roleBaseConfig, userConfig]); // 检查特定功能是否应该显示 const isModuleVisible = (sectionKey, moduleKey = null) => { if (moduleKey) { return finalConfig[sectionKey]?.[moduleKey] === true; } else { return finalConfig[sectionKey]?.enabled === true; } }; // 检查区域是否有任何可见的功能 const hasSectionVisibleModules = (sectionKey) => { const section = finalConfig[sectionKey]; if (!section?.enabled) return false; return Object.keys(section).some( (key) => key !== 'enabled' && section[key] === true, ); }; // 获取区域的可见功能列表 const getVisibleModules = (sectionKey) => { const section = finalConfig[sectionKey]; if (!section?.enabled) return []; return Object.keys(section).filter( (key) => key !== 'enabled' && section[key] === true, ); }; return { loading, roleBaseConfig, userConfig, finalConfig, isModuleVisible, hasSectionVisibleModules, getVisibleModules, refreshUserConfig, }; }; // 辅助函数:基于角色配置生成默认用户配置 function generateDefaultFromRoleConfig(roleConfig) { const defaultUserConfig = {}; Object.keys(roleConfig).forEach((sectionKey) => { if (roleConfig[sectionKey]?.enabled) { defaultUserConfig[sectionKey] = { enabled: true }; Object.keys(roleConfig[sectionKey]).forEach((moduleKey) => { if (moduleKey !== 'enabled' && roleConfig[sectionKey][moduleKey]) { defaultUserConfig[sectionKey][moduleKey] = true; } }); } }); return defaultUserConfig; }