S8ConfigDraftService.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. using Admin.NET.Plugin.AiDOP.Dto.S8;
  2. using Admin.NET.Plugin.AiDOP.Entity.S8;
  3. namespace Admin.NET.Plugin.AiDOP.Service.S8;
  4. internal static class S8ConfigDraftStatus
  5. {
  6. public const string InProgress = "IN_PROGRESS";
  7. public const string Generated = "GENERATED";
  8. }
  9. public class S8ConfigDraftService : ITransient
  10. {
  11. private readonly SqlSugarRepository<AdoS8ConfigDraft> _rep;
  12. private readonly S8WatchRuleService _watchRuleService;
  13. public S8ConfigDraftService(
  14. SqlSugarRepository<AdoS8ConfigDraft> rep,
  15. S8WatchRuleService watchRuleService)
  16. {
  17. _rep = rep;
  18. _watchRuleService = watchRuleService;
  19. }
  20. public async Task<AdoS8ConfigDraftListResultDto> ListAsync(AdoS8ConfigDraftListQueryDto query)
  21. {
  22. var page = query.Page < 1 ? 1 : query.Page;
  23. var pageSize = query.PageSize < 1 ? 20 : Math.Min(query.PageSize, 200);
  24. var status = string.IsNullOrWhiteSpace(query.Status) ? null : query.Status.Trim();
  25. var q = _rep.AsQueryable()
  26. .Where(x => x.TenantId == query.TenantId && x.FactoryId == query.FactoryId);
  27. if (status != null)
  28. q = q.Where(x => x.Status == status);
  29. RefAsync<int> total = 0;
  30. var rows = await q
  31. .OrderBy(x => x.Id, OrderByType.Desc)
  32. .Select(x => new AdoS8ConfigDraftListItemDto
  33. {
  34. Id = x.Id,
  35. TenantId = x.TenantId,
  36. FactoryId = x.FactoryId,
  37. DraftCode = x.DraftCode,
  38. DraftName = x.DraftName,
  39. Status = x.Status,
  40. CurrentStep = x.CurrentStep,
  41. Mechanism = x.Mechanism,
  42. StageCode = x.StageCode,
  43. OrderFlowCode = x.OrderFlowCode,
  44. ExceptionTypeCode = x.ExceptionTypeCode,
  45. GeneratedRuleId = x.GeneratedRuleId,
  46. Remark = x.Remark,
  47. CreatedAt = x.CreatedAt,
  48. UpdatedAt = x.UpdatedAt
  49. })
  50. .ToPageListAsync(page, pageSize, total);
  51. return new AdoS8ConfigDraftListResultDto
  52. {
  53. Items = rows,
  54. Total = total.Value,
  55. Page = page,
  56. PageSize = pageSize
  57. };
  58. }
  59. public async Task<AdoS8ConfigDraftDetailDto> GetAsync(long id)
  60. {
  61. var e = await _rep.GetByIdAsync(id) ?? throw new S8BizException("草稿不存在");
  62. return ToDetail(e);
  63. }
  64. public async Task<AdoS8ConfigDraftDetailDto> CreateAsync(AdoS8ConfigDraftCreateDto dto)
  65. {
  66. if (string.IsNullOrWhiteSpace(dto.DraftCode))
  67. throw new S8BizException("草稿编码必填");
  68. if (string.IsNullOrWhiteSpace(dto.WizardJson))
  69. throw new S8BizException("草稿 wizard_json 必填");
  70. var draftCode = dto.DraftCode.Trim();
  71. var exists = await _rep.AsQueryable()
  72. .AnyAsync(x => x.TenantId == dto.TenantId && x.FactoryId == dto.FactoryId && x.DraftCode == draftCode);
  73. if (exists) throw new S8BizException("草稿编码已存在");
  74. var entity = new AdoS8ConfigDraft
  75. {
  76. TenantId = dto.TenantId,
  77. FactoryId = dto.FactoryId,
  78. DraftCode = draftCode,
  79. DraftName = NormalizeOrNull(dto.DraftName),
  80. WizardJson = dto.WizardJson,
  81. CurrentStep = dto.CurrentStep ?? 0,
  82. Mechanism = NormalizeOrNull(dto.Mechanism),
  83. StageCode = NormalizeOrNull(dto.StageCode),
  84. OrderFlowCode = NormalizeOrNull(dto.OrderFlowCode),
  85. ExceptionTypeCode = NormalizeOrNull(dto.ExceptionTypeCode),
  86. Remark = NormalizeOrNull(dto.Remark),
  87. Status = S8ConfigDraftStatus.InProgress,
  88. CreatedAt = DateTime.Now
  89. };
  90. entity.Id = await _rep.AsInsertable(entity).ExecuteReturnBigIdentityAsync();
  91. return ToDetail(entity);
  92. }
  93. public async Task<AdoS8ConfigDraftDetailDto> UpdateAsync(long id, AdoS8ConfigDraftUpdateDto dto)
  94. {
  95. var e = await _rep.GetByIdAsync(id) ?? throw new S8BizException("草稿不存在");
  96. if (e.Status == S8ConfigDraftStatus.Generated)
  97. throw new S8BizException("草稿已生成正式规则,禁止再编辑");
  98. if (dto.DraftName != null) e.DraftName = NormalizeOrNull(dto.DraftName);
  99. if (dto.WizardJson != null)
  100. {
  101. if (string.IsNullOrWhiteSpace(dto.WizardJson))
  102. throw new S8BizException("wizard_json 不能为空字符串");
  103. e.WizardJson = dto.WizardJson;
  104. }
  105. if (dto.CurrentStep.HasValue) e.CurrentStep = dto.CurrentStep.Value;
  106. if (dto.Mechanism != null) e.Mechanism = NormalizeOrNull(dto.Mechanism);
  107. if (dto.StageCode != null) e.StageCode = NormalizeOrNull(dto.StageCode);
  108. if (dto.OrderFlowCode != null) e.OrderFlowCode = NormalizeOrNull(dto.OrderFlowCode);
  109. if (dto.ExceptionTypeCode != null) e.ExceptionTypeCode = NormalizeOrNull(dto.ExceptionTypeCode);
  110. if (dto.Remark != null) e.Remark = NormalizeOrNull(dto.Remark);
  111. e.UpdatedAt = DateTime.Now;
  112. await _rep.UpdateAsync(e);
  113. return ToDetail(e);
  114. }
  115. public async Task DeleteAsync(long id)
  116. {
  117. var e = await _rep.GetByIdAsync(id) ?? throw new S8BizException("草稿不存在");
  118. await _rep.DeleteByIdAsync(e.Id);
  119. }
  120. public async Task<AdoS8ConfigDraftGenerateRuleResultDto> GenerateRuleAsync(long id, AdoS8ConfigDraftGenerateRuleDto dto)
  121. {
  122. var draft = await _rep.GetByIdAsync(id) ?? throw new S8BizException("草稿不存在");
  123. if (draft.GeneratedRuleId.HasValue)
  124. {
  125. return new AdoS8ConfigDraftGenerateRuleResultDto
  126. {
  127. RuleId = draft.GeneratedRuleId.Value,
  128. RuleCode = await ResolveExistingRuleCodeAsync(draft.GeneratedRuleId.Value),
  129. DraftStatus = draft.Status
  130. };
  131. }
  132. if (draft.Status == S8ConfigDraftStatus.Generated)
  133. throw new S8BizException("草稿状态异常:已标记 GENERATED 但未回写规则 ID");
  134. var payload = dto.RulePayload ?? throw new S8BizException("rulePayload 必填");
  135. if (string.IsNullOrWhiteSpace(payload.RuleCode))
  136. throw new S8BizException("rulePayload.ruleCode 必填");
  137. // 安全收口:强制对齐草稿租户/工厂、强制 enabled=false。
  138. payload.Id = 0;
  139. payload.TenantId = draft.TenantId;
  140. payload.FactoryId = draft.FactoryId;
  141. payload.Enabled = false;
  142. var db = _rep.Context;
  143. await db.Ado.BeginTranAsync();
  144. try
  145. {
  146. var created = await _watchRuleService.CreateAsync(payload);
  147. // S8WatchRuleService.CreateAsync 内部用 InsertAsync 不回填 Id;按 RuleCode 反查真实 id。
  148. var newRuleId = created.Id;
  149. if (newRuleId <= 0)
  150. {
  151. newRuleId = await db.Queryable<AdoS8WatchRule>()
  152. .Where(x => x.TenantId == draft.TenantId
  153. && x.FactoryId == draft.FactoryId
  154. && x.RuleCode == created.RuleCode)
  155. .Select(x => x.Id)
  156. .FirstAsync();
  157. }
  158. if (newRuleId <= 0)
  159. throw new S8BizException("生成规则失败:无法定位新规则 id");
  160. await db.Updateable<AdoS8ConfigDraft>()
  161. .SetColumns(x => new AdoS8ConfigDraft
  162. {
  163. GeneratedRuleId = newRuleId,
  164. Status = S8ConfigDraftStatus.Generated,
  165. UpdatedAt = DateTime.Now
  166. })
  167. .Where(x => x.Id == draft.Id)
  168. .ExecuteCommandAsync();
  169. await db.Ado.CommitTranAsync();
  170. return new AdoS8ConfigDraftGenerateRuleResultDto
  171. {
  172. RuleId = newRuleId,
  173. RuleCode = created.RuleCode,
  174. DraftStatus = S8ConfigDraftStatus.Generated
  175. };
  176. }
  177. catch
  178. {
  179. await db.Ado.RollbackTranAsync();
  180. throw;
  181. }
  182. }
  183. private async Task<string> ResolveExistingRuleCodeAsync(long ruleId)
  184. {
  185. var rule = await _rep.Context.Queryable<AdoS8WatchRule>()
  186. .Where(x => x.Id == ruleId)
  187. .Select(x => new { x.RuleCode })
  188. .FirstAsync();
  189. return rule?.RuleCode ?? string.Empty;
  190. }
  191. private static AdoS8ConfigDraftDetailDto ToDetail(AdoS8ConfigDraft e) => new()
  192. {
  193. Id = e.Id,
  194. TenantId = e.TenantId,
  195. FactoryId = e.FactoryId,
  196. DraftCode = e.DraftCode,
  197. DraftName = e.DraftName,
  198. Status = e.Status,
  199. CurrentStep = e.CurrentStep,
  200. Mechanism = e.Mechanism,
  201. StageCode = e.StageCode,
  202. OrderFlowCode = e.OrderFlowCode,
  203. ExceptionTypeCode = e.ExceptionTypeCode,
  204. GeneratedRuleId = e.GeneratedRuleId,
  205. Remark = e.Remark,
  206. CreatedAt = e.CreatedAt,
  207. UpdatedAt = e.UpdatedAt,
  208. WizardJson = e.WizardJson
  209. };
  210. private static string? NormalizeOrNull(string? value)
  211. {
  212. if (string.IsNullOrWhiteSpace(value)) return null;
  213. var trimmed = value.Trim();
  214. return trimmed.Length == 0 ? null : trimmed;
  215. }
  216. }