Pārlūkot izejas kodu

feat(aidop): show FUNC codes in navigation (plan A)

Add S0-S9 path mapping, sidebar badges, breadcrumb/search labels, and page headers; add global rule for new menu FUNC registration. Web 2.4.189

Co-authored-by: Cursor <cursoragent@cursor.com>
skygu 1 nedēļu atpakaļ
vecāks
revīzija
2d4b285d53

+ 1 - 0
.cursor/rules/README.md

@@ -14,6 +14,7 @@
 | `collaboration-scope.mdc` | 改前清单待确认、跨模块影响须先预警、小问题最小改动不大重构等 | `alwaysApply: true` |
 | `git-submit-intent.mdc` | 用户说「提交」时默认 **commit + push**;仅用户明确说不 push 时才只 commit | `alwaysApply: true` |
 | `version-bump-on-commit.mdc` | 发版必升号;提交改动到前端/后端代码或配置时递增对应端版本号,纯文档/规则不升号 | `alwaysApply: true` |
+| `aidop-func-code-menu.mdc` | 新 Ai-DOP 功能菜单须登记 `FUNC-Sn-nnn`(`aidopFuncCodes.ts` + 三联文档),导航按方案 A 展示、不改 `Title` | `alwaysApply: true` |
 | `approval-flow-integration.mdc` | 将审批流接入任意业务模块时的必读清单、前置决策、硬性禁止 | 按 `globs` 自动注入(命中 `*BizHandler*.cs`、审批流插件代码、`approvalFlow` 前端、审批流相关文档时) |
 
 ## 业务方案索引(便于对话对齐)

+ 55 - 0
.cursor/rules/aidop-func-code-menu.mdc

@@ -0,0 +1,55 @@
+---
+description: Ai-DOP 新功能菜单须登记 FUNC-Sn-nnn 编号并按方案 A 展示(侧栏短标+映射表,不改 Title)
+alwaysApply: true
+---
+
+# Ai-DOP 功能菜单编号(FUNC)与导航展示
+
+凡新增或调整 **Ai-DOP 业务叶子菜单**(`sys_menu` 种子、前端隐藏路由、智慧运营看板子项等),须同步登记 **FUNC 编号**,展示遵循 **方案 A**(已实现,勿另起一套)。
+
+## 编号格式
+
+| 类型 | 格式 | 示例 |
+|------|------|------|
+| 功能设计 | `FUNC-Sn-nnn` | `FUNC-S1-003` |
+| 模块 | `n` = 0–9 | S0 运营建模 … S9 运营指标 |
+| 序号 | `nnn` = 三位递增 | 同模块内不重用、不重排已有号 |
+
+业务需求 `REQ-Sn-nnn`、测试 `TC-Sn-nnn` 与三联对照表对齐,见 [`doc/requirements/README.md`](doc/requirements/README.md)。
+
+## 新菜单必须做的登记(缺一不可)
+
+1. **`Web/src/constants/aidopFuncCodes.ts`**  
+   在 `FUNC_DEFS` 增加一条:`code`、`name`(与功能设计/菜单语义一致)、`paths`(绝对 path)、`names`(`route.name`,有则填)。
+2. **有需求文档的模块(S0–S4 等)**  
+   同步更新对应 `doc/requirements/Sn-*/` 三联对照表 / 功能设计说明(**先查已有编号,禁止擅自改号**)。
+3. **尚无三联文档的模块(S5–S9 等)**  
+   在该模块已用最大序号 **+1** 扩展(当前实现见 `aidopFuncCodes.ts`);后续补文档时**沿用已分配 FUNC**,不整体重排。
+4. **`sys_menu` 种子**(`Admin.NET.Plugin.AiDOP/SeedData/SysMenuSeedData.cs`)  
+   `Title` **只写业务短名**;`Remark` 可写业务说明,**不要把** `FUNC-Sn-nnn` 写入 `Title`。
+
+登录后 `patchAidopMenuTitles` → `patchAidopFuncCodes` 会自动注入 `meta.funcCode/funcName/funcSeq`,侧栏/搜索/面包屑/`AidopDemoShell` 无需再改展示逻辑。
+
+## 方案 A 展示(禁止加长 Title)
+
+| 位置 | 做法 |
+|------|------|
+| 侧栏叶子 | 业务名 + 短标 `[nnn]`;悬停显示 `FUNC-Sn-nnn 功能名` |
+| 目录节点 | **不加**编号 |
+| 面包屑末级 / 页头 | 完整 `FUNC-Sn-nnn`(`AidopDemoShell` 副标题) |
+| 禁止 | `Title = "FUNC-S1-003 订单评审"` 或把编号拼进侧栏主文案 |
+
+## 特殊项
+
+- **同一页面多入口**(如看板在模块目录与智慧运营看板各一条):同一 `FUNC` 可挂多个 `paths`/`names`。
+- **隐藏路由**(表单页、详情页、`isHide`):仍须登记,供标签页与面包屑追溯。
+- **动态 path**(如 `/aidop/s8/exceptions/:id`):登记 path 模板 + `route.name`。
+- **跨模块平台项**(智慧诊断、数据中台):暂归入 **S9 扩展段**(`060+` / `010+`),新增时延续该段序号。
+
+## 自检清单(交付前)
+
+- [ ] `aidopFuncCodes.ts` 已含新 path/name  
+- [ ] 未修改已有 FUNC 编号  
+- [ ] `sys_menu.Title` 仍为短业务名  
+- [ ] 有文档模块已更新三联/功能设计(若本次属正式功能交付)  
+- [ ] 未在 `aidopMenuDisplay.ts` 用 `meta.title` 拼接 FUNC 全文(映射表为唯一数据源)

+ 1 - 0
AGENTS.md

@@ -9,6 +9,7 @@
 - 小问题**最小改动**,非必要不大重构;更大方案以**建议**形式交负责人决策  
 - **发版必升号**;执行 Git 提交时,版本号只跟随**本次提交实际纳入的对应端代码/配置改动**递增:提交前端代码/配置才递增 `Web/package.json` 的 `version` patch,提交后端代码/配置才递增 `server/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj` 的 `<Version>` / `<AssemblyVersion>` / `<FileVersion>` patch;某端未纳入本次提交则不升该端版本,**纯文档/规则提交不递增前后端版本号**。详见 **[`.cursor/rules/version-bump-on-commit.mdc`](.cursor/rules/version-bump-on-commit.mdc)**。
 - 用户说 **「提交」** 时默认 **commit + push** 到跟踪远端,不得只 commit 不 push;详见 **[`.cursor/rules/git-submit-intent.mdc`](.cursor/rules/git-submit-intent.mdc)**。
+- 新增 **Ai-DOP 功能菜单** 须登记 **`FUNC-Sn-nnn`** 并维护 [`Web/src/constants/aidopFuncCodes.ts`](Web/src/constants/aidopFuncCodes.ts);导航展示用方案 A(侧栏短标、映射表注入),**勿**把编号写入 `sys_menu.Title`。详见 **[`.cursor/rules/aidop-func-code-menu.mdc`](.cursor/rules/aidop-func-code-menu.mdc)**。
 
 说明与索引:[`.cursor/rules/README.md`](.cursor/rules/README.md)
 

