|
|
@@ -0,0 +1,140 @@
|
|
|
+-- ===========================================================================
|
|
|
+-- UAT 租户占位菜单收口(S0 / S5 / S6 / S7)
|
|
|
+--
|
|
|
+-- 背景:一批菜单已在 SysMenu 全局登记,但 Component 仍指向通用占位页
|
|
|
+-- `/aidop/planning/index`(AidopDemoShell + el-empty「后续在此接入 Ai-DOP
|
|
|
+-- 业务页面」),对应前端业务目录与组件均不存在,属「纯菜单占位、零实现」。
|
|
|
+-- UAT 租户(SysOrg.Code = 'UATTEST_CHL')的测试账号能正常点进这些空壳页。
|
|
|
+--
|
|
|
+-- 目标:只让该 UAT 租户看不到这些占位功能。
|
|
|
+-- - 不删除、不禁用、不隐藏任何 SysMenu 全局记录
|
|
|
+-- - 不影响其余 9 个租户
|
|
|
+-- - 不改前端,不硬编码 tenantId
|
|
|
+--
|
|
|
+-- 机制:菜单可见性 = SysMenu(Type≠Btn ∧ Status=Enable)
|
|
|
+-- ∩ SysTenantMenu[登录租户]
|
|
|
+-- ∩ SysRoleMenu[用户角色集](含祖先补全)
|
|
|
+-- 其中 SysTenantMenu 是唯一的「租户维度」硬白名单
|
|
|
+-- (SysMenuService.GetSugarQueryableAndTenantId → InnerJoinIF<SysTenantMenu>),
|
|
|
+-- 对该租户内所有账号类型生效(含 SysAdmin 888),且会同时收窄
|
|
|
+-- 「该租户内新建角色时的可选菜单范围」
|
|
|
+-- (SysRoleMenuService.GrantRoleMenu 只落 SysTenantMenu 允许集合的交集)。
|
|
|
+-- 因此从 SysTenantMenu 移除,正是「租户级隐藏」的语义。
|
|
|
+--
|
|
|
+-- ⚠️ 为什么还要配一张抑制表:
|
|
|
+-- AidopMenuLinkSync.EnsureLinked(Plugin.AiDOP/Startup.cs:79,每次进程启动
|
|
|
+-- 无条件执行)会把 Ai-DOP 种子菜单回填到**全部租户**的 SysTenantMenu,判据
|
|
|
+-- 只有「这行还在吗」,且主键是 (tenantId, menuId) 的确定性哈希 —— 单纯 DELETE
|
|
|
+-- 会在下一次 restart_aidop.sh 后以同一主键原样复活。ado_tenant_menu_suppression
|
|
|
+-- 给回填逻辑一个「这是有意取消的」显式信号,并由启动逻辑强制执行,重启自愈。
|
|
|
+--
|
|
|
+-- 范围:12 个占位叶子(S0×1 + S5×4 + S6×5 + S7×2)
|
|
|
+-- + 4 个「子项全为占位」的父目录 = 16 对 (TenantId, MenuId)。
|
|
|
+-- S0 的父节点「S0 运营建模」下另有「数据建模」真实子树(58 个已实现页面),
|
|
|
+-- 故父节点**不摘**。
|
|
|
+-- S8 经审计**无**任何 planning 占位菜单,本脚本不涉及 S8。
|
|
|
+-- S9 / S4 / M11-M16 的占位菜单**本轮明确不处理**。
|
|
|
+--
|
|
|
+-- 幂等:CREATE TABLE IF NOT EXISTS / INSERT ... WHERE NOT EXISTS / DELETE,
|
|
|
+-- 可重复执行,重跑影响行数为 0。
|
|
|
+-- 校验:1.0.424.verify.sql(AutoVersionUpdate 自动逐条真值断言)
|
|
|
+-- 对账/回滚:UAT-PLACEHOLDER-MENU-HIDE.ops.sql(人工执行,不会被自动运行)
|
|
|
+-- ===========================================================================
|
|
|
+
|
|
|
+-- 租户由稳定业务键解析,不写死数字 Id(与 1.0.420.sql 同口径)
|
|
|
+SET @t_uat := (SELECT t.Id FROM SysTenant t JOIN SysOrg o ON o.Id = t.OrgId
|
|
|
+ WHERE o.Code = 'UATTEST_CHL' AND t.Status = 1 LIMIT 1);
|
|
|
+
|
|
|
+
|
|
|
+-- ---------------------------------------------------------------------------
|
|
|
+-- 00 · 抑制清单表
|
|
|
+-- ---------------------------------------------------------------------------
|
|
|
+CREATE TABLE IF NOT EXISTS `ado_tenant_menu_suppression` (
|
|
|
+ `Id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
|
|
+ `TenantId` bigint NOT NULL COMMENT '租户 Id(SysTenant.Id)',
|
|
|
+ `MenuId` bigint NOT NULL COMMENT '菜单 Id(SysMenu.Id)',
|
|
|
+ `Reason` varchar(256) NULL COMMENT '抑制原因(为何该租户不应看到该菜单)',
|
|
|
+ `CreatedAt` datetime NOT NULL COMMENT '创建时间',
|
|
|
+ PRIMARY KEY (`Id`),
|
|
|
+ UNIQUE KEY `uk_tenant_menu_suppression` (`TenantId`, `MenuId`)
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户级菜单抑制清单';
|
|
|
+
|
|
|
+
|
|
|
+-- ---------------------------------------------------------------------------
|
|
|
+-- 01 · 占位叶子(15 条)
|
|
|
+-- 双重业务键:Path 命中 + Component 必须仍是占位页。
|
|
|
+-- 若某条日后被换成真实组件,这里自然不再命中,不会误抑制真实功能。
|
|
|
+-- ---------------------------------------------------------------------------
|
|
|
+INSERT INTO ado_tenant_menu_suppression (TenantId, MenuId, Reason, CreatedAt)
|
|
|
+SELECT @t_uat, m.Id, CONCAT('UAT 收口:未实现占位页 ', m.Path), NOW()
|
|
|
+FROM SysMenu m
|
|
|
+WHERE @t_uat IS NOT NULL
|
|
|
+ AND m.Component = '/aidop/planning/index'
|
|
|
+ AND m.Path IN (
|
|
|
+ -- S0 业务建模(FUNC-S0-065)
|
|
|
+ -- 该条 SysMenu.Status 已为 2/停用、当前本就不渲染;纳入抑制是为了口径一致 +
|
|
|
+ -- 防御「日后有人把 Status 改回 1 时它在 UAT 租户重新冒出来」。
|
|
|
+ '/aidop/s0/002',
|
|
|
+ -- S5 物料仓储看板(FUNC-S5-014 ~ 017)
|
|
|
+ '/aidop/s5/warehouse-kanban/receiving-task',
|
|
|
+ '/aidop/s5/warehouse-kanban/issuing-task',
|
|
|
+ '/aidop/s5/warehouse-kanban/turnover-report',
|
|
|
+ '/aidop/s5/warehouse-kanban/age-analysis',
|
|
|
+ -- S6 生产记录管理(FUNC-S6-001)
|
|
|
+ '/aidop/s6/production-record/order-list',
|
|
|
+ -- S6 生产执行看板(FUNC-S6-005 ~ 008)
|
|
|
+ '/aidop/s6/execution-kanban/work-order',
|
|
|
+ '/aidop/s6/execution-kanban/workshop-efficiency',
|
|
|
+ '/aidop/s6/execution-kanban/equipment-oee',
|
|
|
+ '/aidop/s6/execution-kanban/labor-hours',
|
|
|
+ -- S7 成品仓储看板(FUNC-S7-005 / 006)
|
|
|
+ '/aidop/s7/finished-warehouse-kanban/shipment-task',
|
|
|
+ '/aidop/s7/finished-warehouse-kanban/sluggish'
|
|
|
+ )
|
|
|
+ AND NOT EXISTS (SELECT 1 FROM ado_tenant_menu_suppression s
|
|
|
+ WHERE s.TenantId = @t_uat AND s.MenuId = m.Id);
|
|
|
+
|
|
|
+
|
|
|
+-- ---------------------------------------------------------------------------
|
|
|
+-- 02 · 纯占位父目录(5 条)
|
|
|
+-- 菜单树不会自动裁掉空父节点:后端 ToTree 无 children.Any() 判断,
|
|
|
+-- ExpandMenuIdsWithAncestorsAsync 只正向补祖先;前端 vertical.vue 对
|
|
|
+-- children.length===0 的目录走 v-else 渲染成**可点击的死链 el-menu-item**。
|
|
|
+-- 所以父目录必须显式一并移除。
|
|
|
+--
|
|
|
+-- 安全断言:只在「该目录下所有非按钮子菜单都是占位」时才登记。
|
|
|
+-- 任何一个真实子菜单存在 → 整条不命中 → 绝不会摘掉还有真实功能的目录。
|
|
|
+-- ---------------------------------------------------------------------------
|
|
|
+INSERT INTO ado_tenant_menu_suppression (TenantId, MenuId, Reason, CreatedAt)
|
|
|
+SELECT @t_uat, m.Id, CONCAT('UAT 收口:子项全为占位,避免留下空壳目录 ', m.Path), NOW()
|
|
|
+FROM SysMenu m
|
|
|
+WHERE @t_uat IS NOT NULL
|
|
|
+ AND m.Path IN (
|
|
|
+ '/aidop/s5/warehouse-kanban', -- 物料仓储看板
|
|
|
+ '/aidop/s6/production-record', -- 生产记录管理
|
|
|
+ '/aidop/s6/execution-kanban', -- 生产执行看板
|
|
|
+ '/aidop/s7/finished-warehouse-kanban' -- 成品仓储看板
|
|
|
+ )
|
|
|
+ -- 必须确有子菜单(防止把一个孤立节点当目录摘掉)
|
|
|
+ AND EXISTS (SELECT 1 FROM SysMenu c WHERE c.Pid = m.Id AND c.Type <> 3)
|
|
|
+ -- 且非按钮子菜单必须 100% 是占位页
|
|
|
+ AND NOT EXISTS (
|
|
|
+ SELECT 1 FROM SysMenu c
|
|
|
+ WHERE c.Pid = m.Id
|
|
|
+ AND c.Type <> 3
|
|
|
+ AND (c.Component IS NULL OR c.Component <> '/aidop/planning/index')
|
|
|
+ )
|
|
|
+ AND NOT EXISTS (SELECT 1 FROM ado_tenant_menu_suppression s
|
|
|
+ WHERE s.TenantId = @t_uat AND s.MenuId = m.Id);
|
|
|
+
|
|
|
+
|
|
|
+-- ---------------------------------------------------------------------------
|
|
|
+-- 03 · 按抑制清单移除该租户的菜单授权
|
|
|
+-- 只删 SysTenantMenu,且只删 @t_uat 这一个租户的行。
|
|
|
+-- **不动 SysRoleMenu** —— 角色授权保留,撤销抑制后可精确还原原可见性。
|
|
|
+-- **不动 SysMenu** —— 全局菜单定义零改动。
|
|
|
+-- ---------------------------------------------------------------------------
|
|
|
+DELETE tm FROM SysTenantMenu tm
|
|
|
+JOIN ado_tenant_menu_suppression s
|
|
|
+ ON s.TenantId = tm.TenantId AND s.MenuId = tm.MenuId
|
|
|
+WHERE tm.TenantId = @t_uat;
|