Files
OrpaonVision/OrpaonVision.SiteApp/Runtime/Services/StatisticsService.cs
2026-04-06 22:04:05 +08:00

1973 lines
81 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
/// <summary>
/// 统计服务实现。
/// </summary>
#if DISABLED_LEGACY_STATISTICS_SERVICE
public sealed class StatisticsService : IStatisticsService
{
private readonly ILogger<StatisticsService> _logger;
private readonly RuntimeOptions _options;
private readonly ConcurrentDictionary<string, StatisticsConfig> _statisticsConfigs = new();
private readonly ConcurrentDictionary<string, object> _statisticsCache = new();
private readonly object _lock = new();
/// <summary>
/// 构造函数。
/// </summary>
public StatisticsService(ILogger<StatisticsService> logger, IOptions<RuntimeOptions> options)
{
_logger = logger;
_options = options.Value;
InitializeDefaultStatisticsConfigs();
_logger.LogInformation("统计服务已初始化");
}
/// <inheritdoc />
public async Task<Result<CycleTimeStatistics>> 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<CycleTimeStatistics>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<ShiftStatistics>> 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<ShiftStatistics>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<IReadOnlyList<ShiftInfo>>> 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<IReadOnlyList<ShiftInfo>>(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<IReadOnlyList<ShiftInfo>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<ProductionEfficiencyStatistics>> 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<ProductionEfficiencyStatistics>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<QualityStatistics>> 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<QualityStatistics>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<EquipmentUtilizationStatistics>> 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<EquipmentUtilizationStatistics>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<AlarmStatisticsSummary>> 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<AlarmStatisticsSummary>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<ComprehensiveProductionReport>> 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<ComprehensiveProductionReport>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<RealTimeStatisticsDashboard>> 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<RealTimeStatisticsDashboard>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<HistoricalTrendData>> 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<HistoricalTrendData>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<StatisticsConfig>> 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<StatisticsConfig>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result> 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());
}
}
/// <inheritdoc />
public async Task<Result<StatisticsConfig>> 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<StatisticsConfig>("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<StatisticsConfig>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<StatisticsExportResult>> 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<string, object>
{
["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<StatisticsExportResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
#region
/// <summary>
/// 初始化默认统计配置。
/// </summary>
private void InitializeDefaultStatisticsConfigs()
{
var defaultConfigs = new List<StatisticsConfig>
{
new()
{
ConfigId = Guid.NewGuid(),
ConfigType = StatisticsConfigType.CycleTime,
ProductTypeCode = "default",
ConfigName = "默认节拍统计配置",
ConfigDescription = "系统默认的节拍统计配置",
Parameters = new Dictionary<string, object>
{
["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<string, object>
{
["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<string, object>
{
["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;
}
}
/// <summary>
/// 生成节拍统计信息。
/// </summary>
private async Task<CycleTimeStatistics> 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<string, object>
{
["generation_time_ms"] = 50,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成班次统计信息。
/// </summary>
private async Task<ShiftStatistics> 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<string, object>
{
["generation_time_ms"] = 60,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成班次列表。
/// </summary>
private async Task<IReadOnlyList<ShiftInfo>> GenerateShiftListAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var shiftList = new List<ShiftInfo>();
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();
}
/// <summary>
/// 生成生产效率统计。
/// </summary>
private async Task<ProductionEfficiencyStatistics> 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<string, object>
{
["generation_time_ms"] = 70,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成质量统计信息。
/// </summary>
private async Task<QualityStatistics> 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<string, object>
{
["generation_time_ms"] = 80,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成设备利用率统计。
/// </summary>
private async Task<EquipmentUtilizationStatistics> 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<string, object>
{
["generation_time_ms"] = 90,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成报警统计摘要。
/// </summary>
private async Task<AlarmStatisticsSummary> 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, int>
{
[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, int>
{
[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<string, object>
{
["generation_time_ms"] = 100,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成综合生产报告。
/// </summary>
private async Task<ComprehensiveProductionReport> 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<string, object>
{
["generation_time_ms"] = 200,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成实时统计仪表板。
/// </summary>
private async Task<RealTimeStatisticsDashboard> 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<string, object>
{
["generation_time_ms"] = 30,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成历史趋势数据。
/// </summary>
private async Task<HistoricalTrendData> 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<string, object>
{
["generation_time_ms"] = 120,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成统计数据导出。
/// </summary>
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
/// <summary>
/// 计算标准差。
/// </summary>
private double CalculateStandardDeviation(IEnumerable<double> 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);
}
/// <summary>
/// 生成按小时分组的节拍统计。
/// </summary>
private Dictionary<int, HourlyCycleTimeStatistics> GenerateHourlyCycleTimeStatistics(DateTime startTime, DateTime endTime, List<double> cycleTimes)
{
var hourlyStats = new Dictionary<int, HourlyCycleTimeStatistics>();
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;
}
/// <summary>
/// 生成按产品类型分组的节拍统计。
/// </summary>
private Dictionary<string, ProductTypeCycleTimeStatistics> GenerateProductTypeCycleTimeStatistics(string? productTypeCode, int totalProcessed, int successCount, double avgCycleTime)
{
return new Dictionary<string, ProductTypeCycleTimeStatistics>
{
[productTypeCode ?? "default"] = new ProductTypeCycleTimeStatistics
{
ProductTypeCode = productTypeCode ?? "default",
ProcessedCount = totalProcessed,
SuccessCount = successCount,
AverageCycleTimeSeconds = avgCycleTime
}
};
}
/// <summary>
/// 生成节拍时间分布。
/// </summary>
private CycleTimeDistribution GenerateCycleTimeDistribution(List<double> 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
};
}
/// <summary>
/// 生成节拍趋势分析。
/// </summary>
private CycleTimeTrend GenerateCycleTimeTrend(List<double> 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
};
}
/// <summary>
/// 生成班次信息。
/// </summary>
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"
};
}
/// <summary>
/// 生成按小时分组的班次统计。
/// </summary>
private Dictionary<int, HourlyShiftStatistics> GenerateHourlyShiftStatistics(ShiftInfo shiftInfo, int actualProduction, int qualifiedCount)
{
var hourlyStats = new Dictionary<int, HourlyShiftStatistics>();
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;
}
/// <summary>
/// 生成按产品类型分组的班次统计。
/// </summary>
private Dictionary<string, ProductTypeShiftStatistics> GenerateProductTypeShiftStatistics(string? productTypeCode, int actualProduction, int qualifiedCount, double avgCycleTime)
{
return new Dictionary<string, ProductTypeShiftStatistics>
{
[productTypeCode ?? "default"] = new ProductTypeShiftStatistics
{
ProductTypeCode = productTypeCode ?? "default",
ProductionCount = actualProduction,
QualifiedCount = qualifiedCount,
AverageCycleTimeSeconds = avgCycleTime
}
};
}
/// <summary>
/// 生成班次异常统计。
/// </summary>
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
};
}
/// <summary>
/// 生成时间段效率。
/// </summary>
private Dictionary<DateTime, TimeSlotEfficiency> GenerateTimeSlotEfficiency(DateTime startTime, DateTime endTime, int actualProduction, int qualifiedCount, double equipmentHours)
{
var timeSlotEfficiency = new Dictionary<DateTime, TimeSlotEfficiency>();
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;
}
/// <summary>
/// 生成效率趋势分析。
/// </summary>
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
};
}
/// <summary>
/// 生成效率基准对比。
/// </summary>
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
};
}
/// <summary>
/// 生成缺陷统计。
/// </summary>
private Dictionary<DefectType, DefectStatistics> GenerateDefectStatistics(int totalDefects)
{
var random = new Random();
var defectStats = new Dictionary<DefectType, DefectStatistics>();
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;
}
/// <summary>
/// 生成严重程度统计。
/// </summary>
private Dictionary<DefectSeverity, SeverityStatistics> GenerateSeverityStatistics(int totalDefects)
{
var random = new Random();
var severityStats = new Dictionary<DefectSeverity, SeverityStatistics>();
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;
}
/// <summary>
/// 生成按产品类型分组的质量统计。
/// </summary>
private Dictionary<string, ProductTypeQualityStatistics> GenerateProductTypeQualityStatistics(string? productTypeCode, int totalInspection, int qualifiedCount)
{
return new Dictionary<string, ProductTypeQualityStatistics>
{
[productTypeCode ?? "default"] = new ProductTypeQualityStatistics
{
ProductTypeCode = productTypeCode ?? "default",
InspectionCount = totalInspection,
QualifiedCount = qualifiedCount
}
};
}
/// <summary>
/// 生成按检测时间的质量统计。
/// </summary>
private Dictionary<DateTime, QualityTimeSlotStatistics> GenerateQualityTimeSlotStatistics(DateTime startTime, DateTime endTime, int totalInspection, int qualifiedCount)
{
var timeSlotStats = new Dictionary<DateTime, QualityTimeSlotStatistics>();
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;
}
/// <summary>
/// 生成质量趋势分析。
/// </summary>
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
};
}
/// <summary>
/// 生成质量改进建议。
/// </summary>
private IReadOnlyList<QualityImprovementSuggestion> GenerateQualityImprovementSuggestions()
{
var random = new Random();
var suggestions = new List<QualityImprovementSuggestion>();
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();
}
/// <summary>
/// 生成按日期分组的利用率统计。
/// </summary>
private Dictionary<DateTime, DailyUtilizationStatistics> GenerateDailyUtilizationStatistics(DateTime startTime, DateTime endTime, double plannedHours, double actualHours)
{
var dailyStats = new Dictionary<DateTime, DailyUtilizationStatistics>();
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;
}
/// <summary>
/// 生成利用率趋势分析。
/// </summary>
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
};
}
/// <summary>
/// 生成维护建议。
/// </summary>
private IReadOnlyList<MaintenanceSuggestion> GenerateMaintenanceSuggestions()
{
var random = new Random();
var suggestions = new List<MaintenanceSuggestion>();
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();
}
/// <summary>
/// 生成报警趋势分析。
/// </summary>
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
};
}
/// <summary>
/// 生成执行摘要。
/// </summary>
private ExecutiveSummary GenerateExecutiveSummary()
{
var random = new Random();
return new ExecutiveSummary
{
OverallScore = 75 + random.NextDouble() * 15,
KeyMetrics = new Dictionary<string, double>
{
["生产完成率"] = 85 + random.NextDouble() * 10,
["质量合格率"] = 92 + random.NextDouble() * 6,
["设备利用率"] = 80 + random.NextDouble() * 15,
["OEE"] = 70 + random.NextDouble() * 20
},
Achievements = new[] { "生产效率提升5%", "质量指标达标" },
Issues = new[] { "设备故障率偏高", "人员操作需优化" },
SummaryDescription = "整体运行状况良好,部分指标需持续改进"
};
}
/// <summary>
/// 生成生产统计。
/// </summary>
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
};
}
/// <summary>
/// 生成设备统计。
/// </summary>
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
};
}
/// <summary>
/// 生成趋势分析。
/// </summary>
private TrendAnalysis GenerateTrendAnalysis()
{
var random = new Random();
return new TrendAnalysis
{
ProductionTrend = TrendDirection.Stable,
QualityTrend = TrendDirection.Increasing,
EquipmentTrend = TrendDirection.Fluctuating,
AlarmTrend = TrendDirection.Decreasing,
TrendDescription = "生产稳定,质量提升,设备需关注"
};
}
/// <summary>
/// 生成改进建议。
/// </summary>
private IReadOnlyList<ImprovementRecommendation> GenerateImprovementRecommendations()
{
var random = new Random();
var recommendations = new List<ImprovementRecommendation>();
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();
}
/// <summary>
/// 生成实时生产指标。
/// </summary>
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
};
}
/// <summary>
/// 生成实时质量指标。
/// </summary>
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
};
}
/// <summary>
/// 生成实时设备指标。
/// </summary>
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
};
}
/// <summary>
/// 生成实时报警指标。
/// </summary>
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
};
}
/// <summary>
/// 生成实时效率指标。
/// </summary>
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
};
}
/// <summary>
/// 生成趋势数据点。
/// </summary>
private IReadOnlyList<TrendDataPoint> GenerateTrendDataPoints(MetricType metricType, DateTime startTime, DateTime endTime, StatisticsGranularity granularity, Random random)
{
var dataPoints = new List<TrendDataPoint>();
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();
}
/// <summary>
/// 获取指标值。
/// </summary>
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
};
}
/// <summary>
/// 获取指标单位。
/// </summary>
private string GetMetricUnit(MetricType metricType)
{
return metricType switch
{
MetricType.Production => "个",
MetricType.Quality => "%",
MetricType.EquipmentUtilization => "%",
MetricType.CycleTime => "秒",
MetricType.OEE => "%",
MetricType.AlarmCount => "个",
MetricType.Downtime => "小时",
MetricType.Efficiency => "%",
_ => ""
};
}
/// <summary>
/// 生成趋势统计摘要。
/// </summary>
private TrendStatisticsSummary GenerateTrendStatisticsSummary(IReadOnlyList<TrendDataPoint> 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)
};
}
/// <summary>
/// 生成导出文件内容。
/// </summary>
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();
}
/// <summary>
/// 获取当前班次类型。
/// </summary>
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
/// <summary>
/// 统计服务实现(最小可编译版本)。
/// </summary>
public sealed class StatisticsService : IStatisticsService
{
private readonly ILogger<StatisticsService> _logger;
public StatisticsService(ILogger<StatisticsService> logger, IOptions<RuntimeOptions> options)
{
_logger = logger;
}
public Task<Result<CycleTimeStatistics>> 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<CycleTimeStatistics>.Success(data));
}
public Task<Result<ShiftStatistics>> 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<ShiftStatistics>.Success(data));
}
public Task<Result<IReadOnlyList<ShiftInfo>>> GetShiftListAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default)
{
IReadOnlyList<ShiftInfo> data = Array.Empty<ShiftInfo>();
return Task.FromResult(Result<IReadOnlyList<ShiftInfo>>.Success(data));
}
public Task<Result<ProductionEfficiencyStatistics>> 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<ProductionEfficiencyStatistics>.Success(data));
}
public Task<Result<QualityStatistics>> 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<QualityStatistics>.Success(data));
}
public Task<Result<EquipmentUtilizationStatistics>> 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<EquipmentUtilizationStatistics>.Success(data));
}
public Task<Result<AlarmStatisticsSummary>> 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<AlarmStatisticsSummary>.Success(data));
}
public Task<Result<ComprehensiveProductionReport>> 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<ComprehensiveProductionReport>.Success(data));
}
public Task<Result<RealTimeStatisticsDashboard>> GetRealTimeStatisticsDashboardAsync(string? productTypeCode = null, CancellationToken cancellationToken = default)
{
var data = new RealTimeStatisticsDashboard
{
ProductTypeCode = productTypeCode ?? string.Empty,
LastUpdatedUtc = DateTime.UtcNow
};
return Task.FromResult(Result<RealTimeStatisticsDashboard>.Success(data));
}
public Task<Result<HistoricalTrendData>> 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<HistoricalTrendData>.Success(data));
}
public Task<Result<StatisticsConfig>> CreateStatisticsConfigAsync(StatisticsConfig config, CancellationToken cancellationToken = default)
{
return Task.FromResult(Result<StatisticsConfig>.Success(config));
}
public Task<Result> UpdateStatisticsConfigAsync(StatisticsConfig config, CancellationToken cancellationToken = default)
{
return Task.FromResult(Result.Success());
}
public Task<Result<StatisticsConfig>> 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<StatisticsConfig>.Success(config));
}
public Task<Result<StatisticsExportResult>> 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<StatisticsExportResult>.Success(result));
}
}