refactor: 菜单栏角色化降噪(role-based-navigation-simplification)

这个提交包含在:
2026-05-29 21:11:32 +08:00
父节点 325a7950c9
当前提交 541593a5b6
共修改 58 个文件,包含 796 行新增和 366 行删除
+76 -27
查看文件
@@ -1,41 +1,90 @@
import { Link } from "react-router-dom";
import { useAuth } from "../auth/AuthContext";
import { hasAnyPermission } from "../auth/permissions";
import { ListWorkspace, WorkspaceHeader } from "../components/patterns/ListWorkspace";
const ITEMS = [
{ to: "/system/workspace", icon: "dashboard_customize", title: "工作区设置", description: "导航与模块显隐。" },
{ to: "/people", icon: "badge", title: "人员管理", description: "入转调离与档案。" },
{ to: "/system/approval-rules", icon: "account_tree", title: "审批规则", description: "审批链与规则。" },
{ to: "/system/expense-standards", icon: "rule_settings", title: "费用标准", description: "费用上限与管控。" },
{ to: "/system/reimbursement-templates", icon: "receipt_long", title: "报销模板", description: "常见报销模板。" },
{ to: "/system/master-data", icon: "database", title: "主数据", description: "法体、成本中心、供应商。" },
{ to: "/system/notification-channels", icon: "notifications", title: "通知渠道", description: "IM / 邮件补充通知。" },
{ to: "/system/integrations/erp", icon: "hub", title: "外部系统桥接", description: "财务出入口与桥接。" },
type ManagementItem = {
to: string;
icon: string;
title: string;
description: string;
group: "人员与组织" | "流程与规则" | "系统与审计" | "功能管理";
anyOf: string[];
};
const ITEMS: ManagementItem[] = [
{ to: "/people", icon: "badge", title: "人员", description: "员工档案、入转调离和人员状态。", group: "人员与组织", anyOf: ["system.users", "report.dashboard.view"] },
{ to: "/organization", icon: "account_tree", title: "组织", description: "组织结构、部门和汇报关系。", group: "人员与组织", anyOf: ["system.users", "report.dashboard.view"] },
{ to: "/system/users", icon: "manage_accounts", title: "账号", description: "账号、角色和登录权限。", group: "人员与组织", anyOf: ["system.users"] },
{ to: "/system/departments", icon: "account_tree", title: "部门", description: "部门基础数据维护。", group: "人员与组织", anyOf: ["system.users"] },
{ to: "/system/approval-rules", icon: "rule", title: "审批规则", description: "金额段、审批层级和处理规则。", group: "流程与规则", anyOf: ["system.settings"] },
{ to: "/system/workflow-definitions", icon: "schema", title: "流程定义", description: "流程模板和节点治理。", group: "流程与规则", anyOf: ["system.settings"] },
{ to: "/system/expense-standards", icon: "rule_settings", title: "费用标准", description: "费用上限、类别和管控口径。", group: "流程与规则", anyOf: ["system.settings"] },
{ to: "/system/reimbursement-templates", icon: "receipt_long", title: "报销模板", description: "常见报销场景模板。", group: "流程与规则", anyOf: ["system.settings"] },
{ to: "/system/workspace", icon: "dashboard_customize", title: "工作区", description: "菜单入口、模块显隐和小团队基线。", group: "系统与审计", anyOf: ["system.settings"] },
{ to: "/audit-logs", icon: "manage_search", title: "审计日志", description: "关键操作留痕和排障。", group: "系统与审计", anyOf: ["system.audit.view"] },
{ to: "/system/master-data", icon: "dataset", title: "主数据", description: "法体、成本中心、供应商等基础数据。", group: "功能管理", anyOf: ["masterdata.view", "masterdata.manage"] },
{ to: "/system/notification-channels", icon: "notifications_active", title: "通知渠道", description: "企业微信、邮件等补充通知。", group: "功能管理", anyOf: ["notification.channel.manage"] },
{ to: "/system/feature-flags", icon: "toggle_on", title: "功能管理", description: "功能开关、灰度和试运行边界。", group: "功能管理", anyOf: ["system.settings"] },
{ to: "/system/integrations/erp", icon: "hub", title: "外部系统", description: "财务、ERP 和外部系统连接。", group: "功能管理", anyOf: ["integration.manage"] },
];
const GROUPS: ManagementItem["group"][] = ["人员与组织", "流程与规则", "系统与审计", "功能管理"];
export function SystemSettingsPage() {
const { permissions } = useAuth();
const visibleItems = ITEMS.filter((item) => hasAnyPermission(permissions, item.anyOf));
const visibleGroups = GROUPS.map((group) => ({
group,
items: visibleItems.filter((item) => item.group === group),
})).filter((entry) => entry.items.length > 0);
return (
<ListWorkspace>
<WorkspaceHeader title="系统设置" subtitle="后台能力入口按管理职责收拢。" />
<WorkspaceHeader title="管理" subtitle="低频配置集中到这里,侧边栏只保留一个管理入口。" />
<div className="finance-status-strip" data-testid="system-settings-summary">
<div className="finance-metric-card"><div className="finance-metric-card__label">入口总数</div><div className="finance-metric-card__value">{ITEMS.length}</div></div>
<div className="finance-metric-card"><div className="finance-metric-card__label">业务配置</div><div className="finance-metric-card__value">5</div></div>
<div className="finance-metric-card"><div className="finance-metric-card__label">外部桥接</div><div className="finance-metric-card__value">2</div></div>
<div className="finance-metric-card"><div className="finance-metric-card__label">人员相关</div><div className="finance-metric-card__value">1</div></div>
<div className="finance-metric-card"><div className="finance-metric-card__label">模式</div><div className="finance-metric-card__value text-base">小团队</div></div>
<div className="finance-metric-card">
<div className="finance-metric-card__label">可用入口</div>
<div className="finance-metric-card__value">{visibleItems.length}</div>
</div>
<div className="finance-metric-card">
<div className="finance-metric-card__label">人员与组织</div>
<div className="finance-metric-card__value">{visibleItems.filter((item) => item.group === "人员与组织").length}</div>
</div>
<div className="finance-metric-card">
<div className="finance-metric-card__label">流程与规则</div>
<div className="finance-metric-card__value">{visibleItems.filter((item) => item.group === "流程与规则").length}</div>
</div>
<div className="finance-metric-card">
<div className="finance-metric-card__label">系统与审计</div>
<div className="finance-metric-card__value">{visibleItems.filter((item) => item.group === "系统与审计").length}</div>
</div>
<div className="finance-metric-card">
<div className="finance-metric-card__label">模式</div>
<div className="finance-metric-card__value text-base">小团队</div>
</div>
</div>
<div className="admin-tile-grid">
{ITEMS.map((item) => (
<Link key={item.to} to={item.to} className="admin-tile-card">
<div className="flex items-start gap-3">
<span className="admin-tile-card__icon">
<span className="material-symbols-outlined text-[20px]">{item.icon}</span>
</span>
<span className="min-w-0">
<span className="block text-base font-semibold text-zinc-900">{item.title}</span>
<span className="mt-1 block text-sm leading-5 text-zinc-600">{item.description}</span>
</span>
<div className="space-y-5">
{visibleGroups.map(({ group, items }) => (
<section key={group} className="admin-command-panel space-y-3">
<h2 className="text-base font-semibold text-zinc-900">{group}</h2>
<div className="admin-tile-grid">
{items.map((item) => (
<Link key={item.to} to={item.to} className="admin-tile-card">
<div className="flex items-start gap-3">
<span className="admin-tile-card__icon">
<span className="material-symbols-outlined text-[20px]">{item.icon}</span>
</span>
<span className="min-w-0">
<span className="block text-base font-semibold text-zinc-900">{item.title}</span>
<span className="mt-1 block text-sm leading-5 text-zinc-600">{item.description}</span>
</span>
</div>
</Link>
))}
</div>
</Link>
</section>
))}
</div>
</ListWorkspace>