|
@@ -1,6 +1,7 @@
|
|
|
using Admin.NET.Core;
|
|
using Admin.NET.Core;
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
using SqlSugar;
|
|
using SqlSugar;
|
|
|
|
|
+using System.Diagnostics;
|
|
|
|
|
|
|
|
namespace Admin.NET.Plugin.AiDOP.Infrastructure;
|
|
namespace Admin.NET.Plugin.AiDOP.Infrastructure;
|
|
|
|
|
|
|
@@ -367,16 +368,56 @@ public static class AidopMenuLinkSync
|
|
|
.ExecuteCommand();
|
|
.ExecuteCommand();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- var deprecatedExists = db.Queryable<SysMenu>().Any(m => m.Id == deprecatedMenuId);
|
|
|
|
|
- if (!deprecatedExists)
|
|
|
|
|
|
|
+ // Id 1329002000004 历史上是旧「物料替代」菜单,已迁移到 1329003000005;但该 Id 现被
|
|
|
|
|
+ // SysMenuSeedData「合同评审周期」(/aidop/s0/sales/contract-review-cycle) 合法复用。
|
|
|
|
|
+ // 旧逻辑仅凭 Id 无条件删除,会在每次启动抹掉合同评审周期菜单及其租户/角色授权。
|
|
|
|
|
+ // 改为语义判别:是合同评审周期则保护,明确是旧物料替代才清理,语义不明保守跳过。
|
|
|
|
|
+ // 用原生 SQL 读取该行,绕过 SqlSugar 查询缓存/全局过滤:直连 DB 写入的合同评审周期行
|
|
|
|
|
+ // 在 ORM 缓存路径下可能被读成迁移前的旧「物料替代」陈旧行,导致误判删除(启动期偶发)。
|
|
|
|
|
+ var deprecated = db.Ado
|
|
|
|
|
+ .SqlQuery<SysMenu>("SELECT * FROM SysMenu WHERE Id = @id", new SugarParameter("@id", deprecatedMenuId))
|
|
|
|
|
+ .FirstOrDefault();
|
|
|
|
|
+ if (deprecated == null)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ if (IsContractReviewCycleMenu(deprecated))
|
|
|
|
|
+ {
|
|
|
|
|
+ Trace.TraceInformation($"AidopMenuLinkSync: Id={deprecatedMenuId} 现为「合同评审周期」菜单,跳过旧物料替代清理(保护)。");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!IsLegacyMaterialSubstitutionMenu(deprecated))
|
|
|
|
|
+ {
|
|
|
|
|
+ Trace.TraceWarning($"AidopMenuLinkSync: Id={deprecatedMenuId} 语义不明(Title={deprecated.Title}, Path={deprecated.Path}),保守跳过,不删除。");
|
|
|
return;
|
|
return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ // 仅当确认为旧「物料替代」菜单时,才执行历史清理。
|
|
|
db.Deleteable<SysUserMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
|
|
db.Deleteable<SysUserMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
|
|
|
db.Deleteable<SysRoleMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
|
|
db.Deleteable<SysRoleMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
|
|
|
db.Deleteable<SysTenantMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
|
|
db.Deleteable<SysTenantMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
|
|
|
db.Deleteable<SysMenu>().Where(x => x.Id == deprecatedMenuId).ExecuteCommand();
|
|
db.Deleteable<SysMenu>().Where(x => x.Id == deprecatedMenuId).ExecuteCommand();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 判断给定菜单是否为 S0「合同评审周期」菜单(Id 1329002000004 的当前合法占用者)。
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ private static bool IsContractReviewCycleMenu(SysMenu m) =>
|
|
|
|
|
+ m.Title == "合同评审周期"
|
|
|
|
|
+ || m.Path == "/aidop/s0/sales/contract-review-cycle"
|
|
|
|
|
+ || m.Name == "aidopS0SalesContractReviewCycle"
|
|
|
|
|
+ || m.Component == "/aidop/s0/sales/ContractReviewCycleList";
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// 判断给定菜单是否为旧「物料替代」菜单(迁移前曾占用 Id 1329002000004)。
|
|
|
|
|
+ /// 依据 Phase 0 已举证的旧字段语义:Title 含「物料替代」,或 Path/Name/Component 含 material-substitution / MaterialSubstitution。
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ private static bool IsLegacyMaterialSubstitutionMenu(SysMenu m) =>
|
|
|
|
|
+ (m.Title?.Contains("物料替代") ?? false)
|
|
|
|
|
+ || (m.Path?.Contains("material-substitution") ?? false)
|
|
|
|
|
+ || (m.Name?.Contains("MaterialSubstitution") ?? false)
|
|
|
|
|
+ || (m.Component?.Contains("MaterialSubstitution") ?? false);
|
|
|
|
|
+
|
|
|
private static void RemoveDeprecatedS8DashboardChildMenu(ISqlSugarClient db)
|
|
private static void RemoveDeprecatedS8DashboardChildMenu(ISqlSugarClient db)
|
|
|
{
|
|
{
|
|
|
const long deprecatedMenuId = DeprecatedS8DashboardChildMenuId;
|
|
const long deprecatedMenuId = DeprecatedS8DashboardChildMenuId;
|