| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- using Serilog;
- using YZWater.Core.Models;
- namespace YZWater.Core.Services;
- /// <summary>
- /// 鎶ヨ〃鏈嶅姟 - 鐢熸垚鏃ユ姤/鏈堟姤
- /// </summary>
- public static class ReportService
- {
- /// <summary>
- /// 鐢熸垚鏃ユ姤锛圚TML 鏍煎紡锛
- /// </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骞碝M鏈坉d鏃</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;
- }
- }
- }
|