S8IssueLedgerService.cs 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. using Admin.NET.Plugin.AiDOP.Dto.S8;
  2. using Admin.NET.Plugin.AiDOP.Entity.S8;
  3. using Admin.NET.Plugin.AiDOP.Infrastructure;
  4. using Admin.NET.Plugin.AiDOP.Infrastructure.S8;
  5. namespace Admin.NET.Plugin.AiDOP.Service.S8;
  6. /// <summary>
  7. /// G-06 只读最小问题台账服务。
  8. /// 仅按《G-06 开发清单 最小问题台账》§4.1~§4.3 对 ado_s8_exception 做只读聚合;
  9. /// 一异常单一台账条目;不写库、不落缓存、不建独立表;State 仅接受 discovered / processing / closed 或空。
  10. /// </summary>
  11. public class S8IssueLedgerService : ITransient
  12. {
  13. private readonly SqlSugarRepository<AdoS8Exception> _rep;
  14. public S8IssueLedgerService(SqlSugarRepository<AdoS8Exception> rep)
  15. {
  16. _rep = rep;
  17. }
  18. /// <summary>
  19. /// 查询台账条目。State 非法、分页越界由 PagingGuard 收敛;State 非法抛 S8BizException。
  20. /// </summary>
  21. public async Task<(int total, List<AdoS8IssueLedgerItemDto> list)> QueryAsync(
  22. AdoS8IssueLedgerQueryDto q)
  23. {
  24. (q.Page, q.PageSize) = PagingGuard.Normalize(q.Page, q.PageSize, maxPageSize: 100);
  25. var statuses = ResolveStatuses(q.State);
  26. var query = _rep.AsQueryable()
  27. .Where(x => x.TenantId == q.TenantId && x.FactoryId == q.FactoryId)
  28. .Where(x => !x.IsDeleted)
  29. .Where(x => statuses.Contains(x.Status))
  30. .WhereIF(q.ExceptionId.HasValue, x => x.Id == q.ExceptionId!.Value)
  31. .WhereIF(q.BeginTime.HasValue, x => x.CreatedAt >= q.BeginTime!.Value)
  32. .WhereIF(q.EndTime.HasValue, x => x.CreatedAt <= q.EndTime!.Value)
  33. .OrderBy(x => x.CreatedAt, OrderByType.Desc);
  34. var total = await query.CountAsync();
  35. var rows = await query
  36. .Skip((q.Page - 1) * q.PageSize)
  37. .Take(q.PageSize)
  38. .ToListAsync();
  39. var list = rows.Select(x => new AdoS8IssueLedgerItemDto
  40. {
  41. Id = x.Id,
  42. TenantId = x.TenantId,
  43. FactoryId = x.FactoryId,
  44. SourceType = x.SourceType,
  45. State = S8IssueLedgerStates.TryGetShortCode(x.Status) ?? string.Empty,
  46. RawStatus = x.Status,
  47. CreatedAt = x.CreatedAt,
  48. ClosedAt = x.ClosedAt
  49. }).ToList();
  50. return (total, list);
  51. }
  52. // 入参短码 → 主链状态集合:
  53. // "discovered" → [NEW]
  54. // "processing" → [ASSIGNED, IN_PROGRESS, PENDING_VERIFICATION, ESCALATED, RESOLVED]
  55. // "closed" → [CLOSED, REJECTED]
  56. // null / 空 → 三档合并(即八个现行主链状态全量)
  57. // 其他(含 hold / suspend / pending / all)→ 抛 S8BizException(参数非法)
  58. private static IReadOnlyList<string> ResolveStatuses(string? state)
  59. {
  60. if (string.IsNullOrWhiteSpace(state))
  61. return S8IssueLedgerStates.AllStatuses;
  62. var normalized = state.Trim().ToLowerInvariant();
  63. return normalized switch
  64. {
  65. S8IssueLedgerStates.Discovered => S8IssueLedgerStates.GetStatuses(S8IssueLedgerStates.Discovered),
  66. S8IssueLedgerStates.Processing => S8IssueLedgerStates.GetStatuses(S8IssueLedgerStates.Processing),
  67. S8IssueLedgerStates.Closed => S8IssueLedgerStates.GetStatuses(S8IssueLedgerStates.Closed),
  68. _ => throw new S8BizException("state 仅支持 discovered / processing / closed 或留空")
  69. };
  70. }
  71. }