feat(management-navigation-single-company-ux): 收敛管理导航与单公司配置体验

这个提交包含在:
2026-08-03 12:43:00 +08:00
父节点 f4ddc18f12
当前提交 4b0184c64b
共修改 36 个文件,包含 1249 行新增和 178 行删除
@@ -0,0 +1,360 @@
import { hasAnyPermission } from "../../auth/permissions";
export type ManagementGroup = "人员与组织" | "流程与规则" | "系统与审计" | "功能管理";
type ManagementRouteMatch =
| { type: "exact"; path: string }
| { type: "prefix"; path: string }
| { type: "pattern"; pattern: RegExp };
export type ManagementRouteDefinition = {
key: string;
path: string;
title: string;
parentKey: string | null;
group: ManagementGroup | null;
icon: string;
description: string;
anyOf: readonly string[];
showOnLanding: boolean;
match: ManagementRouteMatch;
};
const MANAGEMENT_CHILD_ROUTES: ManagementRouteDefinition[] = [
{
key: "people",
path: "/people",
title: "人员",
parentKey: "management",
group: "人员与组织",
icon: "badge",
description: "员工档案、入转调离和人员状态。",
anyOf: ["system.users"],
showOnLanding: true,
match: { type: "exact", path: "/people" },
},
{
key: "people_stats",
path: "/people/stats",
title: "人员统计",
parentKey: "people",
group: null,
icon: "query_stats",
description: "",
anyOf: ["system.users"],
showOnLanding: false,
match: { type: "exact", path: "/people/stats" },
},
{
key: "employee_profile",
path: "/people/:employeeId",
title: "员工档案",
parentKey: "people",
group: null,
icon: "badge",
description: "",
anyOf: ["system.users"],
showOnLanding: false,
match: { type: "pattern", pattern: /^\/people\/[^/]+$/ },
},
{
key: "organization",
path: "/organization",
title: "组织",
parentKey: "management",
group: "人员与组织",
icon: "account_tree",
description: "组织结构、部门和汇报关系。",
anyOf: ["system.users", "report.dashboard.view"],
showOnLanding: true,
match: { type: "prefix", path: "/organization" },
},
{
key: "user_accounts",
path: "/system/users",
title: "账号",
parentKey: "management",
group: "人员与组织",
icon: "manage_accounts",
description: "账号、角色和登录权限。",
anyOf: ["system.accounts.manage", "system.roles.manage"],
showOnLanding: true,
match: { type: "prefix", path: "/system/users" },
},
{
key: "departments",
path: "/system/departments",
title: "部门",
parentKey: "management",
group: "人员与组织",
icon: "account_tree",
description: "部门基础数据维护。",
anyOf: ["system.users"],
showOnLanding: true,
match: { type: "prefix", path: "/system/departments" },
},
{
key: "approval_rules",
path: "/system/approval-rules",
title: "审批规则",
parentKey: "management",
group: "流程与规则",
icon: "rule",
description: "金额段、审批层级和处理规则。",
anyOf: ["system.settings"],
showOnLanding: true,
match: { type: "prefix", path: "/system/approval-rules" },
},
{
key: "workflow_definitions",
path: "/system/workflow-definitions",
title: "流程定义",
parentKey: "management",
group: "流程与规则",
icon: "schema",
description: "流程模板和节点治理。",
anyOf: ["system.settings"],
showOnLanding: true,
match: { type: "prefix", path: "/system/workflow-definitions" },
},
{
key: "expense_standards",
path: "/system/expense-standards",
title: "费用标准",
parentKey: "management",
group: "流程与规则",
icon: "rule_settings",
description: "费用上限、类别和管控口径。",
anyOf: ["system.settings"],
showOnLanding: true,
match: { type: "prefix", path: "/system/expense-standards" },
},
{
key: "reimbursement_templates",
path: "/system/reimbursement-templates",
title: "报销模板",
parentKey: "management",
group: "流程与规则",
icon: "receipt_long",
description: "常见报销场景模板。",
anyOf: ["system.settings"],
showOnLanding: true,
match: { type: "prefix", path: "/system/reimbursement-templates" },
},
{
key: "workspace",
path: "/system/workspace",
title: "工作区",
parentKey: "management",
group: "系统与审计",
icon: "dashboard_customize",
description: "菜单入口、模块显隐和小团队基线。",
anyOf: ["system.settings"],
showOnLanding: true,
match: { type: "prefix", path: "/system/workspace" },
},
{
key: "audit_logs",
path: "/audit-logs",
title: "审计日志",
parentKey: "management",
group: "系统与审计",
icon: "manage_search",
description: "关键操作留痕和排障。",
anyOf: ["system.audit.view"],
showOnLanding: true,
match: { type: "prefix", path: "/audit-logs" },
},
{
key: "company_information",
path: "/system/master-data",
title: "主数据",
parentKey: "management",
group: "功能管理",
icon: "dataset",
description: "公司信息、成本中心、供应商等基础数据。",
anyOf: ["masterdata.view", "masterdata.manage"],
showOnLanding: true,
match: { type: "prefix", path: "/system/master-data" },
},
{
key: "payment_accounts",
path: "/system/payment-accounts",
title: "企业银行账户",
parentKey: "management",
group: "功能管理",
icon: "account_balance",
description: "维护付款来源账户、脱敏查看与变更留痕。",
anyOf: ["payment.account.read", "payment.account.manage"],
showOnLanding: true,
match: { type: "prefix", path: "/system/payment-accounts" },
},
{
key: "notification_channels",
path: "/system/notification-channels",
title: "通知渠道",
parentKey: "management",
group: "功能管理",
icon: "notifications_active",
description: "企业微信、邮件等补充通知。",
anyOf: ["notification.channel.manage"],
showOnLanding: true,
match: { type: "prefix", path: "/system/notification-channels" },
},
{
key: "feature_flags",
path: "/system/feature-flags",
title: "功能管理",
parentKey: "management",
group: "功能管理",
icon: "toggle_on",
description: "功能开关、灰度和试运行边界。",
anyOf: ["system.settings"],
showOnLanding: true,
match: { type: "prefix", path: "/system/feature-flags" },
},
{
key: "system_announcements",
path: "/system/announcements",
title: "公告管理",
parentKey: "management",
group: null,
icon: "campaign",
description: "",
anyOf: ["system.settings"],
showOnLanding: false,
match: { type: "prefix", path: "/system/announcements" },
},
{
key: "cutover",
path: "/system/cutover",
title: "切换控制台",
parentKey: "management",
group: null,
icon: "swap_calls",
description: "",
anyOf: ["system.settings"],
showOnLanding: false,
match: { type: "prefix", path: "/system/cutover" },
},
{
key: "performance",
path: "/performance",
title: "绩效管理",
parentKey: "management",
group: null,
icon: "monitoring",
description: "",
anyOf: ["system.settings"],
showOnLanding: false,
match: { type: "prefix", path: "/performance" },
},
];
function uniquePermissions(routes: readonly ManagementRouteDefinition[]) {
return Array.from(new Set(routes.flatMap((route) => route.anyOf)));
}
export const MANAGEMENT_ROOT_PERMISSIONS = uniquePermissions(
MANAGEMENT_CHILD_ROUTES.filter((route) => route.showOnLanding),
);
const MANAGEMENT_ROOT_ROUTE: ManagementRouteDefinition = {
key: "management",
path: "/system/settings",
title: "管理",
parentKey: null,
group: null,
icon: "settings",
description: "人员、组织、流程、基础资料和系统审计。",
anyOf: MANAGEMENT_ROOT_PERMISSIONS,
showOnLanding: false,
match: { type: "exact", path: "/system/settings" },
};
export const MANAGEMENT_ROUTES: readonly ManagementRouteDefinition[] = [
MANAGEMENT_ROOT_ROUTE,
...MANAGEMENT_CHILD_ROUTES,
];
export const MANAGEMENT_GROUPS: readonly ManagementGroup[] = [
"人员与组织",
"流程与规则",
"系统与审计",
"功能管理",
];
const ROUTES_BY_KEY = new Map(MANAGEMENT_ROUTES.map((route) => [route.key, route]));
function matchesRoute(route: ManagementRouteDefinition, pathname: string) {
if (route.match.type === "pattern") {
return route.match.pattern.test(pathname);
}
if (route.match.type === "exact") {
return pathname === route.match.path;
}
return pathname === route.match.path || pathname.startsWith(`${route.match.path}/`);
}
export function canAccessManagementRoute(route: ManagementRouteDefinition, permissions: string[]) {
return hasAnyPermission(permissions, [...route.anyOf]);
}
export function resolveManagementRouteDefinition(pathname: string) {
return MANAGEMENT_ROUTES.find((route) => matchesRoute(route, pathname)) ?? null;
}
export function resolveManagementRoute(pathname: string, permissions: string[]) {
const route = resolveManagementRouteDefinition(pathname);
return route && canAccessManagementRoute(route, permissions) ? route : null;
}
export function isKnownManagementPath(pathname: string) {
return Boolean(resolveManagementRouteDefinition(pathname));
}
export function isManagementPath(pathname: string, permissions: string[]) {
return Boolean(resolveManagementRoute(pathname, permissions));
}
export function getVisibleManagementItems(permissions: string[]) {
return MANAGEMENT_ROUTES.filter(
(route) => route.showOnLanding && canAccessManagementRoute(route, permissions),
);
}
export type ManagementBreadcrumb = {
key: string;
title: string;
href: string | null;
};
export function resolveManagementBreadcrumbs(pathname: string, permissions: string[]) {
const current = resolveManagementRoute(pathname, permissions);
if (!current) {
return [];
}
const chain: ManagementRouteDefinition[] = [];
const visited = new Set<string>();
let cursor: ManagementRouteDefinition | undefined = current;
while (cursor && !visited.has(cursor.key)) {
chain.unshift(cursor);
visited.add(cursor.key);
cursor = cursor.parentKey ? ROUTES_BY_KEY.get(cursor.parentKey) : undefined;
}
return chain.map((route, index) => ({
key: route.key,
title: route.title,
href: index < chain.length - 1 ? route.path : null,
}));
}
export function getManagementRoutePermissions(key: string) {
const route = ROUTES_BY_KEY.get(key);
if (!route) {
throw new Error(`Unknown management route key: ${key}`);
}
return [...route.anyOf];
}
+15 -10
查看文件
@@ -1,3 +1,8 @@
import {
isKnownManagementPath,
resolveManagementRoute,
} from "./managementRoutes";
export const MAIN_NAV_ORDER = ["/portal", "/workflow/tasks", "/reimbursements", "/purchase-requests", "/contracts-registry", "/projects", "/assets", "/payment-batches", "/ap-operations", "/invoice-pool", "/team", "/leave-requests"];
export const ADMIN_NAV_ORDER = ["/system/settings"];
export const BACKUP_NAV_ORDER = ["/weekly-reports", "/announcements", "/budgets", "/attendance", "/wecom-approval-archive", "/travel-requests", "/inventory-checks", "/dashboard"];
@@ -38,19 +43,19 @@ const PAGE_TITLES: Array<{ path: string; title: string; group: string }> = [
{ path: "/mobile/reimbursements", title: "移动报销", group: "移动工作台" },
{ path: "/mobile", title: "移动首页", group: "移动工作台" },
{ path: "/settings/profile", title: "个人设置", group: "账号设置" },
{ path: "/system/workspace", title: "工作区设置", group: "管理" },
{ path: "/people", title: "人员管理", group: "管理" },
{ path: "/organization", title: "组织架构", group: "管理" },
{ path: "/system/approval-rules", title: "审批规则", group: "管理" },
{ path: "/system/workflow-definitions", title: "流程定义", group: "管理" },
{ path: "/system/settings", title: "管理", group: "管理" },
{ path: "/system/feature-flags", title: "功能管理", group: "管理" },
{ path: "/system/cutover", title: "切换控制台", group: "更多" },
{ path: "/dashboard", title: "数据看板", group: "更多" },
{ path: "/audit-logs", title: "审计日志", group: "管理" },
];
export function resolvePageMeta(pathname: string) {
export function resolvePageMeta(pathname: string, permissions: string[] = []) {
const managementRoute = resolveManagementRoute(pathname, permissions);
if (managementRoute) {
return { title: managementRoute.title, group: "管理" };
}
if (isKnownManagementPath(pathname)) {
return { title: "管理", group: "管理" };
}
const matched = [...PAGE_TITLES].sort((left, right) => right.path.length - left.path.length)
.find((item) => pathname === item.path || pathname.startsWith(item.path));