| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- using Serilog;
- using YZWater.Core.Models;
- namespace YZWater.Core.Services;
- /// <summary>
- /// 报表服务 - 生成日报/月报
- /// </summary>
- public static class ReportService
- {
- /// <summary>
- /// 生成日报(HTML 格式)
- /// </summary>
- public static async Task<string> GenerateDailyReportAsync(DateTime date)
- {
- try
- {
- var start = date.Date;
- var end = start.AddDays(1);
- // 查询流量数据
- var flowRecords = await DatabaseService.Db.Queryable<FlowRecord>()
- .Where(r => r.RecordTime >= start && r.RecordTime < end)
- .OrderBy(r => r.RecordTime)
- .ToListAsync();
- // 查询报警数据
- var alarmRecords = await DatabaseService.Db.Queryable<AlarmRecord>()
- .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 = $@"<!DOCTYPE html>
- <html>
- <head>
- <meta charset='utf-8'>
- <title>日报 - {date:yyyy-MM-dd}</title>
- <style>
- body {{ font-family: 'Microsoft YaHei', sans-serif; margin: 20px; }}
- h1 {{ color: #1976D2; border-bottom: 2px solid #1976D2; padding-bottom: 8px; }}
- h2 {{ color: #424242; margin-top: 24px; }}
- table {{ border-collapse: collapse; width: 100%; margin: 12px 0; }}
- th, td {{ border: 1px solid #ddd; padding: 8px 12px; text-align: left; }}
- th {{ background: #f5f5f5; }}
- .summary {{ background: #E3F2FD; padding: 16px; border-radius: 8px; margin: 16px 0; }}
- .alarm {{ color: #E53935; }}
- .footer {{ color: #999; font-size: 12px; margin-top: 32px; border-top: 1px solid #eee; padding-top: 8px; }}
- </style>
- </head>
- <body>
- <h1>{companyName} - 日报</h1>
- <p>日期: {date:yyyy年MM月dd日}</p>
- <h2>流量统计</h2>
- <div class='summary'>
- <p><b>累计进水量:</b> {totalInflow:F1} m³ | <b>累计出水量:</b> {totalOutflow:F1} m³</p>
- <p><b>平均进水流量:</b> {avgInflow:F1} m³/h | <b>平均出水流量:</b> {avgOutflow:F1} m³/h</p>
- <p><b>最大进水流量:</b> {maxInflow:F1} m³/h | <b>最大出水流量:</b> {maxOutflow:F1} m³/h</p>
- <p><b>记录数:</b> {flowRecords.Count} 条</p>
- </div>
- <h2>报警统计</h2>
- <div class='summary'>
- <p><b>报警总数:</b> {alarmRecords.Count} 条</p>
- <p><b>未确认:</b> {alarmRecords.Count(r => !r.IsConfirmed)} 条</p>
- <p><b>已确认:</b> {alarmRecords.Count(r => r.IsConfirmed)} 条</p>
- </div>
- {(alarmRecords.Count > 0 ? $@"
- <h2>报警详情</h2>
- <table>
- <tr><th>时间</th><th>类型</th><th>内容</th><th>级别</th><th>状态</th></tr>
- {string.Join("", alarmRecords.Take(50).Select(a => $@"
- <tr>
- <td>{a.AlarmTime:HH:mm:ss}</td>
- <td>{a.AlarmType}</td>
- <td>{a.AlarmMessage}</td>
- <td>{a.AlarmLevel}</td>
- <td>{(a.IsConfirmed ? "已确认" : "<span class='alarm'>未确认</span>")}</td>
- </tr>"))}
- </table>" : "")}
- <div class='footer'>
- <p>报表生成时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss} | YZWater 污水处理监控系统</p>
- </div>
- </body>
- </html>";
- // 保存文件
- 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;
- }
- }
- /// <summary>
- /// 生成月报
- /// </summary>
- public static async Task<string> GenerateMonthlyReportAsync(int year, int month)
- {
- try
- {
- var start = new DateTime(year, month, 1);
- var end = start.AddMonths(1);
- var flowRecords = await DatabaseService.Db.Queryable<FlowRecord>()
- .Where(r => r.RecordTime >= start && r.RecordTime < end)
- .ToListAsync();
- var alarmRecords = await DatabaseService.Db.Queryable<AlarmRecord>()
- .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 = $@"<!DOCTYPE html>
- <html>
- <head>
- <meta charset='utf-8'>
- <title>月报 - {year}年{month}月</title>
- <style>
- body {{ font-family: 'Microsoft YaHei', sans-serif; margin: 20px; }}
- h1 {{ color: #1976D2; border-bottom: 2px solid #1976D2; padding-bottom: 8px; }}
- h2 {{ color: #424242; margin-top: 24px; }}
- table {{ border-collapse: collapse; width: 100%; margin: 12px 0; }}
- th, td {{ border: 1px solid #ddd; padding: 8px 12px; text-align: left; }}
- th {{ background: #f5f5f5; }}
- .summary {{ background: #E3F2FD; padding: 16px; border-radius: 8px; margin: 16px 0; }}
- .footer {{ color: #999; font-size: 12px; margin-top: 32px; border-top: 1px solid #eee; padding-top: 8px; }}
- </style>
- </head>
- <body>
- <h1>{companyName} - 月报</h1>
- <p>期间: {year}年{month}月</p>
- <h2>汇总统计</h2>
- <div class='summary'>
- <p><b>累计进水量:</b> {totalInflow:F1} m³ | <b>累计出水量:</b> {totalOutflow:F1} m³</p>
- <p><b>平均进水流量:</b> {avgInflow:F1} m³/h | <b>平均出水流量:</b> {avgOutflow:F1} m³/h</p>
- <p><b>报警总数:</b> {alarmRecords.Count} 条</p>
- <p><b>有效记录天数:</b> {dailyStats.Count} 天</p>
- </div>
- <h2>每日统计</h2>
- <table>
- <tr><th>日期</th><th>平均进水 (m³/h)</th><th>平均出水 (m³/h)</th><th>记录数</th></tr>
- {string.Join("", dailyStats.Select(d => $@"
- <tr>
- <td>{d.Date:MM-dd}</td>
- <td>{d.AvgInflow:F1}</td>
- <td>{d.AvgOutflow:F1}</td>
- <td>{d.Count}</td>
- </tr>"))}
- </table>
- <div class='footer'>
- <p>报表生成时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss} | YZWater 污水处理监控系统</p>
- </div>
- </body>
- </html>";
- 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;
- }
- }
- }
|