using Admin.NET.Core;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
namespace Admin.NET.Plugin.AiDOP.Infrastructure;
///
/// 将 Ai-DOP 种子菜单 Id 补写到 sys_tenant_menu / sys_role_menu。
/// 解决:SysTenantMenuSeedData 带 IgnoreUpdateSeed,库已存在时新增菜单不会自动进租户/角色;多租户下仅补默认租户会导致其它租户侧栏与菜单管理不可见。
///
public static class AidopMenuLinkSync
{
/// 与框架种子中首条「系统管理员」角色 Id 一致。
private const long SysAdminRoleId = 1300000000101L;
private const long LegacyMaterialSubstitutionMenuId = 1329003000005L;
private const long DeprecatedMaterialSubstitutionMenuId = 1329002000004L;
public static void EnsureLinked(IServiceProvider services)
{
using var scope = services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService();
NormalizeMaterialSubstitutionMenu(db);
var seedMenus = new global::Admin.NET.Plugin.AiDOP.SysMenuSeedData().HasData().ToList();
var seedMenuIds = seedMenus.Select(m => m.Id).ToHashSet();
var existingMenuIds = db.Queryable()
.Where(m => seedMenuIds.Contains(m.Id))
.Select(m => m.Id)
.ToList()
.ToHashSet();
if (existingMenuIds.Count == 0)
return;
var tenantIds = db.Queryable().Select(t => t.Id).ToList();
if (tenantIds.Count == 0)
return;
var tenantMenuPairs = db.Queryable()
.Where(tm => tenantIds.Contains(tm.TenantId) && seedMenuIds.Contains(tm.MenuId))
.Select(tm => new { tm.TenantId, tm.MenuId })
.ToList()
.Select(x => (x.TenantId, x.MenuId))
.ToHashSet();
var tenantRows = new List();
foreach (var tid in tenantIds)
{
foreach (var menu in seedMenus)
{
if (!existingMenuIds.Contains(menu.Id))
continue;
if (tenantMenuPairs.Contains((tid, menu.Id)))
continue;
tenantRows.Add(new SysTenantMenu
{
Id = CommonUtil.GetFixedHashCode("" + tid + menu.Id, 1300000000000),
TenantId = tid,
MenuId = menu.Id
});
}
}
if (tenantRows.Count > 0)
db.Insertable(tenantRows).ExecuteCommand();
// 已为任一 Ai-DOP 种子菜单授权的角色,补全新增子菜单;并始终包含默认租户系统管理员角色。
var roleIdsWithAnyAidop = db.Queryable()
.Where(rm => seedMenuIds.Contains(rm.MenuId))
.Select(rm => rm.RoleId)
.ToList()
.Distinct()
.ToHashSet();
roleIdsWithAnyAidop.Add(SysAdminRoleId);
var roleMenuPairs = db.Queryable()
.Where(rm => roleIdsWithAnyAidop.Contains(rm.RoleId) && seedMenuIds.Contains(rm.MenuId))
.Select(rm => new { rm.RoleId, rm.MenuId })
.ToList()
.Select(x => (x.RoleId, x.MenuId))
.ToHashSet();
var roleRows = new List();
foreach (var roleId in roleIdsWithAnyAidop)
{
foreach (var menu in seedMenus)
{
if (!existingMenuIds.Contains(menu.Id))
continue;
if (roleMenuPairs.Contains((roleId, menu.Id)))
continue;
roleRows.Add(new SysRoleMenu
{
Id = menu.Id + (roleId % 1300000000000),
RoleId = roleId,
MenuId = menu.Id
});
}
}
if (roleRows.Count > 0)
db.Insertable(roleRows).ExecuteCommand();
}
private static void NormalizeMaterialSubstitutionMenu(ISqlSugarClient db)
{
var deprecatedMenuId = DeprecatedMaterialSubstitutionMenuId;
var legacyMenuId = LegacyMaterialSubstitutionMenuId;
var legacyMenu = db.Queryable()
.First(m => m.Id == legacyMenuId);
if (legacyMenu != null)
{
legacyMenu.Title = "物料替代";
legacyMenu.Path = "/aidop/s0/manufacturing/material-substitution";
legacyMenu.Name = "aidopS0MfgMaterialSubstitution";
legacyMenu.Component = "/aidop/s0/manufacturing/MaterialSubstitutionList";
legacyMenu.Remark = "S0 物料替代";
db.Updateable(legacyMenu)
.UpdateColumns(m => new { m.Title, m.Path, m.Name, m.Component, m.Remark })
.ExecuteCommand();
}
var deprecatedExists = db.Queryable().Any(m => m.Id == deprecatedMenuId);
if (!deprecatedExists)
return;
db.Deleteable().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
db.Deleteable().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
db.Deleteable().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
db.Deleteable().Where(x => x.Id == deprecatedMenuId).ExecuteCommand();
}
}