AidopImprovementApprovalSeed.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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. TenantId = ApprovalFlowTenantSeed.ResolveTenantId(db, orgId),
  153. CreateTime = now,
  154. UpdateTime = now,
  155. };
  156. db.Insertable(flow).ExecuteCommand();
  157. db.Insertable(new ApprovalFlowVersion
  158. {
  159. Id = YitIdHelper.NextId(),
  160. FlowId = flow.Id,
  161. Version = flow.Version,
  162. FlowJson = flow.FlowJson,
  163. FormJson = flow.FormJson,
  164. PublishTime = now,
  165. PublisherName = "系统初始化",
  166. CreateTime = now,
  167. UpdateTime = now,
  168. }).ExecuteCommand();
  169. }
  170. public static string BuildFormalFlowJson()
  171. {
  172. var item = new ApprovalFlowItem
  173. {
  174. Nodes = new List<ApprovalFlowNodeItem>
  175. {
  176. Node("start", "bpmn:startEvent", 80, 200, "开始"),
  177. new()
  178. {
  179. Id = "routeGw",
  180. Type = "bpmn:exclusiveGateway",
  181. X = 220,
  182. Y = 200,
  183. Properties = new FlowProperties
  184. {
  185. NodeName = "问题分级",
  186. Conditions = new List<GatewayCondition>
  187. {
  188. new() { TargetNodeId = "deptHeadYellow", Expression = "route == yellow", Label = "黄色" },
  189. new() { TargetNodeId = "deptHeadRed", Expression = "route == red", Label = "红色" },
  190. new() { TargetNodeId = "deptHeadGlobal", Expression = "", Label = "跨部门/S9", IsDefault = true },
  191. },
  192. },
  193. Text = new FlowTextItem { X = 220, Y = 234, Value = "问题分级" },
  194. },
  195. RoleNode("deptHeadYellow", 420, 80, "责任部门负责人", SmartOpsImprovementApprovalRules.DeptHeadRole),
  196. RoleNode("deptHeadRed", 420, 200, "责任部门负责人", SmartOpsImprovementApprovalRules.DeptHeadRole),
  197. RoleNode("opsRed", 620, 200, "运营负责人", SmartOpsImprovementApprovalRules.OpsOwnerRole),
  198. RoleNode("deptHeadGlobal", 420, 320, "责任部门负责人", SmartOpsImprovementApprovalRules.DeptHeadRole),
  199. RoleNode("moduleGlobal", 620, 320, "模块负责人", SmartOpsImprovementApprovalRules.ModuleOwnerRole),
  200. RoleNode("opsGlobal", 820, 320, "运营负责人", SmartOpsImprovementApprovalRules.OpsOwnerRole),
  201. Node("end", "bpmn:endEvent", 1020, 200, "结束"),
  202. },
  203. Edges = new List<ApprovalFlowEdgeItem>
  204. {
  205. BuildEdge("e-start-gw", "start", "routeGw", 120, 200, 180, 200),
  206. BuildEdge("e-gw-y", "routeGw", "deptHeadYellow", 250, 180, 380, 80),
  207. BuildEdge("e-gw-r", "routeGw", "deptHeadRed", 260, 200, 380, 200),
  208. BuildEdge("e-gw-g", "routeGw", "deptHeadGlobal", 250, 220, 380, 320),
  209. BuildEdge("e-y-end", "deptHeadYellow", "end", 460, 80, 980, 180),
  210. BuildEdge("e-r-ops", "deptHeadRed", "opsRed", 460, 200, 580, 200),
  211. BuildEdge("e-ops-end", "opsRed", "end", 660, 200, 980, 200),
  212. BuildEdge("e-g-mod", "deptHeadGlobal", "moduleGlobal", 460, 320, 580, 320),
  213. BuildEdge("e-mod-ops", "moduleGlobal", "opsGlobal", 660, 320, 780, 320),
  214. BuildEdge("e-gops-end", "opsGlobal", "end", 860, 320, 980, 220),
  215. }
  216. };
  217. return JsonSerializer.Serialize(item);
  218. }
  219. private static ApprovalFlowNodeItem Node(string id, string type, float x, float y, string name) => new()
  220. {
  221. Id = id,
  222. Type = type,
  223. X = x,
  224. Y = y,
  225. Properties = new FlowProperties { NodeName = name },
  226. Text = new FlowTextItem { X = x, Y = y + 34, Value = name },
  227. };
  228. private static ApprovalFlowNodeItem RoleNode(string id, float x, float y, string name, string roleCode) => new()
  229. {
  230. Id = id,
  231. Type = "bpmn:userTask",
  232. X = x,
  233. Y = y,
  234. Properties = new FlowProperties
  235. {
  236. NodeName = name,
  237. ApproverType = nameof(ApproverTypeEnum.Role),
  238. ApproverIds = roleCode,
  239. ApproverNames = name,
  240. MultiApproveMode = "Any",
  241. TimeoutHours = 72,
  242. TimeoutAction = "Notify",
  243. },
  244. Text = new FlowTextItem { X = x, Y = y + 34, Value = name },
  245. };
  246. private static ApprovalFlowEdgeItem BuildEdge(string id, string source, string target, float sx, float sy, float ex, float ey)
  247. {
  248. return new ApprovalFlowEdgeItem
  249. {
  250. Id = id,
  251. Type = "bpmn:sequenceFlow",
  252. SourceNodeId = source,
  253. TargetNodeId = target,
  254. StartPoint = new FlowEdgePointItem { X = sx, Y = sy },
  255. EndPoint = new FlowEdgePointItem { X = ex, Y = ey },
  256. Properties = new FlowProperties(),
  257. PointsList = new List<FlowEdgePointItem>
  258. {
  259. new() { X = sx, Y = sy },
  260. new() { X = ex, Y = ey },
  261. },
  262. };
  263. }
  264. }