+ 1 - 1
Web/package.json

@@ -1,7 +1,7 @@
 {
 	"name": "admin.net",
 	"type": "module",
-	"version": "2.4.188",
+	"version": "2.4.189",
 	"packageManager": "pnpm@10.32.1",
 	"lastBuildTime": "2026.03.15",
 	"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",

+ 291 - 0
Web/src/constants/aidopFuncCodes.ts

@@ -0,0 +1,291 @@
+/**
+ * Ai-DOP 功能编号(FUNC-Sn-nnn)与路由 path / route name 对照。
+ * S0–S4:以 doc/requirements 三联对照表为准;S5–S9 及尚无文档项按菜单语义扩展编号。
+ */
+export type AidopFuncMeta = {
+	code: string;
+	name: string;
+};
+
+type FuncDef = AidopFuncMeta & {
+	paths?: string[];
+	names?: string[];
+};
+
+/** 模块内三位序号,用于侧栏短标 [nnn] */
+export function parseFuncSeq(code: string | undefined | null): string {
+	if (!code) return '';
+	const m = /^FUNC-S\d+-(\d{3})$/.exec(code.trim());
+	return m ? m[1] : '';
+}
+
+export function formatFuncTooltip(meta: AidopFuncMeta | null | undefined): string {
+	if (!meta?.code) return '';
+	return meta.name ? `${meta.code} ${meta.name}` : meta.code;
+}
+
+function normalizePath(path: string): string {
+	const p = path.startsWith('/') ? path : `/${path}`;
+	return p.replace(/\/+$/, '') || '/';
+}
+
+const FUNC_DEFS: FuncDef[] = [
+	// ── S0 运营建模(三联对照表 FUNC-S0-001~059;060+ 为菜单扩展项)──
+	{ code: 'FUNC-S0-001', name: '标准 BOM 管理', paths: ['/aidop/s0/manufacturing/standard-bom'] },
+	{ code: 'FUNC-S0-002', name: '标准工艺路线管理', paths: ['/aidop/s0/manufacturing/routing'] },
+	{ code: 'FUNC-S0-003', name: '标准工序管理', paths: ['/aidop/s0/manufacturing/standard-operation'] },
+	{ code: 'FUNC-S0-004', name: '工作中心管理', paths: ['/aidop/s0/manufacturing/work-center'] },
+	{ code: 'FUNC-S0-005', name: '产线管理', paths: ['/aidop/s0/manufacturing/production-line'] },
+	{ code: 'FUNC-S0-006', name: '产线物料管理', paths: ['/aidop/s0/manufacturing/line-material'] },
+	{ code: 'FUNC-S0-007', name: '产线工位管理', paths: ['/aidop/s0/manufacturing/line-post'] },
+	{ code: 'FUNC-S0-008', name: '人员技能管理', paths: ['/aidop/s0/manufacturing/person-skill'] },
+	{ code: 'FUNC-S0-009', name: '人员技能分配', paths: ['/aidop/s0/manufacturing/person-skill-assignment'] },
+	{ code: 'FUNC-S0-010', name: '前置工序要素管理', paths: ['/aidop/s0/manufacturing/preprocess-element'] },
+	{ code: 'FUNC-S0-011', name: '前置工序要素参数管理', paths: ['/aidop/s0/manufacturing/preprocess-element-param'] },
+	{ code: 'FUNC-S0-012', name: '生产要素参数管理', paths: ['/aidop/s0/manufacturing/element-param-production'] },
+	{ code: 'FUNC-S0-013', name: '工艺流程卡管理', paths: ['/aidop/s0/manufacturing/process-flow-card'] },
+	{ code: 'FUNC-S0-014', name: '物料代替方案管理', paths: ['/aidop/s0/manufacturing/substitute-scheme-select'] },
+	{ code: 'FUNC-S0-015', name: '物料替代明细管理(制造域)', paths: ['/aidop/s0/manufacturing/material-substitution'] },
+	{ code: 'FUNC-S0-016', name: 'SOP 文件类型管理', paths: ['/aidop/s0/manufacturing/sop-file-type'] },
+	{ code: 'FUNC-S0-017', name: 'SOP 维护管理', paths: ['/aidop/s0/manufacturing/sop-document'] },
+	{ code: 'FUNC-S0-018', name: '工单控制参数管理', paths: ['/aidop/s0/manufacturing/work-order-control'] },
+	{ code: 'FUNC-S0-019', name: '订单排程周期管理', paths: ['/aidop/s0/manufacturing/order-schedule-cycle'] },
+	{ code: 'FUNC-S0-020', name: '物料管理', paths: ['/aidop/s0/sales/material'] },
+	{ code: 'FUNC-S0-021', name: '客户管理', paths: ['/aidop/s0/sales/customer'] },
+	{ code: 'FUNC-S0-023', name: '订单评审周期规则管理', paths: ['/aidop/s0/sales/order-review-cycle'] },
+	{ code: 'FUNC-S0-024', name: '产品设计周期规则管理', paths: ['/aidop/s0/sales/product-design-cycle'] },
+	{ code: 'FUNC-S0-025', name: '合同评审周期规则管理', paths: ['/aidop/s0/sales/contract-review-cycle'] },
+	{ code: 'FUNC-S0-026', name: '订单优先级规则管理', paths: ['/aidop/s0/sales/order-priority-rule'] },
+	{ code: 'FUNC-S0-027', name: '供应商管理', paths: ['/aidop/s0/supply/supplier'] },
+	{ code: 'FUNC-S0-028', name: '采购分类与货源管理', paths: ['/aidop/s0/supply/sourcing-item'] },
+	{ code: 'FUNC-S0-029', name: '品类交货周期管理', paths: ['/aidop/s0/supply/category-lead-time'] },
+	{ code: 'FUNC-S0-030', name: '物料计划周期管理', paths: ['/aidop/s0/supply/material-plan-cycle'] },
+	{ code: 'FUNC-S0-031', name: '部门管理', paths: ['/aidop/s0/warehouse/department'] },
+	{ code: 'FUNC-S0-032', name: '员工管理', paths: ['/aidop/s0/warehouse/employee'] },
+	{ code: 'FUNC-S0-033', name: '员工工作职责管理', paths: ['/aidop/s0/warehouse/emp-work-duty'] },
+	{ code: 'FUNC-S0-034', name: '库位管理', paths: ['/aidop/s0/warehouse/location'] },
+	{ code: 'FUNC-S0-035', name: '库位货架管理', paths: ['/aidop/s0/warehouse/location-shelf'] },
+	{ code: 'FUNC-S0-036', name: '物料包装规格管理', paths: ['/aidop/s0/warehouse/item-pack'] },
+	{ code: 'FUNC-S0-037', name: '批次号控制管理', paths: ['/aidop/s0/warehouse/nbr-control'] },
+	{ code: 'FUNC-S0-038', name: '批次类型管理', paths: ['/aidop/s0/warehouse/nbr-type'] },
+	{ code: 'FUNC-S0-039', name: '标签类型管理', paths: ['/aidop/s0/warehouse/label-type'] },
+	{ code: 'FUNC-S0-040', name: '成本中心管理', paths: ['/aidop/s0/warehouse/cost-center'] },
+	{ code: 'FUNC-S0-041', name: '任务分配管理', paths: ['/aidop/s0/warehouse/task-assignment'] },
+	{ code: 'FUNC-S0-042', name: '检验基准管理', paths: ['/aidop/s0/quality/inspection-basis'] },
+	{ code: 'FUNC-S0-043', name: '检验频次管理', paths: ['/aidop/s0/quality/inspection-frequency'] },
+	{ code: 'FUNC-S0-044', name: '检验仪器管理', paths: ['/aidop/s0/quality/instrument'] },
+	{ code: 'FUNC-S0-045', name: '检验项目管理', paths: ['/aidop/s0/quality/inspection-item'] },
+	{ code: 'FUNC-S0-046', name: '检验方法管理', paths: ['/aidop/s0/quality/inspection-method'] },
+	{ code: 'FUNC-S0-047', name: '检验标准管理', paths: ['/aidop/s0/quality/inspection-standard'] },
+	{ code: 'FUNC-S0-048', name: '抽样方案管理', paths: ['/aidop/s0/quality/sampling-scheme'] },
+	{ code: 'FUNC-S0-049', name: '检验计划管理', paths: ['/aidop/s0/quality/inspection-plan'] },
+	{ code: 'FUNC-S0-050', name: '来料检验规范(IQC)', paths: ['/aidop/s0/quality/raw-inspection-spec'] },
+	{ code: 'FUNC-S0-051', name: '过程检验规范(IPQC)', paths: ['/aidop/s0/quality/process-inspection-spec'] },
+	{
+		code: 'FUNC-S0-052',
+		name: '成品检验规范(OQC/FQC)',
+		paths: ['/aidop/s0/quality/fqc-inspection-spec', '/aidop/s0/quality/oqc-inspection-spec'],
+	},
+	{ code: 'FUNC-S0-053', name: '来料白名单管理', paths: ['/aidop/s0/quality/raw-whitelist'] },
+	{ code: 'FUNC-S0-054', name: '质量字典管理', paths: ['/aidop/s0/quality/dictionary'] },
+	{
+		code: 'FUNC-S0-055',
+		name: '指标图谱浏览',
+		paths: ['/aidop/smart-ops/modeling', '/aidop/kanban/s0'],
+		names: ['aidopSmartOpsModeling'],
+	},
+	{ code: 'FUNC-S0-058', name: '指标目录管理(KpiMaster)', paths: ['/aidop/smart-ops/kpi-master', '/aidop/kanban/kpiMaster'], names: ['aidopSmartOpsKpiMaster'] },
+	{ code: 'FUNC-S0-060', name: '条码规则管理', paths: ['/aidop/s0/warehouse/barcode-rule'] },
+	{ code: 'FUNC-S0-061', name: '计量器具管理', paths: ['/aidop/s0/quality/gauge-instrument'] },
+	{ code: 'FUNC-S0-062', name: '业务事实字典', paths: ['/aidop/smart-ops/business-fact', '/aidop/kanban/businessFact'], names: ['aidopSmartOpsBusinessFact'] },
+	{ code: 'FUNC-S0-063', name: '物料工艺要素管理', paths: ['/aidop/s0/manufacturing/material-process-element'] },
+	{ code: 'FUNC-S0-064', name: '详情看板配置', paths: ['/aidop/smart-ops/dashboard-config'], names: ['aidopSmartOpsDashboardConfig'] },
+	{ code: 'FUNC-S0-065', name: '业务建模(规划占位)', paths: ['/aidop/s0/002'] },
+
+	// ── S1 产销协同 ──
+	{ code: 'FUNC-S1-001', name: '产品设计管理', paths: ['/aidop/s1/order-mgmt/product-design'], names: ['aidopS1ProductDesign'] },
+	{ code: 'FUNC-S1-002', name: '合同评审管理', paths: ['/aidop/s1/order-mgmt/contract-review'], names: ['aidopS1ContractReview'] },
+	{ code: 'FUNC-S1-003', name: '订单评审管理', paths: ['/aidop/s1/order-mgmt/order'], names: ['aidopS1SalesOrder'] },
+	{ code: 'FUNC-S1-004', name: '订单交付管理', paths: ['/aidop/s1/order-mgmt/orderDelivery'], names: ['aidopS1OrderDelivery'] },
+	{ code: 'FUNC-S1-005', name: '订单发货管理', paths: ['/aidop/s1/order-mgmt/asnShipper'], names: ['aidopS1AsnShipper'] },
+	{ code: 'FUNC-S1-006', name: '工单下达', paths: ['/aidop/s1/workorder-mgmt/dispatch'], names: ['aidopS1WorkOrderDispatch'] },
+	{ code: 'FUNC-S1-007', name: '计划联动看板', paths: ['/aidop/s1/SalesKanBan/linkage-plan'], names: ['aidopS1LinkagePlan'] },
+	{ code: 'FUNC-S1-008', name: '需求明细核验', paths: ['/aidop/s1/SalesKanBan/requirement-examine-detail'], names: ['aidopS1RequirementExamineDetail'] },
+	{
+		code: 'FUNC-S1-009',
+		name: '产销协同看板',
+		paths: ['/aidop/s1/SalesKanBan/kanban', '/aidop/smart-ops/s1', '/aidop/kanban/s1'],
+		names: ['aidopS1SalesKanBanKanban', 'aidopSmartOpsS1'],
+	},
+
+	// ── S2 制造协同 ──
+	{ code: 'FUNC-S2-001', name: '生产排程', paths: ['/aidop/s2/production-scheduling/work-order-scheduling'], names: ['aidopS2WorkOrderScheduling'] },
+	{ code: 'FUNC-S2-002', name: '排产异常记录', paths: ['/aidop/s2/production-scheduling/scheduling-exception'], names: ['aidopS2SchedulingException'] },
+	{ code: 'FUNC-S2-003', name: '可执行日计划', paths: ['/aidop/s2/operation-plan/executable-daily-plan'], names: ['aidopS2ExecutableDailyPlan'] },
+	{ code: 'FUNC-S2-004', name: '产线工作日历管理', paths: ['/aidop/s2/operation-plan/line-work-calendar'], names: ['aidopS2LineWorkCalendar'] },
+	{ code: 'FUNC-S2-005', name: '产线休息时间管理', paths: ['/aidop/s2/operation-plan/line-rest-time'], names: ['aidopS2LineRestTime'] },
+	{ code: 'FUNC-S2-006', name: '产线节假日管理', paths: ['/aidop/s2/operation-plan/line-holiday'], names: ['aidopS2LineHoliday'] },
+	{ code: 'FUNC-S2-007', name: '产线加班管理', paths: ['/aidop/s2/operation-plan/line-overtime'], names: ['aidopS2LineOvertime'] },
+	{ code: 'FUNC-S2-008', name: '工单执行进度看板', paths: ['/aidop/s2/collaboration-kanban/work-order-progress'], names: ['aidopS2WorkOrderProgressKanban'] },
+	{
+		code: 'FUNC-S2-009',
+		name: 'S2制造协同看板(KPI)',
+		paths: ['/aidop/smart-ops/s2', '/aidop/kanban/s2'],
+		names: ['aidopSmartOpsS2'],
+	},
+	{ code: 'FUNC-S2-010', name: '工单执行追踪', paths: ['/aidop/production/work-order-trace'], names: ['aidopProductionWorkOrderTrace'] },
+	{ code: 'FUNC-S2-011', name: '工单物料明细', paths: ['/aidop/production/work-order-materials'], names: ['aidopProductionWorkOrderMaterials'] },
+	{ code: 'FUNC-S2-012', name: '工单工序明细', paths: ['/aidop/production/work-order-routings'], names: ['aidopProductionWorkOrderRoutings'] },
+
+	// ── S3 供应协同 ──
+	{ code: 'FUNC-S3-001', name: '物料需求计划', paths: ['/aidop/s3/material-plan/demand-schedule'], names: ['aidopS3DemandSchedule'] },
+	{ code: 'FUNC-S3-002', name: '物料交货计划', paths: ['/aidop/s3/material-plan/delivery-schedule'], names: ['aidopS3DeliverySchedule'] },
+	{ code: 'FUNC-S3-003', name: '交货单异常记录', paths: ['/aidop/s3/material-plan/delivery-exception'], names: ['aidopS3DeliveryException'] },
+	{ code: 'FUNC-S3-004', name: '物料采购申请', paths: ['/aidop/s3/procurement/purchase-request'], names: ['aidopS3PurchaseRequest'] },
+	{ code: 'FUNC-S3-005', name: '要货令', paths: ['/aidop/s3/procurement/demand-order'], names: ['aidopS3DemandOrder'] },
+	{ code: 'FUNC-S3-006', name: '物料采购订单', paths: ['/aidop/s3/procurement/purchase-order'], names: ['aidopS3PurchaseOrder'] },
+	{ code: 'FUNC-S3-007', name: '委外加工订单', paths: ['/aidop/s3/procurement/outsource-order'], names: ['aidopS3OutsourceOrder'] },
+	{ code: 'FUNC-S3-008', name: '工序外协订单', paths: ['/aidop/s3/procurement/process-outsource-order'], names: ['aidopS3ProcessOutsourceOrder'] },
+	{
+		code: 'FUNC-S3-009',
+		name: '供应协同看板',
+		paths: ['/aidop/s3/supply-kanban/dashboard', '/aidop/smart-ops/s3', '/aidop/kanban/s3'],
+		names: ['aidopS3SupplyKanban', 'aidopSmartOpsS3'],
+	},
+	{ code: 'FUNC-S3-010', name: '工单物料齐套上线看板', paths: ['/aidop/s3/supply-kanban/work-order-material-readiness'], names: ['aidopS3WorkOrderMaterialReadiness'] },
+	{ code: 'FUNC-S3-011', name: 'MDP运行监控', paths: ['/aidop/s3/supply-kanban/mdp-monitor', '/aidop/data-platform/mdp-monitor'], names: ['aidopS3MdpMonitor', 'aidopDataPlatformMdpMonitor'] },
+	{ code: 'FUNC-S3-012', name: '委外采购明细', paths: ['/aidop/s3/supply/outsource-order-details'], names: ['aidopS3OutsourceOrderDetails'] },
+
+	// ── S4 采购执行 ──
+	{ code: 'FUNC-S4-001', name: '供应商交货管理', paths: ['/aidop/s4/delivery/supplier-delivery-management'], names: ['aidopS4SupplierDeliveryManagement'] },
+	{
+		code: 'FUNC-S4-002',
+		name: '供应商发货单',
+		paths: ['/aidop/s4/delivery/supplier-shipment', '/aidop/s4/delivery/supplier-shipment-form'],
+		names: ['aidopS4SupplierShipment', 'aidopS4SupplierShipmentForm'],
+	},
+	{
+		code: 'FUNC-S4-003',
+		name: '采购退货单',
+		paths: ['/aidop/s4/return-mgmt/purchase-return-order', '/aidop/s4/return-mgmt/purchase-return-order-form'],
+		names: ['aidopS4PurchaseReturnOrder', 'aidopS4PurchaseReturnOrderForm'],
+	},
+	{ code: 'FUNC-S4-004', name: 'IQC退货查询', paths: ['/aidop/s4/return-mgmt/iqc-return-query'], names: ['aidopS4IqcReturnQuery'] },
+	{
+		code: 'FUNC-S4-005',
+		name: '采购执行看板主页',
+		paths: ['/aidop/s4/execution-kanban/dashboard', '/aidop/smart-ops/s4', '/aidop/kanban/s4'],
+		names: ['aidopS4ExecutionKanbanDashboard', 'aidopSmartOpsS4'],
+	},
+	{ code: 'FUNC-S4-006', name: '供应商欠料看板', paths: ['/aidop/s4/execution-kanban/supplier-shortage-kanban'], names: ['aidopS4SupplierShortageKanban'] },
+
+	// ── S5 物料仓储(扩展编号)──
+	{ code: 'FUNC-S5-001', name: '来料检验任务列表', paths: ['/aidop/s5/iqc/task-list'], names: ['aidopS5IqcTaskList'] },
+	{ code: 'FUNC-S5-002', name: '来料检验结果列表', paths: ['/aidop/s5/iqc/result-list'], names: ['aidopS5IqcResultList'] },
+	{ code: 'FUNC-S5-003', name: '委外发料单', paths: ['/aidop/s5/warehouse/outsource-issue'], names: ['aidopS5WarehouseOutsourceIssue'] },
+	{ code: 'FUNC-S5-004', name: '采购收货单', paths: ['/aidop/s5/warehouse/purchase-receipt'], names: ['aidopS5WarehousePurchaseReceipt'] },
+	{ code: 'FUNC-S5-005', name: '生产领料单', paths: ['/aidop/s5/warehouse/production-issue'], names: ['aidopS5WarehouseProductionIssue'] },
+	{ code: 'FUNC-S5-006', name: '生产退料单', paths: ['/aidop/s5/warehouse/production-return'], names: ['aidopS5WarehouseProductionReturn'] },
+	{ code: 'FUNC-S5-007', name: '生产入库单', paths: ['/aidop/s5/warehouse/production-receipt'], names: ['aidopS5WarehouseProductionReceipt'] },
+	{ code: 'FUNC-S5-008', name: '标签查询', paths: ['/aidop/s5/inventory/label-query'], names: ['aidopS5InventoryLabelQuery'] },
+	{ code: 'FUNC-S5-009', name: '暂收在检列表', paths: ['/aidop/s5/inventory/pending-inspection'], names: ['aidopS5InventoryPendingInspection'] },
+	{ code: 'FUNC-S5-010', name: '库存查询', paths: ['/aidop/s5/inventory/stock-query'], names: ['aidopS5InventoryStockQuery'] },
+	{ code: 'FUNC-S5-011', name: '进出存查询', paths: ['/aidop/s5/inventory/inout-query'], names: ['aidopS5InventoryInoutQuery'] },
+	{ code: 'FUNC-S5-012', name: '盘点标签确认', paths: ['/aidop/s5/inventory/stocktake-label'], names: ['aidopS5InventoryStocktakeLabel'] },
+	{ code: 'FUNC-S5-013', name: '盘点结果查询', paths: ['/aidop/s5/inventory/stocktake-result'], names: ['aidopS5InventoryStocktakeResult'] },
+	{ code: 'FUNC-S5-014', name: '收料任务看板', paths: ['/aidop/s5/warehouse-kanban/receiving-task'], names: ['aidopS5WarehouseKanbanReceivingTask'] },
+	{ code: 'FUNC-S5-015', name: '发料任务看板', paths: ['/aidop/s5/warehouse-kanban/issuing-task'], names: ['aidopS5WarehouseKanbanIssuingTask'] },
+	{ code: 'FUNC-S5-016', name: '库存周转报表', paths: ['/aidop/s5/warehouse-kanban/turnover-report'], names: ['aidopS5WarehouseKanbanTurnoverReport'] },
+	{ code: 'FUNC-S5-017', name: '物料库龄分析', paths: ['/aidop/s5/warehouse-kanban/age-analysis'], names: ['aidopS5WarehouseKanbanAgeAnalysis'] },
+	{ code: 'FUNC-S5-018', name: 'S5物料仓储看板', paths: ['/aidop/smart-ops/s5', '/aidop/kanban/s5'], names: ['aidopSmartOpsS5'] },
+
+	// ── S6 生产执行(扩展编号)──
+	{ code: 'FUNC-S6-001', name: '生产指令单列表', paths: ['/aidop/s6/production-record/order-list'], names: ['aidopS6ProductionRecordOrderList'] },
+	{ code: 'FUNC-S6-002', name: '过程检验单列表', paths: ['/aidop/s6/process-quality/inspection-list'], names: ['aidopS6ProcessQualityInspectionList'] },
+	{ code: 'FUNC-S6-003', name: '生产设备台账', paths: ['/aidop/s6/equipment-tooling/equipment-ledger'], names: ['aidopS6EquipmentToolingEquipmentLedger'] },
+	{ code: 'FUNC-S6-004', name: '模工具台账管理', paths: ['/aidop/s6/equipment-tooling/tooling-ledger'], names: ['aidopS6EquipmentToolingToolingLedger'] },
+	{ code: 'FUNC-S6-005', name: '工单执行看板', paths: ['/aidop/s6/execution-kanban/work-order'], names: ['aidopS6ExecutionKanbanWorkOrder'] },
+	{ code: 'FUNC-S6-006', name: '车间效率看板', paths: ['/aidop/s6/execution-kanban/workshop-efficiency'], names: ['aidopS6ExecutionKanbanWorkshopEfficiency'] },
+	{ code: 'FUNC-S6-007', name: '设备OEE看板', paths: ['/aidop/s6/execution-kanban/equipment-oee'], names: ['aidopS6ExecutionKanbanEquipmentOee'] },
+	{ code: 'FUNC-S6-008', name: '员工工时看板', paths: ['/aidop/s6/execution-kanban/labor-hours'], names: ['aidopS6ExecutionKanbanLaborHours'] },
+	{ code: 'FUNC-S6-009', name: 'S6生产执行看板', paths: ['/aidop/smart-ops/s6', '/aidop/kanban/s6'], names: ['aidopSmartOpsS6'] },
+
+	// ── S7 成品仓储(扩展编号)──
+	{ code: 'FUNC-S7-001', name: 'FQC检验任务列表', paths: ['/aidop/s7/fqc/task-list'], names: ['aidopS7FqcTaskList'] },
+	{ code: 'FUNC-S7-002', name: 'FQC检验结果列表', paths: ['/aidop/s7/fqc/result-list'], names: ['aidopS7FqcResultList'] },
+	{ code: 'FUNC-S7-003', name: '生产入库单列表', paths: ['/aidop/s7/production-receipt/order-list'], names: ['aidopS7ProductionReceiptOrderList'] },
+	{ code: 'FUNC-S7-004', name: '销售发货通知', paths: ['/aidop/s7/finished-outbound/sales-shipment-notice'], names: ['aidopS7FinishedOutboundSalesShipmentNotice'] },
+	{ code: 'FUNC-S7-005', name: '发货任务看板', paths: ['/aidop/s7/finished-warehouse-kanban/shipment-task'], names: ['aidopS7FinishedWarehouseKanbanShipmentTask'] },
+	{ code: 'FUNC-S7-006', name: '成品滞销看板', paths: ['/aidop/s7/finished-warehouse-kanban/sluggish'], names: ['aidopS7FinishedWarehouseKanbanSluggish'] },
+	{ code: 'FUNC-S7-007', name: 'S7成品仓储看板', paths: ['/aidop/smart-ops/s7', '/aidop/kanban/s7'], names: ['aidopSmartOpsS7'] },
+
+	// ── S8 异常监控(扩展编号)──
+	{ code: 'FUNC-S8-001', name: '异常监控看板', paths: ['/aidop/s8/dashboard', '/aidop/smart-ops/s8', '/aidop/kanban/s8'], names: ['aidopS8Dashboard', 'aidopSmartOpsS8'] },
+	{ code: 'FUNC-S8-002', name: '异常监控大屏', paths: ['/aidop/s8/monitoring/overview'], names: ['aidopS8MonitoringOverview'] },
+	{ code: 'FUNC-S8-003', name: '交付异常大屏', paths: ['/aidop/s8/monitoring/delivery'], names: ['aidopS8MonitoringDelivery'] },
+	{ code: 'FUNC-S8-004', name: '生产异常大屏', paths: ['/aidop/s8/monitoring/production'], names: ['aidopS8MonitoringProduction'] },
+	{ code: 'FUNC-S8-005', name: '供应异常大屏', paths: ['/aidop/s8/monitoring/supply'], names: ['aidopS8MonitoringSupply'] },
+	{ code: 'FUNC-S8-006', name: '订单执行档案', paths: ['/aidop/s8/monitoring/order-execution'], names: ['aidopS8OrderExecution'] },
+	{ code: 'FUNC-S8-007', name: '订单链路全景', paths: ['/aidop/s8/monitoring/order-execution/chain'], names: ['aidopS8OrderExecutionChain'] },
+	{ code: 'FUNC-S8-008', name: '异常列表', paths: ['/aidop/s8/exceptions'], names: ['aidopS8ExceptionList'] },
+	{ code: 'FUNC-S8-009', name: '主动提报', paths: ['/aidop/s8/report'], names: ['aidopS8ManualReport'] },
+	{ code: 'FUNC-S8-010', name: '配置中心', paths: ['/aidop/s8/config'], names: ['aidopS8ConfigHub'] },
+	{ code: 'FUNC-S8-011', name: '场景基础配置', paths: ['/aidop/s8/config/scenes'], names: ['aidopS8ScenarioConfig'] },
+	{ code: 'FUNC-S8-012', name: '通知分层配置', paths: ['/aidop/s8/config/notifications'], names: ['aidopS8NotificationLayerConfig'] },
+	{ code: 'FUNC-S8-013', name: '角色权限配置', paths: ['/aidop/s8/config/roles'], names: ['aidopS8RolePermissionConfig'] },
+	{ code: 'FUNC-S8-014', name: '报警规则配置', paths: ['/aidop/s8/config/alert-rules'], names: ['aidopS8AlertRulesConfig'] },
+	{ code: 'FUNC-S8-015', name: '数据源配置', paths: ['/aidop/s8/config/data-sources'], names: ['aidopS8DataSourceConfig'] },
+	{ code: 'FUNC-S8-016', name: '监视规则配置', paths: ['/aidop/s8/config/watch-rules'], names: ['aidopS8WatchRuleConfig'] },
+	{ code: 'FUNC-S8-017', name: '异常类型配置', paths: ['/aidop/s8/config/exception-types'], names: ['aidopS8ExceptionTypeConfig'] },
+	{ code: 'FUNC-S8-018', name: '大屏卡片配置', paths: ['/aidop/s8/config/dashboard-cells'], names: ['aidopS8DashboardCellConfig'] },
+	{ code: 'FUNC-S8-019', name: '任务详情', paths: ['/aidop/s8/exceptions/:id'], names: ['aidopS8TaskDetail'] },
+
+	// ── S9 运营指标(扩展编号;规划占位菜单 path 为 /aidop/s9/00n)──
+	{ code: 'FUNC-S9-001', name: 'ERP同步', paths: ['/aidop/s9/001'] },
+	{ code: 'FUNC-S9-002', name: '日志查询', paths: ['/aidop/s9/002'] },
+	{ code: 'FUNC-S9-003', name: 'ERP事务', paths: ['/aidop/s9/003'] },
+	{ code: 'FUNC-S9-004', name: 'S9运营指标看板', paths: ['/aidop/smart-ops/s9', '/aidop/kanban/s9'], names: ['aidopSmartOpsS9'] },
+	{ code: 'FUNC-S9-005', name: '九宫格智慧运营看板', paths: ['/aidop/smart-ops/grid', '/dashboard/home'], names: ['aidopSmartOpsGrid'] },
+	{ code: 'FUNC-S9-006', name: '智慧诊断', paths: ['/aidop/smart-diagnosis'], names: ['aidopSmartDiagnosis'] },
+	{ code: 'FUNC-S9-010', name: '数据中台工作台', paths: ['/aidop/data-platform/overview'], names: ['aidopDataPlatformOverview'] },
+	{ code: 'FUNC-S9-011', name: '数据地图', paths: ['/aidop/data-platform/data-map'], names: ['aidopDataPlatformDataMap'] },
+	{ code: 'FUNC-S9-012', name: '数据源管理', paths: ['/aidop/data-platform/sources'], names: ['aidopDataPlatformSources'] },
+	{ code: 'FUNC-S9-013', name: '同步配置中心', paths: ['/aidop/data-platform/sync-tasks'], names: ['aidopDataPlatformSyncTasks'] },
+	{ code: 'FUNC-S9-014', name: '数据任务日志', paths: ['/aidop/data-platform/sync-logs'], names: ['aidopDataPlatformSyncLogs'] },
+];
+
+function buildLookupMaps() {
+	const byPath: Record<string, AidopFuncMeta> = {};
+	const byName: Record<string, AidopFuncMeta> = {};
+	for (const def of FUNC_DEFS) {
+		const meta = { code: def.code, name: def.name };
+		for (const p of def.paths ?? []) byPath[normalizePath(p)] = meta;
+		for (const n of def.names ?? []) byName[n] = meta;
+	}
+	return { byPath, byName };
+}
+
+const { byPath: AIDOP_FUNC_BY_PATH, byName: AIDOP_FUNC_BY_NAME } = buildLookupMaps();
+
+/** 按路由 path 解析(支持动态段:取最长前缀匹配) */
+export function resolveAidopFuncByPath(path: string | undefined | null): AidopFuncMeta | null {
+	if (!path) return null;
+	const normalized = normalizePath(path);
+	if (AIDOP_FUNC_BY_PATH[normalized]) return AIDOP_FUNC_BY_PATH[normalized];
+
+	const segments = normalized.split('/').filter(Boolean);
+	for (let i = segments.length; i > 0; i--) {
+		const prefix = `/${segments.slice(0, i).join('/')}`;
+		if (AIDOP_FUNC_BY_PATH[prefix]) return AIDOP_FUNC_BY_PATH[prefix];
+	}
+	return null;
+}
+
+export function resolveAidopFuncByName(name: string | undefined | null): AidopFuncMeta | null {
+	if (!name) return null;
+	return AIDOP_FUNC_BY_NAME[name] ?? null;
+}
+
+export function resolveAidopFuncCode(path?: string | null, name?: string | null): AidopFuncMeta | null {
+	return resolveAidopFuncByPath(path) ?? resolveAidopFuncByName(name);
+}

+ 9 - 0
Web/src/layout/navBars/topBar/breadcrumb.vue

@@ -12,6 +12,7 @@
                         <SvgIcon v-if="themeConfig.isBreadcrumbIcon" :name="v.meta.icon" />
                         <span v-if="v.meta.title">{{ v.meta.title }}</span>
                         <span v-else>{{ v.meta.tagsViewName }}</span>
+                        <span v-if="v.meta.funcCode" class="bar-breadcrumb-func">{{ v.meta.funcCode }}</span>
                     </div>
                     <div v-else class="bar-breadcrumb-item">
                         <a @click.prevent="onBreadcrumbClick(v)"> 
@@ -138,4 +139,12 @@ onBeforeRouteUpdate((to) => {
 
     &-last { opacity: 0.7; }
 }
+
+.bar-breadcrumb-func {
+	margin-left: 8px;
+	font-size: 11px;
+	font-variant-numeric: tabular-nums;
+	color: var(--el-color-primary);
+	opacity: 0.85;
+}
 </style>

+ 21 - 6
Web/src/layout/navBars/topBar/search.vue

@@ -5,7 +5,7 @@
 				<el-autocomplete
 					v-model="state.menuQuery"
 					:fetch-suggestions="menuSearch"
-					placeholder="菜单搜索:支持中文、路由路径"
+					placeholder="菜单搜索:支持中文、路由路径、功能编号"
 					ref="layoutMenuAutocompleteRef"
 					@select="onHandleSelect"
 					:fit-input-width="true"
@@ -16,9 +16,10 @@
 						</el-icon>
 					</template>
 					<template #default="{ item }">
-						<div style="display: inline-flex; align-items: center;">
+						<div style="display: inline-flex; align-items: center; gap: 6px;">
 							<SvgIcon :name="item.meta.icon" class="mr5" />
-							{{ item.meta.title }}
+							<span>{{ item.meta.title }}</span>
+							<span v-if="item.meta.funcSeq" class="layout-search-func">{{ item.meta.funcSeq }}</span>
 						</div>
 					</template>
 				</el-autocomplete>
@@ -67,10 +68,16 @@ const menuSearch = (queryString: string, cb: Function) => {
 // 菜单搜索过滤
 const createFilter = (queryString: string) => {
 	return (restaurant: RouteItem) => {
+		const title = restaurant.meta?.title ?? '';
+		const funcCode = (restaurant.meta as any)?.funcCode ?? '';
+		const funcSeq = (restaurant.meta as any)?.funcSeq ?? '';
+		const q = queryString.toLowerCase();
 		return (
-			restaurant.path.toLowerCase().indexOf(queryString.toLowerCase()) > -1 ||
-			restaurant.meta!.title!.toLowerCase().indexOf(queryString.toLowerCase()) > -1 ||
-			restaurant.meta!.title!.indexOf(queryString.toLowerCase()) > -1
+			restaurant.path.toLowerCase().indexOf(q) > -1 ||
+			title.toLowerCase().indexOf(q) > -1 ||
+			title.indexOf(queryString) > -1 ||
+			funcCode.toLowerCase().indexOf(q) > -1 ||
+			funcSeq.indexOf(q) > -1
 		);
 	};
 };
@@ -123,4 +130,12 @@ defineExpose({
 		transform: translateX(-50%);
 	}
 }
+
+.layout-search-func {
+	font-size: 10px;
+	padding: 1px 4px;
+	border-radius: 3px;
+	color: var(--el-color-primary);
+	background: var(--el-color-primary-light-9);
+}
 </style>

+ 77 - 0
Web/src/layout/navMenu/AidopMenuTitle.vue

@@ -0,0 +1,77 @@
+<template>
+	<el-tooltip v-if="funcSeq" :content="tooltip" placement="right" :show-after="400" :disabled="isCollapse">
+		<span class="aidop-menu-title" :class="{ 'is-collapse': isCollapse }">
+			<span class="aidop-menu-title__text">{{ title }}</span>
+			<span class="aidop-menu-title__badge">{{ funcSeq }}</span>
+		</span>
+	</el-tooltip>
+	<span v-else class="aidop-menu-title__text-only">{{ title }}</span>
+</template>
+
+<script setup lang="ts" name="aidopMenuTitle">
+import { computed } from 'vue';
+import { formatFuncTooltip } from '/@/utils/aidopFuncCode';
+
+const props = withDefaults(
+	defineProps<{
+		title?: string;
+		funcCode?: string | null;
+		funcName?: string | null;
+		funcSeq?: string | null;
+		isCollapse?: boolean;
+	}>(),
+	{
+		title: '',
+		funcCode: null,
+		funcName: null,
+		funcSeq: null,
+		isCollapse: false,
+	}
+);
+
+const tooltip = computed(() =>
+	formatFuncTooltip(
+		props.funcCode ? { code: props.funcCode, name: props.funcName ?? '' } : null
+	)
+);
+</script>
+
+<style scoped lang="scss">
+.aidop-menu-title {
+	display: inline-flex;
+	align-items: center;
+	gap: 6px;
+	max-width: 100%;
+	min-width: 0;
+	vertical-align: middle;
+
+	&__text {
+		overflow: hidden;
+		text-overflow: ellipsis;
+		white-space: nowrap;
+		min-width: 0;
+	}
+
+	&__badge {
+		flex-shrink: 0;
+		font-size: 10px;
+		line-height: 1;
+		padding: 2px 4px;
+		border-radius: 3px;
+		font-variant-numeric: tabular-nums;
+		color: var(--el-color-primary);
+		background: var(--el-color-primary-light-9);
+		border: 1px solid var(--el-color-primary-light-7);
+	}
+
+	&.is-collapse &__badge {
+		display: none;
+	}
+}
+
+.aidop-menu-title__text-only {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+}
+</style>

+ 7 - 1
Web/src/layout/navMenu/horizontal.vue

@@ -13,7 +13,12 @@
 					<el-menu-item :index="val.path" :key="val.path">
 						<template #title v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)">
 							<SvgIcon :name="val.meta.icon" />
-							{{ val.meta.title }}
+							<AidopMenuTitle
+								:title="val.meta.title"
+								:func-code="val.meta.funcCode"
+								:func-name="val.meta.funcName"
+								:func-seq="val.meta.funcSeq"
+							/>
 						</template>
 						<template #title v-else>
 							<a class="w100" @click.prevent="onALinkClick(val)">
@@ -39,6 +44,7 @@ import mittBus from '/@/utils/mitt';
 
 // 引入组件
 const SubItem = defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue'));
+const AidopMenuTitle = defineAsyncComponent(() => import('/@/layout/navMenu/AidopMenuTitle.vue'));
 
 // 定义父组件传过来的值
 const props = defineProps({

+ 15 - 3
Web/src/layout/navMenu/subItem.vue

@@ -3,7 +3,12 @@
 		<el-sub-menu :index="val.path" :key="val.path" v-if="val.children && val.children.length > 0">
 			<template #title>
 				<SvgIcon :name="val.meta.icon" class="el-icon" />
-				<span>{{ val.meta.title }}</span>
+				<AidopMenuTitle
+					:title="val.meta.title"
+					:func-code="val.meta.funcCode"
+					:func-name="val.meta.funcName"
+					:func-seq="val.meta.funcSeq"
+				/>
 			</template>
 			<sub-item :chil="val.children" />
 		</el-sub-menu>
@@ -11,7 +16,12 @@
 			<el-menu-item :index="val.path" :key="val.path">
 				<template v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)">
 					<SvgIcon :name="val.meta.icon" class="el-icon" />
-					<span>{{ val.meta.title }}</span>
+					<AidopMenuTitle
+						:title="val.meta.title"
+						:func-code="val.meta.funcCode"
+						:func-name="val.meta.funcName"
+						:func-seq="val.meta.funcSeq"
+					/>
 				</template>
 				<template v-else>
 					<a class="w100" @click.prevent="onALinkClick(val)">
@@ -25,10 +35,12 @@
 </template>
 
 <script setup lang="ts" name="navMenuSubItem">
-import { computed } from 'vue';
+import { computed, defineAsyncComponent } from 'vue';
 import { RouteRecordRaw } from 'vue-router';
 import other from '/@/utils/other';
 
+const AidopMenuTitle = defineAsyncComponent(() => import('/@/layout/navMenu/AidopMenuTitle.vue'));
+
 // 定义父组件传过来的值
 const props = defineProps({
 	// 菜单列表

+ 15 - 2
Web/src/layout/navMenu/vertical.vue

@@ -11,7 +11,13 @@
 			<el-sub-menu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
 				<template #title>
 					<SvgIcon :name="val.meta.icon" class="el-icon" />
-					<span>{{ val.meta.title }}</span>
+					<AidopMenuTitle
+						:title="val.meta.title"
+						:func-code="val.meta.funcCode"
+						:func-name="val.meta.funcName"
+						:func-seq="val.meta.funcSeq"
+						:is-collapse="state.isCollapse"
+					/>
 				</template>
 				<SubItem :chil="val.children" />
 			</el-sub-menu>
@@ -19,7 +25,13 @@
 				<el-menu-item :index="val.path" :key="val.path">
 					<SvgIcon :name="val.meta.icon" class="el-icon" />
 					<template #title v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)">
-						<span>{{ val.meta.title }}</span>
+						<AidopMenuTitle
+							:title="val.meta.title"
+							:func-code="val.meta.funcCode"
+							:func-name="val.meta.funcName"
+							:func-seq="val.meta.funcSeq"
+							:is-collapse="state.isCollapse"
+						/>
 					</template>
 					<template #title v-else>
 						<a class="w100" @click.prevent="onALinkClick(val)">{{ val.meta.title }}</a>
@@ -39,6 +51,7 @@ import other from '/@/utils/other';
 
 // 引入组件
 const SubItem = defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue'));
+const AidopMenuTitle = defineAsyncComponent(() => import('/@/layout/navMenu/AidopMenuTitle.vue'));
 
 // 定义父组件传过来的值
 const props = defineProps({

+ 55 - 0
Web/src/utils/aidopFuncCode.ts

@@ -0,0 +1,55 @@
+import {
+	formatFuncTooltip,
+	parseFuncSeq,
+	resolveAidopFuncCode,
+	type AidopFuncMeta,
+} from '/@/constants/aidopFuncCodes';
+
+type MenuLike = Record<string, any>;
+
+const LAYOUT_COMPONENTS = new Set(['Layout', 'Parent']);
+
+function isLeafMenu(item: MenuLike): boolean {
+	if (item.children?.length) return false;
+	const comp = (item.component as string | undefined) ?? '';
+	if (!comp || LAYOUT_COMPONENTS.has(comp)) return false;
+	return true;
+}
+
+/** 为菜单树叶子注入 meta.funcCode / meta.funcName / meta.funcSeq */
+export function patchAidopFuncCodes(routes: MenuLike[] | undefined): void {
+	if (!routes?.length) return;
+	for (const item of routes) {
+		if (item.children?.length) {
+			patchAidopFuncCodes(item.children);
+		}
+		if (!isLeafMenu(item)) continue;
+
+		const path = item.path as string | undefined;
+		const name = item.name as string | undefined;
+		const func = resolveAidopFuncCode(path, name);
+		if (!func) continue;
+
+		item.meta = item.meta ?? {};
+		item.meta.funcCode = func.code;
+		item.meta.funcName = func.name;
+		item.meta.funcSeq = parseFuncSeq(func.code);
+	}
+}
+
+export function getRouteFuncMeta(route: { path?: string; name?: string | symbol | null; meta?: Record<string, any> }): AidopFuncMeta | null {
+	const meta = route.meta;
+	if (meta?.funcCode) {
+		return { code: meta.funcCode as string, name: (meta.funcName as string) ?? '' };
+	}
+	const name = typeof route.name === 'string' ? route.name : null;
+	return resolveAidopFuncCode(route.path, name);
+}
+
+export function buildFuncSubtitle(route: { path?: string; name?: string | symbol | null; meta?: Record<string, any> }, fallback = ''): string {
+	const func = getRouteFuncMeta(route);
+	if (!func?.code) return fallback;
+	return formatFuncTooltip(func);
+}
+
+export { formatFuncTooltip, parseFuncSeq };

+ 3 - 0
Web/src/utils/aidopMenuDisplay.ts

@@ -1,3 +1,5 @@
+import { patchAidopFuncCodes } from '/@/utils/aidopFuncCode';
+
 /**
  * Ai-DOP 侧栏一级目录显示名(与 ai-dop-platform/tools/gen_aidop_menu.py 中模块编码一致)。
  * 在登录菜单树写入路由前覆盖 meta.title,避免库中仍为旧标题时侧栏不更新。
@@ -368,6 +370,7 @@ export function patchAidopMenuTitles(routes: any[] | undefined): void {
 	patchSmartOpsRouteComponents(routes as AMenu[]);
 	patchS8ConfigRouteComponents(routes as AMenu[]);
 	patchS4DeliveryAuxRouteComponents(routes as AMenu[]);
+	patchAidopFuncCodes(routes as AMenu[]);
 	for (const item of routes) {
 		const name = item.name as string | undefined;
 		if (name && AIDOP_DIRECTORY_TITLES[name]) {

+ 27 - 3
Web/src/views/aidop/components/AidopDemoShell.vue

@@ -4,8 +4,11 @@
 			<div class="aidop-demo-shell__bar-left">
 				<div class="aidop-demo-shell__mark" aria-hidden="true" />
 				<div class="aidop-demo-shell__titles">
-					<h2>{{ title }}</h2>
-					<p v-if="subtitle">{{ subtitle }}</p>
+					<h2>
+						{{ title }}
+						<span v-if="funcSeq" class="aidop-demo-shell__func-badge">{{ funcSeq }}</span>
+					</h2>
+					<p v-if="displaySubtitle">{{ displaySubtitle }}</p>
 				</div>
 			</div>
 			<slot name="bar-right" />
@@ -17,7 +20,11 @@
 </template>
 
 <script setup lang="ts" name="aidopDemoShell">
-withDefaults(
+import { computed } from 'vue';
+import { useRoute } from 'vue-router';
+import { buildFuncSubtitle, getRouteFuncMeta, parseFuncSeq } from '/@/utils/aidopFuncCode';
+
+const props = withDefaults(
 	defineProps<{
 		title: string;
 		subtitle?: string;
@@ -30,6 +37,23 @@ withDefaults(
 		cardBodyPadding: '12px',
 	}
 );
+
+const route = useRoute();
+
+const displaySubtitle = computed(() => {
+	const funcLine = buildFuncSubtitle(route);
+	if (!funcLine) return props.subtitle;
+	if (!props.subtitle) return funcLine;
+	if (props.subtitle.includes('FUNC-')) return props.subtitle;
+	return `${funcLine} · ${props.subtitle}`;
+});
+
+const funcSeq = computed(() => {
+	const meta = route.meta as Record<string, unknown>;
+	if (typeof meta.funcSeq === 'string' && meta.funcSeq) return meta.funcSeq;
+	const func = getRouteFuncMeta(route);
+	return func ? parseFuncSeq(func.code) : '';
+});
 </script>
 
 <style scoped lang="scss">

+ 14 - 0
Web/src/views/aidop/styles/aidop-demo.scss

@@ -42,6 +42,20 @@
 	font-weight: 600;
 	color: #f8fafc;
 	letter-spacing: 0.02em;
+	display: inline-flex;
+	align-items: center;
+	gap: 8px;
+}
+
+.aidop-demo-shell__func-badge {
+	font-size: 11px;
+	font-weight: 500;
+	padding: 2px 6px;
+	border-radius: 4px;
+	font-variant-numeric: tabular-nums;
+	color: #38bdf8;
+	background: rgba(56, 189, 248, 0.15);
+	border: 1px solid rgba(56, 189, 248, 0.35);
 }
 
 .aidop-demo-shell__titles p {