refactor: 菜单栏角色化降噪(role-based-navigation-simplification)
这个提交包含在:
@@ -262,7 +262,7 @@ export function ErpIntegrationPage() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<PageHeader
|
||||
title="ERP 集成"
|
||||
title="外部系统"
|
||||
subtitle="主数据同步、业务队列和 ID 映射。"
|
||||
actions={
|
||||
tab === "master-data" ? (
|
||||
|
||||
@@ -81,9 +81,9 @@ function formatRolloutTypeLabel(value: FeatureFlagRolloutType) {
|
||||
}
|
||||
|
||||
function formatSectionLabel(value: FeatureFlagSection) {
|
||||
if (value === "main") return "主导航";
|
||||
if (value === "main") return "常用入口";
|
||||
if (value === "admin") return "管理入口";
|
||||
if (value === "backup") return "备用入口";
|
||||
if (value === "backup") return "更多";
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ export function FeatureFlagsPage() {
|
||||
return (
|
||||
<ListWorkspace className={batchMode ? "pb-32" : undefined}>
|
||||
<WorkspaceHeader
|
||||
title="功能开关"
|
||||
title="功能管理"
|
||||
subtitle="外部桥接、验真、灰度和试运行边界。"
|
||||
/>
|
||||
<WorkspaceNotice title="安全摘要" tone="warning">
|
||||
|
||||
@@ -1033,7 +1033,7 @@ export function MobileApprovalsPage() {
|
||||
/>
|
||||
) : (
|
||||
<PageHeader
|
||||
title={canAccessRemoteApprovals ? "审批" : "审批进度"}
|
||||
title={canAccessRemoteApprovals ? "待办" : "进度"}
|
||||
subtitle={canAccessRemoteApprovals ? "处理待办,查看已处理。" : "查看我发起的申请进度。"}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -128,7 +128,7 @@ export function MobileMePage() {
|
||||
<MobileActionLink to="/mobile/leave" label="请假" icon="event_available" />
|
||||
<MobileActionLink to="/mobile/reimbursements" label="报销" icon="request_quote" />
|
||||
{canAccessPurchase ? <MobileActionLink to="/mobile/purchase-requests" label="采购" icon="shopping_cart" /> : null}
|
||||
<MobileActionLink to="/mobile/approvals" label={canAccessApprovals ? "审批" : "审批进度"} icon="fact_check" />
|
||||
<MobileActionLink to="/mobile/approvals" label={canAccessApprovals ? "待办" : "进度"} icon="fact_check" />
|
||||
{canAccessFinance ? <MobileActionLink to="/mobile#finance" label="财务" description="审批与付款状态" icon="account_balance_wallet" /> : null}
|
||||
{canAccessAssets ? <MobileActionLink to="/mobile/assets/scan" label="资产扫码" icon="inventory_2" /> : null}
|
||||
{canAccessProjects ? <MobileActionLink to="/mobile" label="项目动态" icon="workspaces" /> : null}
|
||||
|
||||
@@ -75,7 +75,7 @@ const ROLE_OPTIONS = [
|
||||
] as const;
|
||||
|
||||
const DOMAIN_SCOPE_OPTIONS = [
|
||||
{ value: "workflow", label: "审批待办" },
|
||||
{ value: "workflow", label: "待我处理" },
|
||||
{ value: "reimbursement", label: "报销" },
|
||||
{ value: "leave", label: "请假" },
|
||||
{ value: "procurement", label: "采购" },
|
||||
|
||||
@@ -16,7 +16,7 @@ const PAGE_SIZE = 20;
|
||||
|
||||
const NOTIFICATION_TYPE_OPTIONS = [
|
||||
{ label: "全部", value: "" },
|
||||
{ label: "审批待办", value: "workflow.task_assigned" },
|
||||
{ label: "待我处理", value: "workflow.task_assigned" },
|
||||
{ label: "报销", value: "reimbursement.approved,reimbursement.rejected,reimbursement.returned,reimbursement.paid" },
|
||||
{ label: "请假", value: "leave.approved,leave.rejected" },
|
||||
{ label: "采购", value: "purchase_request.approved,purchase_request.rejected" },
|
||||
|
||||
@@ -163,8 +163,8 @@ function buildTodoAggregateItems(payload: PortalHomePayload) {
|
||||
const items: TodoAggregateItem[] = [];
|
||||
if (payload.pendingTasks.count > 0) {
|
||||
items.push({
|
||||
title: `审批待办 ${payload.pendingTasks.count} 条`,
|
||||
sourceLabel: "审批",
|
||||
title: `待我处理 ${payload.pendingTasks.count} 条`,
|
||||
sourceLabel: "待办",
|
||||
severity: "warning",
|
||||
href: payload.pendingTasks.href,
|
||||
icon: "fact_check",
|
||||
@@ -925,9 +925,9 @@ export function PortalHomePage() {
|
||||
? {
|
||||
key: "approval-pending",
|
||||
href: payload.pendingTasks.href,
|
||||
label: "审批待办",
|
||||
label: "待我处理",
|
||||
value: `${payload.pendingTasks.count} 条`,
|
||||
note: payload.pendingTasks.count > 0 ? "进入审批中心处理。" : "暂无待处理审批。",
|
||||
note: payload.pendingTasks.count > 0 ? "进入待我处理办理。" : "暂无待处理事项。",
|
||||
tone: payload.pendingTasks.count > 0 ? "warning" as const : "normal" as const,
|
||||
}
|
||||
: null,
|
||||
@@ -1051,7 +1051,7 @@ export function PortalHomePage() {
|
||||
? { label: "报销进度", to: "/reimbursements" }
|
||||
: null,
|
||||
payload.pendingTasks.count > 0 && approvalAction?.to
|
||||
? { label: "审批中心", to: approvalAction.to }
|
||||
? { label: "待我处理", to: approvalAction.to }
|
||||
: null,
|
||||
todoAggregateItems.length > 1
|
||||
? { label: "全部待办", to: "/todos" }
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -11,7 +11,7 @@ import { toast } from "sonner";
|
||||
const MODULE_LABELS: Record<string, string> = {
|
||||
portal: "工作台",
|
||||
team: "团队",
|
||||
leaveRequests: "请假",
|
||||
leaveRequests: "请假记录",
|
||||
attendance: "考勤",
|
||||
reimbursements: "报销",
|
||||
assets: "资产",
|
||||
@@ -24,31 +24,31 @@ const MODULE_LABELS: Record<string, string> = {
|
||||
organization: "组织架构",
|
||||
contractsRegistry: "合同台账",
|
||||
workflowDefinitions: "流程定义",
|
||||
systemSettings: "系统设置",
|
||||
featureFlags: "功能开关",
|
||||
systemSettings: "管理",
|
||||
featureFlags: "功能管理",
|
||||
auditLogs: "审计日志",
|
||||
approvalRules: "审批规则",
|
||||
userManagement: "用户管理",
|
||||
departments: "部门管理",
|
||||
masterData: "主数据",
|
||||
notificationChannels: "通知渠道",
|
||||
workflowTasks: "审批待办",
|
||||
workflowTasks: "待我处理",
|
||||
dashboard: "仪表盘",
|
||||
purchaseRequests: "采购申请",
|
||||
travelRequests: "差旅申请",
|
||||
budgets: "预算管理",
|
||||
paymentBatches: "付款批次",
|
||||
apOperations: "AP 运营",
|
||||
invoicePool: "票据中心",
|
||||
paymentBatches: "付款",
|
||||
apOperations: "应付账款",
|
||||
invoicePool: "票据",
|
||||
inventoryChecks: "资产盘点",
|
||||
cutover: "切换控制台",
|
||||
erpIntegrations: "ERP 集成",
|
||||
erpIntegrations: "外部系统",
|
||||
profile: "个人设置",
|
||||
};
|
||||
|
||||
const VISIBILITY_OPTIONS = [
|
||||
{ value: "main", label: "主导航" },
|
||||
{ value: "admin", label: "管理区" },
|
||||
{ value: "main", label: "常用入口" },
|
||||
{ value: "admin", label: "管理与更多" },
|
||||
{ value: "hidden", label: "隐藏" },
|
||||
] as const;
|
||||
|
||||
@@ -101,7 +101,7 @@ export function WorkspaceSetupPage() {
|
||||
<WorkspaceHeader
|
||||
eyebrow="管理"
|
||||
title="工作区设置"
|
||||
subtitle="按 10 人以下小团队模式收敛主导航与默认入口。"
|
||||
subtitle="按 10 人以下小团队模式收敛常用入口与低频模块。"
|
||||
/>
|
||||
<div className="admin-command-panel text-sm text-zinc-500">加载工作区设置中...</div>
|
||||
</ListWorkspace>
|
||||
@@ -113,7 +113,7 @@ export function WorkspaceSetupPage() {
|
||||
<WorkspaceHeader
|
||||
eyebrow="管理"
|
||||
title="工作区设置"
|
||||
subtitle="按小团队运营模式收敛主导航、管理入口和备用模块。"
|
||||
subtitle="按小团队运营模式收敛常用入口、管理入口和低频模块。"
|
||||
/>
|
||||
|
||||
<div className="finance-status-strip" data-testid="workspace-settings-summary">
|
||||
@@ -122,11 +122,11 @@ export function WorkspaceSetupPage() {
|
||||
<div className="finance-metric-card__value">{workspaceStats.total}</div>
|
||||
</div>
|
||||
<div className="finance-metric-card">
|
||||
<div className="finance-metric-card__label">主导航</div>
|
||||
<div className="finance-metric-card__label">常用入口</div>
|
||||
<div className="finance-metric-card__value">{workspaceStats.main}</div>
|
||||
</div>
|
||||
<div className="finance-metric-card">
|
||||
<div className="finance-metric-card__label">管理区</div>
|
||||
<div className="finance-metric-card__label">管理与更多</div>
|
||||
<div className="finance-metric-card__value">{workspaceStats.admin}</div>
|
||||
</div>
|
||||
<div className="finance-metric-card">
|
||||
@@ -171,9 +171,9 @@ export function WorkspaceSetupPage() {
|
||||
|
||||
<section className="admin-command-panel space-y-4">
|
||||
<div>
|
||||
<h3 className="text-base font-semibold text-zinc-900">模块显隐</h3>
|
||||
<h3 className="text-base font-semibold text-zinc-900">入口显隐</h3>
|
||||
<p className="mt-1 text-sm leading-6 text-zinc-600">
|
||||
主导航只保留高频入口;备用模块保留代码与数据,低频功能默认收进管理区或隐藏。
|
||||
常用入口只保留高频任务;低频能力保留代码与数据,默认收进管理、更多或隐藏。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户