using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OrpaonVision.Core.FinalJudgment;
using OrpaonVision.Core.LayerCompletion;
using OrpaonVision.Core.Results;
using OrpaonVision.SiteApp.Runtime.Options;
using System.Collections.Concurrent;
using System.Text.Json;
namespace OrpaonVision.SiteApp.Runtime.Services;
///
/// 整机完成判定服务实现。
///
#if false
public sealed class FinalJudgmentService : IFinalJudgmentService
{
private readonly ILogger _logger;
private readonly RuntimeOptions _options;
private readonly ConcurrentDictionary _finalRules = new();
private readonly ConcurrentDictionary _judgmentHistory = new();
private readonly ConcurrentDictionary _judgmentRecords = new();
private readonly object _lock = new();
///
/// 构造函数。
///
public FinalJudgmentService(ILogger logger, IOptions options)
{
_logger = logger;
_options = options.Value;
InitializeDefaultFinalRules();
}
#endif
///
/// 整机完成判定服务最小实现。
///
public sealed class FinalJudgmentService : IFinalJudgmentService
{
private readonly ILogger _logger;
private readonly ConcurrentDictionary _rules = new();
private readonly ConcurrentDictionary _results = new();
private readonly ConcurrentDictionary _history = new();
public FinalJudgmentService(ILogger logger, IOptions options)
{
_logger = logger;
_ = options;
var now = DateTime.UtcNow;
var defaultRule = new FinalJudgmentRule
{
RuleId = Guid.NewGuid(),
RuleName = "默认终判规则",
RuleDescription = "最小可运行默认规则",
ProductTypeCode = "default",
RuleType = FinalJudgmentRuleType.CompletionRate,
RuleWeight = 1.0,
Threshold = 90,
ComparisonOperator = ComparisonOperator.GreaterThanOrEqual,
IsMandatory = true,
IsEnabled = true,
Priority = 1,
CreatedAtUtc = now,
UpdatedAtUtc = now,
Version = "1.0"
};
_rules[defaultRule.RuleId] = defaultRule;
}
public Task> ExecuteFinalJudgmentAsync(FinalJudgmentContext judgmentContext, IReadOnlyList finalRules, CancellationToken cancellationToken = default)
{
var start = DateTime.UtcNow;
var score = judgmentContext.OverallCompletionPercentage;
var rules = finalRules.Where(r => r.IsEnabled).ToList();
var passedRules = rules.Select(r => new RuleJudgmentResult
{
RuleId = r.RuleId,
RuleName = r.RuleName,
RuleType = r.RuleType,
IsPassed = true,
RuleScore = score,
RuleWeight = r.RuleWeight,
ActualValue = score,
Threshold = r.Threshold,
Details = "最小实现:默认通过"
}).ToList();
var result = new FinalJudgmentResult
{
JudgmentId = Guid.NewGuid(),
ProductTypeCode = judgmentContext.ProductTypeCode,
SessionId = judgmentContext.SessionId,
IsPassed = true,
JudgmentType = FinalJudgmentType.Automatic,
JudgmentTimeUtc = start,
JudgmentElapsedMs = 0,
OverallScore = score,
JudgmentQuality = JudgmentQuality.Good,
PassedRules = passedRules,
FailedRules = Array.Empty(),
NGCauses = Array.Empty(),
EvidenceChain = new EvidenceChain
{
ChainId = Guid.NewGuid(),
CreatedAtUtc = start,
EvidenceNodes = Array.Empty(),
CompletenessScore = 100,
CredibilityScore = 100
},
Details = "最小实现:终判完成",
Recommendation = null
};
_results[result.JudgmentId] = result;
_history[result.JudgmentId] = new FinalJudgmentHistory
{
JudgmentId = result.JudgmentId,
ProductTypeCode = result.ProductTypeCode,
SessionId = result.SessionId,
JudgmentType = result.JudgmentType,
JudgmentTimeUtc = result.JudgmentTimeUtc,
IsPassed = result.IsPassed,
OverallScore = result.OverallScore,
JudgmentQuality = result.JudgmentQuality,
OperatorUser = "system",
NGCauseCount = 0
};
_logger.LogInformation("最小终判完成:{JudgmentId}", result.JudgmentId);
return Task.FromResult(Result.Success(result));
}
public async Task> BatchExecuteFinalJudgmentAsync(IReadOnlyList judgmentContexts, IReadOnlyList finalRules, CancellationToken cancellationToken = default)
{
var list = new List();
foreach (var context in judgmentContexts)
{
var one = await ExecuteFinalJudgmentAsync(context, finalRules, cancellationToken);
if (one.Data != null)
{
list.Add(one.Data);
}
}
var batch = new BatchFinalJudgmentResult
{
JudgmentResults = list,
TotalJudgments = judgmentContexts.Count,
PassedCount = list.Count(r => r.IsPassed),
FailedCount = list.Count(r => !r.IsPassed),
BatchProcessingTimeUtc = DateTime.UtcNow,
TotalElapsedMs = 0,
Details = "最小实现:批量终判完成"
};
return Result.Success(batch);
}
public Task>> GetJudgmentHistoryAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default)
{
IReadOnlyList records = _history.Values
.Where(x => x.JudgmentTimeUtc >= startTime && x.JudgmentTimeUtc <= endTime)
.OrderByDescending(x => x.JudgmentTimeUtc)
.ToList();
return Task.FromResult(Result>.Success(records));
}
public Task> GetJudgmentStatisticsAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default)
{
var records = _history.Values
.Where(x => x.JudgmentTimeUtc >= startTime && x.JudgmentTimeUtc <= endTime)
.ToList();
var statistics = new FinalJudgmentStatistics
{
StartTimeUtc = startTime,
EndTimeUtc = endTime,
TotalJudgments = records.Count,
PassedCount = records.Count(x => x.IsPassed),
FailedCount = records.Count(x => !x.IsPassed),
ByJudgmentType = records
.GroupBy(x => x.JudgmentType)
.ToDictionary(
g => g.Key,
g => new JudgmentTypeStatistics
{
JudgmentType = g.Key,
JudgmentCount = g.Count(),
PassCount = g.Count(x => x.IsPassed),
AverageScore = g.Average(x => x.OverallScore),
AverageElapsedMs = 0
}),
ByProductType = records
.GroupBy(x => x.ProductTypeCode)
.ToDictionary(
g => g.Key,
g => new ProductTypeJudgmentStatistics
{
ProductTypeCode = g.Key,
JudgmentCount = g.Count(),
PassCount = g.Count(x => x.IsPassed),
AverageScore = g.Average(x => x.OverallScore),
AverageElapsedMs = 0
}),
ByQuality = records
.GroupBy(x => x.JudgmentQuality)
.ToDictionary(
g => g.Key,
g => new QualityStatistics
{
Quality = g.Key,
JudgmentCount = g.Count(),
AverageScore = g.Average(x => x.OverallScore)
}),
AverageScore = records.Any() ? records.Average(x => x.OverallScore) : 0,
AverageElapsedMs = 0
};
return Task.FromResult(Result.Success(statistics));
}
public Task> GetNGCauseAnalysisAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default)
{
var analysis = new NGCauseAnalysis
{
StartTimeUtc = startTime,
EndTimeUtc = endTime,
TotalNGCount = 0,
ByCauseType = new Dictionary(),
ByCauseLevel = new Dictionary(),
ByImpactLevel = new Dictionary(),
ByLayer = new Dictionary(),
HotCauses = Array.Empty(),
Trend = new NGCauseTrend
{
Direction = NGCauseTrendDirection.Stable,
ChangeRate = 0,
TrendDescription = "最小实现:无趋势"
}
};
return Task.FromResult(Result.Success(analysis));
}
public Task> CreateFinalRuleAsync(FinalJudgmentRule rule, CancellationToken cancellationToken = default)
{
var now = DateTime.UtcNow;
var created = new FinalJudgmentRule
{
RuleId = Guid.NewGuid(),
RuleName = rule.RuleName,
RuleDescription = rule.RuleDescription,
ProductTypeCode = rule.ProductTypeCode,
RuleType = rule.RuleType,
RuleWeight = rule.RuleWeight,
Threshold = rule.Threshold,
ComparisonOperator = rule.ComparisonOperator,
IsMandatory = rule.IsMandatory,
IsEnabled = rule.IsEnabled,
Priority = rule.Priority,
CreatedAtUtc = now,
UpdatedAtUtc = now,
Version = "1.0",
ExtendedProperties = new Dictionary(rule.ExtendedProperties)
};
_rules[created.RuleId] = created;
return Task.FromResult(Result.Success(created));
}
public Task UpdateFinalRuleAsync(FinalJudgmentRule rule, CancellationToken cancellationToken = default)
{
if (!_rules.TryGetValue(rule.RuleId, out var existing))
{
return Task.FromResult(Result.Fail("RULE_NOT_FOUND", $"未找到规则:{rule.RuleId}"));
}
var updated = new FinalJudgmentRule
{
RuleId = existing.RuleId,
RuleName = rule.RuleName,
RuleDescription = rule.RuleDescription,
ProductTypeCode = rule.ProductTypeCode,
RuleType = rule.RuleType,
RuleWeight = rule.RuleWeight,
Threshold = rule.Threshold,
ComparisonOperator = rule.ComparisonOperator,
IsMandatory = rule.IsMandatory,
IsEnabled = rule.IsEnabled,
Priority = rule.Priority,
CreatedAtUtc = existing.CreatedAtUtc,
UpdatedAtUtc = DateTime.UtcNow,
Version = existing.Version,
ExtendedProperties = new Dictionary(rule.ExtendedProperties)
};
_rules[updated.RuleId] = updated;
return Task.FromResult(Result.Success());
}
public Task DeleteFinalRuleAsync(Guid ruleId, CancellationToken cancellationToken = default)
{
return Task.FromResult(_rules.TryRemove(ruleId, out _)
? Result.Success()
: Result.Fail("RULE_NOT_FOUND", $"未找到规则:{ruleId}"));
}
public Task>> GetFinalRulesAsync(string? productTypeCode = null, FinalJudgmentRuleType? ruleType = null, CancellationToken cancellationToken = default)
{
IEnumerable query = _rules.Values;
if (!string.IsNullOrWhiteSpace(productTypeCode))
{
query = query.Where(x => string.Equals(x.ProductTypeCode, productTypeCode, StringComparison.OrdinalIgnoreCase));
}
if (ruleType.HasValue)
{
query = query.Where(x => x.RuleType == ruleType.Value);
}
IReadOnlyList rules = query.OrderBy(x => x.Priority).ThenBy(x => x.RuleName).ToList();
return Task.FromResult(Result>.Success(rules));
}
public Task> GenerateJudgmentReportAsync(Guid judgmentId, CancellationToken cancellationToken = default)
{
if (!_results.TryGetValue(judgmentId, out var result))
{
return Task.FromResult(Result.FailWithTrace("JUDGMENT_NOT_FOUND", $"未找到判定记录:{judgmentId}", string.Empty));
}
var report = new FinalJudgmentReport
{
ReportId = Guid.NewGuid(),
JudgmentId = judgmentId,
GeneratedAtUtc = DateTime.UtcNow,
ReportType = ReportType.Standard,
ReportContent = $"最小实现报告: Judgment={result.JudgmentId}, Score={result.OverallScore:F2}",
ReportFormat = ReportFormat.Text
};
return Task.FromResult(Result.Success(report));
}
}
#if false
///
public async Task> ExecuteFinalJudgmentAsync(FinalJudgmentContext judgmentContext, IReadOnlyList finalRules, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("开始整机完成判定:产品类型={ProductTypeCode},会话={SessionId},总层级={TotalLayers},完成层级={CompletedLayers}",
judgmentContext.ProductTypeCode, judgmentContext.SessionId, judgmentContext.TotalLayers, judgmentContext.CompletedLayers);
var startTime = DateTime.UtcNow;
var judgmentId = Guid.NewGuid();
// 执行规则判定
var ruleResults = new List();
var passedRules = new List();
var failedRules = new List();
var ngCauses = new List();
foreach (var rule in finalRules.Where(r => r.IsEnabled))
{
var ruleResult = await ExecuteRuleJudgmentAsync(judgmentContext, rule, cancellationToken);
ruleResults.Add(ruleResult);
if (ruleResult.IsPassed)
{
passedRules.Add(ruleResult);
}
else
{
failedRules.Add(ruleResult);
// 生成NG原因
var ngCause = GenerateNGCause(ruleResult, judgmentContext);
ngCauses.Add(ngCause);
}
}
// 计算总体评分
var overallScore = CalculateOverallScore(ruleResults, finalRules);
// 判定是否通过
var mandatoryRules = finalRules.Where(r => r.IsMandatory && r.IsEnabled).ToList();
var failedMandatoryRules = failedRules.Where(r => mandatoryRules.Any(m => m.RuleId == r.RuleId)).ToList();
var isPassed = failedMandatoryRules.Count == 0 && overallScore >= _options.FinalJudgmentPassThreshold;
// 生成证据链
var evidenceChain = await GenerateEvidenceChainAsync(judgmentContext, ruleResults, cancellationToken);
// 确定判定质量
var judgmentQuality = DetermineJudgmentQuality(overallScore, failedRules.Count, ruleResults.Count);
var result = new FinalJudgmentResult
{
JudgmentId = judgmentId,
ProductTypeCode = judgmentContext.ProductTypeCode,
SessionId = judgmentContext.SessionId,
IsPassed = isPassed,
JudgmentType = FinalJudgmentType.Automatic,
JudgmentTimeUtc = startTime,
JudgmentElapsedMs = (long)(DateTime.UtcNow - startTime).TotalMilliseconds,
OverallScore = overallScore,
JudgmentQuality = judgmentQuality,
PassedRules = passedRules,
FailedRules = failedRules,
NGCauses = ngCauses,
EvidenceChain = evidenceChain,
Details = isPassed
? $"整机完成判定通过:总体评分={overallScore:F2},通过规则={passedRules.Count}/{ruleResults.Count}"
: $"整机完成判定失败:总体评分={overallScore:F2},失败规则={failedRules.Count}/{ruleResults.Count},NG原因={ngCauses.Count}个",
Recommendation = GenerateRecommendation(isPassed, failedRules, ngCauses),
ExtendedProperties = new Dictionary
{
["judgment_type"] = "final_judgment",
["product_type_code"] = judgmentContext.ProductTypeCode,
["session_id"] = judgmentContext.SessionId,
["total_layers"] = judgmentContext.TotalLayers,
["completed_layers"] = judgmentContext.CompletedLayers,
["failed_layers"] = judgmentContext.FailedLayers,
["overall_completion_percentage"] = judgmentContext.OverallCompletionPercentage,
["mandatory_rules_count"] = mandatoryRules.Count,
["failed_mandatory_rules_count"] = failedMandatoryRules.Count
}
};
// 记录判定历史
await AddJudgmentHistoryAsync(result, cancellationToken);
var elapsed = (DateTime.UtcNow - startTime).TotalMilliseconds;
_logger.LogInformation("整机完成判定完成:判定ID={JudgmentId},结果={IsPassed},评分={Score:F2},耗时={ElapsedMs:F1}ms",
judgmentId, result.IsPassed, result.OverallScore, elapsed);
return Result.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "整机完成判定失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "FINAL_JUDGMENT_FAILED", "整机完成判定失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> BatchExecuteFinalJudgmentAsync(IReadOnlyList judgmentContexts, IReadOnlyList finalRules, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("开始批量整机完成判定:判定数量={JudgmentCount},规则数量={RuleCount}",
judgmentContexts.Count, finalRules.Count);
var startTime = DateTime.UtcNow;
var judgmentResults = new List();
var passedCount = 0;
var failedCount = 0;
foreach (var context in judgmentContexts)
{
var judgmentResult = await ExecuteFinalJudgmentAsync(context, finalRules, cancellationToken);
judgmentResults.Add(judgmentResult.Data);
if (judgmentResult.Data.IsPassed)
{
passedCount++;
}
else
{
failedCount++;
}
}
var elapsed = DateTime.UtcNow - startTime;
var result = new BatchFinalJudgmentResult
{
JudgmentResults = judgmentResults,
TotalJudgments = judgmentContexts.Count,
PassedCount = passedCount,
FailedCount = failedCount,
BatchProcessingTimeUtc = startTime,
TotalElapsedMs = (long)elapsed.TotalMilliseconds,
Details = $"批量整机完成判定完成:总数={judgmentContexts.Count},通过={passedCount},失败={failedCount},通过率={result.OverallPassRate:F2}%",
ExtendedProperties = new Dictionary
{
["throughput_per_second"] = judgmentContexts.Count / Math.Max(elapsed.TotalSeconds, 0.001)
}
};
_logger.LogInformation("批量整机完成判定完成:总数={TotalCount},通过={PassedCount},失败={FailedCount},通过率={PassRate:F2}%,耗时={ElapsedMs}ms",
result.TotalJudgments, result.PassedCount, result.FailedCount, result.OverallPassRate, result.TotalElapsedMs);
return Result.Success(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "批量整机完成判定失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "BATCH_FINAL_JUDGMENT_FAILED", "批量整机完成判定失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task>> GetJudgmentHistoryAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("获取整机完成判定历史:开始时间={StartTime},结束时间={EndTime}", startTime, endTime);
var history = _judgmentRecords.Values
.Where(h => h.JudgmentTimeUtc >= startTime && h.JudgmentTimeUtc <= endTime)
.OrderByDescending(h => h.JudgmentTimeUtc)
.ToList();
_logger.LogDebug("获取整机完成判定历史完成:记录数量={Count}", history.Count);
return Result.Success>(history);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取整机完成判定历史失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_JUDGMENT_HISTORY_FAILED", "获取整机完成判定历史失败", traceId);
return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetJudgmentStatisticsAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("获取整机完成判定统计信息:开始时间={StartTime},结束时间={EndTime}", startTime, endTime);
var history = _judgmentRecords.Values
.Where(h => h.JudgmentTimeUtc >= startTime && h.JudgmentTimeUtc <= endTime)
.ToList();
var statistics = new FinalJudgmentStatistics
{
StartTimeUtc = startTime,
EndTimeUtc = endTime,
TotalJudgments = history.Count,
PassedCount = history.Count(h => h.IsPassed),
FailedCount = history.Count(h => !h.IsPassed)
};
// 按判定类型分组统计
var typeGroups = history.GroupBy(h => h.JudgmentType);
foreach (var group in typeGroups)
{
statistics.ByJudgmentType[group.Key] = new JudgmentTypeStatistics
{
JudgmentType = group.Key,
JudgmentCount = group.Count(),
PassCount = group.Count(h => h.IsPassed),
AverageScore = group.Average(h => h.OverallScore),
AverageElapsedMs = group.Average(h => Convert.ToDouble(h.ExtendedProperties.GetValueOrDefault("judgment_elapsed_ms", 0)))
};
}
// 按产品类型分组统计
var productTypeGroups = history.GroupBy(h => h.ProductTypeCode);
foreach (var group in productTypeGroups)
{
statistics.ByProductType[group.Key] = new ProductTypeJudgmentStatistics
{
ProductTypeCode = group.Key,
JudgmentCount = group.Count(),
PassCount = group.Count(h => h.IsPassed),
AverageScore = group.Average(h => h.OverallScore),
AverageElapsedMs = group.Average(h => Convert.ToDouble(h.ExtendedProperties.GetValueOrDefault("judgment_elapsed_ms", 0)))
};
}
// 按判定质量分组统计
var qualityGroups = history.GroupBy(h => h.JudgmentQuality);
foreach (var group in qualityGroups)
{
statistics.ByQuality[group.Key] = new QualityStatistics
{
Quality = group.Key,
JudgmentCount = group.Count(),
AverageScore = group.Average(h => h.OverallScore)
};
}
statistics.AverageScore = history.Any() ? history.Average(h => h.OverallScore) : 0.0;
statistics.AverageElapsedMs = history.Any()
? history.Average(h => Convert.ToDouble(h.ExtendedProperties.GetValueOrDefault("judgment_elapsed_ms", 0)))
: 0.0;
_logger.LogInformation("整机完成判定统计信息获取完成:总判定次数={Total},通过率={PassRate:F2}%,平均评分={AvgScore:F2},平均耗时={AvgElapsedMs:F1}ms",
statistics.TotalJudgments, statistics.OverallPassRate, statistics.AverageScore, statistics.AverageElapsedMs);
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_JUDGMENT_STATISTICS_FAILED", "获取整机完成判定统计信息失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GetNGCauseAnalysisAsync(DateTime startTime, DateTime endTime, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("获取NG原因分析:开始时间={StartTime},结束时间={EndTime}", startTime, endTime);
var history = _judgmentHistory.Values
.Where(h => h.JudgmentTimeUtc >= startTime && h.JudgmentTimeUtc <= endTime && !h.IsPassed)
.ToList();
var allNGCauses = history.SelectMany(h => h.NGCauses).ToList();
var analysis = new NGCauseAnalysis
{
StartTimeUtc = startTime,
EndTimeUtc = endTime,
TotalNGCount = allNGCauses.Count
};
// 按原因类型分组统计
var causeTypeGroups = allNGCauses.GroupBy(c => c.CauseType);
foreach (var group in causeTypeGroups)
{
analysis.ByCauseType[group.Key] = new CauseTypeStatistics
{
CauseType = group.Key,
OccurrenceCount = group.Count(),
AverageImpactLevel = group.Average(c => (double)c.ImpactLevel)
};
}
// 按原因级别分组统计
var causeLevelGroups = allNGCauses.GroupBy(c => c.CauseLevel);
foreach (var group in causeLevelGroups)
{
analysis.ByCauseLevel[group.Key] = new CauseLevelStatistics
{
CauseLevel = group.Key,
OccurrenceCount = group.Count()
};
}
// 按影响程度分组统计
var impactGroups = allNGCauses.GroupBy(c => c.ImpactLevel);
foreach (var group in impactGroups)
{
analysis.ByImpactLevel[group.Key] = new ImpactStatistics
{
ImpactLevel = group.Key,
OccurrenceCount = group.Count()
};
}
// 按层级分组统计
var layerGroups = allNGCauses.Where(c => c.RelatedLayer.HasValue).GroupBy(c => c.RelatedLayer!.Value);
foreach (var group in layerGroups)
{
analysis.ByLayer[group.Key] = new LayerNGStatistics
{
LayerNumber = group.Key,
NGCount = group.Count()
};
}
// 生成热点NG原因
analysis.HotCauses = GenerateHotNGCauses(allNGCauses);
// 生成趋势分析
analysis.Trend = GenerateNGCauseTrend(allNGCauses);
_logger.LogInformation("NG原因分析完成:总NG数量={TotalNG},热点原因数量={HotCauses},趋势方向={Trend}",
analysis.TotalNGCount, analysis.HotCauses.Count, analysis.Trend.Direction);
return Result.Success(analysis);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取NG原因分析失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_NG_CAUSE_ANALYSIS_FAILED", "获取NG原因分析失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> CreateFinalRuleAsync(FinalJudgmentRule rule, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("创建终判规则:规则名称={RuleName},规则类型={RuleType},产品类型={ProductTypeCode}",
rule.RuleName, rule.RuleType, rule.ProductTypeCode);
lock (_lock)
{
rule.RuleId = Guid.NewGuid();
rule.CreatedAtUtc = DateTime.UtcNow;
rule.UpdatedAtUtc = DateTime.UtcNow;
rule.Version = "1.0";
_finalRules[rule.RuleId] = rule;
}
_logger.LogInformation("终判规则创建成功:规则ID={RuleId},规则名称={RuleName}",
rule.RuleId, rule.RuleName);
return Result.Success(rule);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "创建终判规则失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "CREATE_FINAL_RULE_FAILED", "创建终判规则失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task UpdateFinalRuleAsync(FinalJudgmentRule rule, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("更新终判规则:规则ID={RuleId},规则名称={RuleName}",
rule.RuleId, rule.RuleName);
lock (_lock)
{
if (_finalRules.ContainsKey(rule.RuleId))
{
rule.UpdatedAtUtc = DateTime.UtcNow;
_finalRules[rule.RuleId] = rule;
}
else
{
return Result.Fail("RULE_NOT_FOUND", $"未找到规则:{rule.RuleId}");
}
}
_logger.LogInformation("终判规则更新成功:规则ID={RuleId}", rule.RuleId);
return Result.Success();
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "更新终判规则失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "UPDATE_FINAL_RULE_FAILED", "更新终判规则失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task DeleteFinalRuleAsync(Guid ruleId, CancellationToken cancellationToken = default)
{
try
{
_logger.LogInformation("删除终判规则:规则ID={RuleId}", ruleId);
lock (_lock)
{
if (_finalRules.TryRemove(ruleId, out _))
{
_logger.LogInformation("终判规则删除成功:规则ID={RuleId}", ruleId);
return Result.Success();
}
else
{
return Result.Fail("RULE_NOT_FOUND", $"未找到规则:{ruleId}");
}
}
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "删除终判规则失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "DELETE_FINAL_RULE_FAILED", "删除终判规则失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task>> GetFinalRulesAsync(string? productTypeCode = null, FinalJudgmentRuleType? ruleType = null, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("获取终判规则列表:产品类型={ProductTypeCode},规则类型={RuleType}",
productTypeCode, ruleType);
var rules = _finalRules.Values.AsEnumerable();
if (!string.IsNullOrEmpty(productTypeCode))
{
rules = rules.Where(r => r.ProductTypeCode.Equals(productTypeCode, StringComparison.OrdinalIgnoreCase));
}
if (ruleType.HasValue)
{
rules = rules.Where(r => r.RuleType == ruleType.Value);
}
var result = rules.OrderBy(r => r.Priority).ThenBy(r => r.RuleName).ToList();
_logger.LogDebug("获取终判规则列表完成:规则数量={RuleCount}", result.Count);
return Result.Success>(result);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "获取终判规则列表失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GET_FINAL_RULES_FAILED", "获取终判规则列表失败", traceId);
return Result.FailWithTrace>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
///
public async Task> GenerateJudgmentReportAsync(Guid judgmentId, CancellationToken cancellationToken = default)
{
try
{
_logger.LogDebug("生成整机完成判定报告:判定ID={JudgmentId}", judgmentId);
var judgmentResult = _judgmentHistory.GetValueOrDefault(judgmentId);
if (judgmentResult == null)
{
return Result.FailWithTrace("JUDGMENT_NOT_FOUND", $"未找到判定记录:{judgmentId}", string.Empty);
}
var report = await GenerateReportContentAsync(judgmentResult, cancellationToken);
_logger.LogInformation("整机完成判定报告生成完成:判定ID={JudgmentId},报告ID={ReportId}",
judgmentId, report.ReportId);
return Result.Success(report);
}
catch (Exception ex)
{
var traceId = Guid.NewGuid().ToString("N");
_logger.LogError(ex, "生成整机完成判定报告失败。TraceId: {TraceId}", traceId);
var result = Result.FromException(ex, "GENERATE_JUDGMENT_REPORT_FAILED", "生成整机完成判定报告失败", traceId);
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
}
}
#region 私有方法
///
/// 初始化默认终判规则。
///
private void InitializeDefaultFinalRules()
{
var defaultRules = new List
{
new()
{
RuleId = Guid.NewGuid(),
RuleName = "完成度规则",
RuleDescription = "整机完成度必须达到要求",
ProductTypeCode = "default",
RuleType = FinalJudgmentRuleType.CompletionRate,
RuleWeight = 0.4,
Threshold = 95.0,
ComparisonOperator = ComparisonOperator.GreaterThanOrEqual,
IsMandatory = true,
IsEnabled = true,
Priority = 1,
CreatedAtUtc = DateTime.UtcNow,
UpdatedAtUtc = DateTime.UtcNow,
Version = "1.0"
},
new()
{
RuleId = Guid.NewGuid(),
RuleName = "质量评分规则",
RuleDescription = "整机质量评分必须达到要求",
ProductTypeCode = "default",
RuleType = FinalJudgmentRuleType.QualityScore,
RuleWeight = 0.3,
Threshold = 85.0,
ComparisonOperator = ComparisonOperator.GreaterThanOrEqual,
IsMandatory = true,
IsEnabled = true,
Priority = 2,
CreatedAtUtc = DateTime.UtcNow,
UpdatedAtUtc = DateTime.UtcNow,
Version = "1.0"
},
new()
{
RuleId = Guid.NewGuid(),
RuleName = "错误率规则",
RuleDescription = "整机错误率不能超过阈值",
ProductTypeCode = "default",
RuleType = FinalJudgmentRuleType.ErrorRate,
RuleWeight = 0.2,
Threshold = 5.0,
ComparisonOperator = ComparisonOperator.LessThanOrEqual,
IsMandatory = false,
IsEnabled = true,
Priority = 3,
CreatedAtUtc = DateTime.UtcNow,
UpdatedAtUtc = DateTime.UtcNow,
Version = "1.0"
},
new()
{
RuleId = Guid.NewGuid(),
RuleName = "时间约束规则",
RuleDescription = "整机处理时间不能超过限制",
ProductTypeCode = "default",
RuleType = FinalJudgmentRuleType.TimeConstraint,
RuleWeight = 0.1,
Threshold = 300000.0, // 5分钟
ComparisonOperator = ComparisonOperator.LessThanOrEqual,
IsMandatory = false,
IsEnabled = true,
Priority = 4,
CreatedAtUtc = DateTime.UtcNow,
UpdatedAtUtc = DateTime.UtcNow,
Version = "1.0"
}
};
foreach (var rule in defaultRules)
{
_finalRules[rule.RuleId] = rule;
}
}
///
/// 执行规则判定。
///
private async Task ExecuteRuleJudgmentAsync(FinalJudgmentContext context, FinalJudgmentRule rule, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var actualValue = CalculateRuleValue(context, rule);
var isPassed = EvaluateRuleCondition(actualValue, rule.Threshold, rule.ComparisonOperator);
return new RuleJudgmentResult
{
RuleId = rule.RuleId,
RuleName = rule.RuleName,
RuleType = rule.RuleType,
IsPassed = isPassed,
RuleScore = isPassed ? 100.0 : Math.Max(0.0, 100.0 - Math.Abs(actualValue - rule.Threshold)),
RuleWeight = rule.RuleWeight,
ActualValue = actualValue,
Threshold = rule.Threshold,
Details = isPassed
? $"规则通过:实际值{actualValue:F2}满足条件{GetComparisonDescription(rule.ComparisonOperator)}{rule.Threshold:F2}"
: $"规则失败:实际值{actualValue:F2}不满足条件{GetComparisonDescription(rule.ComparisonOperator)}{rule.Threshold:F2}",
ExtendedProperties = new Dictionary
{
["rule_type"] = rule.RuleType.ToString(),
["is_mandatory"] = rule.IsMandatory
}
};
}
///
/// 计算规则值。
///
private double CalculateRuleValue(FinalJudgmentContext context, FinalJudgmentRule rule)
{
return rule.RuleType switch
{
FinalJudgmentRuleType.CompletionRate => context.OverallCompletionPercentage,
FinalJudgmentRuleType.QualityScore => CalculateQualityScore(context),
FinalJudgmentRuleType.ErrorRate => CalculateErrorRate(context),
FinalJudgmentRuleType.TimeConstraint => context.TotalElapsedMs,
_ => 0.0
};
}
///
/// 计算质量评分。
///
private double CalculateQualityScore(FinalJudgmentContext context)
{
if (context.LayerCompletionResults.Count == 0) return 0.0;
var totalScore = context.LayerCompletionResults.Sum(r => r.OverallConfidence * 100);
return totalScore / context.LayerCompletionResults.Count;
}
///
/// 计算错误率。
///
private double CalculateErrorRate(FinalJudgmentContext context)
{
var totalLayers = context.TotalLayers;
var failedLayers = context.FailedLayers;
return totalLayers > 0 ? (double)failedLayers / totalLayers * 100 : 0.0;
}
///
/// 评估规则条件。
///
private bool EvaluateRuleCondition(double actualValue, double threshold, ComparisonOperator comparisonOperator)
{
return comparisonOperator switch
{
ComparisonOperator.Equal => Math.Abs(actualValue - threshold) < 0.001,
ComparisonOperator.NotEqual => Math.Abs(actualValue - threshold) >= 0.001,
ComparisonOperator.GreaterThan => actualValue > threshold,
ComparisonOperator.GreaterThanOrEqual => actualValue >= threshold,
ComparisonOperator.LessThan => actualValue < threshold,
ComparisonOperator.LessThanOrEqual => actualValue <= threshold,
_ => false
};
}
///
/// 获取比较描述。
///
private string GetComparisonDescription(ComparisonOperator comparisonOperator)
{
return comparisonOperator switch
{
ComparisonOperator.Equal => "==",
ComparisonOperator.NotEqual => "!=",
ComparisonOperator.GreaterThan => ">",
ComparisonOperator.GreaterThanOrEqual => ">=",
ComparisonOperator.LessThan => "<",
ComparisonOperator.LessThanOrEqual => "<=",
_ => "?"
};
}
///
/// 计算总体评分。
///
private double CalculateOverallScore(IReadOnlyList ruleResults, IReadOnlyList finalRules)
{
if (ruleResults.Count == 0) return 0.0;
var totalWeightedScore = 0.0;
var totalWeight = 0.0;
foreach (var result in ruleResults)
{
var rule = finalRules.FirstOrDefault(r => r.RuleId == result.RuleId);
if (rule != null && rule.IsEnabled)
{
totalWeightedScore += result.RuleScore * rule.RuleWeight;
totalWeight += rule.RuleWeight;
}
}
return totalWeight > 0 ? totalWeightedScore / totalWeight : 0.0;
}
///
/// 确定判定质量。
///
private JudgmentQuality DetermineJudgmentQuality(double overallScore, int failedRulesCount, int totalRulesCount)
{
var failRate = totalRulesCount > 0 ? (double)failedRulesCount / totalRulesCount : 0.0;
return (overallScore, failRate) switch
{
(>= 95.0, <= 0.05) => JudgmentQuality.Excellent,
(>= 85.0, <= 0.15) => JudgmentQuality.Good,
(>= 70.0, <= 0.30) => JudgmentQuality.Fair,
(>= 50.0, <= 0.50) => JudgmentQuality.Poor,
_ => JudgmentQuality.Unqualified
};
}
///
/// 生成NG原因。
///
private NGCause GenerateNGCause(RuleJudgmentResult ruleResult, FinalJudgmentContext context)
{
var causeType = DetermineNGCauseType(ruleResult.RuleType);
var causeLevel = DetermineNGCauseLevel(ruleResult.RuleWeight, ruleResult.IsMandatory);
return new NGCause
{
CauseId = Guid.NewGuid(),
CauseType = causeType,
CauseLevel = causeLevel,
Description = $"{ruleResult.RuleName}:{ruleResult.Details}",
RelatedLayer = null, // 整机判定不关联特定层级
RelatedPart = null,
OccurrenceTimeUtc = DateTime.UtcNow,
FixSuggestion = GenerateFixSuggestion(ruleResult.RuleType, causeType),
ImpactLevel = DetermineImpactLevel(causeLevel),
ExtendedProperties = new Dictionary
{
["rule_id"] = ruleResult.RuleId,
["rule_name"] = ruleResult.RuleName,
["actual_value"] = ruleResult.ActualValue,
["threshold"] = ruleResult.Threshold
}
};
}
///
/// 确定NG原因类型。
///
private NGCauseType DetermineNGCauseType(FinalJudgmentRuleType ruleType)
{
return ruleType switch
{
FinalJudgmentRuleType.CompletionRate => NGCauseType.ProcessIssue,
FinalJudgmentRuleType.QualityScore => NGCauseType.QualityIssue,
FinalJudgmentRuleType.ErrorRate => NGCauseType.ProcessIssue,
FinalJudgmentRuleType.TimeConstraint => NGCauseType.EquipmentIssue,
_ => NGCauseType.Other
};
}
///
/// 确定NG原因级别。
///
private NGCauseLevel DetermineNGCauseLevel(double ruleWeight, bool isMandatory)
{
if (isMandatory) return NGCauseLevel.Critical;
return ruleWeight switch
{
>= 0.3 => NGCauseLevel.Serious,
>= 0.1 => NGCauseLevel.Normal,
_ => NGCauseLevel.Minor
};
}
///
/// 生成修复建议。
///
private string? GenerateFixSuggestion(FinalJudgmentRuleType ruleType, NGCauseType causeType)
{
return (ruleType, causeType) switch
{
(FinalJudgmentRuleType.CompletionRate, NGCauseType.ProcessIssue) => "检查各层级完成情况,确保所有必要步骤都已完成",
(FinalJudgmentRuleType.QualityScore, NGCauseType.QualityIssue) => "提高各层级检测质量,确保检测精度和稳定性",
(FinalJudgmentRuleType.ErrorRate, NGCauseType.ProcessIssue) => "减少错误发生,优化工艺流程和操作规范",
(FinalJudgmentRuleType.TimeConstraint, NGCauseType.EquipmentIssue) => "优化设备性能,提高处理效率",
_ => "请根据具体情况进行针对性改进"
};
}
///
/// 确定影响程度。
///
private ImpactLevel DetermineImpactLevel(NGCauseLevel causeLevel)
{
return causeLevel switch
{
NGCauseLevel.Critical => ImpactLevel.Critical,
NGCauseLevel.Serious => ImpactLevel.High,
NGCauseLevel.Normal => ImpactLevel.Medium,
NGCauseLevel.Minor => ImpactLevel.Low,
_ => ImpactLevel.Low
};
}
///
/// 生成证据链。
///
private async Task GenerateEvidenceChainAsync(FinalJudgmentContext context, IReadOnlyList ruleResults, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var evidenceNodes = new List();
// 添加判定上下文证据
evidenceNodes.Add(new EvidenceNode
{
NodeId = Guid.NewGuid(),
NodeType = EvidenceNodeType.Data,
NodeName = "判定上下文",
NodeDescription = "整机完成判定的上下文信息",
TimestampUtc = DateTime.UtcNow,
DataContent = new
{
ProductTypeCode = context.ProductTypeCode,
SessionId = context.SessionId,
TotalLayers = context.TotalLayers,
CompletedLayers = context.CompletedLayers,
FailedLayers = context.FailedLayers,
OverallCompletionPercentage = context.OverallCompletionPercentage,
TotalElapsedMs = context.TotalElapsedMs
},
EvidenceWeight = 1.0
});
// 添加层级完成结果证据
foreach (var layerResult in context.LayerCompletionResults)
{
evidenceNodes.Add(new EvidenceNode
{
NodeId = Guid.NewGuid(),
NodeType = EvidenceNodeType.Data,
NodeName = $"层级{layerResult.ExtendedProperties.GetValueOrDefault("current_layer", 0)}完成结果",
NodeDescription = "层级完成判定的详细结果",
TimestampUtc = layerResult.JudgmentTimeUtc,
RelatedLayer = Convert.ToInt32(layerResult.ExtendedProperties.GetValueOrDefault("current_layer", 0)),
DataContent = new
{
IsCompleted = layerResult.IsCompleted,
CompletionPercentage = layerResult.CompletionPercentage,
OverallConfidence = layerResult.OverallConfidence,
CompletionQuality = layerResult.CompletionQuality
},
EvidenceWeight = 0.8
});
}
// 添加规则判定结果证据
foreach (var ruleResult in ruleResults)
{
evidenceNodes.Add(new EvidenceNode
{
NodeId = Guid.NewGuid(),
NodeType = EvidenceNodeType.Data,
NodeName = ruleResult.RuleName,
NodeDescription = "终判规则的判定结果",
TimestampUtc = DateTime.UtcNow,
DataContent = new
{
RuleType = ruleResult.RuleType,
IsPassed = ruleResult.IsPassed,
RuleScore = ruleResult.RuleScore,
ActualValue = ruleResult.ActualValue,
Threshold = ruleResult.Threshold,
Details = ruleResult.Details
},
EvidenceWeight = ruleResult.RuleWeight
});
}
return new EvidenceChain
{
ChainId = Guid.NewGuid(),
CreatedAtUtc = DateTime.UtcNow,
EvidenceNodes = evidenceNodes,
CompletenessScore = 95.0, // 简化处理
CredibilityScore = 90.0, // 简化处理
ExtendedProperties = new Dictionary
{
["evidence_node_count"] = evidenceNodes.Count,
["generation_time_ms"] = 100
}
};
}
///
/// 生成建议。
///
private string? GenerateRecommendation(bool isPassed, IReadOnlyList failedRules, IReadOnlyList ngCauses)
{
if (isPassed)
{
return "整机完成判定通过,产品可以进入下一阶段";
}
var recommendations = new List();
if (failedRules.Any(r => r.RuleType == FinalJudgmentRuleType.CompletionRate))
{
recommendations.Add("建议检查各层级完成情况,确保所有必要步骤都已完成");
}
if (failedRules.Any(r => r.RuleType == FinalJudgmentRuleType.QualityScore))
{
recommendations.Add("建议提高各层级检测质量,确保检测精度和稳定性");
}
if (failedRules.Any(r => r.RuleType == FinalJudgmentRuleType.ErrorRate))
{
recommendations.Add("建议减少错误发生,优化工艺流程和操作规范");
}
if (failedRules.Any(r => r.RuleType == FinalJudgmentRuleType.TimeConstraint))
{
recommendations.Add("建议优化设备性能,提高处理效率");
}
return recommendations.Any() ? string.Join(";", recommendations) : "请根据具体情况进行针对性改进";
}
///
/// 添加判定历史。
///
private async Task AddJudgmentHistoryAsync(FinalJudgmentResult result, CancellationToken cancellationToken = default)
{
await Task.Run(() =>
{
_judgmentHistory.TryAdd(result.JudgmentId, result);
var history = new FinalJudgmentHistory
{
JudgmentId = result.JudgmentId,
ProductTypeCode = result.ProductTypeCode,
SessionId = result.SessionId,
JudgmentType = result.JudgmentType,
JudgmentTimeUtc = result.JudgmentTimeUtc,
IsPassed = result.IsPassed,
OverallScore = result.OverallScore,
JudgmentQuality = result.JudgmentQuality,
OperatorUser = "system", // 简化处理
NGCauseCount = result.NGCauses.Count,
ExtendedProperties = new Dictionary
{
["judgment_elapsed_ms"] = result.JudgmentElapsedMs,
["passed_rules_count"] = result.PassedRules.Count,
["failed_rules_count"] = result.FailedRules.Count
}
};
_judgmentRecords.TryAdd(result.JudgmentId, history);
// 保持历史记录数量在合理范围内
if (_judgmentRecords.Count > _options.MaxFinalJudgmentHistoryCount)
{
var oldestRecords = _judgmentRecords.Values
.OrderBy(h => h.JudgmentTimeUtc)
.Take(_judgmentRecords.Count - _options.MaxFinalJudgmentHistoryCount)
.Select(h => h.JudgmentId)
.ToList();
foreach (var id in oldestRecords)
{
_judgmentRecords.TryRemove(id, out _);
_judgmentHistory.TryRemove(id, out _);
}
}
}, cancellationToken);
}
///
/// 生成热点NG原因。
///
private IReadOnlyList GenerateHotNGCauses(IReadOnlyList ngCauses)
{
var groupedCauses = ngCauses
.GroupBy(c => c.Description)
.Select(g => new HotNGCause
{
Description = g.Key,
OccurrenceCount = g.Count(),
Rank = 0, // 将在排序后设置
Trend = NGCauseTrendDirection.Stable // 简化处理
})
.OrderByDescending(c => c.OccurrenceCount)
.Take(10)
.ToList();
// 设置排名
for (int i = 0; i < groupedCauses.Count; i++)
{
groupedCauses[i] = groupedCauses[i] with { Rank = i + 1 };
}
return groupedCauses;
}
///
/// 生成NG原因趋势。
///
private NGCauseTrend GenerateNGCauseTrend(IReadOnlyList ngCauses)
{
// 简化处理,基于时间分布计算趋势
var recentCount = ngCauses.Count(c => c.OccurrenceTimeUtc >= DateTime.UtcNow.AddDays(-7));
var previousCount = ngCauses.Count(c => c.OccurrenceTimeUtc >= DateTime.UtcNow.AddDays(-14) && c.OccurrenceTimeUtc < DateTime.UtcNow.AddDays(-7));
var changeRate = previousCount > 0 ? (double)(recentCount - previousCount) / previousCount : 0.0;
var direction = changeRate switch
{
> 0.1 => NGCauseTrendDirection.Increasing,
< -0.1 => NGCauseTrendDirection.Decreasing,
_ => NGCauseTrendDirection.Stable
};
return new NGCauseTrend
{
Direction = direction,
ChangeRate = changeRate,
TrendDescription = $"NG原因趋势{direction},变化率{changeRate:P1}"
};
}
///
/// 生成报告内容。
///
private async Task GenerateReportContentAsync(FinalJudgmentResult judgmentResult, CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
var reportContent = GenerateReportText(judgmentResult);
return new FinalJudgmentReport
{
ReportId = Guid.NewGuid(),
JudgmentId = judgmentResult.JudgmentId,
GeneratedAtUtc = DateTime.UtcNow,
ReportType = ReportType.Standard,
ReportContent = reportContent,
ReportFormat = ReportFormat.Text,
ExtendedProperties = new Dictionary
{
["generation_time_ms"] = 50
}
};
}
///
/// 生成报告文本。
///
private string GenerateReportText(FinalJudgmentResult judgmentResult)
{
var report = new System.Text.StringBuilder();
report.AppendLine("=== 整机完成判定报告 ===");
report.AppendLine($"判定ID: {judgmentResult.JudgmentId}");
report.AppendLine($"产品类型: {judgmentResult.ProductTypeCode}");
report.AppendLine($"会话ID: {judgmentResult.SessionId}");
report.AppendLine($"判定时间: {judgmentResult.JudgmentTimeUtc:yyyy-MM-dd HH:mm:ss}");
report.AppendLine($"判定结果: {(judgmentResult.IsPassed ? "通过" : "失败")}");
report.AppendLine($"总体评分: {judgmentResult.OverallScore:F2}");
report.AppendLine($"判定质量: {judgmentResult.JudgmentQuality}");
report.AppendLine($"判定耗时: {judgmentResult.JudgmentElapsedMs}ms");
report.AppendLine();
report.AppendLine("=== 规则判定结果 ===");
report.AppendLine($"通过规则数量: {judgmentResult.PassedRules.Count}");
report.AppendLine($"失败规则数量: {judgmentResult.FailedRules.Count}");
report.AppendLine();
if (judgmentResult.FailedRules.Any())
{
report.AppendLine("失败规则详情:");
foreach (var failedRule in judgmentResult.FailedRules)
{
report.AppendLine($"- {failedRule.RuleName}: {failedRule.Details}");
}
report.AppendLine();
}
if (judgmentResult.NGCauses.Any())
{
report.AppendLine("=== NG原因分析 ===");
foreach (var ngCause in judgmentResult.NGCauses)
{
report.AppendLine($"- {ngCause.Description} (级别: {ngCause.CauseLevel}, 影响: {ngCause.ImpactLevel})");
if (!string.IsNullOrEmpty(ngCause.FixSuggestion))
{
report.AppendLine($" 修复建议: {ngCause.FixSuggestion}");
}
}
report.AppendLine();
}
if (!string.IsNullOrEmpty(judgmentResult.Recommendation))
{
report.AppendLine("=== 改进建议 ===");
report.AppendLine(judgmentResult.Recommendation);
report.AppendLine();
}
report.AppendLine("=== 证据链信息 ===");
report.AppendLine($"证据节点数量: {judgmentResult.EvidenceChain.EvidenceNodes.Count}");
report.AppendLine($"完整性评分: {judgmentResult.EvidenceChain.CompletenessScore:F1}");
report.AppendLine($"可信度评分: {judgmentResult.EvidenceChain.CredibilityScore:F1}");
return report.ToString();
}
#endregion
}
#endif