S8DashboardCellConfigService.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. using Admin.NET.Plugin.AiDOP.Entity.S8;
  2. namespace Admin.NET.Plugin.AiDOP.Service.S8;
  3. /// <summary>
  4. /// S8 大屏卡片配置(ado_s8_dashboard_cell_config)CRUD。
  5. /// 列表合并全局基线(0/0)与工厂覆盖,同 (pageCode, cellCode) 以工厂记录优先。
  6. /// </summary>
  7. public class S8DashboardCellConfigService : ITransient
  8. {
  9. private readonly SqlSugarRepository<AdoS8DashboardCellConfig> _rep;
  10. public S8DashboardCellConfigService(SqlSugarRepository<AdoS8DashboardCellConfig> rep) => _rep = rep;
  11. public async Task<List<AdoS8DashboardCellConfig>> ListAsync(long tenantId, long factoryId)
  12. {
  13. var all = await _rep.AsQueryable()
  14. .Where(x => (x.TenantId == 0 && x.FactoryId == 0)
  15. || (x.TenantId == tenantId && x.FactoryId == factoryId))
  16. .ToListAsync();
  17. return all
  18. .GroupBy(x => (x.PageCode, x.CellCode))
  19. .Select(g => g.OrderByDescending(x => x.FactoryId).First())
  20. .OrderBy(x => x.PageCode)
  21. .ThenBy(x => x.SortNo)
  22. .ThenBy(x => x.CellCode)
  23. .ToList();
  24. }
  25. public async Task<AdoS8DashboardCellConfig> CreateAsync(AdoS8DashboardCellConfig body)
  26. {
  27. ValidateAndNormalize(body);
  28. var exists = await _rep.AsQueryable()
  29. .AnyAsync(x => x.TenantId == body.TenantId && x.FactoryId == body.FactoryId
  30. && x.PageCode == body.PageCode && x.CellCode == body.CellCode);
  31. if (exists) throw new S8BizException("同一工厂下页面与卡片编码组合已存在");
  32. body.Id = 0;
  33. body.CreatedAt = DateTime.Now;
  34. body.UpdatedAt = null;
  35. await _rep.InsertAsync(body);
  36. return body;
  37. }
  38. public async Task<AdoS8DashboardCellConfig> UpdateAsync(long id, AdoS8DashboardCellConfig body)
  39. {
  40. var e = await _rep.GetByIdAsync(id) ?? throw new S8BizException("记录不存在");
  41. ValidateAndNormalize(body);
  42. var dup = await _rep.AsQueryable()
  43. .AnyAsync(x => x.Id != id && x.TenantId == body.TenantId && x.FactoryId == body.FactoryId
  44. && x.PageCode == body.PageCode && x.CellCode == body.CellCode);
  45. if (dup) throw new S8BizException("同一工厂下页面与卡片编码组合已存在");
  46. body.Id = id;
  47. body.CreatedAt = e.CreatedAt;
  48. body.UpdatedAt = DateTime.Now;
  49. await _rep.UpdateAsync(body);
  50. return body;
  51. }
  52. public async Task DeleteAsync(long id) => await _rep.DeleteByIdAsync(id);
  53. private static void ValidateAndNormalize(AdoS8DashboardCellConfig body)
  54. {
  55. if (string.IsNullOrWhiteSpace(body.PageCode) || string.IsNullOrWhiteSpace(body.CellCode))
  56. throw new S8BizException("页面编码与卡片编码必填");
  57. body.PageCode = body.PageCode.Trim();
  58. body.CellCode = body.CellCode.Trim();
  59. if (body.CellTitle != null) body.CellTitle = body.CellTitle.Trim();
  60. if (string.IsNullOrWhiteSpace(body.BindingType))
  61. body.BindingType = "CUSTOM";
  62. body.BindingType = body.BindingType.Trim().ToUpperInvariant();
  63. if (body.BindingType is not ("EXCEPTION_TYPE" or "AGGREGATE" or "CUSTOM"))
  64. throw new S8BizException("绑定类型须为 EXCEPTION_TYPE / AGGREGATE / CUSTOM");
  65. switch (body.BindingType)
  66. {
  67. case "EXCEPTION_TYPE":
  68. if (string.IsNullOrWhiteSpace(body.ExceptionTypeCode))
  69. throw new S8BizException("绑定类型为异常类型时须填写异常类型编码");
  70. body.ExceptionTypeCode = body.ExceptionTypeCode.Trim();
  71. body.AggregateScope = null;
  72. break;
  73. case "AGGREGATE":
  74. if (string.IsNullOrWhiteSpace(body.AggregateScope))
  75. throw new S8BizException("绑定类型为域聚合时须选择聚合范围");
  76. body.AggregateScope = body.AggregateScope!.Trim();
  77. body.ExceptionTypeCode = null;
  78. break;
  79. default:
  80. body.ExceptionTypeCode = null;
  81. body.AggregateScope = null;
  82. break;
  83. }
  84. if (string.IsNullOrWhiteSpace(body.StatMetric)) body.StatMetric = "OPEN_COUNT";
  85. body.StatMetric = body.StatMetric.Trim().ToUpperInvariant();
  86. if (body.StatMetric is not ("OPEN_COUNT" or "FREQUENCY" or "AVG_DURATION" or "CLOSE_RATE"))
  87. throw new S8BizException("统计指标须为 OPEN_COUNT / FREQUENCY / AVG_DURATION / CLOSE_RATE");
  88. if (string.IsNullOrWhiteSpace(body.TimeWindow)) body.TimeWindow = "LAST_24H";
  89. body.TimeWindow = body.TimeWindow.Trim().ToUpperInvariant();
  90. if (body.TimeWindow is not ("TODAY" or "LAST_24H" or "LAST_7D" or "LAST_30D"))
  91. throw new S8BizException("时间窗须为 TODAY / LAST_24H / LAST_7D / LAST_30D");
  92. if (string.IsNullOrWhiteSpace(body.DeptGroupBy)) body.DeptGroupBy = "OWNER";
  93. body.DeptGroupBy = body.DeptGroupBy.Trim().ToUpperInvariant();
  94. if (body.DeptGroupBy is not ("OWNER" or "OCCUR"))
  95. throw new S8BizException("部门聚合维度须为 OWNER(责任部门)或 OCCUR(发生部门)");
  96. if (body.FilterExpression != null && body.FilterExpression.Length > 1000)
  97. throw new S8BizException("筛选表达式过长");
  98. }
  99. }