version 3
This commit is contained in:
185
src/GreenHome.Infrastructure/MonthlyReportService.cs
Normal file
185
src/GreenHome.Infrastructure/MonthlyReportService.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
using GreenHome.Application;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace GreenHome.Infrastructure;
|
||||
|
||||
public sealed class MonthlyReportService : IMonthlyReportService
|
||||
{
|
||||
private readonly GreenHomeDbContext _context;
|
||||
|
||||
public MonthlyReportService(GreenHomeDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<MonthlyReportDto> GetMonthlyReportAsync(
|
||||
int deviceId,
|
||||
int year,
|
||||
int month,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var device = await _context.Devices
|
||||
.FirstOrDefaultAsync(d => d.Id == deviceId, cancellationToken);
|
||||
|
||||
if (device == null)
|
||||
{
|
||||
throw new InvalidOperationException($"دستگاه با شناسه {deviceId} یافت نشد");
|
||||
}
|
||||
|
||||
// Get alert logs for the month
|
||||
var alertLogs = await _context.AlertLogs
|
||||
.Where(al => al.DeviceId == deviceId &&
|
||||
al.SentAt.Year == year &&
|
||||
al.SentAt.Month == month)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var totalAlerts = alertLogs.Count;
|
||||
var smsAlerts = alertLogs.Count(al => al.NotificationType == Domain.AlertNotificationType.SMS);
|
||||
var callAlerts = alertLogs.Count(al => al.NotificationType == Domain.AlertNotificationType.Call);
|
||||
var successfulAlerts = alertLogs.Count(al => al.Status == Domain.AlertStatus.Success);
|
||||
var failedAlerts = alertLogs.Count(al => al.Status == Domain.AlertStatus.Failed);
|
||||
var powerOutageAlerts = alertLogs.Count(al => al.AlertType == Domain.AlertType.PowerOutage);
|
||||
|
||||
// Get telemetry statistics
|
||||
var telemetryData = await _context.TelemetryRecords
|
||||
.Where(t => t.DeviceId == deviceId &&
|
||||
t.PersianYear == year &&
|
||||
t.PersianMonth == month)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var totalTelemetryRecords = telemetryData.Count;
|
||||
var avgTemp = telemetryData.Any() ? telemetryData.Average(t => t.TemperatureC) : 0;
|
||||
var minTemp = telemetryData.Any() ? telemetryData.Min(t => t.TemperatureC) : 0;
|
||||
var maxTemp = telemetryData.Any() ? telemetryData.Max(t => t.TemperatureC) : 0;
|
||||
var avgHumidity = telemetryData.Any() ? telemetryData.Average(t => t.HumidityPercent) : 0;
|
||||
var minHumidity = telemetryData.Any() ? telemetryData.Min(t => t.HumidityPercent) : 0;
|
||||
var maxHumidity = telemetryData.Any() ? telemetryData.Max(t => t.HumidityPercent) : 0;
|
||||
var avgLux = telemetryData.Any() ? telemetryData.Average(t => t.Lux) : 0;
|
||||
var avgGas = telemetryData.Any() ? (int)telemetryData.Average(t => t.GasPPM) : 0;
|
||||
var maxGas = telemetryData.Any() ? telemetryData.Max(t => t.GasPPM) : 0;
|
||||
|
||||
// Get user activity
|
||||
var userReportsCount = await _context.UserDailyReports
|
||||
.CountAsync(r => r.DeviceId == deviceId &&
|
||||
r.PersianYear == year &&
|
||||
r.PersianMonth == month,
|
||||
cancellationToken);
|
||||
|
||||
var checklistCompletionsCount = await _context.ChecklistCompletions
|
||||
.Where(cc => cc.Checklist.DeviceId == deviceId)
|
||||
.CountAsync(cc => cc.PersianDate.StartsWith($"{year}/{month:D2}"), cancellationToken);
|
||||
|
||||
var dailyAnalysesCount = await _context.DailyReports
|
||||
.CountAsync(dr => dr.DeviceId == deviceId &&
|
||||
dr.PersianYear == year &&
|
||||
dr.PersianMonth == month,
|
||||
cancellationToken);
|
||||
|
||||
// Generate performance summary
|
||||
var performanceSummary = GeneratePerformanceSummary(
|
||||
totalTelemetryRecords,
|
||||
totalAlerts,
|
||||
successfulAlerts,
|
||||
failedAlerts,
|
||||
avgTemp,
|
||||
avgHumidity,
|
||||
avgLux,
|
||||
avgGas,
|
||||
userReportsCount,
|
||||
checklistCompletionsCount);
|
||||
|
||||
return new MonthlyReportDto
|
||||
{
|
||||
DeviceId = deviceId,
|
||||
DeviceName = device.DeviceName,
|
||||
Year = year,
|
||||
Month = month,
|
||||
TotalAlerts = totalAlerts,
|
||||
SmsAlerts = smsAlerts,
|
||||
CallAlerts = callAlerts,
|
||||
SuccessfulAlerts = successfulAlerts,
|
||||
FailedAlerts = failedAlerts,
|
||||
PowerOutageAlerts = powerOutageAlerts,
|
||||
TotalTelemetryRecords = totalTelemetryRecords,
|
||||
AverageTemperature = avgTemp,
|
||||
MinTemperature = minTemp,
|
||||
MaxTemperature = maxTemp,
|
||||
AverageHumidity = avgHumidity,
|
||||
MinHumidity = minHumidity,
|
||||
MaxHumidity = maxHumidity,
|
||||
AverageLux = avgLux,
|
||||
AverageGasPPM = avgGas,
|
||||
MaxGasPPM = maxGas,
|
||||
UserDailyReportsCount = userReportsCount,
|
||||
ChecklistCompletionsCount = checklistCompletionsCount,
|
||||
DailyAnalysesCount = dailyAnalysesCount,
|
||||
PerformanceSummary = performanceSummary,
|
||||
GeneratedAt = DateTime.UtcNow
|
||||
};
|
||||
}
|
||||
|
||||
private string GeneratePerformanceSummary(
|
||||
int totalRecords,
|
||||
int totalAlerts,
|
||||
int successfulAlerts,
|
||||
int failedAlerts,
|
||||
decimal avgTemp,
|
||||
decimal avgHumidity,
|
||||
decimal avgLux,
|
||||
int avgGas,
|
||||
int userReports,
|
||||
int checklistCompletions)
|
||||
{
|
||||
var summary = new List<string>();
|
||||
|
||||
summary.Add($"📊 آمار کلی:");
|
||||
summary.Add($" • تعداد رکوردهای ثبت شده: {totalRecords:N0}");
|
||||
summary.Add($" • میانگین دما: {avgTemp:F1}°C");
|
||||
summary.Add($" • میانگین رطوبت: {avgHumidity:F1}%");
|
||||
summary.Add($" • میانگین نور: {avgLux:F0} لوکس");
|
||||
if (avgGas > 0)
|
||||
summary.Add($" • میانگین CO: {avgGas} PPM");
|
||||
|
||||
summary.Add("");
|
||||
summary.Add($"🚨 هشدارها:");
|
||||
summary.Add($" • تعداد کل: {totalAlerts}");
|
||||
summary.Add($" • موفق: {successfulAlerts}");
|
||||
if (failedAlerts > 0)
|
||||
summary.Add($" • ناموفق: {failedAlerts} ⚠️");
|
||||
|
||||
if (userReports > 0 || checklistCompletions > 0)
|
||||
{
|
||||
summary.Add("");
|
||||
summary.Add($"📝 فعالیت کاربران:");
|
||||
if (userReports > 0)
|
||||
summary.Add($" • گزارشهای روزانه: {userReports}");
|
||||
if (checklistCompletions > 0)
|
||||
summary.Add($" • تکمیل چکلیست: {checklistCompletions}");
|
||||
}
|
||||
|
||||
// Performance rating
|
||||
summary.Add("");
|
||||
var rating = CalculatePerformanceRating(totalRecords, failedAlerts, totalAlerts);
|
||||
summary.Add($"⭐ ارزیابی کلی: {rating}");
|
||||
|
||||
return string.Join("\n", summary);
|
||||
}
|
||||
|
||||
private string CalculatePerformanceRating(int totalRecords, int failedAlerts, int totalAlerts)
|
||||
{
|
||||
if (totalRecords == 0)
|
||||
return "بدون داده";
|
||||
|
||||
var failureRate = totalAlerts > 0 ? (double)failedAlerts / totalAlerts : 0;
|
||||
|
||||
if (failureRate == 0 && totalRecords > 1000)
|
||||
return "عالی ✅";
|
||||
else if (failureRate < 0.1 && totalRecords > 500)
|
||||
return "خوب 👍";
|
||||
else if (failureRate < 0.3)
|
||||
return "متوسط ⚠️";
|
||||
else
|
||||
return "نیاز به بررسی 🔧";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user