IpqcInspectionFlowSeed.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. using System.Diagnostics;
  2. using System.Text.Json;
  3. using Admin.NET.Plugin.AiDOP.Entity;
  4. using Admin.NET.Plugin.AiDOP.Manufacturing;
  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. /// S6 过程检验单(IPQC)检验员+主管流程种子(幂等)。
  12. ///
  13. /// 顺序:① 扩展表 ado_s6_ipqc_inspection_flow_state(CodeFirst 建表,无 SQL)
  14. /// ② 角色 ROLE_S6_IPQC_INSPECTOR / ROLE_S6_IPQC_SUPERVISOR ③ UAT 成员绑定(superAdmin.NET 同绑两角色,仅 UAT 自审)
  15. /// ④ ApprovalBizType(IPQC_INSPECTION) ⑤ ApprovalFlow 已发布定义(start→N1_INSPECT→N2_SUP_REVIEW→end,节点绑角色)。
  16. /// 全部幂等:存在则跳过,不覆盖、不删除既有角色/流程。superAdmin.NET 不存在时仅告警不崩溃。
  17. /// 本批不含网关/SQE/不合格处置。
  18. /// </summary>
  19. public static class IpqcInspectionFlowSeed
  20. {
  21. public static void EnsureSeed(ISqlSugarClient db)
  22. {
  23. try
  24. {
  25. db.CodeFirst.InitTables(
  26. typeof(ApprovalBizType),
  27. typeof(ApprovalFlowEntity),
  28. typeof(ApprovalFlowVersion));
  29. // 流程状态轻量扩展表(CodeFirst 建表,无 SQL)
  30. db.CodeFirst.InitTables(typeof(AdoS6IpqcInspectionFlowState));
  31. EnsureRoles(db);
  32. EnsureUatMembers(db);
  33. EnsureBizType(db);
  34. EnsurePublishedFlow(db);
  35. }
  36. catch (Exception ex)
  37. {
  38. Trace.TraceWarning("S6 IPQC inspection flow seed: " + ex);
  39. }
  40. }
  41. private static void EnsureRoles(ISqlSugarClient db)
  42. {
  43. EnsureRole(db, IpqcInspectionFlowConst.RoleInspectorId, IpqcInspectionFlowConst.RoleInspectorCode, "过程检验员", 820);
  44. EnsureRole(db, IpqcInspectionFlowConst.RoleSupervisorId, IpqcInspectionFlowConst.RoleSupervisorCode, "过程检验主管", 821);
  45. }
  46. private static void EnsureRole(ISqlSugarClient db, long id, string code, string name, int orderNo)
  47. {
  48. var exists = db.Queryable<SysRole>().ClearFilter().Any(x => x.Code == code);
  49. if (exists) return;
  50. db.Insertable(new SysRole
  51. {
  52. Id = id,
  53. TenantId = SqlSugarConst.DefaultTenantId,
  54. Name = name,
  55. Code = code,
  56. OrderNo = orderNo,
  57. DataScope = DataScopeEnum.Self,
  58. Status = StatusEnum.Enable,
  59. Remark = "S6 过程检验流程角色",
  60. CreateTime = DateTime.Now,
  61. }).ExecuteCommand();
  62. }
  63. private static void EnsureUatMembers(ISqlSugarClient db)
  64. {
  65. var user = db.Queryable<SysUser>().ClearFilter()
  66. .Where(x => x.Account == IpqcInspectionFlowConst.UatAccount)
  67. .First();
  68. if (user == null)
  69. {
  70. Trace.TraceWarning($"S6 IPQC flow seed: UAT 账号 {IpqcInspectionFlowConst.UatAccount} 不存在,跳过成员绑定(阶段2 冒烟前须指定成员)");
  71. return;
  72. }
  73. EnsureUserRole(db, user.Id, IpqcInspectionFlowConst.RoleInspectorId);
  74. EnsureUserRole(db, user.Id, IpqcInspectionFlowConst.RoleSupervisorId);
  75. }
  76. private static void EnsureUserRole(ISqlSugarClient db, long userId, long roleId)
  77. {
  78. var exists = db.Queryable<SysUserRole>().ClearFilter().Any(x => x.UserId == userId && x.RoleId == roleId);
  79. if (exists) return;
  80. db.Insertable(new SysUserRole
  81. {
  82. Id = YitIdHelper.NextId(),
  83. UserId = userId,
  84. RoleId = roleId,
  85. }).ExecuteCommand();
  86. }
  87. private static void EnsureBizType(ISqlSugarClient db)
  88. {
  89. var exists = db.Queryable<ApprovalBizType>().Any(x => x.Code == IpqcInspectionFlowConst.BizType);
  90. if (exists) return;
  91. db.Insertable(new ApprovalBizType
  92. {
  93. Id = YitIdHelper.NextId(),
  94. Code = IpqcInspectionFlowConst.BizType,
  95. Name = "过程检验单审批",
  96. Remark = "S6 过程检验单 检验员→主管 审批流",
  97. IsEnabled = true,
  98. CreateTime = DateTime.Now,
  99. UpdateTime = DateTime.Now,
  100. }).ExecuteCommand();
  101. }
  102. private static void EnsurePublishedFlow(ISqlSugarClient db)
  103. {
  104. var orgIds = db.Queryable<SysOrg>()
  105. .Select(x => x.Id)
  106. .ToList()
  107. .Where(x => x > 0)
  108. .Distinct()
  109. .ToList();
  110. if (orgIds.Count == 0) orgIds.Add(0);
  111. var now = DateTime.Now;
  112. var flowJson = BuildFlowJson();
  113. foreach (var orgId in orgIds)
  114. {
  115. var existing = db.Queryable<ApprovalFlowEntity>()
  116. .Where(x => x.BizType == IpqcInspectionFlowConst.BizType && x.OrgId == orgId && x.IsPublished && !x.IsDelete)
  117. .OrderByDescending(x => x.Version)
  118. .First();
  119. // 已有已发布定义则跳过(幂等,不覆盖)。历史实例用各自 FlowJsonSnapshot。
  120. if (existing != null) continue;
  121. var flow = new ApprovalFlowEntity
  122. {
  123. Id = YitIdHelper.NextId(),
  124. Code = $"S6IPQC_{orgId}",
  125. Name = "过程检验单审批",
  126. BizType = IpqcInspectionFlowConst.BizType,
  127. FormJson = "{}",
  128. FlowJson = flowJson,
  129. Status = 1,
  130. Remark = "系统默认流程 v1:开始-检验员检验-检验主管审核-结束",
  131. Version = 1,
  132. IsPublished = true,
  133. OrgId = orgId,
  134. CreateTime = now,
  135. UpdateTime = now,
  136. };
  137. db.Insertable(flow).ExecuteCommand();
  138. db.Insertable(new ApprovalFlowVersion
  139. {
  140. Id = YitIdHelper.NextId(),
  141. FlowId = flow.Id,
  142. Version = flow.Version,
  143. FlowJson = flow.FlowJson,
  144. FormJson = flow.FormJson,
  145. PublishTime = now,
  146. PublisherName = "系统初始化",
  147. CreateTime = now,
  148. UpdateTime = now,
  149. }).ExecuteCommand();
  150. }
  151. }
  152. private static string BuildFlowJson()
  153. {
  154. var item = new ApprovalFlowItem
  155. {
  156. Nodes = new List<ApprovalFlowNodeItem>
  157. {
  158. new()
  159. {
  160. Id = "start",
  161. Type = "bpmn:startEvent",
  162. X = 100,
  163. Y = 120,
  164. Properties = new FlowProperties { NodeName = "开始" },
  165. Text = new FlowTextItem { X = 100, Y = 154, Value = "开始" },
  166. },
  167. new()
  168. {
  169. Id = IpqcInspectionFlowConst.NodeInspect,
  170. Type = "bpmn:userTask",
  171. X = 300,
  172. Y = 120,
  173. Properties = new FlowProperties
  174. {
  175. NodeName = "检验员检验",
  176. ApproverType = nameof(ApproverTypeEnum.Role),
  177. ApproverIds = IpqcInspectionFlowConst.RoleInspectorId.ToString(),
  178. ApproverNames = "过程检验员",
  179. MultiApproveMode = "Any",
  180. },
  181. Text = new FlowTextItem { X = 300, Y = 154, Value = "检验员检验" },
  182. },
  183. new()
  184. {
  185. Id = IpqcInspectionFlowConst.NodeSupervisor,
  186. Type = "bpmn:userTask",
  187. X = 500,
  188. Y = 120,
  189. Properties = new FlowProperties
  190. {
  191. NodeName = "检验主管审核",
  192. ApproverType = nameof(ApproverTypeEnum.Role),
  193. ApproverIds = IpqcInspectionFlowConst.RoleSupervisorId.ToString(),
  194. ApproverNames = "过程检验主管",
  195. MultiApproveMode = "Any",
  196. },
  197. Text = new FlowTextItem { X = 500, Y = 154, Value = "检验主管审核" },
  198. },
  199. new()
  200. {
  201. Id = "end",
  202. Type = "bpmn:endEvent",
  203. X = 700,
  204. Y = 120,
  205. Properties = new FlowProperties { NodeName = "结束" },
  206. Text = new FlowTextItem { X = 700, Y = 154, Value = "结束" },
  207. },
  208. },
  209. Edges = new List<ApprovalFlowEdgeItem>
  210. {
  211. BuildEdge("edge-start-n1", "start", IpqcInspectionFlowConst.NodeInspect, 140, 120, 260, 120),
  212. BuildEdge("edge-n1-n2", IpqcInspectionFlowConst.NodeInspect, IpqcInspectionFlowConst.NodeSupervisor, 340, 120, 460, 120),
  213. BuildEdge("edge-n2-end", IpqcInspectionFlowConst.NodeSupervisor, "end", 540, 120, 660, 120),
  214. }
  215. };
  216. return JsonSerializer.Serialize(item);
  217. }
  218. private static ApprovalFlowEdgeItem BuildEdge(string id, string source, string target, float sx, float sy, float ex, float ey)
  219. {
  220. return new ApprovalFlowEdgeItem
  221. {
  222. Id = id,
  223. Type = "bpmn:sequenceFlow",
  224. SourceNodeId = source,
  225. TargetNodeId = target,
  226. StartPoint = new FlowEdgePointItem { X = sx, Y = sy },
  227. EndPoint = new FlowEdgePointItem { X = ex, Y = ey },
  228. Properties = new FlowProperties(),
  229. PointsList = new List<FlowEdgePointItem>
  230. {
  231. new() { X = sx, Y = sy },
  232. new() { X = ex, Y = ey },
  233. },
  234. };
  235. }
  236. }