-- ===========================================================================
-- 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;
