-- ============================================================================ -- 1.0.435:修复 1.0.433 引入的角色授权回归 —— 按钮权限挂载点选错导致父菜单被丢 -- -- 回归现象(RUNTIME VERIFIED): -- UATAdminA 打开 /aidop/s5/inventory/stock-query 返回 404; -- 其菜单树里「库存查询」消失,同级其余 5 个页面均在。 -- 实测 UAT_FUNCTION_USER(838258976469061) 的 SysRoleMenu 已无 MenuId=1329015030003, -- 而对照租户 B 的同名角色仍有。 -- -- 根因(CODE VERIFIED,SysMenuService.cs:468-486 角色授权树「已勾选」计算): -- foreach (var id in menuIds) { -- if (是按钮) continue; -- var children = menuList.ToChildList(..., id, false); -- if (children.Count == 0 || children.All(u => menuIds.Contains(u.Id))) continue; -- exceptList.Add(id); // 有子节点但未全部持有 → 从「已勾选」中排除 -- } -- 1.0.433 把 6 个按钮权限挂在「库存查询」(1329015030003) 下。该菜单原本是**叶子** -- (children.Count==0,永不排除);挂上按钮后,业务角色一个按钮都不持有 -- → children.All(...) 为假 → 「库存查询」被排除出已勾选集合。 -- 前端 editRole.vue:118-120 提交的是 checkedKeys ∪ halfCheckedKeys: -- 它既不在已勾选(被排除),其子节点又全未勾选(不构成半选) -- → 管理员下一次保存该角色时它被 GrantRoleMenu 全量覆盖删除。 -- 祖先目录(库存数据 / S5 物料仓储 / Ai-DOP)因仍有其他已勾选子节点而处于**半选**, -- 得以幸存,所以只丢了这一条。 -- 注:该「已勾选」计算用 GetSugarQueryableAndTenantId(0),**不按租户过滤**, -- 因此 1.0.433 只授权给 AIDOP 租户的按钮,同样会影响 UAT 租户角色的勾选态。 -- -- 修复方案: -- ① 新建**隐藏管理目录**「库存冷链入站(管理)」挂在 S5 物料仓储下, -- 6 个按钮权限改挂到它下面 → 「库存查询」恢复为叶子,永不再被排除。 -- 新目录不授予任何业务角色 → 不在任何业务角色的 menuIds 中 → 排除循环不会遍历到它。 -- 其父节点 S5 物料仓储 仍有多个已授权子节点(实测「持有 S5 目录却不持有其任何子节点」 -- 的角色数 = 0),故各角色对该目录仍为半选,不受影响。 -- ② 恢复 UAT_FUNCTION_USER 丢失的「库存查询」授权(精确到单租户单角色单菜单)。 -- -- 明确不做:不改任何按钮权限的 Permission 名、不改租户级授权范围、 -- 不给任何业务角色新增管理权限、不使用 GrantMenu 全量覆盖、不按 RoleCode 跨租户处理。 -- -- 幂等:INSERT 带 NOT EXISTS;UPDATE 带目标状态限定,重复执行影响行数为 0。 -- ============================================================================ -- --------------------------------------------------------------------------- -- 1. 新建隐藏管理目录(按钮权限的专用挂载点) -- --------------------------------------------------------------------------- INSERT INTO SysMenu (Id, Pid, Type, Name, Title, Icon, IsIframe, IsHide, IsKeepAlive, IsAffix, OrderNo, Status, Remark, CreateTime) SELECT 1329015030100, 1321000006000, 1, 'aidopS5InvInboundAdmin', '库存冷链入站(管理)', 'ele-Menu', 0, 1, 1, 0, 900, 1, 'S5 冷链入站管理权限点的专用挂载目录(隐藏)。刻意独立成节点:SysMenuService 的角色授权树会把「有子节点但未全部持有」的菜单排除出已勾选,若把按钮挂到业务页面下,会导致该页面在下次角色保存时被删除(见 1.0.433 回归)。', NOW() FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM SysMenu WHERE Id = 1329015030100); -- --------------------------------------------------------------------------- -- 2. 6 个按钮权限改挂到该隐藏目录(原挂在「库存查询」1329015030003 下) -- --------------------------------------------------------------------------- UPDATE SysMenu SET Pid = 1329015030100, UpdateTime = NOW() WHERE Type = 3 AND Pid = 1329015030003 AND Permission IN ( 's5InventoryInbound:bootstrap', 's5InventoryInbound:run-once', 's5InventoryInbound:reconcile', 's5InventoryInbound:transform-std', 's5InventoryInbound:transform-inventory-std', 's5InventoryInbound:daily-recon'); -- --------------------------------------------------------------------------- -- 3. 管理租户(AIDOP)对该隐藏目录的租户级授权(与 1.0.433 的按钮授权保持同一租户) -- --------------------------------------------------------------------------- INSERT INTO SysTenantMenu (Id, TenantId, MenuId) SELECT (SELECT IFNULL(MAX(Id), 0) + 1 FROM SysTenantMenu tm2), t.Id, 1329015030100 FROM SysTenant t JOIN SysOrg o ON o.Id = t.OrgId WHERE o.Code = 'AIDOP' AND t.Status = 1 AND EXISTS (SELECT 1 FROM SysMenu WHERE Id = 1329015030100) AND NOT EXISTS ( SELECT 1 FROM SysTenantMenu tm WHERE tm.TenantId = t.Id AND tm.MenuId = 1329015030100) LIMIT 1; -- --------------------------------------------------------------------------- -- 4. 恢复被回归删除的「库存查询」角色授权(精确单租户单角色单菜单) -- TenantId 838257186181189 / RoleId 838258976469061 / MenuId 1329015030003 -- --------------------------------------------------------------------------- INSERT INTO SysRoleMenu (Id, RoleId, MenuId) SELECT (SELECT IFNULL(MAX(Id), 0) + 1 FROM SysRoleMenu rm2), r.Id, m.Id FROM SysRole r JOIN SysMenu m ON m.Id = 1329015030003 AND m.Type = 2 AND m.Status = 1 WHERE r.Id = 838258976469061 AND r.TenantId = 838257186181189 AND r.Status = 1 AND EXISTS ( SELECT 1 FROM SysTenantMenu t WHERE t.TenantId = r.TenantId AND t.MenuId = m.Id) AND NOT EXISTS ( SELECT 1 FROM SysRoleMenu x WHERE x.RoleId = r.Id AND x.MenuId = m.Id);