using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OrpaonVision.Core.Statistics;
using OrpaonVision.Core.Results;
using OrpaonVision.SiteApp.Runtime.Options;
using System.Collections.Concurrent;
using System.Text.Json;
namespace OrpaonVision.SiteApp.Runtime.Services;
///
/// 统计服务实现。
///
#if DISABLED_LEGACY_STATISTICS_SERVICE
public sealed class StatisticsService : IStatisticsService
{
private readonly ILogger _logger;
private readonly RuntimeOptions _options;
private readonly ConcurrentDictionary _statisticsConfigs = new();
private readonly ConcurrentDictionary _statisticsCache = new();
private readonly object _lock = new();
///
/// 构造函数。
///
public StatisticsService(ILogger logger, IOptions options)
{
_logger = logger;
_options = options.Value;
InitializeDefaultStatisticsConfigs();
_logger.LogInformation("统计服务已初始化");
}
///
public async Task> GetCycleTimeStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取节拍统计信息:开始时间={StartTime},结束时间={EndTime},产品类型={ProductTypeCode}",
startTime, endTime, productTypeCode);
var cacheKey = $"cycle_time_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{productTypeCode}";
if (_options.EnableStatisticsCache && _statisticsCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取节拍统计信息");
return Result.Success((CycleTimeStatistics)cached);
}
var statistics = await GenerateCycleTimeStatisticsAsync(startTime, endTime, productTypeCode, cancellationToken);
if (_options.EnableStatisticsCache)
{
_statisticsCache.TryAdd(cacheKey, statistics);
}
_logger.LogInformation("节拍统计信息获取完成:总处理数={Total},成功率={SuccessRate:F2}%,平均节拍={AvgCycleTime:F2}秒",
statistics.TotalProcessedCount, statistics.OverallSuccessRate, statistics.AverageCycleTimeSeconds);
return Result.Success(statistics);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取节拍统计信息失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_CYCLE_TIME_STATISTICS_FAILED", "获取节拍统计信息失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetShiftStatisticsAsync(DateTime shiftDate, ShiftType? shiftType = null, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取班次统计信息:日期={ShiftDate},班次类型={ShiftType},产品类型={ProductTypeCode}",
shiftDate, shiftType, productTypeCode);
var cacheKey = $"shift_{shiftDate:yyyyMMdd}_{shiftType}_{productTypeCode}";
if (_options.EnableStatisticsCache && _statisticsCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取班次统计信息");
return Result.Success((ShiftStatistics)cached);
}
var statistics = await GenerateShiftStatisticsAsync(shiftDate, shiftType, productTypeCode, cancellationToken);
if (_options.EnableStatisticsCache)
{
_statisticsCache.TryAdd(cacheKey, statistics);
}
_logger.LogInformation("班次统计信息获取完成:计划产量={Planned},实际产量={Actual},完成率={CompletionRate:F2}%,合格率={PassRate:F2}%",
statistics.PlannedProductionCount, statistics.ActualProductionCount, statistics.ProductionCompletionRate, statistics.QualityPassRate);
return Result.Success(statistics);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取班次统计信息失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_SHIFT_STATISTICS_FAILED", "获取班次统计信息失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task>> GetShiftListAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取班次列表:开始日期={StartDate},结束日期={EndDate}", startDate, endDate);
var shiftList = await GenerateShiftListAsync(startDate, endDate, cancellationToken);
_logger.LogInformation("班次列表获取完成:班次数量={ShiftCount}", shiftList.Count);
return Result.Success>(shiftList);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取班次列表失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_SHIFT_LIST_FAILED", "获取班次列表失败", traceId);
return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetProductionEfficiencyStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, StatisticsGranularity granularity = StatisticsGranularity.Hourly, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取生产效率统计:开始时间={StartTime},结束时间={EndTime},产品类型={ProductTypeCode},粒度={Granularity}",
startTime, endTime, productTypeCode, granularity);
var cacheKey = $"efficiency_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{productTypeCode}_{granularity}";
if (_options.EnableStatisticsCache && _statisticsCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取生产效率统计");
return Result.Success((ProductionEfficiencyStatistics)cached);
}
var statistics = await GenerateProductionEfficiencyStatisticsAsync(startTime, endTime, productTypeCode, granularity, cancellationToken);
if (_options.EnableStatisticsCache)
{
_statisticsCache.TryAdd(cacheKey, statistics);
}
_logger.LogInformation("生产效率统计获取完成:OEE={OEE:F2}%,时间利用率={TimeUtilization:F2}%,设备利用率={EquipmentUtilization:F2}%",
statistics.OverallEquipmentEffectiveness, statistics.TimeUtilizationRate, statistics.EquipmentUtilizationRate);
return Result.Success(statistics);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取生产效率统计失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_PRODUCTION_EFFICIENCY_STATISTICS_FAILED", "获取生产效率统计失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetQualityStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取质量统计信息:开始时间={StartTime},结束时间={EndTime},产品类型={ProductTypeCode}",
startTime, endTime, productTypeCode);
var cacheKey = $"quality_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{productTypeCode}";
if (_options.EnableStatisticsCache && _statisticsCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取质量统计信息");
return Result.Success((QualityStatistics)cached);
}
var statistics = await GenerateQualityStatisticsAsync(startTime, endTime, productTypeCode, cancellationToken);
if (_options.EnableStatisticsCache)
{
_statisticsCache.TryAdd(cacheKey, statistics);
}
_logger.LogInformation("质量统计信息获取完成:总检测数={Total},合格数={Qualified},合格率={PassRate:F2}%",
statistics.TotalInspectionCount, statistics.QualifiedCount, statistics.OverallPassRate);
return Result.Success(statistics);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取质量统计信息失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_QUALITY_STATISTICS_FAILED", "获取质量统计信息失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetEquipmentUtilizationStatisticsAsync(DateTime startTime, DateTime endTime, string? equipmentId = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取设备利用率统计:开始时间={StartTime},结束时间={EndTime},设备ID={EquipmentId}",
startTime, endTime, equipmentId);
var cacheKey = $"equipment_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{equipmentId}";
if (_options.EnableStatisticsCache && _statisticsCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取设备利用率统计");
return Result.Success((EquipmentUtilizationStatistics)cached);
}
var statistics = await GenerateEquipmentUtilizationStatisticsAsync(startTime, endTime, equipmentId, cancellationToken);
if (_options.EnableStatisticsCache)
{
_statisticsCache.TryAdd(cacheKey, statistics);
}
_logger.LogInformation("设备利用率统计获取完成:总体利用率={Overall:F2}%,生产利用率={Production:F2}%,可用率={Availability:F2}%",
statistics.OverallUtilizationRate, statistics.ProductionUtilizationRate, statistics.AvailabilityRate);
return Result.Success(statistics);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取设备利用率统计失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_EQUIPMENT_UTILIZATION_STATISTICS_FAILED", "获取设备利用率统计失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetAlarmStatisticsSummaryAsync(DateTime startTime, DateTime endTime, OrpaonVision.Core.Common.AlarmLevel? alarmLevel = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取报警统计摘要:开始时间={StartTime},结束时间={EndTime},报警级别={AlarmLevel}",
startTime, endTime, alarmLevel);
var cacheKey = $"alarm_summary_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{alarmLevel}";
if (_options.EnableStatisticsCache && _statisticsCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取报警统计摘要");
return Result.Success((AlarmStatisticsSummary)cached);
}
var statistics = await GenerateAlarmStatisticsSummaryAsync(startTime, endTime, alarmLevel, cancellationToken);
if (_options.EnableStatisticsCache)
{
_statisticsCache.TryAdd(cacheKey, statistics);
}
_logger.LogInformation("报警统计摘要获取完成:总报警数={Total},活跃数={Active},确认数={Confirmed},清除数={Cleared}",
statistics.TotalAlarmCount, statistics.ActiveAlarmCount, statistics.ConfirmedAlarmCount, statistics.ClearedAlarmCount);
return Result.Success(statistics);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取报警统计摘要失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_ALARM_STATISTICS_SUMMARY_FAILED", "获取报警统计摘要失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetComprehensiveProductionReportAsync(OrpaonVision.Core.Statistics.ProductionReportType reportType, DateTime startTime, DateTime endTime, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取综合生产报告:报告类型={ReportType},开始时间={StartTime},结束时间={EndTime},产品类型={ProductTypeCode}",
reportType, startTime, endTime, productTypeCode);
var report = await GenerateComprehensiveProductionReportAsync(reportType, startTime, endTime, productTypeCode, cancellationToken);
_logger.LogInformation("综合生产报告获取完成:报告ID={ReportId},总体评分={OverallScore:F2}",
report.ReportId, report.ExecutiveSummary.OverallScore);
return Result.Success(report);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取综合生产报告失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_COMPREHENSIVE_PRODUCTION_REPORT_FAILED", "获取综合生产报告失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetRealTimeStatisticsDashboardAsync(string? productTypeCode = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取实时统计仪表板:产品类型={ProductTypeCode}", productTypeCode);
var dashboard = await GenerateRealTimeStatisticsDashboardAsync(productTypeCode, cancellationToken);
_logger.LogInformation("实时统计仪表板获取完成:更新时间={UpdateTime},当前OEE={OEE:F2}%",
dashboard.LastUpdatedUtc, dashboard.Efficiency.CurrentOEE);
return Result.Success(dashboard);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取实时统计仪表板失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_REAL_TIME_STATISTICS_DASHBOARD_FAILED", "获取实时统计仪表板失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetHistoricalTrendDataAsync(MetricType metricType, DateTime startTime, DateTime endTime, string? productTypeCode = null, StatisticsGranularity granularity = StatisticsGranularity.Hourly, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取历史趋势数据:指标类型={MetricType},开始时间={StartTime},结束时间={EndTime},产品类型={ProductTypeCode},粒度={Granularity}",
metricType, startTime, endTime, productTypeCode, granularity);
var cacheKey = $"trend_{metricType}_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{productTypeCode}_{granularity}";
if (_options.EnableStatisticsCache && _statisticsCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取历史趋势数据");
return Result.Success((HistoricalTrendData)cached);
}
var trendData = await GenerateHistoricalTrendDataAsync(metricType, startTime, endTime, productTypeCode, granularity, cancellationToken);
if (_options.EnableStatisticsCache)
{
_statisticsCache.TryAdd(cacheKey, trendData);
}
_logger.LogInformation("历史趋势数据获取完成:指标类型={MetricType},数据点数量={DataPointCount},趋势方向={Trend}",
metricType, trendData.DataPoints.Count, trendData.TrendAnalysis.TrendDescription);
return Result.Success(trendData);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取历史趋势数据失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_HISTORICAL_TREND_DATA_FAILED", "获取历史趋势数据失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> CreateStatisticsConfigAsync(StatisticsConfig config, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("创建统计配置:配置类型={ConfigType},产品类型={ProductTypeCode},配置名称={ConfigName}",
config.ConfigType, config.ProductTypeCode, config.ConfigName);
lock (_lock)
{
config.ConfigId = Guid.NewGuid();
config.CreatedAtUtc = DateTime.UtcNow;
config.UpdatedAtUtc = DateTime.UtcNow;
config.Version = "1.0";
var key = $"{config.ConfigType}_{config.ProductTypeCode}_{config.ConfigName}";
_statisticsConfigs[key] = config;
}
_logger.LogInformation("统计配置创建成功:配置ID={ConfigId},配置名称={ConfigName}",
config.ConfigId, config.ConfigName);
return Result.Success(config);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "创建统计配置失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "CREATE_STATISTICS_CONFIG_FAILED", "创建统计配置失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task UpdateStatisticsConfigAsync(StatisticsConfig config, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("更新统计配置:配置ID={ConfigId},配置名称={ConfigName}",
config.ConfigId, config.ConfigName);
lock (_lock)
{
var key = $"{config.ConfigType}_{config.ProductTypeCode}_{config.ConfigName}";
if (_statisticsConfigs.ContainsKey(key))
{
config.UpdatedAtUtc = DateTime.UtcNow;
_statisticsConfigs[key] = config;
}
else
{
return Result.Fail("CONFIG_NOT_FOUND", $"未找到配置:{config.ConfigId}");
}
}
_logger.LogInformation("统计配置更新成功:配置ID={ConfigId}", config.ConfigId);
return Result.Success();
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "更新统计配置失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "UPDATE_STATISTICS_CONFIG_FAILED", "更新统计配置失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetStatisticsConfigAsync(StatisticsConfigType configType, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("获取统计配置:配置类型={ConfigType},产品类型={ProductTypeCode}", configType, productTypeCode);
var key = $"{configType}_{productTypeCode}";
if (_statisticsConfigs.TryGetValue(key, out var config))
{
return Result.Success(config);
}
// 尝试获取默认配置
var defaultKey = $"{configType}_default";
if (_statisticsConfigs.TryGetValue(defaultKey, out var defaultConfig))
{
return Result.Success(defaultConfig);
}
return Result.FailWithTrace("CONFIG_NOT_FOUND", $"未找到配置:{configType}", string.Empty);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取统计配置失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_STATISTICS_CONFIG_FAILED", "获取统计配置失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> ExportStatisticsAsync(StatisticsExportRequest exportRequest, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("导出统计数据:导出类型={ExportType},格式={ExportFormat},统计类型={StatisticsType}",
exportRequest.ExportType, exportRequest.ExportFormat, exportRequest.StatisticsType);
var startTime = DateTime.UtcNow;
var result = await GenerateStatisticsExportAsync(exportRequest, cancellationToken);
var elapsed = DateTime.UtcNow - startTime;
var exportResult = new StatisticsExportResult
{
RequestId = exportRequest.RequestId,
IsSuccess = true,
FilePath = result.FilePath,
FileSizeBytes = result.FileSizeBytes,
RecordCount = result.RecordCount,
ExportElapsedMs = (long)elapsed.TotalMilliseconds,
ExportTimeUtc = DateTime.UtcNow,
ResultDescription = $"导出完成:{result.RecordCount}条记录,文件大小{result.FileSizeBytes}字节",
ExtendedProperties = new Dictionary
{
["export_type"] = exportRequest.ExportType,
["export_format"] = exportRequest.ExportFormat,
["statistics_type"] = exportRequest.StatisticsType
}
};
_logger.LogInformation("统计数据导出完成:文件路径={FilePath},记录数量={RecordCount},耗时={ElapsedMs}ms",
exportResult.FilePath, exportResult.RecordCount, exportResult.ExportElapsedMs);
return Result.Success(exportResult);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "导出统计数据失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "EXPORT_STATISTICS_FAILED", "导出统计数据失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
#region 私有方法
///
/// 初始化默认统计配置。
///
private void InitializeDefaultStatisticsConfigs()
{
var defaultConfigs = new List
{
new()
{
ConfigId = Guid.NewGuid(),
ConfigType = StatisticsConfigType.CycleTime,
ProductTypeCode = "default",
ConfigName = "默认节拍统计配置",
ConfigDescription = "系统默认的节拍统计配置",
Parameters = new Dictionary
{
["target_cycle_time_seconds"] = 60.0,
["tolerance_percentage"] = 10.0,
["enable_trend_analysis"] = true
},
IsEnabled = true,
CreatedAtUtc = DateTime.UtcNow,
UpdatedAtUtc = DateTime.UtcNow,
Version = "1.0"
},
new()
{
ConfigId = Guid.NewGuid(),
ConfigType = StatisticsConfigType.Shift,
ProductTypeCode = "default",
ConfigName = "默认班次统计配置",
ConfigDescription = "系统默认的班次统计配置",
Parameters = new Dictionary
{
["shift_duration_hours"] = 8.0,
["target_production_rate"] = 100,
["enable_anomaly_detection"] = true
},
IsEnabled = true,
CreatedAtUtc = DateTime.UtcNow,
UpdatedAtUtc = DateTime.UtcNow,
Version = "1.0"
},
new()
{
ConfigId = Guid.NewGuid(),
ConfigType = StatisticsConfigType.Quality,
ProductTypeCode = "default",
ConfigName = "默认质量统计配置",
ConfigDescription = "系统默认的质量统计配置",
Parameters = new Dictionary
{
["target_pass_rate"] = 95.0,
["enable_defect_analysis"] = true,
["enable_improvement_suggestions"] = true
},
IsEnabled = true,
CreatedAtUtc = DateTime.UtcNow,
UpdatedAtUtc = DateTime.UtcNow,
Version = "1.0"
}
};
foreach (var config in defaultConfigs)
{
var key = $"{config.ConfigType}_{config.ProductTypeCode}_{config.ConfigName}";
_statisticsConfigs[key] = config;
}
}
///
/// 生成节拍统计信息。
///
private async Task GenerateCycleTimeStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
// 简化处理:生成模拟数据
var random = new Random();
var totalProcessed = random.Next(100, 500);
var successCount = (int)(totalProcessed * (0.85 + random.NextDouble() * 0.1));
var failedCount = totalProcessed - successCount;
var cycleTimes = Enumerable.Range(0, totalProcessed)
.Select(_ => 45 + random.NextDouble() * 30) // 45-75秒
.ToList();
var timeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime };
return new CycleTimeStatistics
{
TimeRange = timeRange,
ProductTypeCode = productTypeCode ?? "default",
TotalProcessedCount = totalProcessed,
SuccessfulProcessedCount = successCount,
FailedProcessedCount = failedCount,
AverageCycleTimeSeconds = cycleTimes.Average(),
MinCycleTimeSeconds = cycleTimes.Min(),
MaxCycleTimeSeconds = cycleTimes.Max(),
CycleTimeStandardDeviationSeconds = CalculateStandardDeviation(cycleTimes),
TargetCycleTimeSeconds = 60.0,
CountAchievedCycleTime = cycleTimes.Count(t => t <= 60.0),
ByHour = GenerateHourlyCycleTimeStatistics(startTime, endTime, cycleTimes),
ByProductType = GenerateProductTypeCycleTimeStatistics(productTypeCode, totalProcessed, successCount, cycleTimes.Average()),
Distribution = GenerateCycleTimeDistribution(cycleTimes, 60.0),
Trend = GenerateCycleTimeTrend(cycleTimes),
ExtendedProperties = new Dictionary
{
["generation_time_ms"] = 50,
["data_source"] = "simulated"
}
};
}
///
/// 生成班次统计信息。
///
private async Task GenerateShiftStatisticsAsync(DateTime shiftDate, ShiftType? shiftType, string? productTypeCode, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var shiftInfo = GenerateShiftInfo(shiftDate, shiftType);
var plannedProduction = random.Next(200, 400);
var actualProduction = (int)(plannedProduction * (0.9 + random.NextDouble() * 0.15));
var qualifiedCount = (int)(actualProduction * (0.92 + random.NextDouble() * 0.06));
return new ShiftStatistics
{
ShiftInfo = shiftInfo,
ProductTypeCode = productTypeCode ?? "default",
PlannedProductionCount = plannedProduction,
ActualProductionCount = actualProduction,
QualifiedProductionCount = qualifiedCount,
UnqualifiedProductionCount = actualProduction - qualifiedCount,
ShiftStartTimeUtc = shiftDate.Add(shiftInfo.StartTime),
ShiftEndTimeUtc = shiftDate.Add(shiftInfo.EndTime),
ActualWorkingHours = shiftInfo.DurationHours * (0.85 + random.NextDouble() * 0.1),
EquipmentDowntimeHours = shiftInfo.DurationHours * (0.05 + random.NextDouble() * 0.05),
AverageCycleTimeSeconds = 55 + random.NextDouble() * 10,
ByHour = GenerateHourlyShiftStatistics(shiftInfo, actualProduction, qualifiedCount),
ByProductType = GenerateProductTypeShiftStatistics(productTypeCode, actualProduction, qualifiedCount, 60.0),
AnomalyStatistics = GenerateShiftAnomalyStatistics(random),
ExtendedProperties = new Dictionary
{
["generation_time_ms"] = 60,
["data_source"] = "simulated"
}
};
}
///
/// 生成班次列表。
///
private async Task> GenerateShiftListAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var shiftList = new List();
var currentDate = startDate;
while (currentDate <= endDate)
{
// 生成当天的班次
var shifts = new[] { ShiftType.Morning, ShiftType.Afternoon, ShiftType.Night };
foreach (var shiftType in shifts)
{
var shiftInfo = GenerateShiftInfo(currentDate, shiftType);
shiftList.Add(shiftInfo);
}
currentDate = currentDate.AddDays(1);
}
return shiftList.AsReadOnly();
}
///
/// 生成生产效率统计。
///
private async Task GenerateProductionEfficiencyStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode, StatisticsGranularity granularity, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var timeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime };
var plannedHours = (endTime - startTime).TotalHours;
var actualHours = plannedHours * (0.85 + random.NextDouble() * 0.1);
var equipmentHours = actualHours * (0.9 + random.NextDouble() * 0.08);
var plannedProduction = (int)(plannedHours * 50); // 每小时50个
var actualProduction = (int)(plannedProduction * (0.88 + random.NextDouble() * 0.1));
var qualifiedCount = (int)(actualProduction * (0.94 + random.NextDouble() * 0.04));
return new ProductionEfficiencyStatistics
{
TimeRange = timeRange,
ProductTypeCode = productTypeCode ?? "default",
Granularity = granularity,
PlannedWorkingHours = plannedHours,
ActualWorkingHours = actualHours,
EquipmentRunningHours = equipmentHours,
PlannedProductionCount = plannedProduction,
ActualProductionCount = actualProduction,
QualifiedProductionCount = qualifiedCount,
ByTimeSlot = GenerateTimeSlotEfficiency(startTime, endTime, actualProduction, qualifiedCount, equipmentHours),
Trend = GenerateEfficiencyTrend(),
Benchmark = GenerateEfficiencyBenchmark(),
ExtendedProperties = new Dictionary
{
["generation_time_ms"] = 70,
["data_source"] = "simulated"
}
};
}
///
/// 生成质量统计信息。
///
private async Task GenerateQualityStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var timeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime };
var totalInspection = random.Next(500, 1000);
var qualifiedCount = (int)(totalInspection * (0.92 + random.NextDouble() * 0.05));
var unqualifiedCount = totalInspection - qualifiedCount;
return new QualityStatistics
{
TimeRange = timeRange,
ProductTypeCode = productTypeCode ?? "default",
TotalInspectionCount = totalInspection,
QualifiedCount = qualifiedCount,
UnqualifiedCount = unqualifiedCount,
ByDefectType = GenerateDefectStatistics(unqualifiedCount),
BySeverity = GenerateSeverityStatistics(unqualifiedCount),
ByProductType = GenerateProductTypeQualityStatistics(productTypeCode, totalInspection, qualifiedCount),
ByTimeSlot = GenerateQualityTimeSlotStatistics(startTime, endTime, totalInspection, qualifiedCount),
Trend = GenerateQualityTrend(),
ImprovementSuggestions = GenerateQualityImprovementSuggestions(),
ExtendedProperties = new Dictionary
{
["generation_time_ms"] = 80,
["data_source"] = "simulated"
}
};
}
///
/// 生成设备利用率统计。
///
private async Task GenerateEquipmentUtilizationStatisticsAsync(DateTime startTime, DateTime endTime, string? equipmentId, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var timeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime };
var plannedHours = (endTime - startTime).TotalHours;
var actualHours = plannedHours * (0.8 + random.NextDouble() * 0.15);
var productionHours = actualHours * (0.85 + random.NextDouble() * 0.1);
var maintenanceHours = plannedHours * (0.02 + random.NextDouble() * 0.03);
var failureHours = plannedHours * (0.01 + random.NextDouble() * 0.02);
var idleHours = actualHours - productionHours - maintenanceHours - failureHours;
return new EquipmentUtilizationStatistics
{
TimeRange = timeRange,
EquipmentId = equipmentId ?? "EQ001",
EquipmentName = "主检测设备",
PlannedRunningHours = plannedHours,
ActualRunningHours = actualHours,
ProductionHours = productionHours,
MaintenanceHours = maintenanceHours,
FailureHours = failureHours,
IdleHours = idleHours,
MeanTimeBetweenFailuresHours = 100 + random.NextDouble() * 50,
MeanTimeToRepairHours = 2 + random.NextDouble() * 3,
ByDate = GenerateDailyUtilizationStatistics(startTime, endTime, plannedHours, actualHours),
Trend = GenerateUtilizationTrend(),
MaintenanceSuggestions = GenerateMaintenanceSuggestions(),
ExtendedProperties = new Dictionary
{
["generation_time_ms"] = 90,
["data_source"] = "simulated"
}
};
}
///
/// 生成报警统计摘要。
///
private async Task GenerateAlarmStatisticsSummaryAsync(DateTime startTime, DateTime endTime, AlarmLevel? alarmLevel, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var timeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime };
var totalAlarms = random.Next(10, 50);
var activeAlarms = random.Next(0, 5);
var confirmedAlarms = (int)(totalAlarms * 0.8);
var clearedAlarms = (int)(totalAlarms * 0.7);
var byAlarmLevel = new Dictionary
{
[AlarmLevel.Info] = random.Next(5, 15),
[AlarmLevel.Warning] = random.Next(3, 10),
[AlarmLevel.Error] = random.Next(2, 8),
[AlarmLevel.Critical] = random.Next(1, 5),
[AlarmLevel.Fatal] = random.Next(0, 2)
};
var byAlarmType = new Dictionary
{
[AlarmType.System] = random.Next(2, 8),
[AlarmType.Equipment] = random.Next(3, 10),
[AlarmType.Process] = random.Next(2, 6),
[AlarmType.Quality] = random.Next(1, 5),
[AlarmType.Safety] = random.Next(0, 3)
};
return new AlarmStatisticsSummary
{
TimeRange = timeRange,
TotalAlarmCount = totalAlarms,
ActiveAlarmCount = activeAlarms,
ConfirmedAlarmCount = confirmedAlarms,
ClearedAlarmCount = clearedAlarms,
ByAlarmLevel = byAlarmLevel,
ByAlarmType = byAlarmType,
AverageConfirmTimeMinutes = 5 + random.NextDouble() * 10,
AverageClearTimeMinutes = 10 + random.NextDouble() * 20,
AlarmFrequencyPerHour = totalAlarms / Math.Max((endTime - startTime).TotalHours, 1),
Trend = GenerateAlarmTrend(),
ExtendedProperties = new Dictionary
{
["generation_time_ms"] = 100,
["data_source"] = "simulated"
}
};
}
///
/// 生成综合生产报告。
///
private async Task GenerateComprehensiveProductionReportAsync(ProductionReportType reportType, DateTime startTime, DateTime endTime, string? productTypeCode, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var timeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime };
var reportId = Guid.NewGuid();
return new ComprehensiveProductionReport
{
ReportId = reportId,
ReportType = reportType,
TimeRange = timeRange,
ProductTypeCode = productTypeCode ?? "default",
GeneratedAtUtc = DateTime.UtcNow,
ExecutiveSummary = GenerateExecutiveSummary(),
Production = GenerateProductionStatistics(),
Quality = await GenerateQualityStatisticsAsync(startTime, endTime, productTypeCode, cancellationToken),
Equipment = GenerateEquipmentStatistics(),
Alarms = await GenerateAlarmStatisticsSummaryAsync(startTime, endTime, null, cancellationToken),
Trends = GenerateTrendAnalysis(),
Recommendations = GenerateImprovementRecommendations(),
ExtendedProperties = new Dictionary
{
["generation_time_ms"] = 200,
["data_source"] = "simulated"
}
};
}
///
/// 生成实时统计仪表板。
///
private async Task GenerateRealTimeStatisticsDashboardAsync(string? productTypeCode, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var now = DateTime.UtcNow;
return new RealTimeStatisticsDashboard
{
LastUpdatedUtc = now,
ProductTypeCode = productTypeCode ?? "default",
CurrentShift = GenerateShiftInfo(now.Date, GetCurrentShiftType(now)),
Production = GenerateRealTimeProductionMetrics(random),
Quality = GenerateRealTimeQualityMetrics(random),
Equipment = GenerateRealTimeEquipmentMetrics(random),
Alarms = GenerateRealTimeAlarmMetrics(random),
Efficiency = GenerateRealTimeEfficiencyMetrics(random),
ExtendedProperties = new Dictionary
{
["generation_time_ms"] = 30,
["data_source"] = "simulated"
}
};
}
///
/// 生成历史趋势数据。
///
private async Task GenerateHistoricalTrendDataAsync(MetricType metricType, DateTime startTime, DateTime endTime, string? productTypeCode, StatisticsGranularity granularity, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var timeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime };
var dataPoints = GenerateTrendDataPoints(metricType, startTime, endTime, granularity, random);
return new HistoricalTrendData
{
MetricType = metricType,
Granularity = granularity,
TimeRange = timeRange,
DataPoints = dataPoints,
TrendAnalysis = GenerateTrendAnalysis(),
Statistics = GenerateTrendStatisticsSummary(dataPoints),
ExtendedProperties = new Dictionary
{
["generation_time_ms"] = 120,
["data_source"] = "simulated"
}
};
}
///
/// 生成统计数据导出。
///
private async Task<(string FilePath, long FileSizeBytes, int RecordCount)> GenerateStatisticsExportAsync(StatisticsExportRequest exportRequest, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var fileName = $"statistics_export_{exportRequest.RequestId:N}.{exportRequest.ExportFormat.ToString().ToLower()}";
var filePath = Path.Combine(Path.GetTempPath(), fileName);
// 简化处理:生成模拟文件
var recordCount = 1000;
var fileContent = GenerateExportFileContent(exportRequest, recordCount);
await File.WriteAllTextAsync(filePath, fileContent, cancellationToken);
var fileInfo = new FileInfo(filePath);
return (filePath, fileInfo.Length, recordCount);
}
#endregion
#region 辅助方法
///
/// 计算标准差。
///
private double CalculateStandardDeviation(IEnumerable values)
{
var valuesList = values.ToList();
var mean = valuesList.Average();
var variance = valuesList.Sum(x => Math.Pow(x - mean, 2)) / valuesList.Count;
return Math.Sqrt(variance);
}
///
/// 生成按小时分组的节拍统计。
///
private Dictionary GenerateHourlyCycleTimeStatistics(DateTime startTime, DateTime endTime, List cycleTimes)
{
var hourlyStats = new Dictionary();
var random = new Random();
for (int hour = 0; hour < 24; hour++)
{
var count = random.Next(5, 20);
var successCount = (int)(count * (0.85 + random.NextDouble() * 0.1));
var avgCycleTime = 50 + random.NextDouble() * 20;
hourlyStats[hour] = new HourlyCycleTimeStatistics
{
Hour = hour,
ProcessedCount = count,
SuccessCount = successCount,
AverageCycleTimeSeconds = avgCycleTime
};
}
return hourlyStats;
}
///
/// 生成按产品类型分组的节拍统计。
///
private Dictionary GenerateProductTypeCycleTimeStatistics(string? productTypeCode, int totalProcessed, int successCount, double avgCycleTime)
{
return new Dictionary
{
[productTypeCode ?? "default"] = new ProductTypeCycleTimeStatistics
{
ProductTypeCode = productTypeCode ?? "default",
ProcessedCount = totalProcessed,
SuccessCount = successCount,
AverageCycleTimeSeconds = avgCycleTime
}
};
}
///
/// 生成节拍时间分布。
///
private CycleTimeDistribution GenerateCycleTimeDistribution(List cycleTimes, double targetTime)
{
var belowTarget = cycleTimes.Count(t => t < targetTime * 0.9);
var withinRange = cycleTimes.Count(t => t >= targetTime * 0.9 && t <= targetTime * 1.1);
var aboveRange = cycleTimes.Count - belowTarget - withinRange;
var total = cycleTimes.Count;
return new CycleTimeDistribution
{
BelowTargetCount = belowTarget,
WithinTargetRangeCount = withinRange,
AboveTargetRangeCount = aboveRange,
BelowTargetPercentage = (double)belowTarget / total * 100,
WithinTargetRangePercentage = (double)withinRange / total * 100,
AboveTargetRangePercentage = (double)aboveRange / total * 100
};
}
///
/// 生成节拍趋势分析。
///
private CycleTimeTrend GenerateCycleTimeTrend(List cycleTimes)
{
var random = new Random();
var direction = random.NextDouble() > 0.5 ? TrendDirection.Increasing : TrendDirection.Decreasing;
var changeRate = random.NextDouble() * 10 - 5; // -5% to +5%
return new CycleTimeTrend
{
Direction = direction,
ChangeRatePercentage = changeRate,
TrendDescription = $"节拍时间呈{direction}趋势,变化率{changeRate:F2}%",
PredictedNextCycleTimeSeconds = cycleTimes.Average() * (1 + changeRate / 100),
Confidence = 0.7 + random.NextDouble() * 0.2
};
}
///
/// 生成班次信息。
///
private ShiftInfo GenerateShiftInfo(DateTime shiftDate, ShiftType? shiftType)
{
var type = shiftType ?? ShiftType.Morning;
var (startTime, endTime) = type switch
{
ShiftType.Morning => (new TimeSpan(8, 0, 0), new TimeSpan(16, 0, 0)),
ShiftType.Afternoon => (new TimeSpan(16, 0, 0), new TimeSpan(0, 0, 0)),
ShiftType.Night => (new TimeSpan(0, 0, 0), new TimeSpan(8, 0, 0)),
_ => (new TimeSpan(8, 0, 0), new TimeSpan(16, 0, 0))
};
return new ShiftInfo
{
ShiftId = Guid.NewGuid(),
ShiftDate = shiftDate,
ShiftType = type,
ShiftName = $"{type}班",
StartTime = startTime,
EndTime = endTime,
Operators = new[] { "操作员A", "操作员B" },
Supervisor = "主管A"
};
}
///
/// 生成按小时分组的班次统计。
///
private Dictionary GenerateHourlyShiftStatistics(ShiftInfo shiftInfo, int actualProduction, int qualifiedCount)
{
var hourlyStats = new Dictionary();
var random = new Random();
var startHour = (int)shiftInfo.StartTime.TotalHours;
var endHour = (int)shiftInfo.EndTime.TotalHours;
for (int hour = startHour; hour < endHour; hour++)
{
var hourProduction = random.Next(5, 15);
var hourQualified = (int)(hourProduction * (0.9 + random.NextDouble() * 0.08));
hourlyStats[hour] = new HourlyShiftStatistics
{
Hour = hour,
ProductionCount = hourProduction,
QualifiedCount = hourQualified,
EquipmentRunningMinutes = 50 + random.NextDouble() * 10,
EquipmentDowntimeMinutes = random.NextDouble() * 5
};
}
return hourlyStats;
}
///
/// 生成按产品类型分组的班次统计。
///
private Dictionary GenerateProductTypeShiftStatistics(string? productTypeCode, int actualProduction, int qualifiedCount, double avgCycleTime)
{
return new Dictionary
{
[productTypeCode ?? "default"] = new ProductTypeShiftStatistics
{
ProductTypeCode = productTypeCode ?? "default",
ProductionCount = actualProduction,
QualifiedCount = qualifiedCount,
AverageCycleTimeSeconds = avgCycleTime
}
};
}
///
/// 生成班次异常统计。
///
private ShiftAnomalyStatistics GenerateShiftAnomalyStatistics(Random random)
{
var totalAnomalies = random.Next(0, 10);
return new ShiftAnomalyStatistics
{
TotalAnomalyCount = totalAnomalies,
EquipmentFailureCount = random.Next(0, totalAnomalies / 2),
QualityAnomalyCount = random.Next(0, totalAnomalies / 2),
ProcessAnomalyCount = random.Next(0, totalAnomalies / 2),
DowntimeMinutes = random.NextDouble() * 30,
AnomalyRate = totalAnomalies > 0 ? random.NextDouble() * 5 : 0.0
};
}
///
/// 生成时间段效率。
///
private Dictionary GenerateTimeSlotEfficiency(DateTime startTime, DateTime endTime, int actualProduction, int qualifiedCount, double equipmentHours)
{
var timeSlotEfficiency = new Dictionary();
var random = new Random();
var current = startTime;
while (current < endTime)
{
var slotProduction = random.Next(5, 20);
var slotQualified = (int)(slotProduction * (0.9 + random.NextDouble() * 0.08));
var slotEfficiency = 0.7 + random.NextDouble() * 0.2;
timeSlotEfficiency[current] = new TimeSlotEfficiency
{
TimeSlot = current,
ProductionCount = slotProduction,
QualifiedCount = slotQualified,
EquipmentRunningMinutes = 50 + random.NextDouble() * 10,
OverallEfficiency = slotEfficiency * 100
};
current = current.AddHours(1);
}
return timeSlotEfficiency;
}
///
/// 生成效率趋势分析。
///
private EfficiencyTrend GenerateEfficiencyTrend()
{
var random = new Random();
var direction = random.NextDouble() > 0.5 ? TrendDirection.Increasing : TrendDirection.Decreasing;
var changeRate = random.NextDouble() * 8 - 4; // -4% to +4%
return new EfficiencyTrend
{
Direction = direction,
ChangeRatePercentage = changeRate,
TrendDescription = $"效率呈{direction}趋势,变化率{changeRate:F2}%",
PredictedNextEfficiency = 75 + random.NextDouble() * 15,
Confidence = 0.6 + random.NextDouble() * 0.3
};
}
///
/// 生成效率基准对比。
///
private EfficiencyBenchmark GenerateEfficiencyBenchmark()
{
var random = new Random();
return new EfficiencyBenchmark
{
HistoricalBestEfficiency = 85 + random.NextDouble() * 10,
HistoricalAverageEfficiency = 75 + random.NextDouble() * 8,
IndustryBenchmarkEfficiency = 80 + random.NextDouble() * 10,
TargetEfficiency = 82 + random.NextDouble() * 8
};
}
///
/// 生成缺陷统计。
///
private Dictionary GenerateDefectStatistics(int totalDefects)
{
var random = new Random();
var defectStats = new Dictionary();
var defectTypes = new[] { DefectType.Appearance, DefectType.Dimension, DefectType.Function, DefectType.Material, DefectType.Process };
var remainingDefects = totalDefects;
foreach (var defectType in defectTypes)
{
if (remainingDefects <= 0) break;
var count = random.Next(0, remainingDefects / 2 + 1);
remainingDefects -= count;
defectStats[defectType] = new DefectStatistics
{
DefectType = defectType,
DefectCount = count,
Percentage = totalDefects > 0 ? (double)count / totalDefects * 100 : 0,
AverageSeverity = 1 + random.NextDouble() * 2
};
}
return defectStats;
}
///
/// 生成严重程度统计。
///
private Dictionary GenerateSeverityStatistics(int totalDefects)
{
var random = new Random();
var severityStats = new Dictionary();
var severities = new[] { DefectSeverity.Minor, DefectSeverity.Normal, DefectSeverity.Serious, DefectSeverity.Critical };
var remainingDefects = totalDefects;
foreach (var severity in severities)
{
if (remainingDefects <= 0) break;
var count = random.Next(0, remainingDefects / 2 + 1);
remainingDefects -= count;
severityStats[severity] = new SeverityStatistics
{
Severity = severity,
DefectCount = count,
Percentage = totalDefects > 0 ? (double)count / totalDefects * 100 : 0
};
}
return severityStats;
}
///
/// 生成按产品类型分组的质量统计。
///
private Dictionary GenerateProductTypeQualityStatistics(string? productTypeCode, int totalInspection, int qualifiedCount)
{
return new Dictionary
{
[productTypeCode ?? "default"] = new ProductTypeQualityStatistics
{
ProductTypeCode = productTypeCode ?? "default",
InspectionCount = totalInspection,
QualifiedCount = qualifiedCount
}
};
}
///
/// 生成按检测时间的质量统计。
///
private Dictionary GenerateQualityTimeSlotStatistics(DateTime startTime, DateTime endTime, int totalInspection, int qualifiedCount)
{
var timeSlotStats = new Dictionary();
var random = new Random();
var current = startTime;
while (current < endTime)
{
var slotInspection = random.Next(10, 30);
var slotQualified = (int)(slotInspection * (0.9 + random.NextDouble() * 0.08));
timeSlotStats[current] = new QualityTimeSlotStatistics
{
InspectionTime = current,
InspectionCount = slotInspection,
QualifiedCount = slotQualified
};
current = current.AddHours(2);
}
return timeSlotStats;
}
///
/// 生成质量趋势分析。
///
private QualityTrend GenerateQualityTrend()
{
var random = new Random();
var direction = random.NextDouble() > 0.3 ? TrendDirection.Stable : (random.NextDouble() > 0.5 ? TrendDirection.Increasing : TrendDirection.Decreasing);
var changeRate = random.NextDouble() * 6 - 3; // -3% to +3%
return new QualityTrend
{
Direction = direction,
ChangeRatePercentage = changeRate,
TrendDescription = $"质量呈{direction}趋势,变化率{changeRate:F2}%",
PredictedNextPassRate = 92 + random.NextDouble() * 6,
Confidence = 0.7 + random.NextDouble() * 0.2
};
}
///
/// 生成质量改进建议。
///
private IReadOnlyList GenerateQualityImprovementSuggestions()
{
var random = new Random();
var suggestions = new List();
var suggestionTypes = new[] { SuggestionType.ProcessImprovement, SuggestionType.EquipmentMaintenance, SuggestionType.OperatorTraining };
var difficulties = new[] { ImplementationDifficulty.Easy, ImplementationDifficulty.Medium, ImplementationDifficulty.Difficult };
foreach (var type in suggestionTypes.Take(2))
{
suggestions.Add(new QualityImprovementSuggestion
{
SuggestionId = Guid.NewGuid(),
SuggestionType = type,
Title = $"{type}建议",
Description = $"通过{type}提升产品质量",
Priority = random.Next(1, 5),
ExpectedImpact = "预计提升合格率2-5%",
Difficulty = difficulties[random.Next(difficulties.Length)]
});
}
return suggestions.AsReadOnly();
}
///
/// 生成按日期分组的利用率统计。
///
private Dictionary GenerateDailyUtilizationStatistics(DateTime startTime, DateTime endTime, double plannedHours, double actualHours)
{
var dailyStats = new Dictionary();
var random = new Random();
var current = startTime.Date;
while (current <= endTime.Date)
{
dailyStats[current] = new DailyUtilizationStatistics
{
Date = current,
PlannedRunningHours = 24,
ActualRunningHours = 20 + random.NextDouble() * 4
};
current = current.AddDays(1);
}
return dailyStats;
}
///
/// 生成利用率趋势分析。
///
private UtilizationTrend GenerateUtilizationTrend()
{
var random = new Random();
var direction = random.NextDouble() > 0.4 ? TrendDirection.Stable : TrendDirection.Fluctuating;
var changeRate = random.NextDouble() * 4 - 2; // -2% to +2%
return new UtilizationTrend
{
Direction = direction,
ChangeRatePercentage = changeRate,
TrendDescription = $"设备利用率呈{direction}趋势,变化率{changeRate:F2}%",
PredictedNextUtilization = 80 + random.NextDouble() * 15,
Confidence = 0.6 + random.NextDouble() * 0.3
};
}
///
/// 生成维护建议。
///
private IReadOnlyList GenerateMaintenanceSuggestions()
{
var random = new Random();
var suggestions = new List();
var maintenanceTypes = new[] { MaintenanceType.Preventive, MaintenanceType.Predictive, MaintenanceType.Corrective };
foreach (var type in maintenanceTypes.Take(2))
{
suggestions.Add(new MaintenanceSuggestion
{
SuggestionId = Guid.NewGuid(),
MaintenanceType = type,
Title = $"{type}维护建议",
Description = $"建议进行{type}维护",
Priority = random.Next(1, 5),
EstimatedMaintenanceHours = 2 + random.NextDouble() * 4,
EstimatedCost = 1000 + random.NextDouble() * 3000,
SuggestedMaintenanceTime = DateTime.UtcNow.AddDays(random.Next(1, 7))
});
}
return suggestions.AsReadOnly();
}
///
/// 生成报警趋势分析。
///
private AlarmTrend GenerateAlarmTrend()
{
var random = new Random();
var direction = random.NextDouble() > 0.6 ? TrendDirection.Stable : (random.NextDouble() > 0.5 ? TrendDirection.Increasing : TrendDirection.Decreasing);
var changeRate = random.NextDouble() * 15 - 7.5; // -7.5% to +7.5%
return new AlarmTrend
{
Direction = direction,
ChangeRatePercentage = changeRate,
TrendDescription = $"报警数量呈{direction}趋势,变化率{changeRate:F2}%",
PredictedNextAlarmCount = random.Next(5, 25),
Confidence = 0.5 + random.NextDouble() * 0.4
};
}
///
/// 生成执行摘要。
///
private ExecutiveSummary GenerateExecutiveSummary()
{
var random = new Random();
return new ExecutiveSummary
{
OverallScore = 75 + random.NextDouble() * 15,
KeyMetrics = new Dictionary
{
["生产完成率"] = 85 + random.NextDouble() * 10,
["质量合格率"] = 92 + random.NextDouble() * 6,
["设备利用率"] = 80 + random.NextDouble() * 15,
["OEE"] = 70 + random.NextDouble() * 20
},
Achievements = new[] { "生产效率提升5%", "质量指标达标" },
Issues = new[] { "设备故障率偏高", "人员操作需优化" },
SummaryDescription = "整体运行状况良好,部分指标需持续改进"
};
}
///
/// 生成生产统计。
///
private ProductionStatistics GenerateProductionStatistics()
{
var random = new Random();
return new ProductionStatistics
{
PlannedProduction = 1000,
ActualProduction = (int)(1000 * (0.88 + random.NextDouble() * 0.1)),
QualifiedProduction = (int)(950 * (0.92 + random.NextDouble() * 0.06)),
AverageCycleTimeSeconds = 55 + random.NextDouble() * 10
};
}
///
/// 生成设备统计。
///
private EquipmentStatistics GenerateEquipmentStatistics()
{
var random = new Random();
return new EquipmentStatistics
{
EquipmentCount = 5,
AverageUtilizationRate = 75 + random.NextDouble() * 15,
AverageAvailabilityRate = 85 + random.NextDouble() * 10,
TotalDowntimeHours = 2 + random.NextDouble() * 3
};
}
///
/// 生成趋势分析。
///
private TrendAnalysis GenerateTrendAnalysis()
{
var random = new Random();
return new TrendAnalysis
{
ProductionTrend = TrendDirection.Stable,
QualityTrend = TrendDirection.Increasing,
EquipmentTrend = TrendDirection.Fluctuating,
AlarmTrend = TrendDirection.Decreasing,
TrendDescription = "生产稳定,质量提升,设备需关注"
};
}
///
/// 生成改进建议。
///
private IReadOnlyList GenerateImprovementRecommendations()
{
var random = new Random();
var recommendations = new List();
var categories = new[] { RecommendationCategory.ProductionOptimization, RecommendationCategory.QualityImprovement, RecommendationCategory.EquipmentMaintenance };
foreach (var category in categories.Take(3))
{
recommendations.Add(new ImprovementRecommendation
{
RecommendationId = Guid.NewGuid(),
Category = category,
Title = $"{category}建议",
Description = $"建议进行{category}改进",
Priority = random.Next(1, 5),
ExpectedBenefit = "预计提升效率3-8%",
ImplementationCost = 5000 + random.NextDouble() * 10000,
ReturnOnInvestment = 150 + random.NextDouble() * 100
});
}
return recommendations.AsReadOnly();
}
///
/// 生成实时生产指标。
///
private RealTimeProductionMetrics GenerateRealTimeProductionMetrics(Random random)
{
return new RealTimeProductionMetrics
{
CurrentHourProduction = random.Next(8, 15),
CurrentShiftProduction = random.Next(80, 120),
TodayProduction = random.Next(200, 300),
CurrentCycleTimeSeconds = 50 + random.NextDouble() * 15,
CycleTimeAchievementRate = 85 + random.NextDouble() * 10,
ProductionSpeedTrend = TrendDirection.Stable
};
}
///
/// 生成实时质量指标。
///
private RealTimeQualityMetrics GenerateRealTimeQualityMetrics(Random random)
{
return new RealTimeQualityMetrics
{
CurrentHourPassRate = 92 + random.NextDouble() * 6,
CurrentShiftPassRate = 93 + random.NextDouble() * 5,
TodayPassRate = 94 + random.NextDouble() * 4,
RecentDefectCount = random.Next(0, 5),
QualityTrend = TrendDirection.Stable
};
}
///
/// 生成实时设备指标。
///
private RealTimeEquipmentMetrics GenerateRealTimeEquipmentMetrics(Random random)
{
return new RealTimeEquipmentMetrics
{
RunningEquipmentCount = 4,
DownEquipmentCount = 1,
CurrentUtilizationRate = 78 + random.NextDouble() * 12,
CurrentAvailabilityRate = 88 + random.NextDouble() * 8,
EquipmentStatusTrend = TrendDirection.Stable
};
}
///
/// 生成实时报警指标。
///
private RealTimeAlarmMetrics GenerateRealTimeAlarmMetrics(Random random)
{
return new RealTimeAlarmMetrics
{
ActiveAlarmCount = random.Next(0, 3),
TodayNewAlarmCount = random.Next(5, 15),
CriticalAlarmCount = random.Next(0, 2),
LastAlarmTime = random.NextDouble() > 0.3 ? DateTime.UtcNow.AddMinutes(-random.Next(10, 120)) : null,
AlarmTrend = TrendDirection.Stable
};
}
///
/// 生成实时效率指标。
///
private RealTimeEfficiencyMetrics GenerateRealTimeEfficiencyMetrics(Random random)
{
return new RealTimeEfficiencyMetrics
{
CurrentOEE = 72 + random.NextDouble() * 16,
TimeUtilizationRate = 85 + random.NextDouble() * 10,
EquipmentUtilizationRate = 80 + random.NextDouble() * 15,
PerformanceEfficiency = 88 + random.NextDouble() * 8,
EfficiencyTrend = TrendDirection.Stable
};
}
///
/// 生成趋势数据点。
///
private IReadOnlyList GenerateTrendDataPoints(MetricType metricType, DateTime startTime, DateTime endTime, StatisticsGranularity granularity, Random random)
{
var dataPoints = new List();
var current = startTime;
var interval = granularity switch
{
StatisticsGranularity.Minutely => TimeSpan.FromMinutes(1),
StatisticsGranularity.Hourly => TimeSpan.FromHours(1),
StatisticsGranularity.Daily => TimeSpan.FromDays(1),
_ => TimeSpan.FromHours(1)
};
while (current <= endTime)
{
var value = GetMetricValue(metricType, random);
dataPoints.Add(new TrendDataPoint
{
Timestamp = current,
Value = value,
Unit = GetMetricUnit(metricType)
});
current = current.Add(interval);
}
return dataPoints.AsReadOnly();
}
///
/// 获取指标值。
///
private double GetMetricValue(MetricType metricType, Random random)
{
return metricType switch
{
MetricType.Production => 50 + random.NextDouble() * 30,
MetricType.Quality => 90 + random.NextDouble() * 8,
MetricType.EquipmentUtilization => 75 + random.NextDouble() * 20,
MetricType.CycleTime => 45 + random.NextDouble() * 25,
MetricType.OEE => 70 + random.NextDouble() * 20,
MetricType.AlarmCount => random.NextDouble() * 10,
MetricType.Downtime => random.NextDouble() * 5,
MetricType.Efficiency => 80 + random.NextDouble() * 15,
_ => random.NextDouble() * 100
};
}
///
/// 获取指标单位。
///
private string GetMetricUnit(MetricType metricType)
{
return metricType switch
{
MetricType.Production => "个",
MetricType.Quality => "%",
MetricType.EquipmentUtilization => "%",
MetricType.CycleTime => "秒",
MetricType.OEE => "%",
MetricType.AlarmCount => "个",
MetricType.Downtime => "小时",
MetricType.Efficiency => "%",
_ => ""
};
}
///
/// 生成趋势统计摘要。
///
private TrendStatisticsSummary GenerateTrendStatisticsSummary(IReadOnlyList dataPoints)
{
if (!dataPoints.Any())
{
return new TrendStatisticsSummary();
}
var values = dataPoints.Select(dp => dp.Value).ToList();
var sortedValues = values.OrderBy(v => v).ToList();
return new TrendStatisticsSummary
{
DataPointCount = dataPoints.Count,
MinValue = sortedValues.First(),
MaxValue = sortedValues.Last(),
AverageValue = values.Average(),
MedianValue = sortedValues[sortedValues.Count / 2],
StandardDeviation = CalculateStandardDeviation(values)
};
}
///
/// 生成导出文件内容。
///
private string GenerateExportFileContent(StatisticsExportRequest exportRequest, int recordCount)
{
var random = new Random();
var content = new System.Text.StringBuilder();
// 简化处理:生成CSV格式内容
content.AppendLine("ID,时间,数值,单位");
for (int i = 0; i < recordCount; i++)
{
var timestamp = DateTime.UtcNow.AddMinutes(-random.Next(0, 1440));
var value = random.NextDouble() * 100;
var unit = "个";
content.AppendLine($"{i + 1},{timestamp:yyyy-MM-dd HH:mm:ss},{value:F2},{unit}");
}
return content.ToString();
}
///
/// 获取当前班次类型。
///
private ShiftType GetCurrentShiftType(DateTime dateTime)
{
var hour = dateTime.Hour;
return hour switch
{
>= 8 and < 16 => ShiftType.Morning,
>= 16 and < 24 => ShiftType.Afternoon,
_ => ShiftType.Night
};
}
#endregion
}
#endif
///
/// 统计服务实现(最小可编译版本)。
///
public sealed class StatisticsService : IStatisticsService
{
private readonly ILogger _logger;
public StatisticsService(ILogger logger, IOptions options)
{
_logger = logger;
}
public Task> GetCycleTimeStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
var data = new CycleTimeStatistics
{
TimeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime },
ProductTypeCode = productTypeCode ?? string.Empty,
TotalProcessedCount = 0,
SuccessfulProcessedCount = 0,
FailedProcessedCount = 0,
AverageCycleTimeSeconds = 0,
MinCycleTimeSeconds = 0,
MaxCycleTimeSeconds = 0,
CycleTimeStandardDeviationSeconds = 0,
TargetCycleTimeSeconds = 0,
CountAchievedCycleTime = 0
};
return Task.FromResult(Result.Success(data));
}
public Task> GetShiftStatisticsAsync(DateTime shiftDate, ShiftType? shiftType = null, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
var actualShiftType = shiftType ?? ShiftType.Morning;
var data = new ShiftStatistics
{
ShiftInfo = new ShiftInfo
{
ShiftId = Guid.NewGuid(),
ShiftDate = shiftDate.Date,
ShiftType = actualShiftType,
ShiftName = actualShiftType.ToString(),
StartTime = TimeSpan.Zero,
EndTime = TimeSpan.FromHours(8)
},
ProductTypeCode = productTypeCode ?? string.Empty,
PlannedProductionCount = 0,
ActualProductionCount = 0,
QualifiedProductionCount = 0,
UnqualifiedProductionCount = 0,
ShiftStartTimeUtc = shiftDate,
ShiftEndTimeUtc = shiftDate.AddHours(8),
ActualWorkingHours = 0,
EquipmentDowntimeHours = 0,
AverageCycleTimeSeconds = 0
};
return Task.FromResult(Result.Success(data));
}
public Task>> GetShiftListAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default)
{
IReadOnlyList data = Array.Empty();
return Task.FromResult(Result>.Success(data));
}
public Task> GetProductionEfficiencyStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, StatisticsGranularity granularity = StatisticsGranularity.Hourly, CancellationToken cancellationToken = default)
{
var data = new ProductionEfficiencyStatistics
{
TimeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime },
ProductTypeCode = productTypeCode ?? string.Empty,
Granularity = granularity,
PlannedWorkingHours = 0,
ActualWorkingHours = 0,
EquipmentRunningHours = 0,
PlannedProductionCount = 0,
ActualProductionCount = 0,
QualifiedProductionCount = 0
};
return Task.FromResult(Result.Success(data));
}
public Task> GetQualityStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
var data = new QualityStatistics
{
TimeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime },
ProductTypeCode = productTypeCode ?? string.Empty,
TotalInspectionCount = 0,
QualifiedCount = 0,
UnqualifiedCount = 0
};
return Task.FromResult(Result.Success(data));
}
public Task> GetEquipmentUtilizationStatisticsAsync(DateTime startTime, DateTime endTime, string? equipmentId = null, CancellationToken cancellationToken = default)
{
var data = new EquipmentUtilizationStatistics
{
TimeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime },
EquipmentId = equipmentId ?? string.Empty,
PlannedRunningHours = 0,
ActualRunningHours = 0,
ProductionHours = 0,
MaintenanceHours = 0,
FailureHours = 0,
IdleHours = 0
};
return Task.FromResult(Result.Success(data));
}
public Task> GetAlarmStatisticsSummaryAsync(DateTime startTime, DateTime endTime, OrpaonVision.Core.Common.AlarmLevel? alarmLevel = null, CancellationToken cancellationToken = default)
{
var data = new AlarmStatisticsSummary
{
TimeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime },
TotalAlarmCount = 0,
ActiveAlarmCount = 0,
ConfirmedAlarmCount = 0,
ClearedAlarmCount = 0
};
return Task.FromResult(Result.Success(data));
}
public Task> GetComprehensiveProductionReportAsync(OrpaonVision.Core.Statistics.ProductionReportType reportType, DateTime startTime, DateTime endTime, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
var data = new ComprehensiveProductionReport
{
ReportId = Guid.NewGuid(),
ReportType = reportType,
TimeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime },
ProductTypeCode = productTypeCode ?? string.Empty,
GeneratedAtUtc = DateTime.UtcNow
};
return Task.FromResult(Result.Success(data));
}
public Task> GetRealTimeStatisticsDashboardAsync(string? productTypeCode = null, CancellationToken cancellationToken = default)
{
var data = new RealTimeStatisticsDashboard
{
ProductTypeCode = productTypeCode ?? string.Empty,
LastUpdatedUtc = DateTime.UtcNow
};
return Task.FromResult(Result.Success(data));
}
public Task> GetHistoricalTrendDataAsync(MetricType metricType, DateTime startTime, DateTime endTime, string? productTypeCode = null, StatisticsGranularity granularity = StatisticsGranularity.Hourly, CancellationToken cancellationToken = default)
{
var data = new HistoricalTrendData
{
MetricType = metricType,
TimeRange = new TimeRange { StartTimeUtc = startTime, EndTimeUtc = endTime },
Granularity = granularity
};
return Task.FromResult(Result.Success(data));
}
public Task> CreateStatisticsConfigAsync(StatisticsConfig config, CancellationToken cancellationToken = default)
{
return Task.FromResult(Result.Success(config));
}
public Task UpdateStatisticsConfigAsync(StatisticsConfig config, CancellationToken cancellationToken = default)
{
return Task.FromResult(Result.Success());
}
public Task> GetStatisticsConfigAsync(StatisticsConfigType configType, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
var config = new StatisticsConfig
{
ConfigId = Guid.NewGuid(),
ConfigType = configType,
ProductTypeCode = productTypeCode ?? string.Empty,
ConfigName = $"{configType}-default",
IsEnabled = true,
CreatedAtUtc = DateTime.UtcNow,
UpdatedAtUtc = DateTime.UtcNow,
Version = "1.0"
};
return Task.FromResult(Result.Success(config));
}
public Task> ExportStatisticsAsync(StatisticsExportRequest exportRequest, CancellationToken cancellationToken = default)
{
_logger.LogInformation("统计导出请求: {RequestId}", exportRequest.RequestId);
var result = new StatisticsExportResult
{
RequestId = exportRequest.RequestId,
IsSuccess = true,
FilePath = string.Empty,
FileSizeBytes = 0,
RecordCount = 0,
ExportElapsedMs = 0,
ExportTimeUtc = DateTime.UtcNow,
ResultDescription = "OK"
};
return Task.FromResult(Result.Success(result));
}
}