优化数据隔离,进行权限控制

This commit is contained in:
2025-06-03 15:17:09 +08:00
parent 15ef4a3ced
commit 057563ba5e
10 changed files with 244 additions and 94 deletions
+15
View File
@@ -68,6 +68,21 @@ export function Layout({ children, userRole = 'developer' }: LayoutProps) {
}
}, []);
// 路由变化时,检查并更新应用模块
useEffect(() => {
if (typeof window !== 'undefined') {
try {
const reviewType = sessionStorage.getItem('reviewType');
console.log('Layout 路由变化, reviewType:', reviewType, '路径:', location.pathname);
if (reviewType && REVIEW_TYPE_TO_APP[reviewType]) {
setSelectedApp(REVIEW_TYPE_TO_APP[reviewType]);
}
} catch (error) {
console.error('路由变化时获取reviewType失败:', error);
}
}
}, [location.pathname]);
const toggleSidebar = () => {
const newState = !sidebarCollapsed;
setSidebarCollapsed(newState);
+55 -51
View File
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import { Link, useLocation } from '@remix-run/react';
import { Link, useLocation, useNavigate } from '@remix-run/react';
import type { UserRole } from '~/root';
interface MenuItem {
@@ -44,31 +44,24 @@ export function Sidebar({ onToggle, collapsed, userRole, selectedApp = 'contract
const location = useLocation();
const [expandedMenus, setExpandedMenus] = useState<Record<string, boolean>>({});
const [currentApp, setCurrentApp] = useState<string>(selectedApp);
const navigate = useNavigate();
// 组件挂载后从 sessionStorage 读取初始 reviewType
useEffect(() => {
try {
const reviewType = sessionStorage.getItem('reviewType');
// console.log('初始 reviewType:', reviewType);
if (reviewType) {
setCurrentApp(reviewType);
}
} catch (error) {
console.error('读取 reviewType 失败:', error);
}
}, []);
// 从 sessionStorage 获取 reviewType 并设置当前应用模块
useEffect(() => {
// 初始加载时获取 reviewType
const updateReviewType = () => {
if (typeof window !== 'undefined') {
const reviewType = sessionStorage.getItem('reviewType');
if (reviewType) {
setCurrentApp(reviewType);
}
}
};
// 首次执行
updateReviewType();
// 设置轮询,每秒检查一次 reviewType 变化
const intervalId = setInterval(updateReviewType, 1000);
// 添加自定义事件监听
const handleReviewTypeChange = () => {
updateReviewType();
};
// 监听 sessionStorage 变化
// 监听 sessionStorage 变化(主要用于多标签页情况)
const handleStorageChange = (e: StorageEvent) => {
if (e.key === 'reviewType' && e.newValue) {
setCurrentApp(e.newValue);
@@ -76,23 +69,23 @@ export function Sidebar({ onToggle, collapsed, userRole, selectedApp = 'contract
};
// 添加事件监听器
window.addEventListener('reviewTypeChange', handleReviewTypeChange);
window.addEventListener('storage', handleStorageChange);
return () => {
clearInterval(intervalId);
window.removeEventListener('reviewTypeChange', handleReviewTypeChange);
window.removeEventListener('storage', handleStorageChange);
};
}, []);
// 监听路由变化,重新检查 reviewType
useEffect(() => {
if (typeof window !== 'undefined') {
try {
const reviewType = sessionStorage.getItem('reviewType');
// console.log('路由变化, 检查 reviewType:', reviewType, '路径:', location.pathname);
if (reviewType) {
setCurrentApp(reviewType);
}
} catch (error) {
console.error('路由变化时读取 reviewType 失败:', error);
}
}, [location.pathname]);
@@ -110,26 +103,6 @@ export function Sidebar({ onToggle, collapsed, userRole, selectedApp = 'contract
path: '/home',
icon: 'ri-home-line'
},
{
id: 'contract-template',
title: '合同模板',
path: '/contract-template',
icon: 'ri-file-search-line',
children: [
{
id: 'contract-search-ai',
title: '智能搜索',
path: '/contract-template/search',
icon: 'ri-search-line'
},
{
id: 'contract-list',
title: '合同列表',
path: '/contract-template/list',
icon: 'ri-folder-line'
}
]
},
{
id: 'file-management',
title: '文件管理',
@@ -178,6 +151,7 @@ export function Sidebar({ onToggle, collapsed, userRole, selectedApp = 'contract
id: 'rule-new',
title: '新增评查点',
path: '/rules-new',
requiredRole: 'developer',
icon: 'ri-add-circle-line'
},
// {
@@ -188,6 +162,26 @@ export function Sidebar({ onToggle, collapsed, userRole, selectedApp = 'contract
// }
]
},
{
id: 'contract-template',
title: '合同模板',
path: '/contract-template',
icon: 'ri-file-search-line',
children: [
{
id: 'contract-search-ai',
title: '智能搜索',
path: '/contract-template/search',
icon: 'ri-search-line'
},
{
id: 'contract-list',
title: '合同列表',
path: '/contract-template/list',
icon: 'ri-folder-line'
}
]
},
{
id: 'system-settings',
title: '系统设置',
@@ -270,6 +264,7 @@ export function Sidebar({ onToggle, collapsed, userRole, selectedApp = 'contract
// 获取当前应用模式下应显示的菜单ID列表
const visibleMenuIds = APP_MENU_MAP[currentApp as keyof typeof APP_MENU_MAP] || APP_MENU_MAP['contract'];
// console.log('当前应用模式:', currentApp, '可见菜单ID:', visibleMenuIds);
// 根据用户角色和当前应用模式过滤菜单项
const filteredMenuItems = menuItems.filter(item => {
@@ -289,7 +284,19 @@ export function Sidebar({ onToggle, collapsed, userRole, selectedApp = 'contract
return (
<div className={`sidebar ${collapsed ? 'collapsed' : ''}`}>
<div className="py-6 px-4 border-b border-gray-100 flex justify-between items-center">
<div className="flex items-center">
<div className="flex items-center"
onClick={() => {
navigate('/');
}}
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
navigate('/');
}
}}
>
<img src="/logo.svg" alt="智慧法务" className="w-12 h-12 mr-2" />
{!collapsed && <h2 className="text-lg font-medium"></h2>}
</div>
@@ -309,9 +316,6 @@ export function Sidebar({ onToggle, collapsed, userRole, selectedApp = 'contract
<i className={`${APP_ICON_MAP[currentApp] || 'ri-file-list-2-fill'} mr-2 text-xl`}></i>
<span className="font-medium">{APP_NAME_MAP[currentApp] || '合同管理'}</span>
</div>
<div className="text-xs text-gray-500 mt-1">
: {APP_NAME_MAP[currentApp] || '合同管理'}
</div>
</div>
)}