| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /**
- * Ai-DOP 侧栏一级目录显示名(与 ai-dop-platform/tools/gen_aidop_menu.py 中模块编码一致)。
- * 在登录菜单树写入路由前覆盖 meta.title,避免库中仍为旧标题时侧栏不更新。
- */
- export const AIDOP_DIRECTORY_TITLES: Record<string, string> = {
- aidopDirS0: 'S0 运营建模',
- aidopDirS1: 'S1 产销协同',
- aidopDirS2: 'S2 制造协同',
- aidopDirS3: 'S3 供应协同',
- aidopDirS4: 'S4 采购执行',
- aidopDirS5: 'S5 物料仓储',
- aidopDirS6: 'S6 生产执行',
- aidopDirS7: 'S7 成品仓储',
- aidopDirS8: 'S8 异常监控',
- aidopDirS9: 'S9 运营指标',
- // 兼容旧种子路由名(数据库未迁移到新 Path/Name 时)
- aidopDirM01: 'S0 运营建模',
- aidopDirM02: 'S1 产销协同',
- aidopDirM03: 'S2 制造协同',
- aidopDirM04: 'S3 供应协同',
- aidopDirM05: 'S4 采购执行',
- aidopDirM06: 'S5 物料仓储',
- aidopDirM07: 'S6 生产执行',
- aidopDirM08: 'S7 成品仓储',
- aidopDirM09: 'S8 异常监控',
- aidopDirM10: 'S9 运营指标',
- };
- /**
- * 兼容库中旧菜单 component:
- * 例如 M16/系统首页 仍指向占位页时,前端在菜单树注入阶段改为新首页组件。
- */
- const AIDOP_COMPONENT_OVERRIDES: Record<string, string> = {
- '/aidop/m16/001': '/dashboard/home',
- };
- type AMenu = Record<string, any>;
- /** 侧栏「智慧运营看板」下 10 个看板(九宫格+S1~S9);统一查询条件仅应出现在这些 component 对应页面 */
- /** 工单排产子页(新标签打开,侧栏隐藏) */
- const PRODUCTION_AUX_ROUTES: Array<{ path: string; title: string; component: string; name: string }> = [
- { path: '/aidop/production/work-order-trace', title: '工单执行追踪', component: '/aidop/production/workOrderSchedulingTraceForm', name: 'aidopProductionWorkOrderTrace' },
- { path: '/aidop/production/work-order-materials', title: '工单物料明细', component: '/aidop/production/workOrderMaterialDetailList', name: 'aidopProductionWorkOrderMaterials' },
- { path: '/aidop/production/work-order-routings', title: '工单工序明细', component: '/aidop/production/workOrderRoutingDetailList', name: 'aidopProductionWorkOrderRoutings' },
- ];
- const SMART_OPS_CHILDREN: Array<{ path: string; title: string; component: string; name: string }> = [
- { path: '/aidop/smart-ops/grid', title: '九宫格智慧运营看板', component: '/dashboard/home', name: 'aidopSmartOpsGrid' },
- { path: '/aidop/smart-ops/modeling', title: '运营指标建模', component: '/aidop/kanban/s0', name: 'aidopSmartOpsModeling' },
- { path: '/aidop/smart-ops/dashboard-config', title: '详情看板配置', component: '/aidop/kanban/dashboardConfig', name: 'aidopSmartOpsDashboardConfig' },
- { path: '/aidop/smart-ops/s1', title: 'S1产销协同看板', component: '/aidop/kanban/s1', name: 'aidopSmartOpsS1' },
- { path: '/aidop/smart-ops/s2', title: 'S2制造协同看板', component: '/aidop/kanban/s2', name: 'aidopSmartOpsS2' },
- { path: '/aidop/smart-ops/s3', title: 'S3供应协同看板', component: '/aidop/kanban/s3', name: 'aidopSmartOpsS3' },
- { path: '/aidop/smart-ops/s4', title: 'S4采购执行看板', component: '/aidop/kanban/s4', name: 'aidopSmartOpsS4' },
- { path: '/aidop/smart-ops/s5', title: 'S5物料仓储看板', component: '/aidop/kanban/s5', name: 'aidopSmartOpsS5' },
- { path: '/aidop/smart-ops/s6', title: 'S6生产执行看板', component: '/aidop/kanban/s6', name: 'aidopSmartOpsS6' },
- { path: '/aidop/smart-ops/s7', title: 'S7成品仓储看板', component: '/aidop/kanban/s7', name: 'aidopSmartOpsS7' },
- { path: '/aidop/smart-ops/s8', title: 'S8异常监控看板', component: '/aidop/kanban/s8', name: 'aidopSmartOpsS8' },
- { path: '/aidop/smart-ops/s9', title: 'S9运营指标看板', component: '/aidop/kanban/s9', name: 'aidopSmartOpsS9' },
- ];
- /**
- * S8 异常监控大屏下的可见子菜单兜底(visible,非 hidden)。
- * 用于 SysMenuSeedData 已新增但库尚未刷新的过渡期,避免侧栏不显示「订单执行档案」。
- * 数据库刷新后由 upsertMenu 合并 component/meta,行为幂等。
- */
- const S8_MONITORING_VISIBLE_ROUTES: Array<{ path: string; title: string; component: string; name: string; icon: string }> = [
- {
- path: '/aidop/s8/monitoring/order-execution',
- title: '订单执行档案',
- component: '/aidop/s8/monitoring/SoOrderExecutionDashboardPage',
- name: 'aidopS8OrderExecution',
- icon: 'ele-Tickets',
- },
- ];
- /** S8 配置中心中的隐藏详情页;库中若缺少授权或未同步新种子,前端补齐后可避免点卡片进入 404 */
- const S8_CONFIG_HIDDEN_ROUTES: Array<{ path: string; title: string; component: string; name: string }> = [
- {
- path: '/aidop/s8/config/exception-types',
- title: '异常类型配置',
- component: '/aidop/s8/config/S8ExceptionTypeConfigPage',
- name: 'aidopS8ExceptionTypeConfig',
- },
- {
- path: '/aidop/s8/config/dashboard-cells',
- title: '大屏卡片配置',
- component: '/aidop/s8/config/S8DashboardCellConfigPage',
- name: 'aidopS8DashboardCellConfig',
- },
- {
- path: '/aidop/s8/config/notifications',
- title: '通知分层配置',
- component: '/aidop/s8/config/S8NotificationLayerPage',
- name: 'aidopS8NotificationLayerConfig',
- },
- ];
- function collectPathsUnder(node: AMenu, acc: Set<string>): void {
- const p = node.path as string | undefined;
- if (p) acc.add(p);
- for (const c of node.children ?? []) collectPathsUnder(c as AMenu, acc);
- }
- function upsertMenu(parent: AMenu, menu: AMenu): void {
- parent.children = parent.children ?? [];
- const idx = parent.children.findIndex((x: AMenu) => x.path === menu.path);
- if (idx >= 0) {
- parent.children[idx] = { ...parent.children[idx], ...menu, meta: { ...(parent.children[idx].meta ?? {}), ...(menu.meta ?? {}) } };
- } else {
- parent.children.unshift(menu);
- }
- }
- /**
- * 用户已有 /aidop 根菜单时,patchAidopCustomMenusIfMissing 会补全智慧运营等子路由;
- * 个性化首页校验须认可这些 path(避免库中子项 path 与绝对 path 不一致时误判回退)。
- */
- export function augmentAllowedPathsForAidopHomepage(menuTree: any[] | undefined, allowed: Set<string>): void {
- if (!menuTree?.length) return;
- const aidopRoot = menuTree.find((x: AMenu) => x.path === '/aidop' || x.name === 'aidopRoot');
- if (!aidopRoot) return;
- for (const c of SMART_OPS_CHILDREN) allowed.add(c.path);
- for (const c of PRODUCTION_AUX_ROUTES) allowed.add(c.path);
- allowed.add('/aidop/smart-ops');
- allowed.add('/aidop/smart-diagnosis');
- }
- /** 仅当接口返回的树里尚不存在对应 path 时补节点,避免与 sys_menu 重复;库已同步时等价于 no-op。 */
- function patchAidopCustomMenusIfMissing(routes: AMenu[] | undefined): void {
- if (!routes?.length) return;
- const aidopRoot = routes.find((x) => x.path === '/aidop' || x.name === 'aidopRoot');
- if (!aidopRoot) return;
- const existing = new Set<string>();
- collectPathsUnder(aidopRoot, existing);
- if (!existing.has('/aidop/smart-ops')) {
- upsertMenu(aidopRoot, {
- path: '/aidop/smart-ops',
- name: 'aidopSmartOpsRoot',
- component: 'Layout',
- meta: { title: '智慧运营看板', icon: 'ele-DataBoard' },
- });
- existing.add('/aidop/smart-ops');
- }
- const smartOps = aidopRoot.children.find((x: AMenu) => x.path === '/aidop/smart-ops');
- if (smartOps) {
- for (const child of SMART_OPS_CHILDREN) {
- if (existing.has(child.path)) continue;
- upsertMenu(smartOps, {
- path: child.path,
- name: child.name,
- component: child.component,
- meta: { title: child.title, icon: 'ele-DataAnalysis' },
- });
- existing.add(child.path);
- }
- const orderMap = new Map(SMART_OPS_CHILDREN.map((c, i) => [c.path, i]));
- smartOps.children = (smartOps.children ?? []).sort((a: AMenu, b: AMenu) => {
- const ai = orderMap.has(a.path) ? (orderMap.get(a.path) as number) : 9999;
- const bi = orderMap.has(b.path) ? (orderMap.get(b.path) as number) : 9999;
- return ai - bi;
- });
- }
- if (!existing.has('/aidop/smart-diagnosis')) {
- upsertMenu(aidopRoot, {
- path: '/aidop/smart-diagnosis',
- name: 'aidopSmartDiagnosis',
- component: '/aidop/diagnosis/index',
- meta: { title: '智慧诊断', icon: 'ele-TrendCharts' },
- });
- }
- for (const child of PRODUCTION_AUX_ROUTES) {
- if (existing.has(child.path)) continue;
- upsertMenu(aidopRoot, {
- path: child.path,
- name: child.name,
- component: child.component,
- meta: { title: child.title, isHide: true, icon: 'ele-Document' },
- });
- existing.add(child.path);
- }
- }
- /** 为 S8 异常监控目录补可见子路由(如「订单执行档案」),兼容库未刷新到最新菜单的过渡期。 */
- function patchS8MonitoringVisibleRoutesIfMissing(routes: AMenu[] | undefined): void {
- if (!routes?.length) return;
- const aidopRoot = routes.find((x) => x.path === '/aidop' || x.name === 'aidopRoot');
- if (!aidopRoot?.children?.length) return;
- const s8Root = aidopRoot.children.find(
- (x: AMenu) => x.path === '/aidop/s8' || x.name === 'aidopDirS8' || x.name === 'aidopDirM09',
- );
- if (!s8Root?.children?.length) return;
- const monitoringDir = s8Root.children.find(
- (x: AMenu) => x.path === '/aidop/s8/monitoring' || x.name === 'aidopS8MonitoringDir',
- );
- if (!monitoringDir) return;
- for (const route of S8_MONITORING_VISIBLE_ROUTES) {
- upsertMenu(monitoringDir, {
- path: route.path,
- name: route.name,
- component: route.component,
- meta: { title: route.title, icon: route.icon },
- });
- }
- }
- /** 为 S8 配置中心补隐藏子路由,兼容数据库未刷新到最新菜单/角色授权时的直达 404 */
- function patchS8ConfigHiddenRoutesIfMissing(routes: AMenu[] | undefined): void {
- if (!routes?.length) return;
- const aidopRoot = routes.find((x) => x.path === '/aidop' || x.name === 'aidopRoot');
- if (!aidopRoot?.children?.length) return;
- const s8Root = aidopRoot.children.find((x: AMenu) => x.path === '/aidop/s8' || x.name === 'aidopDirS8' || x.name === 'aidopDirM09');
- if (!s8Root) return;
- const existing = new Set<string>();
- collectPathsUnder(s8Root, existing);
- for (const route of S8_CONFIG_HIDDEN_ROUTES) {
- upsertMenu(s8Root, {
- path: route.path,
- name: route.name,
- component: route.component,
- meta: { title: route.title, icon: 'ele-Document', isHide: true },
- });
- existing.add(route.path);
- }
- }
- /**
- * 递归覆盖 Ai-DOP 一级目录的 meta.title,供侧栏 / tagsView / 菜单搜索使用。
- * 智慧诊断、智慧运营看板以 sys_menu 为准;若租户/角色未关联到库中菜单,则仅补缺失 path,避免双份。
- */
- /** 强制智慧运营子菜单 component,避免库中仍为占位/错误路径时前端仍加载旧页 */
- function patchSmartOpsRouteComponents(nodes: AMenu[] | undefined): void {
- if (!nodes?.length) return;
- const byPath = Object.fromEntries(SMART_OPS_CHILDREN.map((c) => [c.path, c.component])) as Record<string, string>;
- for (const item of nodes) {
- const raw = item.path as string | undefined;
- const p = raw ? (raw.startsWith('/') ? raw : `/${raw}`) : '';
- const comp = p ? byPath[p] : undefined;
- if (comp) item.component = comp;
- if (item.children?.length) patchSmartOpsRouteComponents(item.children as AMenu[]);
- }
- }
- function patchS8ConfigRouteComponents(nodes: AMenu[] | undefined): void {
- if (!nodes?.length) return;
- const byPath = Object.fromEntries(S8_CONFIG_HIDDEN_ROUTES.map((c) => [c.path, c.component])) as Record<string, string>;
- for (const item of nodes) {
- const raw = item.path as string | undefined;
- const p = raw ? (raw.startsWith('/') ? raw : `/${raw}`) : '';
- const comp = p ? byPath[p] : undefined;
- if (comp) item.component = comp;
- if (item.children?.length) patchS8ConfigRouteComponents(item.children as AMenu[]);
- }
- }
- export function patchAidopMenuTitles(routes: any[] | undefined): void {
- if (!routes?.length) return;
- patchAidopCustomMenusIfMissing(routes as AMenu[]);
- patchS8MonitoringVisibleRoutesIfMissing(routes as AMenu[]);
- patchS8ConfigHiddenRoutesIfMissing(routes as AMenu[]);
- patchSmartOpsRouteComponents(routes as AMenu[]);
- patchS8ConfigRouteComponents(routes as AMenu[]);
- for (const item of routes) {
- const name = item.name as string | undefined;
- if (name && AIDOP_DIRECTORY_TITLES[name]) {
- item.meta = item.meta ?? {};
- item.meta.title = AIDOP_DIRECTORY_TITLES[name];
- }
- const path = item.path as string | undefined;
- if (path && AIDOP_COMPONENT_OVERRIDES[path]) {
- item.component = AIDOP_COMPONENT_OVERRIDES[path];
- }
- if (item.children?.length) patchAidopMenuTitles(item.children);
- }
- }
|