WarningService.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. using EasyTemplate.Tool;
  2. using EasyTemplate.Tool.Entity;
  3. using EasyTemplate.Tool.Entity.App;
  4. using SqlSugar;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Threading.Tasks;
  9. namespace EasyTemplate.Service
  10. {
  11. /// <summary>
  12. /// 预警告统计服务
  13. /// </summary>
  14. public class WarningService
  15. {
  16. private readonly SqlSugarRepository<TPrewarning> _prewarning;
  17. private readonly SqlSugarRepository<TRecord> _record;
  18. public WarningService(SqlSugarRepository<TPrewarning> prewarning, SqlSugarRepository<TRecord> record)
  19. {
  20. _prewarning = prewarning;
  21. _record = record;
  22. }
  23. /// <summary>
  24. /// 获取 35 天内所有油枪的统计数据
  25. /// </summary>
  26. public async Task<List<WarningStatistics>> Get35DaysStatisticsAsync()
  27. {
  28. var endDate = DateOnly.FromDateTime(DateTime.Today);
  29. var startDate = endDate.AddDays(-34); // 包含今天共 35 天
  30. return await CalculateStatisticsAsync(startDate, endDate);
  31. }
  32. /// <summary>
  33. /// 按日期范围获取统计数据
  34. /// </summary>
  35. public async Task<List<WarningStatistics>> GetStatisticsByDateRangeAsync(DateOnly startDate, DateOnly endDate)
  36. {
  37. return await CalculateStatisticsAsync(startDate, endDate);
  38. }
  39. /// <summary>
  40. /// 按油枪和日期范围筛选统计数据
  41. /// </summary>
  42. public async Task<List<WarningStatistics>> GetStatisticsByFilterAsync(WarningStatisticsQuery query)
  43. {
  44. var endDate = query.EndDate ?? DateOnly.FromDateTime(DateTime.Today);
  45. var startDate = query.StartDate ?? endDate.AddDays(-34);
  46. var allStats = await CalculateStatisticsAsync(startDate, endDate);
  47. // 按油枪筛选
  48. if (query.NozzleId.HasValue)
  49. {
  50. allStats = allStats.Where(s => s.nozzle == query.NozzleId.Value).ToList();
  51. }
  52. return allStats;
  53. }
  54. /// <summary>
  55. /// 更新指定日期的统计数据(用于新交易插入后)
  56. /// </summary>
  57. public async Task UpdateDailyStatisticsAsync(DateOnly date, int nozzleId)
  58. {
  59. try
  60. {
  61. Console.WriteLine($"[预警告统计] 开始更新油枪{nozzleId},日期:{date} 的统计数据");
  62. // 重新计算该油枪在该日期的统计
  63. var stats = await CalculateSingleDayStatisticsAsync(date, nozzleId);
  64. if (stats != null)
  65. {
  66. Console.WriteLine($"[预警告统计] 更新成功 - 总笔数:{stats.daily_total}, 超标:{stats.daily_overproof}, 超标率:{stats.daily_overproofrate}%");
  67. }
  68. }
  69. catch (Exception ex)
  70. {
  71. Console.WriteLine($"[预警告统计] 更新失败:{ex.Message}");
  72. }
  73. }
  74. /// <summary>
  75. /// 计算单个日期的统计数据
  76. /// </summary>
  77. private async Task<WarningStatistics> CalculateSingleDayStatisticsAsync(DateOnly date, int nozzleId)
  78. {
  79. // 获取当天的预警告记录
  80. var prewarning = await _prewarning.AsQueryable()
  81. .Where(p => p.date == date && p.nozzle == nozzleId)
  82. .FirstAsync();
  83. if (prewarning == null)
  84. {
  85. return null;
  86. }
  87. return new WarningStatistics
  88. {
  89. nozzle = nozzleId,
  90. statistics_date = date,
  91. daily_total = prewarning.total,
  92. daily_overproof = prewarning.overproof,
  93. daily_overproofrate = prewarning.overproofrate,
  94. daily_overproof_alert = prewarning.overproof_alert,
  95. daily_overproofrate_alert = prewarning.overproofrate_alert,
  96. daily_overproof_2 = prewarning.overproof_2,
  97. daily_overproofrate_2 = prewarning.overproofrate_2,
  98. is_accumulated = prewarning.total >= 5,
  99. accumulated_days = 1
  100. };
  101. }
  102. /// <summary>
  103. /// 核心统计计算逻辑
  104. /// </summary>
  105. private async Task<List<WarningStatistics>> CalculateStatisticsAsync(DateOnly startDate, DateOnly endDate)
  106. {
  107. Console.WriteLine($"[预警告统计] 开始计算统计,范围:{startDate} 至 {endDate}");
  108. var results = new List<WarningStatistics>();
  109. // 获取该日期范围内的所有预警告记录
  110. var prewarnings = await _prewarning.AsQueryable()
  111. .Where(p => p.date >= startDate && p.date <= endDate)
  112. .ToListAsync();
  113. // 按油枪分组
  114. var groupedByNozzle = prewarnings.GroupBy(p => p.nozzle);
  115. foreach (var nozzleGroup in groupedByNozzle)
  116. {
  117. var nozzleId = nozzleGroup.Key;
  118. var sortedData = nozzleGroup.OrderBy(p => p.date).ToList();
  119. // 为每一天计算统计数据
  120. for (int i = 0; i < sortedData.Count; i++)
  121. {
  122. var currentPrewarning = sortedData[i];
  123. var currentDate = currentPrewarning.date;
  124. var stats = new WarningStatistics
  125. {
  126. nozzle = nozzleId,
  127. statistics_date = currentDate,
  128. daily_total = currentPrewarning.total,
  129. daily_overproof = currentPrewarning.overproof,
  130. daily_overproofrate = currentPrewarning.overproofrate,
  131. daily_overproof_alert = currentPrewarning.overproof_alert,
  132. daily_overproofrate_alert = currentPrewarning.overproofrate_alert,
  133. daily_overproof_2 = currentPrewarning.overproof_2,
  134. daily_overproofrate_2 = currentPrewarning.overproofrate_2
  135. };
  136. // 计算 35 天累计统计
  137. CalculateAccumulatedStatistics(sortedData, i, stats);
  138. results.Add(stats);
  139. }
  140. }
  141. Console.WriteLine($"[预警告统计] 计算完成,共{results.Count}条记录");
  142. return results;
  143. }
  144. /// <summary>
  145. /// 计算累计统计数据(核心业务逻辑)
  146. /// 规则:从当前日期往前找,直到累计笔数>=5 或达到 35 天上限
  147. /// </summary>
  148. private void CalculateAccumulatedStatistics(List<TPrewarning> sortedData, int currentIndex, WarningStatistics stats)
  149. {
  150. int accumulatedTotal = 0;
  151. int accumulatedOverproof = 0;
  152. int accumulatedOverproofAlert = 0;
  153. int accumulatedOverproof2 = 0;
  154. int accumulatedDays = 0;
  155. // 从当前日期往前累加,直到满足条件或达到 35 天
  156. for (int i = currentIndex; i >= 0 && (currentIndex - i) < 35; i--)
  157. {
  158. var day = sortedData[i];
  159. accumulatedTotal += day.total;
  160. accumulatedOverproof += day.overproof;
  161. accumulatedOverproofAlert += day.overproof_alert;
  162. accumulatedOverproof2 += day.overproof_2;
  163. accumulatedDays++;
  164. // 如果累计笔数>=5,停止累加
  165. if (accumulatedTotal >= 5)
  166. {
  167. break;
  168. }
  169. }
  170. // 设置累计统计结果
  171. stats.total_count = accumulatedTotal;
  172. stats.total_overproof = accumulatedOverproof;
  173. stats.total_overproof_alert = accumulatedOverproofAlert;
  174. stats.total_overproof_2 = accumulatedOverproof2;
  175. stats.accumulated_days = accumulatedDays;
  176. stats.is_accumulated = accumulatedTotal >= 5;
  177. // 计算累计超标率(避免除以 0)
  178. if (accumulatedTotal > 0)
  179. {
  180. stats.total_overproofrate = (100 * accumulatedOverproof) / accumulatedTotal;
  181. stats.total_overproofrate_alert = (100 * accumulatedOverproofAlert) / accumulatedTotal;
  182. stats.total_overproofrate_2 = (100 * accumulatedOverproof2) / accumulatedTotal;
  183. }
  184. else
  185. {
  186. stats.total_overproofrate = 0;
  187. stats.total_overproofrate_alert = 0;
  188. stats.total_overproofrate_2 = 0;
  189. }
  190. }
  191. /// <summary>
  192. /// 获取所有有数据的油枪 ID 列表
  193. /// </summary>
  194. public async Task<List<int>> GetAllNozzleIdsAsync()
  195. {
  196. var nozzles = await _prewarning.AsQueryable()
  197. .Select(p => p.nozzle)
  198. .Distinct()
  199. .ToListAsync();
  200. return nozzles;
  201. }
  202. /// <summary>
  203. /// 获取统计日期范围(最早到最新)
  204. /// </summary>
  205. public async Task<(DateOnly minDate, DateOnly maxDate)> GetDateRangeAsync()
  206. {
  207. var dates = await _prewarning.AsQueryable()
  208. .Select(p => p.date)
  209. .ToListAsync();
  210. if (dates == null || dates.Count == 0)
  211. {
  212. return (new DateOnly(), new DateOnly());
  213. }
  214. var minDate = dates.Min();
  215. var maxDate = dates.Max();
  216. return (minDate, maxDate);
  217. }
  218. }
  219. }