using Serilog; using YZWater.Core.Models; namespace YZWater.Core.Services; /// /// 报表服务 - 生成日报/月报 /// public static class ReportService { /// /// 生成日报(HTML 格式) /// public static async Task GenerateDailyReportAsync(DateTime date) { try { var start = date.Date; var end = start.AddDays(1); // 查询流量数据 var flowRecords = await DatabaseService.Db.Queryable() .Where(r => r.RecordTime >= start && r.RecordTime < end) .OrderBy(r => r.RecordTime) .ToListAsync(); // 查询报警数据 var alarmRecords = await DatabaseService.Db.Queryable() .Where(r => r.AlarmTime >= start && r.AlarmTime < end) .OrderBy(r => r.AlarmTime) .ToListAsync(); // 计算统计 var avgInflow = flowRecords.Count > 0 ? flowRecords.Average(r => r.InflowRate) : 0; var avgOutflow = flowRecords.Count > 0 ? flowRecords.Average(r => r.OutflowRate) : 0; var maxInflow = flowRecords.Count > 0 ? flowRecords.Max(r => r.InflowRate) : 0; var maxOutflow = flowRecords.Count > 0 ? flowRecords.Max(r => r.OutflowRate) : 0; var totalInflow = flowRecords.Count > 0 ? flowRecords.Last().TotalInflow : 0; var totalOutflow = flowRecords.Count > 0 ? flowRecords.Last().TotalOutflow : 0; var config = ConfigService.GetConfig(); var companyName = config?.CompanyName ?? "污水处理厂"; var html = $@" 日报 - {date:yyyy-MM-dd}

{companyName} - 日报

日期: {date:yyyy年MM月dd日}

流量统计

累计进水量: {totalInflow:F1} m³ | 累计出水量: {totalOutflow:F1} m³

平均进水流量: {avgInflow:F1} m³/h | 平均出水流量: {avgOutflow:F1} m³/h

最大进水流量: {maxInflow:F1} m³/h | 最大出水流量: {maxOutflow:F1} m³/h

记录数: {flowRecords.Count} 条

报警统计

报警总数: {alarmRecords.Count} 条

未确认: {alarmRecords.Count(r => !r.IsConfirmed)} 条

已确认: {alarmRecords.Count(r => r.IsConfirmed)} 条

{(alarmRecords.Count > 0 ? $@"

报警详情

{string.Join("", alarmRecords.Take(50).Select(a => $@" "))}
时间类型内容级别状态
{a.AlarmTime:HH:mm:ss} {a.AlarmType} {a.AlarmMessage} {a.AlarmLevel} {(a.IsConfirmed ? "已确认" : "未确认")}
" : "")} "; // 保存文件 var reportsDir = "Reports"; Directory.CreateDirectory(reportsDir); var filePath = Path.Combine(reportsDir, $"日报_{date:yyyyMMdd}.html"); await File.WriteAllTextAsync(filePath, html); Log.Information("日报已生成: {Path}", filePath); AuditService.Log("系统", "Report", $"生成日报: {filePath}"); return filePath; } catch (Exception ex) { Log.Error(ex, "生成日报失败"); return string.Empty; } } /// /// 生成月报 /// public static async Task GenerateMonthlyReportAsync(int year, int month) { try { var start = new DateTime(year, month, 1); var end = start.AddMonths(1); var flowRecords = await DatabaseService.Db.Queryable() .Where(r => r.RecordTime >= start && r.RecordTime < end) .ToListAsync(); var alarmRecords = await DatabaseService.Db.Queryable() .Where(r => r.AlarmTime >= start && r.AlarmTime < end) .ToListAsync(); var config = ConfigService.GetConfig(); var companyName = config?.CompanyName ?? "污水处理厂"; var avgInflow = flowRecords.Count > 0 ? flowRecords.Average(r => r.InflowRate) : 0; var avgOutflow = flowRecords.Count > 0 ? flowRecords.Average(r => r.OutflowRate) : 0; var totalInflow = flowRecords.Count > 0 ? flowRecords.Last().TotalInflow : 0; var totalOutflow = flowRecords.Count > 0 ? flowRecords.Last().TotalOutflow : 0; // 按日统计 var dailyStats = flowRecords .GroupBy(r => r.RecordTime.Date) .Select(g => new { Date = g.Key, AvgInflow = g.Average(r => r.InflowRate), AvgOutflow = g.Average(r => r.OutflowRate), Count = g.Count() }) .OrderBy(d => d.Date) .ToList(); var html = $@" 月报 - {year}年{month}月

{companyName} - 月报

期间: {year}年{month}月

汇总统计

累计进水量: {totalInflow:F1} m³ | 累计出水量: {totalOutflow:F1} m³

平均进水流量: {avgInflow:F1} m³/h | 平均出水流量: {avgOutflow:F1} m³/h

报警总数: {alarmRecords.Count} 条

有效记录天数: {dailyStats.Count} 天

每日统计

{string.Join("", dailyStats.Select(d => $@" "))}
日期平均进水 (m³/h)平均出水 (m³/h)记录数
{d.Date:MM-dd} {d.AvgInflow:F1} {d.AvgOutflow:F1} {d.Count}
"; var reportsDir = "Reports"; Directory.CreateDirectory(reportsDir); var filePath = Path.Combine(reportsDir, $"月报_{year}{month:D2}.html"); await File.WriteAllTextAsync(filePath, html); Log.Information("月报已生成: {Path}", filePath); AuditService.Log("系统", "Report", $"生成月报: {filePath}"); return filePath; } catch (Exception ex) { Log.Error(ex, "生成月报失败"); return string.Empty; } } }