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

1907 lines
84 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.Common;
using OrpaonVision.Core.HistoryTrace;
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_HISTORY_TRACE_SERVICE
public sealed class HistoryTraceService : IHistoryTraceService
{
private readonly ILogger<HistoryTraceService> _logger;
private readonly RuntimeOptions _options;
private readonly ConcurrentDictionary<string, object> _tracebackCache = new();
private readonly object _lock = new();
/// <summary>
/// 构造函数。
/// </summary>
public HistoryTraceService(ILogger<HistoryTraceService> logger, IOptions<RuntimeOptions> options)
{
_logger = logger;
_options = options.Value;
_logger.LogInformation("历史追溯服务已初始化");
}
/// <inheritdoc />
public async Task<Result<IReadOnlyList<ProductSessionHistory>>> GetProductSessionHistoryAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, SessionStatus? sessionStatus = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取产品会话历史:开始时间={StartTime},结束时间={EndTime},产品类型={ProductTypeCode},会话状态={SessionStatus}",
startTime, endTime, productTypeCode, sessionStatus);
var cacheKey = $"session_history_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{productTypeCode}_{sessionStatus}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取产品会话历史");
return Result.Success((IReadOnlyList<ProductSessionHistory>)cached);
}
var sessionHistory = await GenerateProductSessionHistoryAsync(startTime, endTime, productTypeCode, sessionStatus, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, sessionHistory);
}
_logger.LogInformation("产品会话历史获取完成:会话数量={SessionCount}", sessionHistory.Count);
return Result.Success(sessionHistory);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取产品会话历史失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_PRODUCT_SESSION_HISTORY_FAILED", "获取产品会话历史失败", traceId);
return Result.FailWithTrace<IReadOnlyList<ProductSessionHistory>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<ProductSessionDetail>> GetSessionDetailAsync(Guid sessionId, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取会话详细信息会话ID={SessionId}", sessionId);
var cacheKey = $"session_detail_{sessionId}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取会话详细信息");
return Result.Success((ProductSessionDetail)cached);
}
var sessionDetail = await GenerateSessionDetailAsync(sessionId, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, sessionDetail);
}
_logger.LogInformation("会话详细信息获取完成会话ID={SessionId},层数={LayerCount},截图数={ScreenshotCount}",
sessionId, sessionDetail.LayerHistories.Count, sessionDetail.ScreenshotHistories.Count);
return Result.Success(sessionDetail);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取会话详细信息失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_SESSION_DETAIL_FAILED", "获取会话详细信息失败", traceId);
return Result.FailWithTrace<ProductSessionDetail>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<IReadOnlyList<LayerProcessingHistory>>> GetLayerProcessingHistoryAsync(Guid sessionId, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取层处理历史会话ID={SessionId}", sessionId);
var cacheKey = $"layer_history_{sessionId}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取层处理历史");
return Result.Success((IReadOnlyList<LayerProcessingHistory>)cached);
}
var layerHistory = await GenerateLayerProcessingHistoryAsync(sessionId, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, layerHistory);
}
_logger.LogInformation("层处理历史获取完成会话ID={SessionId},层数={LayerCount}", sessionId, layerHistory.Count);
return Result.Success(layerHistory);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取层处理历史失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_LAYER_PROCESSING_HISTORY_FAILED", "获取层处理历史失败", traceId);
return Result.FailWithTrace<IReadOnlyList<LayerProcessingHistory>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<LayerProcessingDetail>> GetLayerDetailAsync(Guid layerId, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取层详细信息层ID={LayerId}", layerId);
var cacheKey = $"layer_detail_{layerId}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取层详细信息");
return Result.Success((LayerProcessingDetail)cached);
}
var layerDetail = await GenerateLayerDetailAsync(layerId, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, layerDetail);
}
_logger.LogInformation("层详细信息获取完成层ID={LayerId},检测数={DetectionCount},截图数={ScreenshotCount}",
layerId, layerDetail.PartDetectionResults.Count, layerDetail.ScreenshotHistories.Count);
return Result.Success(layerDetail);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取层详细信息失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_LAYER_DETAIL_FAILED", "获取层详细信息失败", traceId);
return Result.FailWithTrace<LayerProcessingDetail>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<IReadOnlyList<ScreenshotHistory>>> GetScreenshotHistoryAsync(Guid? sessionId = null, Guid? layerId = null, DateTime? startTime = null, DateTime? endTime = null, ScreenshotType? screenshotType = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取截图历史会话ID={SessionId}层ID={LayerId},开始时间={StartTime},结束时间={EndTime},截图类型={ScreenshotType}",
sessionId, layerId, startTime, endTime, screenshotType);
var cacheKey = $"screenshot_history_{sessionId}_{layerId}_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{screenshotType}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取截图历史");
return Result.Success((IReadOnlyList<ScreenshotHistory>)cached);
}
var screenshotHistory = await GenerateScreenshotHistoryAsync(sessionId, layerId, startTime, endTime, screenshotType, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, screenshotHistory);
}
_logger.LogInformation("截图历史获取完成:截图数量={ScreenshotCount}", screenshotHistory.Count);
return Result.Success(screenshotHistory);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取截图历史失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_SCREENSHOT_HISTORY_FAILED", "获取截图历史失败", traceId);
return Result.FailWithTrace<IReadOnlyList<ScreenshotHistory>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<ScreenshotDetail>> GetScreenshotDetailAsync(Guid screenshotId, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取截图详细信息截图ID={ScreenshotId}", screenshotId);
var cacheKey = $"screenshot_detail_{screenshotId}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取截图详细信息");
return Result.Success((ScreenshotDetail)cached);
}
var screenshotDetail = await GenerateScreenshotDetailAsync(screenshotId, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, screenshotDetail);
}
_logger.LogInformation("截图详细信息获取完成截图ID={ScreenshotId},检测数={DetectionCount},缺陷数={DefectCount},标注数={AnnotationCount}",
screenshotId, screenshotDetail.AssociatedDetections.Count, screenshotDetail.AssociatedDefects.Count, screenshotDetail.Annotations.Count);
return Result.Success(screenshotDetail);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取截图详细信息失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_SCREENSHOT_DETAIL_FAILED", "获取截图详细信息失败", traceId);
return Result.FailWithTrace<ScreenshotDetail>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<byte[]>> GetScreenshotContentAsync(Guid screenshotId, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取截图文件内容截图ID={ScreenshotId}", screenshotId);
var content = await GenerateScreenshotContentAsync(screenshotId, cancellationToken);
_logger.LogInformation("截图文件内容获取完成截图ID={ScreenshotId},文件大小={FileSizeBytes}字节",
screenshotId, content.Length);
return Result.Success(content);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取截图文件内容失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_SCREENSHOT_CONTENT_FAILED", "获取截图文件内容失败", traceId);
return Result.FailWithTrace<byte[]>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<EvidenceChain>> GetEvidenceChainAsync(Guid sessionId, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取证据链信息会话ID={SessionId}", sessionId);
var cacheKey = $"evidence_chain_{sessionId}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取证据链信息");
return Result.Success((EvidenceChain)cached);
}
var evidenceChain = await GenerateEvidenceChainAsync(sessionId, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, evidenceChain);
}
_logger.LogInformation("证据链信息获取完成会话ID={SessionId},节点数={NodeCount},完整性={Completeness:F2},可信度={Credibility:F2}",
sessionId, evidenceChain.EvidenceNodes.Count, evidenceChain.CompletenessScore, evidenceChain.CredibilityScore);
return Result.Success(evidenceChain);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取证据链信息失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_EVIDENCE_CHAIN_FAILED", "获取证据链信息失败", traceId);
return Result.FailWithTrace<EvidenceChain>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<LayerEvidenceTraceback>> GetLayerEvidenceTracebackAsync(Guid sessionId, int? layerSequence = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取层级证据回溯会话ID={SessionId},层序号={LayerSequence}", sessionId, layerSequence);
var cacheKey = $"layer_traceback_{sessionId}_{layerSequence}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取层级证据回溯");
return Result.Success((LayerEvidenceTraceback)cached);
}
var layerTraceback = await GenerateLayerEvidenceTracebackAsync(sessionId, layerSequence, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, layerTraceback);
}
_logger.LogInformation("层级证据回溯获取完成会话ID={SessionId},链路数={LinkCount},完整性={Completeness:F2}",
sessionId, layerTraceback.LayerEvidenceLinks.Count, layerTraceback.Summary.TracebackCompletenessScore);
return Result.Success(layerTraceback);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取层级证据回溯失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_LAYER_EVIDENCE_TRACEBACK_FAILED", "获取层级证据回溯失败", traceId);
return Result.FailWithTrace<LayerEvidenceTraceback>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<DefectTraceback>> GetDefectTracebackAsync(Guid sessionId, DefectType? defectType = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取缺陷追溯信息会话ID={SessionId},缺陷类型={DefectType}", sessionId, defectType);
var cacheKey = $"defect_traceback_{sessionId}_{defectType}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取缺陷追溯信息");
return Result.Success((DefectTraceback)cached);
}
var defectTraceback = await GenerateDefectTracebackAsync(sessionId, defectType, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, defectTraceback);
}
_logger.LogInformation("缺陷追溯信息获取完成会话ID={SessionId},链路数={LinkCount},缺陷数={DefectCount}",
sessionId, defectTraceback.DefectTracebackLinks.Count, defectTraceback.DefectStatistics.TotalDefectCount);
return Result.Success(defectTraceback);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取缺陷追溯信息失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_DEFECT_TRACEBACK_FAILED", "获取缺陷追溯信息失败", traceId);
return Result.FailWithTrace<DefectTraceback>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<IReadOnlyList<OperationHistory>>> GetOperationHistoryAsync(Guid? sessionId = null, string? operatorId = null, DateTime? startTime = null, DateTime? endTime = null, OperationType? operationType = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取操作历史记录会话ID={SessionId}操作员ID={OperatorId},开始时间={StartTime},结束时间={EndTime},操作类型={OperationType}",
sessionId, operatorId, startTime, endTime, operationType);
var cacheKey = $"operation_history_{sessionId}_{operatorId}_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{operationType}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取操作历史记录");
return Result.Success((IReadOnlyList<OperationHistory>)cached);
}
var operationHistory = await GenerateOperationHistoryAsync(sessionId, operatorId, startTime, endTime, operationType, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, operationHistory);
}
_logger.LogInformation("操作历史记录获取完成:操作数量={OperationCount}", operationHistory.Count);
return Result.Success(operationHistory);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取操作历史记录失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_OPERATION_HISTORY_FAILED", "获取操作历史记录失败", traceId);
return Result.FailWithTrace<IReadOnlyList<OperationHistory>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<ComprehensiveTracebackReport>> GetComprehensiveTracebackReportAsync(Guid sessionId, OrpaonVision.Core.HistoryTrace.TracebackReportType reportType, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取综合追溯报告会话ID={SessionId},报告类型={ReportType}", sessionId, reportType);
var report = await GenerateComprehensiveTracebackReportAsync(sessionId, reportType, cancellationToken);
_logger.LogInformation("综合追溯报告获取完成报告ID={ReportId},报告类型={ReportType},评分={OverallScore:F2}",
report.ReportId, report.ReportType, 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_TRACEBACK_REPORT_FAILED", "获取综合追溯报告失败", traceId);
return Result.FailWithTrace<ComprehensiveTracebackReport>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<TracebackStatistics>> GetTracebackStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("获取追溯统计数据:开始时间={StartTime},结束时间={EndTime},产品类型={ProductTypeCode}",
startTime, endTime, productTypeCode);
var cacheKey = $"traceback_statistics_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{productTypeCode}";
if (_options.EnableStatisticsCache && _tracebackCache.TryGetValue(cacheKey, out var cached))
{
_logger.LogDebug("从缓存获取追溯统计数据");
return Result.Success((TracebackStatistics)cached);
}
var statistics = await GenerateTracebackStatisticsAsync(startTime, endTime, productTypeCode, cancellationToken);
if (_options.EnableStatisticsCache)
{
_tracebackCache.TryAdd(cacheKey, statistics);
}
_logger.LogInformation("追溯统计数据获取完成:总会话数={TotalSession},完成率={CompletionRate:F2}%,平均时长={AvgDuration:F2}分钟",
statistics.TotalSessionCount, statistics.SessionCompletionRate, statistics.AverageSessionDurationMinutes);
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_TRACEBACK_STATISTICS_FAILED", "获取追溯统计数据失败", traceId);
return Result.FailWithTrace<TracebackStatistics>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<HistorySearchResult>> SearchHistoryAsync(HistorySearchRequest searchRequest, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("搜索历史记录搜索ID={SearchId},关键词={Keyword},搜索类型={SearchType}",
searchRequest.SearchId, searchRequest.SearchKeyword, searchRequest.SearchType);
var searchResult = await GenerateHistorySearchResultAsync(searchRequest, cancellationToken);
_logger.LogInformation("历史记录搜索完成搜索ID={SearchId},总结果数={TotalCount},返回数={ReturnedCount},耗时={ElapsedMs}ms",
searchRequest.SearchId, searchResult.TotalResultCount, searchResult.ReturnedResultCount, searchResult.SearchElapsedMs);
return Result.Success(searchResult);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "搜索历史记录失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "SEARCH_HISTORY_FAILED", "搜索历史记录失败", traceId);
return Result.FailWithTrace<HistorySearchResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
/// <inheritdoc />
public async Task<Result<TracebackExportResult>> ExportTracebackDataAsync(TracebackExportRequest exportRequest, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("导出追溯数据导出ID={ExportId},导出类型={ExportType},格式={ExportFormat}",
exportRequest.ExportId, exportRequest.ExportType, exportRequest.ExportFormat);
var startTime = DateTime.UtcNow;
var result = await GenerateTracebackExportAsync(exportRequest, cancellationToken);
var elapsed = DateTime.UtcNow - startTime;
var exportResult = new TracebackExportResult
{
ExportId = exportRequest.ExportId,
IsSuccess = true,
FilePath = result.FilePath,
FileSizeBytes = result.FileSizeBytes,
RecordCount = result.RecordCount,
ExportElapsedMs = (long)elapsed.TotalMilliseconds,
ExportTimeUtc = DateTime.UtcNow,
ResultDescription = $"导出完成:{result.RecordCount}条记录,文件大小{result.FileSizeBytes}字节",
ExportStatistics = result.ExportStatistics,
ExtendedProperties = new Dictionary<string, object>
{
["export_type"] = exportRequest.ExportType,
["export_format"] = exportRequest.ExportFormat,
["request_user"] = exportRequest.RequestUser
}
};
_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_TRACEBACK_DATA_FAILED", "导出追溯数据失败", traceId);
return Result.FailWithTrace<TracebackExportResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
#region
/// <summary>
/// 生成产品会话历史。
/// </summary>
private async Task<IReadOnlyList<ProductSessionHistory>> GenerateProductSessionHistoryAsync(DateTime startTime, DateTime endTime, string? productTypeCode, SessionStatus? sessionStatus, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var sessionHistory = new List<ProductSessionHistory>();
var current = startTime;
while (current <= endTime)
{
var sessionCount = random.Next(5, 15);
for (int i = 0; i < sessionCount; i++)
{
var status = sessionStatus ?? (SessionStatus)random.Next(0, 6);
var sessionStartTime = current.AddHours(random.Next(0, 24)).AddMinutes(random.Next(0, 60));
var sessionEndTime = status == SessionStatus.Completed ? sessionStartTime.AddMinutes(random.Next(30, 120)) : null;
sessionHistory.Add(new ProductSessionHistory
{
SessionId = Guid.NewGuid(),
ProductSerialNumber = $"SN{random.Next(100000, 999999)}",
ProductTypeCode = productTypeCode ?? $"PT{random.Next(1, 10)}",
SessionStatus = status,
SessionStartTimeUtc = sessionStartTime,
SessionEndTimeUtc = sessionEndTime,
OperatorId = $"OP{random.Next(1, 10):D3}",
OperatorName = $"操作员{random.Next(1, 10)}",
StationId = $"ST{random.Next(1, 5):D3}",
StationName = $"工位{random.Next(1, 5)}",
TotalLayerCount = random.Next(3, 8),
CompletedLayerCount = random.Next(0, 8),
FinalJudgmentResult = status == SessionStatus.Completed ? (FinalJudgmentResult)random.Next(0, 4) : null,
DefectCount = random.Next(0, 10),
AlarmCount = random.Next(0, 5),
ScreenshotCount = random.Next(10, 50),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 20,
["data_source"] = "simulated"
}
});
}
current = current.AddDays(1);
}
return sessionHistory.AsReadOnly();
}
/// <summary>
/// 生成会话详细信息。
/// </summary>
private async Task<ProductSessionDetail> GenerateSessionDetailAsync(Guid sessionId, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var sessionHistory = new ProductSessionHistory
{
SessionId = sessionId,
ProductSerialNumber = $"SN{random.Next(100000, 999999)}",
ProductTypeCode = $"PT{random.Next(1, 10)}",
SessionStatus = SessionStatus.Completed,
SessionStartTimeUtc = DateTime.UtcNow.AddHours(-random.Next(1, 24)),
SessionEndTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 60)),
OperatorId = $"OP{random.Next(1, 10):D3}",
OperatorName = $"操作员{random.Next(1, 10)}",
StationId = $"ST{random.Next(1, 5):D3}",
StationName = $"工位{random.Next(1, 5)}",
TotalLayerCount = random.Next(3, 8),
CompletedLayerCount = random.Next(3, 8),
FinalJudgmentResult = (FinalJudgmentResult)random.Next(0, 4),
DefectCount = random.Next(0, 10),
AlarmCount = random.Next(0, 5),
ScreenshotCount = random.Next(10, 50)
};
var layerHistories = await GenerateLayerProcessingHistoryAsync(sessionId, cancellationToken);
var screenshotHistories = await GenerateScreenshotHistoryAsync(sessionId, null, null, null, null, cancellationToken);
var operationHistories = await GenerateOperationHistoryAsync(sessionId, null, null, null, null, cancellationToken);
var evidenceChain = await GenerateEvidenceChainAsync(sessionId, cancellationToken);
var defectTraceback = await GenerateDefectTracebackAsync(sessionId, null, cancellationToken);
return new ProductSessionDetail
{
SessionHistory = sessionHistory,
LayerHistories = layerHistories,
ScreenshotHistories = screenshotHistories,
OperationHistories = operationHistories,
EvidenceChain = evidenceChain,
DefectTraceback = defectTraceback,
PerformanceMetrics = GenerateSessionPerformanceMetrics(random),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 50,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成层处理历史。
/// </summary>
private async Task<IReadOnlyList<LayerProcessingHistory>> GenerateLayerProcessingHistoryAsync(Guid sessionId, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var layerHistory = new List<LayerProcessingHistory>();
var layerCount = random.Next(3, 8);
for (int i = 1; i <= layerCount; i++)
{
var layerStartTime = DateTime.UtcNow.AddHours(-random.Next(1, 24)).AddMinutes(i * 10);
var layerEndTime = layerStartTime.AddSeconds(random.Next(30, 120));
layerHistory.Add(new LayerProcessingHistory
{
LayerId = Guid.NewGuid(),
SessionId = sessionId,
LayerSequence = i,
LayerName = $"第{i}层",
LayerType = $"LayerType{random.Next(1, 5)}",
LayerStatus = LayerStatus.Completed,
LayerStartTimeUtc = layerStartTime,
LayerEndTimeUtc = layerEndTime,
DetectedPartCount = random.Next(5, 20),
QualifiedPartCount = random.Next(4, 20),
DefectivePartCount = random.Next(0, 5),
LayerJudgmentResult = (LayerJudgmentResult)random.Next(0, 4),
Defects = GenerateLayerDefects(random, i),
ScreenshotCount = random.Next(3, 10),
AlarmCount = random.Next(0, 3),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 15,
["data_source"] = "simulated"
}
});
}
return layerHistory.AsReadOnly();
}
/// <summary>
/// 生成层详细信息。
/// </summary>
private async Task<LayerProcessingDetail> GenerateLayerDetailAsync(Guid layerId, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var layerHistory = new LayerProcessingHistory
{
LayerId = layerId,
SessionId = Guid.NewGuid(),
LayerSequence = random.Next(1, 8),
LayerName = $"第{random.Next(1, 8)}层",
LayerType = $"LayerType{random.Next(1, 5)}",
LayerStatus = LayerStatus.Completed,
LayerStartTimeUtc = DateTime.UtcNow.AddHours(-random.Next(1, 24)),
LayerEndTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 60)),
DetectedPartCount = random.Next(5, 20),
QualifiedPartCount = random.Next(4, 20),
DefectivePartCount = random.Next(0, 5),
LayerJudgmentResult = (LayerJudgmentResult)random.Next(0, 4),
Defects = GenerateLayerDefects(random, random.Next(1, 8)),
ScreenshotCount = random.Next(3, 10),
AlarmCount = random.Next(0, 3)
};
var screenshotHistories = await GenerateScreenshotHistoryAsync(layerHistory.SessionId, layerId, null, null, null, cancellationToken);
var operationHistories = await GenerateOperationHistoryAsync(layerHistory.SessionId, null, null, null, null, cancellationToken);
var partDetectionResults = GeneratePartDetectionResults(random, layerId);
var ruleExecutionResults = GenerateRuleExecutionResults(random, layerId);
return new LayerProcessingDetail
{
LayerHistory = layerHistory,
ScreenshotHistories = screenshotHistories,
OperationHistories = operationHistories,
PartDetectionResults = partDetectionResults,
RuleExecutionResults = ruleExecutionResults,
PerformanceMetrics = GenerateLayerPerformanceMetrics(random),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 25,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成截图历史。
/// </summary>
private async Task<IReadOnlyList<ScreenshotHistory>> GenerateScreenshotHistoryAsync(Guid? sessionId, Guid? layerId, DateTime? startTime, DateTime? endTime, ScreenshotType? screenshotType, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var screenshotHistory = new List<ScreenshotHistory>();
var screenshotCount = random.Next(5, 20);
for (int i = 0; i < screenshotCount; i++)
{
var screenshotTime = startTime?.AddMinutes(random.Next(0, (int)(endTime - startTime).Value.TotalMinutes)) ?? DateTime.UtcNow.AddMinutes(-random.Next(10, 120));
var type = screenshotType ?? (ScreenshotType)random.Next(0, 8);
screenshotHistory.Add(new ScreenshotHistory
{
ScreenshotId = Guid.NewGuid(),
SessionId = sessionId ?? Guid.NewGuid(),
LayerId = layerId,
ScreenshotType = type,
ScreenshotTimeUtc = screenshotTime,
FilePath = $"/screenshots/{Guid.NewGuid():N}.jpg",
FileSizeBytes = random.Next(100000, 5000000),
FileFormat = "JPEG",
ImageWidth = random.Next(1920, 4096),
ImageHeight = random.Next(1080, 2160),
ImageDescription = $"{type}截图",
AssociatedDetectionCount = random.Next(0, 20),
AssociatedDefectCount = random.Next(0, 5),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 10,
["data_source"] = "simulated"
}
});
}
return screenshotHistory.AsReadOnly();
}
/// <summary>
/// 生成截图详细信息。
/// </summary>
private async Task<ScreenshotDetail> GenerateScreenshotDetailAsync(Guid screenshotId, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var screenshotHistory = new ScreenshotHistory
{
ScreenshotId = screenshotId,
SessionId = Guid.NewGuid(),
LayerId = Guid.NewGuid(),
ScreenshotType = (ScreenshotType)random.Next(0, 8),
ScreenshotTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 120)),
FilePath = $"/screenshots/{screenshotId:N}.jpg",
FileSizeBytes = random.Next(100000, 5000000),
FileFormat = "JPEG",
ImageWidth = random.Next(1920, 4096),
ImageHeight = random.Next(1080, 2160),
ImageDescription = "检测截图",
AssociatedDetectionCount = random.Next(0, 20),
AssociatedDefectCount = random.Next(0, 5)
};
var imageMetadata = GenerateImageMetadata(random);
var associatedDetections = GeneratePartDetectionResults(random, Guid.NewGuid());
var associatedDefects = GenerateLayerDefects(random, random.Next(1, 8));
var annotations = GenerateImageAnnotations(random);
return new ScreenshotDetail
{
ScreenshotHistory = screenshotHistory,
ImageMetadata = imageMetadata,
AssociatedDetections = associatedDetections,
AssociatedDefects = associatedDefects,
Annotations = annotations,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 20,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成截图文件内容。
/// </summary>
private async Task<byte[]> GenerateScreenshotContentAsync(Guid screenshotId, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
// 简化处理生成模拟的JPEG文件头
var random = new Random();
var fileSize = random.Next(100000, 5000000);
var content = new byte[fileSize];
// JPEG文件头
var jpegHeader = new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 };
Array.Copy(jpegHeader, content, jpegHeader.Length);
// 填充随机数据
for (int i = jpegHeader.Length; i < fileSize - 2; i++)
{
content[i] = (byte)random.Next(0, 256);
}
// JPEG文件尾
content[fileSize - 2] = 0xFF;
content[fileSize - 1] = 0xD9;
return content;
}
/// <summary>
/// 生成证据链。
/// </summary>
private async Task<EvidenceChain> GenerateEvidenceChainAsync(Guid sessionId, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var evidenceNodes = new List<EvidenceNode>();
var nodeCount = random.Next(10, 30);
for (int i = 0; i < nodeCount; i++)
{
evidenceNodes.Add(new EvidenceNode
{
NodeId = Guid.NewGuid(),
NodeType = (EvidenceNodeType)random.Next(0, 10),
NodeWeight = random.NextDouble(),
NodeTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 120)),
NodeDescription = $"证据节点{i + 1}",
AssociatedDataId = Guid.NewGuid(),
AssociatedDataType = $"DataType{random.Next(1, 5)}",
ChildNodes = new List<EvidenceNode>(),
ExtendedProperties = new Dictionary<string, object>
{
["node_index"] = i,
["generation_time_ms"] = 5
}
});
}
return new EvidenceChain
{
EvidenceChainId = Guid.NewGuid(),
SessionId = sessionId,
CreatedAtUtc = DateTime.UtcNow,
CompletenessScore = 0.8 + random.NextDouble() * 0.2,
CredibilityScore = 0.85 + random.NextDouble() * 0.15,
EvidenceNodes = evidenceNodes.AsReadOnly(),
Summary = GenerateEvidenceChainSummary(random, evidenceNodes.Count),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 30,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成层级证据回溯。
/// </summary>
private async Task<LayerEvidenceTraceback> GenerateLayerEvidenceTracebackAsync(Guid sessionId, int? layerSequence, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var layerEvidenceLinks = new List<LayerEvidenceLink>();
var linkCount = random.Next(3, 8);
for (int i = 1; i <= linkCount; i++)
{
if (layerSequence.HasValue && i != layerSequence.Value)
continue;
var keyScreenshots = await GenerateScreenshotHistoryAsync(sessionId, Guid.NewGuid(), null, null, null, cancellationToken);
var keyDefects = GenerateLayerDefects(random, i);
var keyOperations = await GenerateOperationHistoryAsync(sessionId, null, null, null, null, cancellationToken);
layerEvidenceLinks.Add(new LayerEvidenceLink
{
LinkId = Guid.NewGuid(),
LayerSequence = i,
LayerName = $"第{i}层",
LayerProcessingTimeUtc = DateTime.UtcNow.AddHours(-random.Next(1, 24)).AddMinutes(i * 10),
KeyScreenshots = keyScreenshots.Take(random.Next(1, 4)).ToList(),
KeyDefects = keyDefects,
KeyOperations = keyOperations.Take(random.Next(1, 3)).ToList(),
LinkCompleteness = 0.7 + random.NextDouble() * 0.3,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 15
}
});
}
return new LayerEvidenceTraceback
{
SessionId = sessionId,
TracebackTimeUtc = DateTime.UtcNow,
LayerEvidenceLinks = layerEvidenceLinks.AsReadOnly(),
Summary = GenerateLayerTracebackSummary(random, layerEvidenceLinks.Count),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 40,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成缺陷追溯。
/// </summary>
private async Task<DefectTraceback> GenerateDefectTracebackAsync(Guid sessionId, DefectType? defectType, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var defectTracebackLinks = new List<DefectTracebackLink>();
var linkCount = random.Next(0, 10);
for (int i = 0; i < linkCount; i++)
{
var type = defectType ?? (DefectType)random.Next(0, 8);
var associatedScreenshot = (await GenerateScreenshotHistoryAsync(sessionId, null, null, null, null, cancellationToken)).FirstOrDefault();
var associatedOperations = (await GenerateOperationHistoryAsync(sessionId, null, null, null, null, cancellationToken)).Take(random.Next(1, 3)).ToList();
defectTracebackLinks.Add(new DefectTracebackLink
{
LinkId = Guid.NewGuid(),
DefectId = Guid.NewGuid(),
DefectType = type,
DefectSeverity = (DefectSeverity)random.Next(0, 4),
DiscoveryTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 120)),
LayerSequence = random.Next(1, 8),
LayerName = $"第{random.Next(1, 8)}层",
RootCauseAnalysis = $"根本原因分析{i + 1}",
AssociatedScreenshot = associatedScreenshot,
AssociatedOperations = associatedOperations,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 12
}
});
}
return new DefectTraceback
{
SessionId = sessionId,
TracebackTimeUtc = DateTime.UtcNow,
DefectTracebackLinks = defectTracebackLinks.AsReadOnly(),
DefectStatistics = GenerateDefectStatisticsAnalysis(random, defectTracebackLinks.Count),
PatternAnalysis = GenerateDefectPatternAnalysis(random),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 35,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成操作历史。
/// </summary>
private async Task<IReadOnlyList<OperationHistory>> GenerateOperationHistoryAsync(Guid? sessionId, string? operatorId, DateTime? startTime, DateTime? endTime, OperationType? operationType, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var operationHistory = new List<OperationHistory>();
var operationCount = random.Next(5, 20);
for (int i = 0; i < operationCount; i++)
{
var operationTime = startTime?.AddMinutes(random.Next(0, (int)(endTime - startTime).Value.TotalMinutes)) ?? DateTime.UtcNow.AddMinutes(-random.Next(10, 120));
var type = operationType ?? (OperationType)random.Next(0, 14);
operationHistory.Add(new OperationHistory
{
OperationId = Guid.NewGuid(),
SessionId = sessionId ?? Guid.NewGuid(),
LayerId = Guid.NewGuid(),
OperationType = type,
OperationTimeUtc = operationTime,
OperatorId = operatorId ?? $"OP{random.Next(1, 10):D3}",
OperatorName = $"操作员{random.Next(1, 10)}",
OperationDescription = $"{type}操作{i + 1}",
OperationResult = (OperationResult)random.Next(0, 6),
OperationParameters = new Dictionary<string, object>
{
["param1"] = $"value{random.Next(1, 100)}",
["param2"] = random.NextDouble()
},
OperationDurationMs = random.Next(100, 5000),
AssociatedScreenshotId = Guid.NewGuid(),
ErrorMessage = random.NextDouble() > 0.8 ? $"错误信息{random.Next(1, 10)}" : null,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 8,
["data_source"] = "simulated"
}
});
}
return operationHistory.AsReadOnly();
}
/// <summary>
/// 生成综合追溯报告。
/// </summary>
private async Task<ComprehensiveTracebackReport> GenerateComprehensiveTracebackReportAsync(Guid sessionId, OrpaonVision.Core.HistoryTrace.TracebackReportType reportType, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var sessionDetail = await GenerateSessionDetailAsync(sessionId, cancellationToken);
return new ComprehensiveTracebackReport
{
ReportId = Guid.NewGuid(),
ReportType = reportType,
SessionId = sessionId,
GeneratedAtUtc = DateTime.UtcNow,
ReportTitle = $"{reportType}追溯报告",
ExecutiveSummary = GenerateReportExecutiveSummary(random),
SessionOverview = sessionDetail,
LayerAnalyses = GenerateLayerAnalysisReports(random, sessionDetail.LayerHistories.Count),
DefectAnalysis = GenerateDefectAnalysisReport(random),
PerformanceAnalysis = GeneratePerformanceAnalysisReport(random),
EvidenceChainAnalysis = GenerateEvidenceChainAnalysis(random),
ImprovementSuggestions = GenerateTracebackImprovementSuggestions(random),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 100,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成追溯统计数据。
/// </summary>
private async Task<TracebackStatistics> GenerateTracebackStatisticsAsync(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 totalSessionCount = random.Next(50, 200);
var completedSessionCount = (int)(totalSessionCount * (0.8 + random.NextDouble() * 0.15));
return new TracebackStatistics
{
TimeRange = timeRange,
ProductTypeCode = productTypeCode ?? "default",
TotalSessionCount = totalSessionCount,
CompletedSessionCount = completedSessionCount,
TotalLayerCount = totalSessionCount * random.Next(3, 8),
TotalScreenshotCount = totalSessionCount * random.Next(10, 50),
TotalDefectCount = random.Next(0, totalSessionCount * 5),
TotalOperationCount = totalSessionCount * random.Next(20, 100),
AverageSessionDurationMinutes = 45 + random.NextDouble() * 30,
AverageLayerProcessingTimeSeconds = 30 + random.NextDouble() * 20,
ByDate = GenerateDailyTracebackStatistics(startTime, endTime, random),
ByProductType = GenerateProductTypeTracebackStatistics(random),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 60,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成历史搜索结果。
/// </summary>
private async Task<HistorySearchResult> GenerateHistorySearchResultAsync(HistorySearchRequest searchRequest, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var startTime = DateTime.UtcNow;
var sessionResults = await GenerateProductSessionHistoryAsync(
searchRequest.TimeRange?.StartTimeUtc ?? DateTime.UtcNow.AddDays(-7),
searchRequest.TimeRange?.EndTimeUtc ?? DateTime.UtcNow,
searchRequest.ProductTypeCode,
null,
cancellationToken);
var layerResults = sessionResults.SelectMany(s => Enumerable.Range(1, random.Next(3, 8))
.Select(i => new LayerProcessingHistory
{
LayerId = Guid.NewGuid(),
SessionId = s.SessionId,
LayerSequence = i,
LayerName = $"第{i}层",
LayerType = $"LayerType{random.Next(1, 5)}",
LayerStatus = LayerStatus.Completed,
LayerStartTimeUtc = s.SessionStartTimeUtc.AddMinutes(i * 10),
LayerEndTimeUtc = s.SessionStartTimeUtc.AddMinutes(i * 10 + random.Next(30, 120)),
DetectedPartCount = random.Next(5, 20),
QualifiedPartCount = random.Next(4, 20),
DefectivePartCount = random.Next(0, 5),
LayerJudgmentResult = (LayerJudgmentResult)random.Next(0, 4),
Defects = GenerateLayerDefects(random, i),
ScreenshotCount = random.Next(3, 10),
AlarmCount = random.Next(0, 3)
})).ToList();
var screenshotResults = sessionResults.SelectMany(s => Enumerable.Range(0, random.Next(5, 15))
.Select(i => new ScreenshotHistory
{
ScreenshotId = Guid.NewGuid(),
SessionId = s.SessionId,
ScreenshotType = (ScreenshotType)random.Next(0, 8),
ScreenshotTimeUtc = s.SessionStartTimeUtc.AddMinutes(random.Next(0, 120)),
FilePath = $"/screenshots/{Guid.NewGuid():N}.jpg",
FileSizeBytes = random.Next(100000, 5000000),
FileFormat = "JPEG",
ImageWidth = random.Next(1920, 4096),
ImageHeight = random.Next(1080, 2160),
ImageDescription = "检测截图",
AssociatedDetectionCount = random.Next(0, 20),
AssociatedDefectCount = random.Next(0, 5)
})).ToList();
var defectResults = layerResults.SelectMany(l => l.Defects).ToList();
var operationResults = sessionResults.SelectMany(s => Enumerable.Range(0, random.Next(10, 30))
.Select(i => new OperationHistory
{
OperationId = Guid.NewGuid(),
SessionId = s.SessionId,
OperationType = (OperationType)random.Next(0, 14),
OperationTimeUtc = s.SessionStartTimeUtc.AddMinutes(random.Next(0, 120)),
OperatorId = $"OP{random.Next(1, 10):D3}",
OperatorName = $"操作员{random.Next(1, 10)}",
OperationDescription = "操作记录",
OperationResult = (OperationResult)random.Next(0, 6),
OperationDurationMs = random.Next(100, 5000)
})).ToList();
var elapsed = DateTime.UtcNow - startTime;
return new HistorySearchResult
{
SearchId = searchRequest.SearchId,
SearchTimeUtc = searchRequest.SearchTimeUtc,
TotalResultCount = sessionResults.Count + layerResults.Count + screenshotResults.Count + defectResults.Count + operationResults.Count,
ReturnedResultCount = Math.Min(searchRequest.MaxResultCount, sessionResults.Count + layerResults.Count + screenshotResults.Count + defectResults.Count + operationResults.Count),
SearchElapsedMs = (long)elapsed.TotalMilliseconds,
SessionResults = sessionResults.Take(searchRequest.MaxResultCount / 5).ToList(),
LayerResults = layerResults.Take(searchRequest.MaxResultCount / 5).ToList(),
ScreenshotResults = screenshotResults.Take(searchRequest.MaxResultCount / 5).ToList(),
DefectResults = defectResults.Take(searchRequest.MaxResultCount / 5).ToList(),
OperationResults = operationResults.Take(searchRequest.MaxResultCount / 5).ToList(),
SearchSuggestions = new[] { "建议1", "建议2", "建议3" },
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 80,
["data_source"] = "simulated"
}
};
}
/// <summary>
/// 生成追溯数据导出。
/// </summary>
private async Task<(string FilePath, long FileSizeBytes, int RecordCount, ExportStatistics ExportStatistics)> GenerateTracebackExportAsync(TracebackExportRequest exportRequest, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var random = new Random();
var fileName = $"traceback_export_{exportRequest.ExportId:N}.{exportRequest.ExportFormat.ToString().ToLower()}";
var filePath = Path.Combine(Path.GetTempPath(), fileName);
// 简化处理:生成模拟文件
var recordCount = random.Next(100, 1000);
var fileContent = GenerateExportFileContent(exportRequest, recordCount);
await File.WriteAllTextAsync(filePath, fileContent, cancellationToken);
var fileInfo = new FileInfo(filePath);
var exportStatistics = new ExportStatistics
{
SessionCount = exportRequest.SessionIds.Count > 0 ? exportRequest.SessionIds.Count : random.Next(10, 50),
LayerCount = random.Next(30, 200),
ScreenshotCount = random.Next(100, 500),
DefectCount = random.Next(0, 50),
OperationCount = random.Next(200, 1000),
EvidenceChainCount = exportRequest.IncludeEvidenceChain ? random.Next(10, 50) : 0
};
return (filePath, fileInfo.Length, recordCount, exportStatistics);
}
#endregion
#region
/// <summary>
/// 生成层缺陷列表。
/// </summary>
private IReadOnlyList<LayerDefect> GenerateLayerDefects(Random random, int layerSequence)
{
var defects = new List<LayerDefect>();
var defectCount = random.Next(0, 5);
for (int i = 0; i < defectCount; i++)
{
defects.Add(new LayerDefect
{
DefectId = Guid.NewGuid(),
DefectType = (DefectType)random.Next(0, 8),
DefectSeverity = (DefectSeverity)random.Next(0, 4),
DefectDescription = $"缺陷{i + 1}",
PartName = $"部件{random.Next(1, 20)}",
DefectPositionX = random.NextDouble() * 1000,
DefectPositionY = random.NextDouble() * 1000,
DefectConfidence = 0.7 + random.NextDouble() * 0.3,
DetectionTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 60)),
AssociatedScreenshotId = Guid.NewGuid(),
ExtendedProperties = new Dictionary<string, object>
{
["layer_sequence"] = layerSequence
}
});
}
return defects.AsReadOnly();
}
/// <summary>
/// 生成部件检测结果。
/// </summary>
private IReadOnlyList<PartDetectionResult> GeneratePartDetectionResults(Random random, Guid layerId)
{
var results = new List<PartDetectionResult>();
var detectionCount = random.Next(5, 20);
for (int i = 0; i < detectionCount; i++)
{
results.Add(new PartDetectionResult
{
DetectionId = Guid.NewGuid(),
PartName = $"部件{i + 1}",
PartType = $"PartType{random.Next(1, 10)}",
DetectionStatus = (PartDetectionStatus)random.Next(0, 6),
Confidence = 0.6 + random.NextDouble() * 0.4,
BoundingBox = new BoundingBox
{
X = random.NextDouble() * 1000,
Y = random.NextDouble() * 1000,
Width = 50 + random.NextDouble() * 100,
Height = 50 + random.NextDouble() * 100
},
DetectionTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 60)),
AssociatedScreenshotId = Guid.NewGuid(),
ExtendedProperties = new Dictionary<string, object>
{
["layer_id"] = layerId
}
});
}
return results.AsReadOnly();
}
/// <summary>
/// 生成规则执行结果。
/// </summary>
private IReadOnlyList<RuleExecutionResult> GenerateRuleExecutionResults(Random random, Guid layerId)
{
var results = new List<RuleExecutionResult>();
var ruleCount = random.Next(5, 15);
for (int i = 0; i < ruleCount; i++)
{
results.Add(new RuleExecutionResult
{
ExecutionId = Guid.NewGuid(),
RuleName = $"规则{i + 1}",
RuleType = $"RuleType{random.Next(1, 5)}",
ExecutionStatus = (RuleExecutionStatus)random.Next(0, 5),
ExecutionResult = random.NextDouble() > 0.2,
ExecutionTimeMs = random.Next(10, 1000),
ExecutionTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 60)),
ErrorMessage = random.NextDouble() > 0.8 ? $"规则执行错误{i + 1}" : null,
ExecutionDetails = $"规则{i + 1}执行详情",
ExtendedProperties = new Dictionary<string, object>
{
["layer_id"] = layerId
}
});
}
return results.AsReadOnly();
}
/// <summary>
/// 生成图像元数据。
/// </summary>
private ImageMetadata GenerateImageMetadata(Random random)
{
return new ImageMetadata
{
CaptureTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 120)),
CameraId = $"CAM{random.Next(1, 5):D3}",
CameraName = $"相机{random.Next(1, 5)}",
ExposureTimeMs = 0.001 + random.NextDouble() * 0.1,
ISO = random.Next(100, 3200),
Aperture = 1.4 + random.NextDouble() * 8,
FocalLength = 24 + random.NextDouble() * 100,
FlashUsed = random.NextDouble() > 0.7,
ImageQualityScore = 0.7 + random.NextDouble() * 0.3,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 5
}
};
}
/// <summary>
/// 生成图像标注。
/// </summary>
private IReadOnlyList<ImageAnnotation> GenerateImageAnnotations(Random random)
{
var annotations = new List<ImageAnnotation>();
var annotationCount = random.Next(0, 10);
for (int i = 0; i < annotationCount; i++)
{
annotations.Add(new ImageAnnotation
{
AnnotationId = Guid.NewGuid(),
AnnotationType = (AnnotationType)random.Next(0, 8),
AnnotationContent = $"标注{i + 1}",
AnnotationPosition = new BoundingBox
{
X = random.NextDouble() * 1000,
Y = random.NextDouble() * 1000,
Width = 50 + random.NextDouble() * 100,
Height = 50 + random.NextDouble() * 100
},
AnnotationColor = $"#{random.Next(0x1000000):X6}",
AnnotationTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 60)),
Annotator = $"标注员{random.Next(1, 5)}",
ExtendedProperties = new Dictionary<string, object>
{
["annotation_index"] = i
}
});
}
return annotations.AsReadOnly();
}
/// <summary>
/// 生成证据链摘要。
/// </summary>
private EvidenceChainSummary GenerateEvidenceChainSummary(Random random, int nodeCount)
{
return new EvidenceChainSummary
{
TotalNodeCount = nodeCount,
CriticalNodeCount = (int)(nodeCount * (0.2 + random.NextDouble() * 0.2)),
ScreenshotNodeCount = (int)(nodeCount * (0.3 + random.NextDouble() * 0.2)),
DefectNodeCount = (int)(nodeCount * (0.1 + random.NextDouble() * 0.1)),
AlarmNodeCount = (int)(nodeCount * (0.05 + random.NextDouble() * 0.05)),
TimeSpanMinutes = 60 + random.NextDouble() * 60,
QualityRating = (EvidenceChainQuality)random.Next(0, 5),
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 10
}
};
}
/// <summary>
/// 生成层级回溯摘要。
/// </summary>
private LayerTracebackSummary GenerateLayerTracebackSummary(Random random, int linkCount)
{
return new LayerTracebackSummary
{
TotalLayerCount = linkCount,
CompleteLinkCount = (int)(linkCount * (0.7 + random.NextDouble() * 0.2)),
PartialLinkCount = (int)(linkCount * (0.1 + random.NextDouble() * 0.1)),
MissingLinkCount = linkCount - (int)(linkCount * (0.7 + random.NextDouble() * 0.2)) - (int)(linkCount * (0.1 + random.NextDouble() * 0.1)),
TotalScreenshotCount = linkCount * random.Next(3, 10),
TotalDefectCount = random.Next(0, linkCount * 2),
TracebackCompletenessScore = 0.7 + random.NextDouble() * 0.25,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 8
}
};
}
/// <summary>
/// 生成缺陷统计分析。
/// </summary>
private DefectStatisticsAnalysis GenerateDefectStatisticsAnalysis(Random random, int defectCount)
{
var defectsByType = new Dictionary<DefectType, int>();
var defectsBySeverity = new Dictionary<DefectSeverity, int>();
var defectsByLayer = new Dictionary<int, int>();
for (int i = 0; i < defectCount; i++)
{
var type = (DefectType)random.Next(0, 8);
var severity = (DefectSeverity)random.Next(0, 4);
var layer = random.Next(1, 8);
defectsByType[type] = defectsByType.GetValueOrDefault(type, 0) + 1;
defectsBySeverity[severity] = defectsBySeverity.GetValueOrDefault(severity, 0) + 1;
defectsByLayer[layer] = defectsByLayer.GetValueOrDefault(layer, 0) + 1;
}
return new DefectStatisticsAnalysis
{
TotalDefectCount = defectCount,
DefectsByType = defectsByType,
DefectsBySeverity = defectsBySeverity,
DefectsByLayer = defectsByLayer,
DefectDensity = defectCount > 0 ? random.NextDouble() * 10 : 0.0,
DefectRate = defectCount > 0 ? random.NextDouble() * 5 : 0.0,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 12
}
};
}
/// <summary>
/// 生成缺陷模式分析。
/// </summary>
private DefectPatternAnalysis GenerateDefectPatternAnalysis(Random random)
{
var recurringPatterns = new List<DefectPattern>();
var anomalousPatterns = new List<DefectPattern>();
for (int i = 0; i < random.Next(0, 3); i++)
{
recurringPatterns.Add(new DefectPattern
{
PatternId = Guid.NewGuid(),
PatternName = $"重复模式{i + 1}",
PatternDescription = $"重复出现的缺陷模式{i + 1}",
OccurrenceFrequency = random.NextDouble(),
PatternConfidence = 0.6 + random.NextDouble() * 0.4,
RelatedDefectIds = Enumerable.Range(0, random.Next(1, 5)).Select(_ => Guid.NewGuid()).ToList(),
ExtendedProperties = new Dictionary<string, object>
{
["pattern_type"] = "recurring"
}
});
}
for (int i = 0; i < random.Next(0, 2); i++)
{
anomalousPatterns.Add(new DefectPattern
{
PatternId = Guid.NewGuid(),
PatternName = $"异常模式{i + 1}",
PatternDescription = $"异常出现的缺陷模式{i + 1}",
OccurrenceFrequency = random.NextDouble() * 0.1,
PatternConfidence = 0.5 + random.NextDouble() * 0.3,
RelatedDefectIds = Enumerable.Range(0, random.Next(1, 3)).Select(_ => Guid.NewGuid()).ToList(),
ExtendedProperties = new Dictionary<string, object>
{
["pattern_type"] = "anomalous"
}
});
}
return new DefectPatternAnalysis
{
RecurringPatterns = recurringPatterns.AsReadOnly(),
AnomalousPatterns = anomalousPatterns.AsReadOnly(),
TrendAnalysis = new DefectTrendAnalysis
{
TrendDirection = (TrendDirection)random.Next(0, 4),
ChangeRate = random.NextDouble() * 10 - 5,
TrendDescription = "缺陷趋势分析",
PredictedNextDefectCount = random.Next(0, 10),
Confidence = 0.6 + random.NextDouble() * 0.3,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 8
}
},
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 15
}
};
}
/// <summary>
/// 生成会话性能指标。
/// </summary>
private SessionPerformanceMetrics GenerateSessionPerformanceMetrics(Random random)
{
return new SessionPerformanceMetrics
{
TotalProcessingTimeMinutes = 30 + random.NextDouble() * 60,
AverageLayerProcessingTimeSeconds = 30 + random.NextDouble() * 30,
SystemAvailability = 0.95 + random.NextDouble() * 0.04,
ProcessingEfficiency = 0.8 + random.NextDouble() * 0.2,
ResourceUtilization = 0.7 + random.NextDouble() * 0.25,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 6
}
};
}
/// <summary>
/// 生成层性能指标。
/// </summary>
private LayerPerformanceMetrics GenerateLayerPerformanceMetrics(Random random)
{
return new LayerPerformanceMetrics
{
LayerProcessingTimeSeconds = 30 + random.NextDouble() * 30,
DetectionProcessingTimeMs = random.Next(100, 2000),
RuleExecutionTimeMs = random.Next(50, 1000),
ScreenshotProcessingTimeMs = random.Next(200, 3000),
MemoryUsageMb = 50 + random.NextDouble() * 100,
CpuUsagePercentage = 20 + random.NextDouble() * 60,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 5
}
};
}
/// <summary>
/// 生成报告执行摘要。
/// </summary>
private ReportExecutiveSummary GenerateReportExecutiveSummary(Random random)
{
return new ReportExecutiveSummary
{
OverallScore = 70 + random.NextDouble() * 25,
KeyFindings = new[] { "关键发现1", "关键发现2", "关键发现3" },
MajorIssues = new[] { "主要问题1", "主要问题2" },
ImprovementOpportunities = new[] { "改进机会1", "改进机会2", "改进机会3" },
SummaryDescription = "综合追溯报告执行摘要",
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 10
}
};
}
/// <summary>
/// 生成层级分析报告。
/// </summary>
private IReadOnlyList<LayerAnalysisReport> GenerateLayerAnalysisReports(Random random, int layerCount)
{
var reports = new List<LayerAnalysisReport>();
for (int i = 1; i <= layerCount; i++)
{
reports.Add(new LayerAnalysisReport
{
LayerSequence = i,
LayerName = $"第{i}层",
LayerPerformanceScore = 70 + random.NextDouble() * 25,
LayerQualityScore = 75 + random.NextDouble() * 20,
LayerEfficiencyScore = 65 + random.NextDouble() * 30,
KeyMetrics = new Dictionary<string, double>
{
["处理时间"] = 30 + random.NextDouble() * 30,
["检测数量"] = random.Next(5, 20),
["缺陷数量"] = random.Next(0, 5)
},
IdentifiedIssues = new[] { $"问题{i}.1", $"问题{i}.2" },
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 8
}
});
}
return reports.AsReadOnly();
}
/// <summary>
/// 生成缺陷分析报告。
/// </summary>
private DefectAnalysisReport GenerateDefectAnalysisReport(Random random)
{
var defectCount = random.Next(0, 20);
var defectsByType = new Dictionary<DefectType, int>();
var defectsBySeverity = new Dictionary<DefectSeverity, int>();
for (int i = 0; i < defectCount; i++)
{
var type = (DefectType)random.Next(0, 8);
var severity = (DefectSeverity)random.Next(0, 4);
defectsByType[type] = defectsByType.GetValueOrDefault(type, 0) + 1;
defectsBySeverity[severity] = defectsBySeverity.GetValueOrDefault(severity, 0) + 1;
}
return new DefectAnalysisReport
{
TotalDefectCount = defectCount,
DefectRate = defectCount > 0 ? random.NextDouble() * 5 : 0.0,
DefectDistribution = defectsByType,
SeverityDistribution = defectsBySeverity,
HighFrequencyDefects = new List<DefectPattern>(),
DefectTrend = new DefectTrendAnalysis
{
TrendDirection = (TrendDirection)random.Next(0, 4),
ChangeRate = random.NextDouble() * 10 - 5,
TrendDescription = "缺陷趋势分析",
PredictedNextDefectCount = random.Next(0, 10),
Confidence = 0.6 + random.NextDouble() * 0.3,
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 8
}
},
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 12
}
};
}
/// <summary>
/// 生成性能分析报告。
/// </summary>
private PerformanceAnalysisReport GeneratePerformanceAnalysisReport(Random random)
{
return new PerformanceAnalysisReport
{
TotalProcessingTimeMinutes = 45 + random.NextDouble() * 30,
AverageLayerProcessingTimeSeconds = 30 + random.NextDouble() * 30,
SystemAvailability = 0.95 + random.NextDouble() * 0.04,
ProcessingEfficiency = 0.8 + random.NextDouble() * 0.2,
ResourceUtilization = 0.7 + random.NextDouble() * 0.25,
PerformanceBottlenecks = new[] { "瓶颈1", "瓶颈2" },
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 10
}
};
}
/// <summary>
/// 生成证据链分析。
/// </summary>
private EvidenceChainAnalysis GenerateEvidenceChainAnalysis(Random random)
{
return new EvidenceChainAnalysis
{
EvidenceChainCompleteness = 0.8 + random.NextDouble() * 0.2,
EvidenceChainCredibility = 0.85 + random.NextDouble() * 0.15,
CriticalEvidenceNodes = new List<EvidenceNode>(),
EvidenceGaps = new List<EvidenceGap>
{
new EvidenceGap
{
GapId = Guid.NewGuid(),
GapType = (EvidenceGapType)random.Next(0, 7),
GapDescription = "证据缺口",
GapSeverity = (GapSeverity)random.Next(0, 4),
RecommendedAction = "建议措施",
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 5
}
}
},
ExtendedProperties = new Dictionary<string, object>
{
["generation_time_ms"] = 15
}
};
}
/// <summary>
/// 生成追溯改进建议。
/// </summary>
private IReadOnlyList<TracebackImprovementSuggestion> GenerateTracebackImprovementSuggestions(Random random)
{
var suggestions = new List<TracebackImprovementSuggestion>();
for (int i = 0; i < random.Next(3, 8); i++)
{
suggestions.Add(new TracebackImprovementSuggestion
{
SuggestionId = Guid.NewGuid(),
SuggestionCategory = (SuggestionCategory)random.Next(0, 8),
SuggestionTitle = $"改进建议{i + 1}",
SuggestionDescription = $"改进建议描述{i + 1}",
Priority = random.Next(1, 5),
ExpectedImpact = $"预期效果{i + 1}",
ImplementationDifficulty = (ImplementationDifficulty)random.Next(0, 4),
RelatedEvidenceIds = Enumerable.Range(0, random.Next(1, 3)).Select(_ => Guid.NewGuid()).ToList(),
ExtendedProperties = new Dictionary<string, object>
{
["suggestion_index"] = i
}
});
}
return suggestions.AsReadOnly();
}
/// <summary>
/// 生成按日期分组的追溯统计。
/// </summary>
private Dictionary<DateTime, DailyTracebackStatistics> GenerateDailyTracebackStatistics(DateTime startTime, DateTime endTime, Random random)
{
var dailyStats = new Dictionary<DateTime, DailyTracebackStatistics>();
var current = startTime.Date;
while (current <= endTime.Date)
{
dailyStats[current] = new DailyTracebackStatistics
{
Date = current,
SessionCount = random.Next(5, 20),
CompletedSessionCount = random.Next(4, 20),
LayerCount = random.Next(15, 100),
ScreenshotCount = random.Next(50, 300),
DefectCount = random.Next(0, 20)
};
current = current.AddDays(1);
}
return dailyStats;
}
/// <summary>
/// 生成按产品类型分组的追溯统计。
/// </summary>
private Dictionary<string, ProductTypeTracebackStatistics> GenerateProductTypeTracebackStatistics(Random random)
{
var productTypeStats = new Dictionary<string, ProductTypeTracebackStatistics>();
for (int i = 1; i <= 5; i++)
{
productTypeStats[$"PT{i}"] = new ProductTypeTracebackStatistics
{
ProductTypeCode = $"PT{i}",
SessionCount = random.Next(10, 50),
CompletedSessionCount = random.Next(8, 50),
LayerCount = random.Next(30, 200),
ScreenshotCount = random.Next(100, 600),
DefectCount = random.Next(0, 50)
};
}
return productTypeStats;
}
/// <summary>
/// 生成导出文件内容。
/// </summary>
private string GenerateExportFileContent(TracebackExportRequest 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 type = exportRequest.ExportType.ToString();
var status = "Completed";
var description = $"记录{i + 1}";
content.AppendLine($"{i + 1},{timestamp:yyyy-MM-dd HH:mm:ss},{type},{status},{description}");
}
return content.ToString();
}
#endregion
}
#endif
/// <summary>
/// 历史追溯服务实现(最小可编译版本)。
/// </summary>
public sealed class HistoryTraceService : IHistoryTraceService
{
private readonly ILogger<HistoryTraceService> _logger;
/// <summary>
/// 构造函数。
/// </summary>
public HistoryTraceService(ILogger<HistoryTraceService> logger, IOptions<RuntimeOptions> options)
{
_logger = logger;
_ = options;
_logger.LogInformation("历史追溯服务已初始化(最小实现)");
}
public Task<Result<IReadOnlyList<ProductSessionHistory>>> GetProductSessionHistoryAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, OrpaonVision.Core.HistoryTrace.SessionStatus? sessionStatus = null, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<IReadOnlyList<ProductSessionHistory>>.Success(Array.Empty<ProductSessionHistory>()));
public Task<Result<ProductSessionDetail>> GetSessionDetailAsync(Guid sessionId, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<ProductSessionDetail>.Success(new ProductSessionDetail()));
public Task<Result<IReadOnlyList<LayerProcessingHistory>>> GetLayerProcessingHistoryAsync(Guid sessionId, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<IReadOnlyList<LayerProcessingHistory>>.Success(Array.Empty<LayerProcessingHistory>()));
public Task<Result<LayerProcessingDetail>> GetLayerDetailAsync(Guid layerId, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<LayerProcessingDetail>.Success(new LayerProcessingDetail()));
public Task<Result<IReadOnlyList<ScreenshotHistory>>> GetScreenshotHistoryAsync(Guid? sessionId = null, Guid? layerId = null, DateTime? startTime = null, DateTime? endTime = null, ScreenshotType? screenshotType = null, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<IReadOnlyList<ScreenshotHistory>>.Success(Array.Empty<ScreenshotHistory>()));
public Task<Result<ScreenshotDetail>> GetScreenshotDetailAsync(Guid screenshotId, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<ScreenshotDetail>.Success(new ScreenshotDetail()));
public Task<Result<byte[]>> GetScreenshotContentAsync(Guid screenshotId, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<byte[]>.Success(Array.Empty<byte>()));
public Task<Result<EvidenceChain>> GetEvidenceChainAsync(Guid sessionId, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<EvidenceChain>.Success(new EvidenceChain()));
public Task<Result<LayerEvidenceTraceback>> GetLayerEvidenceTracebackAsync(Guid sessionId, int? layerSequence = null, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<LayerEvidenceTraceback>.Success(new LayerEvidenceTraceback()));
public Task<Result<DefectTraceback>> GetDefectTracebackAsync(Guid sessionId, DefectType? defectType = null, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<DefectTraceback>.Success(new DefectTraceback()));
public Task<Result<IReadOnlyList<OperationHistory>>> GetOperationHistoryAsync(Guid? sessionId = null, string? operatorId = null, DateTime? startTime = null, DateTime? endTime = null, OperationType? operationType = null, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<IReadOnlyList<OperationHistory>>.Success(Array.Empty<OperationHistory>()));
public Task<Result<ComprehensiveTracebackReport>> GetComprehensiveTracebackReportAsync(Guid sessionId, OrpaonVision.Core.HistoryTrace.TracebackReportType reportType, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<ComprehensiveTracebackReport>.Success(new ComprehensiveTracebackReport()));
public Task<Result<TracebackStatistics>> GetTracebackStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<TracebackStatistics>.Success(new TracebackStatistics()));
public Task<Result<HistorySearchResult>> SearchHistoryAsync(HistorySearchRequest searchRequest, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<HistorySearchResult>.Success(new HistorySearchResult()));
public Task<Result<TracebackExportResult>> ExportTracebackDataAsync(TracebackExportRequest exportRequest, CancellationToken cancellationToken = default)
=> Task.FromResult(Result<TracebackExportResult>.Success(new TracebackExportResult
{
ExportId = exportRequest.ExportId,
IsSuccess = true,
FilePath = string.Empty,
FileSizeBytes = 0,
RecordCount = 0,
ExportElapsedMs = 0,
ExportTimeUtc = DateTime.UtcNow,
ResultDescription = "最小实现返回。"
}));
}