AidopMenuLinkSync.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  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. private const long DeprecatedS8DashboardChildMenuId = 1329008000001L;
  16. private const long S8DirMenuId = 1321000009000L;
  17. public static void EnsureLinked(IServiceProvider services)
  18. {
  19. using var scope = services.CreateScope();
  20. var db = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
  21. // Database.json 常关闭 EnableInitSeed/EnableIncreSeed,新增种子菜单不会入库;先补插 S2 三级结构再挂租户/角色。
  22. EnsureS2ManufacturingCollaborationSeedMenus(db);
  23. NormalizeMaterialSubstitutionMenu(db);
  24. NormalizeS1OrderWorkOrderParents(db);
  25. NormalizeS2ManufacturingParents(db);
  26. NormalizeS2ScheduleExceptionMenu(db);
  27. NormalizeS2OperationPlanLeafMenus(db);
  28. NormalizeS2WorkOrderProgressKanbanMenu(db);
  29. NormalizeS3SupplyMenus(db);
  30. EnsureLinkagePlanMenu(db);
  31. RemoveDeprecatedS8DashboardChildMenu(db);
  32. NormalizeS8MenuParents(db);
  33. var seedMenus = new global::Admin.NET.Plugin.AiDOP.SysMenuSeedData().HasData().ToList();
  34. var seedMenuIds = seedMenus.Select(m => m.Id).ToHashSet();
  35. var existingMenuIds = db.Queryable<SysMenu>()
  36. .Where(m => seedMenuIds.Contains(m.Id))
  37. .Select(m => m.Id)
  38. .ToList()
  39. .ToHashSet();
  40. if (existingMenuIds.Count == 0)
  41. return;
  42. var tenantIds = db.Queryable<SysTenant>().Select(t => t.Id).ToList();
  43. if (tenantIds.Count == 0)
  44. return;
  45. var tenantMenuPairs = db.Queryable<SysTenantMenu>()
  46. .Where(tm => tenantIds.Contains(tm.TenantId) && seedMenuIds.Contains(tm.MenuId))
  47. .Select(tm => new { tm.TenantId, tm.MenuId })
  48. .ToList()
  49. .Select(x => (x.TenantId, x.MenuId))
  50. .ToHashSet();
  51. var tenantRows = new List<SysTenantMenu>();
  52. foreach (var tid in tenantIds)
  53. {
  54. foreach (var menu in seedMenus)
  55. {
  56. if (!existingMenuIds.Contains(menu.Id))
  57. continue;
  58. if (tenantMenuPairs.Contains((tid, menu.Id)))
  59. continue;
  60. tenantRows.Add(new SysTenantMenu
  61. {
  62. Id = CommonUtil.GetFixedHashCode("" + tid + menu.Id, 1300000000000),
  63. TenantId = tid,
  64. MenuId = menu.Id
  65. });
  66. }
  67. }
  68. if (tenantRows.Count > 0)
  69. db.Insertable(tenantRows).ExecuteCommand();
  70. // 已为任一 Ai-DOP 种子菜单授权的角色,补全新增子菜单;并始终包含默认租户系统管理员角色。
  71. var roleIdsWithAnyAidop = db.Queryable<SysRoleMenu>()
  72. .Where(rm => seedMenuIds.Contains(rm.MenuId))
  73. .Select(rm => rm.RoleId)
  74. .ToList()
  75. .Distinct()
  76. .ToHashSet();
  77. roleIdsWithAnyAidop.Add(SysAdminRoleId);
  78. var roleMenuPairs = db.Queryable<SysRoleMenu>()
  79. .Where(rm => roleIdsWithAnyAidop.Contains(rm.RoleId) && seedMenuIds.Contains(rm.MenuId))
  80. .Select(rm => new { rm.RoleId, rm.MenuId })
  81. .ToList()
  82. .Select(x => (x.RoleId, x.MenuId))
  83. .ToHashSet();
  84. // SysRoleMenu 主键须全局唯一。使用 menu.Id + (roleId % 1300000000000) 时,不同 (MenuId, RoleId) 会算出相同 Id(如 1322000000208),
  85. // 批量插入失败,新菜单无法进入 sys_role_menu,侧栏不刷新。与 SysTenantMenu 一致,用固定哈希避免碰撞。
  86. var roleRows = new List<SysRoleMenu>();
  87. var pendingRoleMenuIds = new HashSet<long>();
  88. foreach (var roleId in roleIdsWithAnyAidop)
  89. {
  90. foreach (var menu in seedMenus)
  91. {
  92. if (!existingMenuIds.Contains(menu.Id))
  93. continue;
  94. if (roleMenuPairs.Contains((roleId, menu.Id)))
  95. continue;
  96. var rmId = CommonUtil.GetFixedHashCode($"{roleId}:{menu.Id}", 1300000000000);
  97. while (!pendingRoleMenuIds.Add(rmId))
  98. rmId++;
  99. roleRows.Add(new SysRoleMenu
  100. {
  101. Id = rmId,
  102. RoleId = roleId,
  103. MenuId = menu.Id
  104. });
  105. }
  106. }
  107. if (roleRows.Count > 0)
  108. db.Insertable(roleRows).ExecuteCommand();
  109. }
  110. /// <summary>
  111. /// S2「制造协同」二级目录与三级子菜单:<c>Database.json</c> 关闭种子时不会入库,导致侧栏无「工单工序排程」等项。
  112. /// 从 <see cref="SysMenuSeedData.HasData"/> 取完整行一次性补插(含目录 Redirect)。
  113. /// </summary>
  114. private static void EnsureS2ManufacturingCollaborationSeedMenus(ISqlSugarClient db)
  115. {
  116. const long aidopRootId = 1320990000101L;
  117. var fullSeed = new global::Admin.NET.Plugin.AiDOP.SysMenuSeedData().HasData().ToList();
  118. var byId = fullSeed.GroupBy(m => m.Id).ToDictionary(g => g.Key, g => g.First());
  119. // 父链:Ai-DOP 根 → S2 一级目录 → 三个二级目录 → 三级菜单(同批插入时父行尚未落库,用 cumulativeIds 判定)
  120. var orderedIds = new long[]
  121. {
  122. aidopRootId,
  123. 1321000003000L,
  124. 1322000000006L,
  125. 1322000000007L,
  126. 1322000000008L,
  127. 1322000000108L,
  128. 1329002100001L,
  129. 1329002100011L,
  130. 1329002100012L,
  131. 1329002100013L,
  132. 1329002100014L,
  133. 1329002100015L,
  134. 1329002100021L,
  135. };
  136. var existing = db.Queryable<SysMenu>().Where(m => orderedIds.Contains(m.Id)).Select(m => m.Id).ToList().ToHashSet();
  137. var cumulativeIds = new HashSet<long>(existing);
  138. var toInsert = new List<SysMenu>();
  139. foreach (var id in orderedIds)
  140. {
  141. if (cumulativeIds.Contains(id))
  142. continue;
  143. if (!byId.TryGetValue(id, out var row))
  144. continue;
  145. if (row.Pid != 0 && !cumulativeIds.Contains(row.Pid))
  146. continue;
  147. toInsert.Add(row);
  148. cumulativeIds.Add(id);
  149. }
  150. if (toInsert.Count > 0)
  151. db.Insertable(toInsert).ExecuteCommand();
  152. }
  153. /// <summary>
  154. /// 计划联动看板(Id=1322000000107):<c>Database.json</c> 常关闭 <c>EnableIncreSeed</c>,种子不会入库,故在启动时补插/纠偏。
  155. /// 父级为产销协同看板目录 1322000000005。
  156. /// </summary>
  157. private static void EnsureLinkagePlanMenu(ISqlSugarClient db)
  158. {
  159. const long menuId = 1322000000107L;
  160. const long salesKanBanDirId = 1322000000005L;
  161. if (!db.Queryable<SysMenu>().Any(m => m.Id == salesKanBanDirId))
  162. return;
  163. var ct = DateTime.Parse("2022-02-10 00:00:00");
  164. if (!db.Queryable<SysMenu>().Any(m => m.Id == menuId))
  165. {
  166. db.Insertable(new SysMenu
  167. {
  168. Id = menuId,
  169. Pid = salesKanBanDirId,
  170. Title = "计划联动看板",
  171. Path = "/aidop/s1/SalesKanBan/linkage-plan",
  172. Name = "aidopS1LinkagePlan",
  173. Component = "/aidop/business/linkagePlanList",
  174. Icon = "ele-DataBoard",
  175. Type = MenuTypeEnum.Menu,
  176. CreateTime = ct,
  177. OrderNo = 30,
  178. Status = StatusEnum.Enable,
  179. Remark = "S1 计划联动看板(LinkagePlan)"
  180. }).ExecuteCommand();
  181. return;
  182. }
  183. var row = db.Queryable<SysMenu>().First(m => m.Id == menuId);
  184. if (row.Pid != salesKanBanDirId
  185. || row.Path != "/aidop/s1/SalesKanBan/linkage-plan"
  186. || row.Component != "/aidop/business/linkagePlanList")
  187. {
  188. row.Pid = salesKanBanDirId;
  189. row.Path = "/aidop/s1/SalesKanBan/linkage-plan";
  190. row.Name = "aidopS1LinkagePlan";
  191. row.Component = "/aidop/business/linkagePlanList";
  192. row.Title = "计划联动看板";
  193. row.Icon = "ele-DataBoard";
  194. row.OrderNo = 30;
  195. row.Type = MenuTypeEnum.Menu;
  196. db.Updateable(row)
  197. .UpdateColumns(m => new { m.Pid, m.Path, m.Name, m.Component, m.Title, m.Icon, m.OrderNo, m.Type })
  198. .ExecuteCommand();
  199. }
  200. }
  201. private static void NormalizeMaterialSubstitutionMenu(ISqlSugarClient db)
  202. {
  203. var deprecatedMenuId = DeprecatedMaterialSubstitutionMenuId;
  204. var legacyMenuId = LegacyMaterialSubstitutionMenuId;
  205. var legacyMenu = db.Queryable<SysMenu>()
  206. .First(m => m.Id == legacyMenuId);
  207. if (legacyMenu != null)
  208. {
  209. legacyMenu.Title = "物料替代";
  210. legacyMenu.Path = "/aidop/s0/manufacturing/material-substitution";
  211. legacyMenu.Name = "aidopS0MfgMaterialSubstitution";
  212. legacyMenu.Component = "/aidop/s0/manufacturing/MaterialSubstitutionList";
  213. legacyMenu.Remark = "S0 物料替代";
  214. db.Updateable(legacyMenu)
  215. .UpdateColumns(m => new { m.Title, m.Path, m.Name, m.Component, m.Remark })
  216. .ExecuteCommand();
  217. }
  218. var deprecatedExists = db.Queryable<SysMenu>().Any(m => m.Id == deprecatedMenuId);
  219. if (!deprecatedExists)
  220. return;
  221. db.Deleteable<SysUserMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
  222. db.Deleteable<SysRoleMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
  223. db.Deleteable<SysTenantMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
  224. db.Deleteable<SysMenu>().Where(x => x.Id == deprecatedMenuId).ExecuteCommand();
  225. }
  226. private static void RemoveDeprecatedS8DashboardChildMenu(ISqlSugarClient db)
  227. {
  228. const long deprecatedMenuId = DeprecatedS8DashboardChildMenuId;
  229. var deprecatedExists = db.Queryable<SysMenu>().Any(m => m.Id == deprecatedMenuId);
  230. if (!deprecatedExists)
  231. return;
  232. db.Deleteable<SysUserMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
  233. db.Deleteable<SysRoleMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
  234. db.Deleteable<SysTenantMenu>().Where(x => x.MenuId == deprecatedMenuId).ExecuteCommand();
  235. db.Deleteable<SysMenu>().Where(x => x.Id == deprecatedMenuId).ExecuteCommand();
  236. }
  237. private static void NormalizeS8MenuParents(ISqlSugarClient db)
  238. {
  239. var s8MenuIds = new long[]
  240. {
  241. 1329008000002L,
  242. 1329008000003L,
  243. 1329008000004L,
  244. 1329008000010L,
  245. 1329008000011L,
  246. 1329008000012L,
  247. 1329008000013L,
  248. 1329008000014L,
  249. 1329008000015L,
  250. 1329008000016L,
  251. 1329008000020L
  252. };
  253. db.Updateable<SysMenu>()
  254. .SetColumns(x => x.Pid == S8DirMenuId)
  255. .Where(x => s8MenuIds.Contains(x.Id) && x.Pid != S8DirMenuId)
  256. .ExecuteCommand();
  257. }
  258. /// <summary>
  259. /// 将 S1「订单管理」「工单管理」升级为目录并修正 path/name;
  260. /// 「产销协同看板」单独菜单路径为 /aidop/s1/SalesKanBan;
  261. /// 「工单下达」父级须为工单管理目录 1322000000004(历史错误曾挂到 0005)。
  262. /// 「工单工序排产」1322000000108 已迁至 S2「生产排程」下,见 <see cref="NormalizeS2ManufacturingParents"/>。
  263. /// </summary>
  264. private static void NormalizeS1OrderWorkOrderParents(ISqlSugarClient db)
  265. {
  266. const long orderMgmtId = 1322000000003L;
  267. const long workOrderMgmtId = 1322000000004L;
  268. const long salesKanBanMenuId = 1322000000005L;
  269. const long workOrderDispatchMenuId = 1322000000106L;
  270. var orderMgmt = db.Queryable<SysMenu>().First(m => m.Id == orderMgmtId);
  271. if (orderMgmt != null)
  272. {
  273. orderMgmt.Type = MenuTypeEnum.Dir;
  274. orderMgmt.Component = "Layout";
  275. orderMgmt.Path = "/aidop/s1/order-mgmt";
  276. orderMgmt.Name = "aidopS1OrderMgmt";
  277. orderMgmt.Icon = "ele-Folder";
  278. db.Updateable(orderMgmt)
  279. .UpdateColumns(m => new { m.Type, m.Component, m.Path, m.Name, m.Icon })
  280. .ExecuteCommand();
  281. }
  282. var workOrderMgmt = db.Queryable<SysMenu>().First(m => m.Id == workOrderMgmtId);
  283. if (workOrderMgmt != null)
  284. {
  285. workOrderMgmt.Type = MenuTypeEnum.Dir;
  286. workOrderMgmt.Component = "Layout";
  287. workOrderMgmt.Path = "/aidop/s1/workorder-mgmt";
  288. workOrderMgmt.Name = "aidopS1WorkOrderMgmt";
  289. workOrderMgmt.Icon = "ele-Folder";
  290. db.Updateable(workOrderMgmt)
  291. .UpdateColumns(m => new { m.Type, m.Component, m.Path, m.Name, m.Icon })
  292. .ExecuteCommand();
  293. }
  294. var salesKanBan = db.Queryable<SysMenu>().First(m => m.Id == salesKanBanMenuId);
  295. if (salesKanBan != null)
  296. {
  297. salesKanBan.Type = MenuTypeEnum.Menu;
  298. salesKanBan.Component = "/aidop/kanban/s1";
  299. salesKanBan.Path = "/aidop/s1/SalesKanBan";
  300. salesKanBan.Name = "aidopS1003";
  301. salesKanBan.Icon = "ele-DataAnalysis";
  302. db.Updateable(salesKanBan)
  303. .UpdateColumns(m => new { m.Type, m.Component, m.Path, m.Name, m.Icon })
  304. .ExecuteCommand();
  305. }
  306. var dispatch = db.Queryable<SysMenu>().First(m => m.Id == workOrderDispatchMenuId);
  307. if (dispatch != null)
  308. {
  309. var needFix = dispatch.Pid != workOrderMgmtId
  310. || dispatch.Path != "/aidop/s1/workorder-mgmt/dispatch";
  311. if (needFix)
  312. {
  313. dispatch.Pid = workOrderMgmtId;
  314. dispatch.Path = "/aidop/s1/workorder-mgmt/dispatch";
  315. db.Updateable(dispatch)
  316. .UpdateColumns(m => new { m.Pid, m.Path })
  317. .ExecuteCommand();
  318. }
  319. }
  320. }
  321. /// <summary>
  322. /// S2「生产排程 / 作业计划 / 制造协同看板」升级为目录;「工单工序排产」父级为生产排程 1322000000006,path 为 S2 路由。
  323. /// </summary>
  324. private static void NormalizeS2ManufacturingParents(ISqlSugarClient db)
  325. {
  326. const long productionSchedulingId = 1322000000006L;
  327. const long operationPlanId = 1322000000007L;
  328. const long collaborationKanbanId = 1322000000008L;
  329. const long workOrderSchedulingMenuId = 1322000000108L;
  330. void EnsureDir(long id, string path, string name)
  331. {
  332. var m = db.Queryable<SysMenu>().First(x => x.Id == id);
  333. if (m == null)
  334. return;
  335. m.Type = MenuTypeEnum.Dir;
  336. m.Component = "Layout";
  337. m.Path = path;
  338. m.Name = name;
  339. m.Icon = "ele-Folder";
  340. db.Updateable(m)
  341. .UpdateColumns(x => new { x.Type, x.Component, x.Path, x.Name, x.Icon })
  342. .ExecuteCommand();
  343. }
  344. EnsureDir(productionSchedulingId, "/aidop/s2/production-scheduling", "aidopS2ProductionScheduling");
  345. EnsureDir(operationPlanId, "/aidop/s2/operation-plan", "aidopS2OperationPlan");
  346. EnsureDir(collaborationKanbanId, "/aidop/s2/collaboration-kanban", "aidopS2CollaborationKanban");
  347. var scheduling = db.Queryable<SysMenu>().First(m => m.Id == workOrderSchedulingMenuId);
  348. if (scheduling == null)
  349. return;
  350. const string s2SchedulingPath = "/aidop/s2/production-scheduling/work-order-scheduling";
  351. var needFix = scheduling.Pid != productionSchedulingId
  352. || scheduling.Path != s2SchedulingPath
  353. || scheduling.Name != "aidopS2WorkOrderScheduling";
  354. if (!needFix)
  355. return;
  356. scheduling.Pid = productionSchedulingId;
  357. scheduling.Path = s2SchedulingPath;
  358. scheduling.Name = "aidopS2WorkOrderScheduling";
  359. db.Updateable(scheduling)
  360. .UpdateColumns(m => new { m.Pid, m.Path, m.Name })
  361. .ExecuteCommand();
  362. }
  363. /// <summary>
  364. /// S2「排产异常记录」由占位页 <c>/aidop/planning/index</c> 改为真实列表页 <c>/aidop/production/scheduleExceptionList</c>。
  365. /// </summary>
  366. private static void NormalizeS2ScheduleExceptionMenu(ISqlSugarClient db)
  367. {
  368. const long menuId = 1329002100001L;
  369. const string component = "/aidop/production/scheduleExceptionList";
  370. var m = db.Queryable<SysMenu>().First(x => x.Id == menuId);
  371. if (m == null)
  372. return;
  373. if (m.Component == component)
  374. return;
  375. m.Component = component;
  376. m.Remark = "S2 排产异常记录";
  377. db.Updateable(m)
  378. .UpdateColumns(x => new { x.Component, x.Remark })
  379. .ExecuteCommand();
  380. }
  381. /// <summary>
  382. /// S2「作业计划」下三页由占位改为真实组件(库中已落旧 <c>/aidop/planning/index</c> 时纠偏)。
  383. /// </summary>
  384. private static void NormalizeS2OperationPlanLeafMenus(ISqlSugarClient db)
  385. {
  386. (long Id, string Component, string Title)[] map =
  387. {
  388. (1329002100011L, "/aidop/production/executableDailyPlanList", "可执行日计划"),
  389. (1329002100012L, "/aidop/production/shopCalendarWorkCtrList", "产线工作日历管理"),
  390. (1329002100013L, "/aidop/production/qualityLineRestDetailList", "产线休息时间管理"),
  391. (1329002100014L, "/aidop/production/holidayMasterList", "产线节假日管理"),
  392. (1329002100015L, "/aidop/production/lineOvertimeList", "产线加班管理"),
  393. };
  394. foreach (var (id, component, title) in map)
  395. {
  396. var m = db.Queryable<SysMenu>().First(x => x.Id == id);
  397. if (m == null)
  398. continue;
  399. if (m.Component == component && m.Title == title)
  400. continue;
  401. m.Component = component;
  402. m.Title = title;
  403. db.Updateable(m)
  404. .UpdateColumns(x => new { x.Component, x.Title })
  405. .ExecuteCommand();
  406. }
  407. }
  408. /// <summary>
  409. /// S2「工单执行进度看板」由占位 <c>/aidop/kanban/s2</c> 改为列表页 <c>/aidop/production/workOrderProgressDashboardList</c>。
  410. /// </summary>
  411. private static void NormalizeS2WorkOrderProgressKanbanMenu(ISqlSugarClient db)
  412. {
  413. const long menuId = 1329002100021L;
  414. const string component = "/aidop/production/workOrderProgressDashboardList";
  415. var m = db.Queryable<SysMenu>().First(x => x.Id == menuId);
  416. if (m == null)
  417. return;
  418. if (m.Component == component)
  419. return;
  420. m.Component = component;
  421. m.Remark = "S2 工单执行进度看板(列表)";
  422. db.Updateable(m)
  423. .UpdateColumns(x => new { x.Component, x.Remark })
  424. .ExecuteCommand();
  425. }
  426. /// <summary>
  427. /// S3「物料计划」下三项菜单:种子关闭时补插,已存在时纠偏到真实组件页。
  428. /// </summary>
  429. private static void NormalizeS3SupplyMenus(ISqlSugarClient db)
  430. {
  431. const long s3RootId = 1321000003000L;
  432. const long parentId = 1322000000009L;
  433. const long procurementDirId = 1322000000010L;
  434. if (!db.Queryable<SysMenu>().Any(m => m.Id == parentId) || !db.Queryable<SysMenu>().Any(m => m.Id == procurementDirId))
  435. return;
  436. var procurementDir = db.Queryable<SysMenu>().First(m => m.Id == procurementDirId);
  437. if (procurementDir != null)
  438. {
  439. var procurementNeedFix = procurementDir.Pid != s3RootId
  440. || procurementDir.Title != "采购管理"
  441. || procurementDir.Path != "/aidop/s3/procurement"
  442. || procurementDir.Name != "aidopS3Procurement"
  443. || procurementDir.Component != "Layout"
  444. || procurementDir.Type != MenuTypeEnum.Dir
  445. || procurementDir.Icon != "ele-Folder"
  446. || procurementDir.Redirect != "/aidop/s3/procurement/purchase-request"
  447. || procurementDir.Remark != "S3 采购管理";
  448. if (procurementNeedFix)
  449. {
  450. procurementDir.Pid = s3RootId;
  451. procurementDir.Title = "采购管理";
  452. procurementDir.Path = "/aidop/s3/procurement";
  453. procurementDir.Name = "aidopS3Procurement";
  454. procurementDir.Component = "Layout";
  455. procurementDir.Type = MenuTypeEnum.Dir;
  456. procurementDir.Icon = "ele-Folder";
  457. procurementDir.Redirect = "/aidop/s3/procurement/purchase-request";
  458. procurementDir.Remark = "S3 采购管理";
  459. db.Updateable(procurementDir)
  460. .UpdateColumns(m => new { m.Pid, m.Title, m.Path, m.Name, m.Component, m.Type, m.Icon, m.Redirect, m.Remark })
  461. .ExecuteCommand();
  462. }
  463. }
  464. var ct = DateTime.Parse("2022-02-10 00:00:00");
  465. var defs = new (long Id, string Title, string Path, string Name, string Component, string Icon, int OrderNo, string Remark)[]
  466. {
  467. (
  468. 1329003100001L,
  469. "物料需求计划",
  470. "/aidop/s3/material-plan/demand-schedule",
  471. "aidopS3DemandSchedule",
  472. "/aidop/s3/supply/demandScheduleList",
  473. "ele-Calendar",
  474. 10,
  475. "S3 物料需求计划(ic_demandschedule)"
  476. ),
  477. (
  478. 1329003100002L,
  479. "物料交货计划",
  480. "/aidop/s3/material-plan/delivery-schedule",
  481. "aidopS3DeliverySchedule",
  482. "/aidop/s3/supply/deliveryScheduleList",
  483. "ele-Document",
  484. 20,
  485. "S3 物料交货计划(srm_polist_ds)"
  486. ),
  487. (
  488. 1329003100003L,
  489. "交货单异常记录",
  490. "/aidop/s3/material-plan/delivery-exception",
  491. "aidopS3DeliveryException",
  492. "/aidop/s3/supply/deliveryExceptionList",
  493. "ele-Warning",
  494. 30,
  495. "S3 交货单异常记录(DeliveryExceptionMaster)"
  496. ),
  497. };
  498. foreach (var def in defs)
  499. {
  500. var row = db.Queryable<SysMenu>().First(m => m.Id == def.Id);
  501. if (row == null)
  502. {
  503. db.Insertable(new SysMenu
  504. {
  505. Id = def.Id,
  506. Pid = parentId,
  507. Title = def.Title,
  508. Path = def.Path,
  509. Name = def.Name,
  510. Component = def.Component,
  511. Icon = def.Icon,
  512. Type = MenuTypeEnum.Menu,
  513. CreateTime = ct,
  514. OrderNo = def.OrderNo,
  515. Status = StatusEnum.Enable,
  516. Remark = def.Remark
  517. }).ExecuteCommand();
  518. continue;
  519. }
  520. var needFix = row.Pid != parentId
  521. || row.Path != def.Path
  522. || row.Name != def.Name
  523. || row.Component != def.Component
  524. || row.Title != def.Title
  525. || row.Icon != def.Icon
  526. || row.OrderNo != def.OrderNo
  527. || row.Type != MenuTypeEnum.Menu
  528. || row.Remark != def.Remark;
  529. if (!needFix)
  530. continue;
  531. row.Pid = parentId;
  532. row.Path = def.Path;
  533. row.Name = def.Name;
  534. row.Component = def.Component;
  535. row.Title = def.Title;
  536. row.Icon = def.Icon;
  537. row.OrderNo = def.OrderNo;
  538. row.Type = MenuTypeEnum.Menu;
  539. row.Remark = def.Remark;
  540. db.Updateable(row)
  541. .UpdateColumns(m => new { m.Pid, m.Path, m.Name, m.Component, m.Title, m.Icon, m.OrderNo, m.Type, m.Remark })
  542. .ExecuteCommand();
  543. }
  544. EnsureS3LeafMenu(
  545. db, ct, 1329003100011L, procurementDirId, "物料采购申请",
  546. "/aidop/s3/procurement/purchase-request", "aidopS3PurchaseRequest",
  547. "/aidop/s3/supply/purchaseRequestList", "ele-Document", 10, "S3 物料采购申请(srm_pr_main)");
  548. EnsureS3LeafMenu(
  549. db, ct, 1329003100010L, s3RootId, "供应协同看板",
  550. "/aidop/s3/supply-kanban", "aidopS3SupplyKanban",
  551. "/aidop/kanban/s3", "ele-DataBoard", 102, "S3 供应协同看板");
  552. }
  553. private static void EnsureS3LeafMenu(
  554. ISqlSugarClient db,
  555. DateTime ct,
  556. long id,
  557. long pid,
  558. string title,
  559. string path,
  560. string name,
  561. string component,
  562. string icon,
  563. int orderNo,
  564. string remark)
  565. {
  566. var row = db.Queryable<SysMenu>().First(m => m.Id == id);
  567. if (row == null)
  568. {
  569. db.Insertable(new SysMenu
  570. {
  571. Id = id,
  572. Pid = pid,
  573. Title = title,
  574. Path = path,
  575. Name = name,
  576. Component = component,
  577. Icon = icon,
  578. Type = MenuTypeEnum.Menu,
  579. CreateTime = ct,
  580. OrderNo = orderNo,
  581. Status = StatusEnum.Enable,
  582. Remark = remark
  583. }).ExecuteCommand();
  584. return;
  585. }
  586. var needFix = row.Pid != pid
  587. || row.Title != title
  588. || row.Path != path
  589. || row.Name != name
  590. || row.Component != component
  591. || row.Icon != icon
  592. || row.Type != MenuTypeEnum.Menu
  593. || row.OrderNo != orderNo
  594. || row.Remark != remark;
  595. if (!needFix)
  596. return;
  597. row.Pid = pid;
  598. row.Title = title;
  599. row.Path = path;
  600. row.Name = name;
  601. row.Component = component;
  602. row.Icon = icon;
  603. row.Type = MenuTypeEnum.Menu;
  604. row.OrderNo = orderNo;
  605. row.Remark = remark;
  606. db.Updateable(row)
  607. .UpdateColumns(m => new { m.Pid, m.Title, m.Path, m.Name, m.Component, m.Icon, m.Type, m.OrderNo, m.Remark })
  608. .ExecuteCommand();
  609. }
  610. }