AidopMenuLinkSync.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using Admin.NET.Core;
  2. using Microsoft.Extensions.DependencyInjection;
  3. using SqlSugar;
  4. namespace Admin.NET.Plugin.AiDOP.Infrastructure;
  5. /// <summary>
  6. /// 将 Ai-DOP 种子菜单 Id 补写到 <c>sys_tenant_menu</c> / <c>sys_role_menu</c>。
  7. /// 解决:<c>SysTenantMenuSeedData</c> 带 IgnoreUpdateSeed,库已存在时新增菜单不会自动进租户/角色;多租户下仅补默认租户会导致其它租户侧栏与菜单管理不可见。
  8. /// </summary>
  9. public static class AidopMenuLinkSync
  10. {
  11. /// <summary>与框架种子中首条「系统管理员」角色 Id 一致。</summary>
  12. private const long SysAdminRoleId = 1300000000101L;
  13. private const long LegacyMaterialSubstitutionMenuId = 1329003000005L;
  14. private const long DeprecatedMaterialSubstitutionMenuId = 1329002000004L;
  15. public static void EnsureLinked(IServiceProvider services)
  16. {
  17. using var scope = services.CreateScope();
  18. var db = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
  19. NormalizeMaterialSubstitutionMenu(db);
  20. var seedMenus = new global::Admin.NET.Plugin.AiDOP.SysMenuSeedData().HasData().ToList();
  21. var seedMenuIds = seedMenus.Select(m => m.Id).ToHashSet();
  22. var existingMenuIds = db.Queryable<SysMenu>()
  23. .Where(m => seedMenuIds.Contains(m.Id))
  24. .Select(m => m.Id)
  25. .ToList()
  26. .ToHashSet();
  27. if (existingMenuIds.Count == 0)
  28. return;
  29. var tenantIds = db.Queryable<SysTenant>().Select(t => t.Id).ToList();
  30. if (tenantIds.Count == 0)
  31. return;
  32. var tenantMenuPairs = db.Queryable<SysTenantMenu>()
  33. .Where(tm => tenantIds.Contains(tm.TenantId) && seedMenuIds.Contains(tm.MenuId))
  34. .Select(tm => new { tm.TenantId, tm.MenuId })
  35. .ToList()
  36. .Select(x => (x.TenantId, x.MenuId))
  37. .ToHashSet();
  38. var tenantRows = new List<SysTenantMenu>();
  39. foreach (var tid in tenantIds)
  40. {
  41. foreach (var menu in seedMenus)
  42. {
  43. if (!existingMenuIds.Contains(menu.Id))
  44. continue;
  45. if (tenantMenuPairs.Contains((tid, menu.Id)))
  46. continue;
  47. tenantRows.Add(new SysTenantMenu
  48. {
  49. Id = CommonUtil.GetFixedHashCode("" + tid + menu.Id, 1300000000000),
  50. TenantId = tid,
  51. MenuId = menu.Id
  52. });
  53. }
  54. }
  55. if (tenantRows.Count > 0)
  56. db.Insertable(tenantRows).ExecuteCommand();
  57. // 已为任一 Ai-DOP 种子菜单授权的角色,补全新增子菜单;并始终包含默认租户系统管理员角色。
  58. var roleIdsWithAnyAidop = db.Queryable<SysRoleMenu>()
  59. .Where(rm => seedMenuIds.Contains(rm.MenuId))
  60. .Select(rm => rm.RoleId)
  61. .ToList()
  62. .Distinct()
  63. .ToHashSet();
  64. roleIdsWithAnyAidop.Add(SysAdminRoleId);
  65. var roleMenuPairs = db.Queryable<SysRoleMenu>()
  66. .Where(rm => roleIdsWithAnyAidop.Contains(rm.RoleId) && seedMenuIds.Contains(rm.MenuId))
  67. .Select(rm => new { rm.RoleId, rm.MenuId })
  68. .ToList()
  69. .Select(x => (x.RoleId, x.MenuId))
  70. .ToHashSet();
  71. var roleRows = new List<SysRoleMenu>();
  72. foreach (var roleId in roleIdsWithAnyAidop)
  73. {
  74. foreach (var menu in seedMenus)
  75. {
  76. if (!existingMenuIds.Contains(menu.Id))
  77. continue;
  78. if (roleMenuPairs.Contains((roleId, menu.Id)))
  79. continue;
  80. roleRows.Add(new SysRoleMenu
  81. {
  82. Id = menu.Id + (roleId % 1300000000000),
  83. RoleId = roleId,
  84. MenuId = menu.Id
  85. });
  86. }
  87. }
  88. if (roleRows.Count > 0)
  89. db.Insertable(roleRows).ExecuteCommand();
  90. }
  91. private static void NormalizeMaterialSubstitutionMenu(ISqlSugarClient db)
  92. {
  93. var deprecatedMenuId = DeprecatedMaterialSubstitutionMenuId;
  94. var legacyMenuId = LegacyMaterialSubstitutionMenuId;
  95. var legacyMenu = db.Queryable<SysMenu>()
  96. .First(m => m.Id == legacyMenuId);
  97. if (legacyMenu != null)
  98. {
  99. legacyMenu.Title = "物料替代";
  100. legacyMenu.Path = "/aidop/s0/manufacturing/material-substitution";
  101. legacyMenu.Name = "aidopS0MfgMaterialSubstitution";
  102. legacyMenu.Component = "/aidop/s0/manufacturing/MaterialSubstitutionList";
  103. legacyMenu.Remark = "S0 物料替代";
  104. db.Updateable(legacyMenu)
  105. .UpdateColumns(m => new { m.Title, m.Path, m.Name, m.Component, m.Remark })
  106. .ExecuteCommand();
  107. }
  108. var deprecatedExists = db.Queryable<SysMenu>().Any(m => m.Id == deprecatedMenuId);
  109. if (!deprecatedExists)
  110. return;
  111. db.Deleteable<SysUserMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
  112. db.Deleteable<SysRoleMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
  113. db.Deleteable<SysTenantMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
  114. db.Deleteable<SysMenu>().Where(x => x.Id == deprecatedMenuId).ExecuteCommand();
  115. }
  116. }