AidopImprovementApprovalSeed.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. using System.Diagnostics;
  2. using System.Text.Json;
  3. using Admin.NET.Core;
  4. using Admin.NET.Plugin.AiDOP.Service;
  5. using Admin.NET.Plugin.ApprovalFlow;
  6. using Admin.NET.Plugin.ApprovalFlow.Service;
  7. using Yitter.IdGenerator;
  8. using ApprovalFlowEntity = Admin.NET.Plugin.ApprovalFlow.ApprovalFlow;
  9. namespace Admin.NET.Plugin.AiDOP.Infrastructure;
  10. /// <summary>
  11. /// 智慧诊断改善计划正式审批流与角色基线。
  12. /// </summary>
  13. public static class AidopImprovementApprovalSeed
  14. {
  15. public static void EnsureSeed(ISqlSugarClient db)
  16. {
  17. try
  18. {
  19. db.CodeFirst.InitTables(
  20. typeof(ApprovalBizType),
  21. typeof(ApprovalFlowEntity),
  22. typeof(ApprovalFlowVersion));
  23. EnsureBizType(db);
  24. EnsureBaselineRoles(db);
  25. EnsurePublishedFlow(db);
  26. }
  27. catch (Exception ex)
  28. {
  29. Trace.TraceWarning("Ai-DOP improvement approval seed: " + ex);
  30. }
  31. }
  32. public static void EnsureBaselineRoles(ISqlSugarClient db, long? onlyTenantId = null)
  33. {
  34. var tenantIds = onlyTenantId is > 0
  35. ? new List<long> { onlyTenantId.Value }
  36. : db.Queryable<SysTenant>()
  37. .ClearFilter<ITenantIdFilter>()
  38. .Where(x => x.Id > 1 && x.Id != SqlSugarConst.DefaultTenantId)
  39. .Select(x => x.Id)
  40. .ToList();
  41. var now = DateTime.Now;
  42. foreach (var tenantId in tenantIds.Where(x => x > 1 && x != SqlSugarConst.DefaultTenantId).Distinct())
  43. {
  44. foreach (var (code, name, orderNo) in SmartOpsImprovementApprovalRules.BaselineRoles)
  45. {
  46. var exists = db.Queryable<SysRole>()
  47. .ClearFilter<ITenantIdFilter>()
  48. .Any(r => r.TenantId == tenantId && r.Code == code);
  49. if (exists) continue;
  50. db.Insertable(new SysRole
  51. {
  52. Id = YitIdHelper.NextId(),
  53. TenantId = tenantId,
  54. Name = name,
  55. Code = code,
  56. OrderNo = orderNo,
  57. DataScope = DataScopeEnum.Self,
  58. Status = StatusEnum.Enable,
  59. Remark = "智慧诊断改善计划审批角色基线",
  60. CreateTime = now,
  61. }).ExecuteCommand();
  62. }
  63. }
  64. }
  65. private static void EnsureBizType(ISqlSugarClient db)
  66. {
  67. var exists = db.Queryable<ApprovalBizType>()
  68. .Any(x => x.Code == SmartOpsImprovementBizHandler.BizTypeCode);
  69. if (exists) return;
  70. db.Insertable(new ApprovalBizType
  71. {
  72. Id = YitIdHelper.NextId(),
  73. Code = SmartOpsImprovementBizHandler.BizTypeCode,
  74. Name = "智慧诊断改善计划",
  75. Remark = "智慧运营诊断问题生成的改善计划审批",
  76. IsEnabled = true,
  77. CreateTime = DateTime.Now,
  78. UpdateTime = DateTime.Now,
  79. }).ExecuteCommand();
  80. }
  81. private static void EnsurePublishedFlow(ISqlSugarClient db)
  82. {
  83. var orgIds = db.Queryable<SysOrg>()
  84. .Select(x => x.Id)
  85. .ToList()
  86. .Where(x => x > 0)
  87. .Distinct()
  88. .ToList();
  89. if (orgIds.Count == 0) orgIds.Add(0);
  90. var now = DateTime.Now;
  91. var flowJson = BuildFormalFlowJson();
  92. foreach (var orgId in orgIds)
  93. {
  94. var existing = db.Queryable<ApprovalFlowEntity>()
  95. .Where(x => x.BizType == SmartOpsImprovementBizHandler.BizTypeCode && x.OrgId == orgId && !x.IsDelete)
  96. .OrderByDescending(x => x.IsPublished)
  97. .OrderByDescending(x => x.Version)
  98. .First();
  99. if (existing == null)
  100. {
  101. InsertFlow(db, orgId, flowJson, 2, now);
  102. continue;
  103. }
  104. if (!SmartOpsImprovementApprovalRules.IsLegacyInitiatorFallback(existing.FlowJson)
  105. && existing.FlowJson != null
  106. && existing.FlowJson.Contains(SmartOpsImprovementApprovalRules.DeptHeadRole, StringComparison.Ordinal))
  107. {
  108. if (!existing.IsPublished)
  109. {
  110. existing.IsPublished = true;
  111. existing.UpdateTime = now;
  112. db.Updateable(existing).ExecuteCommand();
  113. }
  114. continue;
  115. }
  116. existing.FlowJson = flowJson;
  117. existing.Version = Math.Max(existing.Version, 1) + 1;
  118. existing.IsPublished = true;
  119. existing.Status = 1;
  120. existing.Remark = "正式流程:黄/红/跨部门网关,按角色解析审批人";
  121. existing.UpdateTime = now;
  122. db.Updateable(existing).ExecuteCommand();
  123. db.Insertable(new ApprovalFlowVersion
  124. {
  125. Id = YitIdHelper.NextId(),
  126. FlowId = existing.Id,
  127. Version = existing.Version,
  128. FlowJson = existing.FlowJson,
  129. FormJson = existing.FormJson,
  130. PublishTime = now,
  131. PublisherName = "系统升级",
  132. CreateTime = now,
  133. UpdateTime = now,
  134. }).ExecuteCommand();
  135. }
  136. }
  137. private static void InsertFlow(ISqlSugarClient db, long orgId, string flowJson, int version, DateTime now)
  138. {
  139. var flow = new ApprovalFlowEntity
  140. {
  141. Id = YitIdHelper.NextId(),
  142. Code = $"SOI_{orgId}",
  143. Name = "智慧诊断改善计划审批",
  144. BizType = SmartOpsImprovementBizHandler.BizTypeCode,
  145. FormJson = "{}",
  146. FlowJson = flowJson,
  147. Status = 1,
  148. Remark = "正式流程:黄/红/跨部门网关,按角色解析审批人",
  149. Version = version,
  150. IsPublished = true,
  151. OrgId = orgId,
  152. CreateTime = now,
  153. UpdateTime = now,
  154. };
  155. db.Insertable(flow).ExecuteCommand();
  156. db.Insertable(new ApprovalFlowVersion
  157. {
  158. Id = YitIdHelper.NextId(),
  159. FlowId = flow.Id,
  160. Version = flow.Version,
  161. FlowJson = flow.FlowJson,
  162. FormJson = flow.FormJson,
  163. PublishTime = now,
  164. PublisherName = "系统初始化",
  165. CreateTime = now,
  166. UpdateTime = now,
  167. }).ExecuteCommand();
  168. }
  169. public static string BuildFormalFlowJson()
  170. {
  171. var item = new ApprovalFlowItem
  172. {
  173. Nodes = new List<ApprovalFlowNodeItem>
  174. {
  175. Node("start", "bpmn:startEvent", 80, 200, "开始"),
  176. new()
  177. {
  178. Id = "routeGw",
  179. Type = "bpmn:exclusiveGateway",
  180. X = 220,
  181. Y = 200,
  182. Properties = new FlowProperties
  183. {
  184. NodeName = "问题分级",
  185. Conditions = new List<GatewayCondition>
  186. {
  187. new() { TargetNodeId = "deptHeadYellow", Expression = "route == yellow", Label = "黄色" },
  188. new() { TargetNodeId = "deptHeadRed", Expression = "route == red", Label = "红色" },
  189. new() { TargetNodeId = "deptHeadGlobal", Expression = "", Label = "跨部门/S9", IsDefault = true },
  190. },
  191. },
  192. Text = new FlowTextItem { X = 220, Y = 234, Value = "问题分级" },
  193. },
  194. RoleNode("deptHeadYellow", 420, 80, "责任部门负责人", SmartOpsImprovementApprovalRules.DeptHeadRole),
  195. RoleNode("deptHeadRed", 420, 200, "责任部门负责人", SmartOpsImprovementApprovalRules.DeptHeadRole),
  196. RoleNode("opsRed", 620, 200, "运营负责人", SmartOpsImprovementApprovalRules.OpsOwnerRole),
  197. RoleNode("deptHeadGlobal", 420, 320, "责任部门负责人", SmartOpsImprovementApprovalRules.DeptHeadRole),
  198. RoleNode("moduleGlobal", 620, 320, "模块负责人", SmartOpsImprovementApprovalRules.ModuleOwnerRole),
  199. RoleNode("opsGlobal", 820, 320, "运营负责人", SmartOpsImprovementApprovalRules.OpsOwnerRole),
  200. Node("end", "bpmn:endEvent", 1020, 200, "结束"),
  201. },
  202. Edges = new List<ApprovalFlowEdgeItem>
  203. {
  204. BuildEdge("e-start-gw", "start", "routeGw", 120, 200, 180, 200),
  205. BuildEdge("e-gw-y", "routeGw", "deptHeadYellow", 250, 180, 380, 80),
  206. BuildEdge("e-gw-r", "routeGw", "deptHeadRed", 260, 200, 380, 200),
  207. BuildEdge("e-gw-g", "routeGw", "deptHeadGlobal", 250, 220, 380, 320),
  208. BuildEdge("e-y-end", "deptHeadYellow", "end", 460, 80, 980, 180),
  209. BuildEdge("e-r-ops", "deptHeadRed", "opsRed", 460, 200, 580, 200),
  210. BuildEdge("e-ops-end", "opsRed", "end", 660, 200, 980, 200),
  211. BuildEdge("e-g-mod", "deptHeadGlobal", "moduleGlobal", 460, 320, 580, 320),
  212. BuildEdge("e-mod-ops", "moduleGlobal", "opsGlobal", 660, 320, 780, 320),
  213. BuildEdge("e-gops-end", "opsGlobal", "end", 860, 320, 980, 220),
  214. }
  215. };
  216. return JsonSerializer.Serialize(item);
  217. }
  218. private static ApprovalFlowNodeItem Node(string id, string type, float x, float y, string name) => new()
  219. {
  220. Id = id,
  221. Type = type,
  222. X = x,
  223. Y = y,
  224. Properties = new FlowProperties { NodeName = name },
  225. Text = new FlowTextItem { X = x, Y = y + 34, Value = name },
  226. };
  227. private static ApprovalFlowNodeItem RoleNode(string id, float x, float y, string name, string roleCode) => new()
  228. {
  229. Id = id,
  230. Type = "bpmn:userTask",
  231. X = x,
  232. Y = y,
  233. Properties = new FlowProperties
  234. {
  235. NodeName = name,
  236. ApproverType = nameof(ApproverTypeEnum.Role),
  237. ApproverIds = roleCode,
  238. ApproverNames = name,
  239. MultiApproveMode = "Any",
  240. TimeoutHours = 72,
  241. TimeoutAction = "Notify",
  242. },
  243. Text = new FlowTextItem { X = x, Y = y + 34, Value = name },
  244. };
  245. private static ApprovalFlowEdgeItem BuildEdge(string id, string source, string target, float sx, float sy, float ex, float ey)
  246. {
  247. return new ApprovalFlowEdgeItem
  248. {
  249. Id = id,
  250. Type = "bpmn:sequenceFlow",
  251. SourceNodeId = source,
  252. TargetNodeId = target,
  253. StartPoint = new FlowEdgePointItem { X = sx, Y = sy },
  254. EndPoint = new FlowEdgePointItem { X = ex, Y = ey },
  255. Properties = new FlowProperties(),
  256. PointsList = new List<FlowEdgePointItem>
  257. {
  258. new() { X = sx, Y = sy },
  259. new() { X = ex, Y = ey },
  260. },
  261. };
  262. }
  263. }