2099 lines
90 KiB
C#
2099 lines
90 KiB
C#
using Microsoft.Extensions.Logging;
|
||
using Microsoft.Extensions.Options;
|
||
using OrpaonVision.Core.ManualOverride;
|
||
using OrpaonVision.Core.Results;
|
||
using OrpaonVision.Core.Common;
|
||
using System.Collections.Concurrent;
|
||
using System.Text.Json;
|
||
using CoreAuditLevel = OrpaonVision.Core.ManualOverride.AuditLevel;
|
||
using OrpaonVision.SiteApp.Runtime.Services;
|
||
using RuntimeOptions = OrpaonVision.SiteApp.Runtime.Options.RuntimeOptions;
|
||
|
||
namespace OrpaonVision.SiteApp.Runtime.Services;
|
||
|
||
/// <summary>
|
||
/// 人工复位放行服务实现,集成状态机和审计功能。
|
||
/// </summary>
|
||
public sealed class ManualOverrideService : IManualOverrideService
|
||
{
|
||
private readonly ILogger<ManualOverrideService> _logger;
|
||
private readonly IRuntimeStateMachineService _stateMachineService;
|
||
private readonly RuntimeOptions _options;
|
||
private readonly ConcurrentDictionary<string, object> _overrideCache = new();
|
||
private readonly object _lock = new();
|
||
|
||
public ManualOverrideService(
|
||
ILogger<ManualOverrideService> logger,
|
||
IOptions<RuntimeOptions> options,
|
||
IRuntimeStateMachineService stateMachineService)
|
||
{
|
||
_logger = logger;
|
||
_options = options.Value;
|
||
_stateMachineService = stateMachineService;
|
||
_logger.LogInformation("人工复位放行服务已初始化");
|
||
}
|
||
|
||
public Task<Result<IReadOnlyList<OverrideableSession>>> GetOverrideableSessionsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, OverrideStatus? overrideStatus = null, CancellationToken cancellationToken = default)
|
||
{
|
||
IReadOnlyList<OverrideableSession> sessions = Array.Empty<OverrideableSession>();
|
||
return Task.FromResult(Result<IReadOnlyList<OverrideableSession>>.Success(sessions));
|
||
}
|
||
|
||
public Task<Result<OverridePermission>> GetOverridePermissionAsync(Guid sessionId, string operatorId, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("获取会话复位放行权限:会话ID={SessionId},操作员ID={OperatorId}", sessionId, operatorId);
|
||
|
||
// 检查当前状态机状态是否允许人工干预
|
||
var currentState = _stateMachineService.GetCurrentState();
|
||
var canIntervene = _stateMachineService.CanExecuteOperation(StateTrigger.ManualIntervention);
|
||
|
||
if (!canIntervene)
|
||
{
|
||
var permission = new OverridePermission
|
||
{
|
||
PermissionId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
OperatorId = operatorId,
|
||
OperatorName = operatorId,
|
||
OperatorPermissionLevel = OperatorPermissionLevel.Operator,
|
||
HasPermission = false,
|
||
PermissionReason = $"当前状态 {currentState} 不允许人工干预"
|
||
};
|
||
return Task.FromResult(Result<OverridePermission>.Success(permission));
|
||
}
|
||
|
||
// 检查操作员权限级别
|
||
var permissionLevel = GetOperatorPermissionLevel(operatorId);
|
||
var hasPermission = CheckOverridePermission(sessionId, operatorId, permissionLevel);
|
||
|
||
var result = new OverridePermission
|
||
{
|
||
PermissionId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
OperatorId = operatorId,
|
||
OperatorName = operatorId,
|
||
OperatorPermissionLevel = permissionLevel,
|
||
HasPermission = hasPermission,
|
||
PermissionReason = hasPermission
|
||
? $"权限检查通过,当前状态 {currentState} 允许干预"
|
||
: $"权限不足,需要 {OperatorPermissionLevel.Administrator} 级别权限"
|
||
};
|
||
|
||
_logger.LogInformation("复位放行权限获取完成:会话ID={SessionId},操作员ID={OperatorId},是否有权限={HasPermission},权限级别={PermissionLevel},当前状态={CurrentState}",
|
||
sessionId, operatorId, result.HasPermission, permissionLevel, currentState);
|
||
|
||
return Task.FromResult(Result<OverridePermission>.Success(result));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取复位放行权限失败。TraceId: {TraceId}", traceId);
|
||
return Task.FromResult(Result<OverridePermission>.FailWithTrace("GET_OVERRIDE_PERMISSION_FAILED", "获取复位放行权限失败", traceId));
|
||
}
|
||
}
|
||
|
||
public Task<Result<OverrideValidationResult>> ValidateOverrideConditionsAsync(Guid sessionId, ManualOverrideRequest overrideRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
var result = new OverrideValidationResult
|
||
{
|
||
ValidationId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
RequestId = overrideRequest.RequestId,
|
||
IsValid = true,
|
||
ValidationResult = ValidationResult.Pass,
|
||
ValidationMessage = "最小实现:验证通过",
|
||
ValidationTimeUtc = DateTime.UtcNow,
|
||
ValidationElapsedMs = 0
|
||
};
|
||
return Task.FromResult(Result<OverrideValidationResult>.Success(result));
|
||
}
|
||
|
||
public async Task<Result<ManualOverrideResult>> ExecuteManualOverrideAsync(ManualOverrideRequest overrideRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("执行人工复位放行:请求ID={RequestId},会话ID={SessionId},操作员ID={OperatorId},干预类型={OverrideType}",
|
||
overrideRequest.RequestId, overrideRequest.SessionId, overrideRequest.OperatorId, overrideRequest.OverrideType);
|
||
|
||
var startTime = DateTime.UtcNow;
|
||
|
||
// 步骤1:权限校验
|
||
var permissionResult = await GetOverridePermissionAsync(overrideRequest.SessionId, overrideRequest.OperatorId, cancellationToken);
|
||
if (!permissionResult.IsSuccess)
|
||
{
|
||
return Result<ManualOverrideResult>.FailWithTrace(permissionResult.Code, permissionResult.Message, permissionResult.TraceId);
|
||
}
|
||
|
||
if (!permissionResult.Data.HasPermission)
|
||
{
|
||
return Result<ManualOverrideResult>.Fail("PERMISSION_DENIED", permissionResult.Data.PermissionReason);
|
||
}
|
||
|
||
// 步骤2:条件验证
|
||
var validationResult = await ValidateOverrideConditionsAsync(overrideRequest.SessionId, overrideRequest, cancellationToken);
|
||
if (!validationResult.IsSuccess)
|
||
{
|
||
return Result<ManualOverrideResult>.FailWithTrace(validationResult.Code, validationResult.Message, validationResult.TraceId);
|
||
}
|
||
|
||
if (!validationResult.Data.IsValid)
|
||
{
|
||
return Result<ManualOverrideResult>.Fail("VALIDATION_FAILED", validationResult.Data.ValidationMessage);
|
||
}
|
||
|
||
// 步骤3:状态迁移
|
||
var stateTransitionResult = await ExecuteStateTransitionAsync(overrideRequest, cancellationToken);
|
||
if (!stateTransitionResult.IsSuccess)
|
||
{
|
||
return Result<ManualOverrideResult>.FailWithTrace(stateTransitionResult.Code, stateTransitionResult.Message, stateTransitionResult.TraceId);
|
||
}
|
||
|
||
// 步骤4:执行具体干预操作
|
||
var overrideResult = await ExecuteOverrideOperationAsync(overrideRequest, cancellationToken);
|
||
|
||
// 步骤5:审计记录
|
||
await LogOverrideAuditAsync(overrideRequest, overrideResult, startTime, cancellationToken);
|
||
|
||
var elapsed = DateTime.UtcNow - startTime;
|
||
var result = new ManualOverrideResult
|
||
{
|
||
OverrideId = Guid.NewGuid(),
|
||
RequestId = overrideRequest.RequestId,
|
||
SessionId = overrideRequest.SessionId,
|
||
OverrideResult = overrideResult,
|
||
OverrideStatus = overrideResult == OverrideResult.Success ? OverrideStatus.Overridden : OverrideStatus.Pending,
|
||
OverrideMessage = GetOverrideMessage(overrideResult),
|
||
ExecutionTimeUtc = DateTime.UtcNow,
|
||
ExecutionElapsedMs = (long)elapsed.TotalMilliseconds,
|
||
Executor = overrideRequest.OperatorName,
|
||
AffectedSessionStatus = GetSessionStatusAfterOverride(overrideRequest.OverrideType)
|
||
};
|
||
|
||
_logger.LogInformation("人工复位放行执行完成:请求ID={RequestId},干预类型={OverrideType},结果={OverrideResult},耗时={ElapsedMs}ms",
|
||
overrideRequest.RequestId, overrideRequest.OverrideType, overrideResult, elapsed.TotalMilliseconds);
|
||
|
||
return Result<ManualOverrideResult>.Success(result);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "执行人工复位放行失败。TraceId: {TraceId}", traceId);
|
||
return Result<ManualOverrideResult>.FailWithTrace("EXECUTE_MANUAL_OVERRIDE_FAILED", "执行人工复位放行失败", traceId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行状态迁移。
|
||
/// </summary>
|
||
private async Task<Result> ExecuteStateTransitionAsync(ManualOverrideRequest overrideRequest, CancellationToken cancellationToken)
|
||
{
|
||
try
|
||
{
|
||
var currentState = _stateMachineService.GetCurrentState();
|
||
|
||
// 统一触发“人工干预”状态转换
|
||
var triggerResult = _stateMachineService.TriggerTransition(
|
||
StateTrigger.ManualIntervention,
|
||
$"人工干预: {overrideRequest.OverrideType}");
|
||
|
||
if (!triggerResult.IsSuccess)
|
||
{
|
||
_logger.LogWarning("状态迁移失败:当前状态={CurrentState},干预类型={OverrideType},错误={Error}",
|
||
currentState, overrideRequest.OverrideType, triggerResult.Message);
|
||
return Result.Fail("STATE_TRANSITION_FAILED", triggerResult.Message);
|
||
}
|
||
|
||
_logger.LogInformation("状态迁移成功:从 {PreviousState} 迁移到 {NewState},干预类型={OverrideType}",
|
||
triggerResult.Data?.PreviousState, triggerResult.Data?.NewState, overrideRequest.OverrideType);
|
||
|
||
return Result.Success();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "执行状态迁移失败。TraceId: {TraceId}", traceId);
|
||
return Result.FailWithTrace("STATE_TRANSITION_ERROR", "执行状态迁移失败", traceId);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行具体干预操作。
|
||
/// </summary>
|
||
private async Task<OverrideResult> ExecuteOverrideOperationAsync(ManualOverrideRequest overrideRequest, CancellationToken cancellationToken)
|
||
{
|
||
try
|
||
{
|
||
// 根据干预类型执行具体操作
|
||
var result = overrideRequest.OverrideType switch
|
||
{
|
||
OverrideType.ResetAndRelease => await ExecuteResetOperationAsync(overrideRequest, cancellationToken),
|
||
OverrideType.ForcePass => await ExecuteReleaseOperationAsync(overrideRequest, cancellationToken),
|
||
OverrideType.SkipInspection => await ExecuteSkipLayerOperationAsync(overrideRequest, cancellationToken),
|
||
_ => OverrideResult.Success // 默认成功
|
||
};
|
||
|
||
_logger.LogDebug("干预操作执行完成:干预类型={OverrideType},结果={Result}", overrideRequest.OverrideType, result);
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "干预操作执行失败:干预类型={OverrideType}", overrideRequest.OverrideType);
|
||
return OverrideResult.Failed;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行放行操作。
|
||
/// </summary>
|
||
private async Task<OverrideResult> ExecuteReleaseOperationAsync(ManualOverrideRequest overrideRequest, CancellationToken cancellationToken)
|
||
{
|
||
// 触发人工干预完成状态转换,返回运行状态
|
||
var completionResult = _stateMachineService.TriggerTransition(StateTrigger.ManualInterventionCompleted, "人工放行完成");
|
||
|
||
if (completionResult.IsSuccess)
|
||
{
|
||
_logger.LogInformation("放行操作完成:会话ID={SessionId},操作员={OperatorId}",
|
||
overrideRequest.SessionId, overrideRequest.OperatorId);
|
||
return OverrideResult.Success;
|
||
}
|
||
else
|
||
{
|
||
_logger.LogWarning("放行操作失败:{Error}", completionResult.Message);
|
||
return OverrideResult.Failed;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行复位操作。
|
||
/// </summary>
|
||
private async Task<OverrideResult> ExecuteResetOperationAsync(ManualOverrideRequest overrideRequest, CancellationToken cancellationToken)
|
||
{
|
||
// 触发重置状态转换
|
||
var resetResult = _stateMachineService.TriggerTransition(StateTrigger.Reset, "人工复位");
|
||
|
||
if (resetResult.IsSuccess)
|
||
{
|
||
_logger.LogInformation("复位操作完成:会话ID={SessionId},操作员={OperatorId}",
|
||
overrideRequest.SessionId, overrideRequest.OperatorId);
|
||
return OverrideResult.Success;
|
||
}
|
||
else
|
||
{
|
||
_logger.LogWarning("复位操作失败:{Error}", resetResult.Message);
|
||
return OverrideResult.Failed;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行跳层操作。
|
||
/// </summary>
|
||
private async Task<OverrideResult> ExecuteSkipLayerOperationAsync(ManualOverrideRequest overrideRequest, CancellationToken cancellationToken)
|
||
{
|
||
// 先完成人工干预,然后移动到下一层
|
||
var completionResult = _stateMachineService.TriggerTransition(StateTrigger.ManualInterventionCompleted, "人工跳层完成");
|
||
|
||
if (completionResult.IsSuccess)
|
||
{
|
||
var nextLayerResult = _stateMachineService.TriggerTransition(StateTrigger.MoveToNextLayer, "人工跳层到下一层");
|
||
|
||
if (nextLayerResult.IsSuccess)
|
||
{
|
||
_logger.LogInformation("跳层操作完成:会话ID={SessionId},操作员={OperatorId},当前层级={CurrentLayer}",
|
||
overrideRequest.SessionId, overrideRequest.OperatorId, _stateMachineService.GetCurrentLayer());
|
||
return OverrideResult.Success;
|
||
}
|
||
else
|
||
{
|
||
_logger.LogWarning("跳层操作失败:{Error}", nextLayerResult.Message);
|
||
return OverrideResult.Failed;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_logger.LogWarning("跳层操作失败(人工干预完成阶段):{Error}", completionResult.Message);
|
||
return OverrideResult.Failed;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 记录审计日志。
|
||
/// </summary>
|
||
private async Task LogOverrideAuditAsync(ManualOverrideRequest request, OverrideResult result, DateTime startTime, CancellationToken cancellationToken)
|
||
{
|
||
try
|
||
{
|
||
var currentState = _stateMachineService.GetCurrentState();
|
||
var currentLayer = _stateMachineService.GetCurrentLayer();
|
||
|
||
var auditLog = new OverrideAuditLog
|
||
{
|
||
LogId = Guid.NewGuid(),
|
||
SessionId = request.SessionId,
|
||
OverrideId = Guid.NewGuid(),
|
||
OperatorId = request.OperatorId,
|
||
OperatorName = request.OperatorName,
|
||
AuditLevel = result == OverrideResult.Success ? CoreAuditLevel.Info : CoreAuditLevel.Error,
|
||
AuditType = AuditType.OverrideExecuted,
|
||
AuditMessage = "人工干预执行",
|
||
AuditDetails = JsonSerializer.Serialize(new
|
||
{
|
||
request.RequestId,
|
||
request.OverrideType,
|
||
request.TargetStatus,
|
||
result,
|
||
elapsed_ms = (long)(DateTime.UtcNow - startTime).TotalMilliseconds,
|
||
state = currentState.ToString(),
|
||
layer = currentLayer,
|
||
reason = request.OverrideReason
|
||
}),
|
||
AuditTimeUtc = DateTime.UtcNow,
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["request_source"] = "ManualOverrideService",
|
||
["execution_elapsed_ms"] = (long)(DateTime.UtcNow - startTime).TotalMilliseconds,
|
||
["state"] = currentState.ToString(),
|
||
["layer"] = currentLayer,
|
||
["integration_with_state_machine"] = true
|
||
}
|
||
};
|
||
|
||
// 这里应该调用审计服务记录日志
|
||
// 暂时只记录到日志文件
|
||
_logger.LogInformation("人工干预审计记录:审计ID={AuditId},会话ID={SessionId},操作员={OperatorId},干预类型={OverrideType},结果={Result},耗时={ElapsedMs}ms",
|
||
auditLog.LogId, auditLog.SessionId, auditLog.OperatorId, request.OverrideType, result, (long)(DateTime.UtcNow - startTime).TotalMilliseconds);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "记录人工干预审计日志失败");
|
||
}
|
||
}
|
||
|
||
public async Task<Result<BatchManualOverrideResult>> ExecuteBatchManualOverrideAsync(IReadOnlyList<ManualOverrideRequest> overrideRequests, CancellationToken cancellationToken = default)
|
||
{
|
||
var results = new List<ManualOverrideResult>();
|
||
foreach (var request in overrideRequests)
|
||
{
|
||
var one = await ExecuteManualOverrideAsync(request, cancellationToken);
|
||
if (one.Data != null)
|
||
{
|
||
results.Add(one.Data);
|
||
}
|
||
}
|
||
|
||
var batch = new BatchManualOverrideResult
|
||
{
|
||
BatchId = Guid.NewGuid(),
|
||
TotalRequestCount = overrideRequests.Count,
|
||
SuccessCount = results.Count,
|
||
FailureCount = Math.Max(0, overrideRequests.Count - results.Count),
|
||
Results = results,
|
||
BatchMessage = "最小实现:批量执行完成",
|
||
BatchExecutionTimeUtc = DateTime.UtcNow,
|
||
BatchExecutionElapsedMs = 0
|
||
};
|
||
|
||
return Result<BatchManualOverrideResult>.Success(batch);
|
||
}
|
||
|
||
public Task<Result<IReadOnlyList<ManualOverrideHistory>>> GetOverrideHistoryAsync(DateTime startTime, DateTime endTime, string? operatorId = null, OverrideResult? overrideResult = null, CancellationToken cancellationToken = default)
|
||
{
|
||
IReadOnlyList<ManualOverrideHistory> history = Array.Empty<ManualOverrideHistory>();
|
||
return Task.FromResult(Result<IReadOnlyList<ManualOverrideHistory>>.Success(history));
|
||
}
|
||
|
||
public Task<Result<ManualOverrideDetail>> GetOverrideDetailAsync(Guid overrideId, CancellationToken cancellationToken = default)
|
||
{
|
||
var detail = new ManualOverrideDetail
|
||
{
|
||
OverrideId = overrideId,
|
||
OverrideResult = new ManualOverrideResult
|
||
{
|
||
OverrideId = overrideId,
|
||
RequestId = Guid.Empty,
|
||
SessionId = Guid.Empty,
|
||
OverrideResult = OverrideResult.Success,
|
||
OverrideStatus = OverrideStatus.Overridden,
|
||
OverrideMessage = "最小实现",
|
||
ExecutionTimeUtc = DateTime.UtcNow,
|
||
ExecutionElapsedMs = 0,
|
||
Executor = string.Empty,
|
||
AffectedSessionStatus = SessionStatus.Completed
|
||
},
|
||
OverrideRequest = new ManualOverrideRequest()
|
||
};
|
||
|
||
return Task.FromResult(Result<ManualOverrideDetail>.Success(detail));
|
||
}
|
||
|
||
public Task<Result<OverrideRevokeResult>> RevokeManualOverrideAsync(Guid overrideId, string revokeReason, string operatorId, CancellationToken cancellationToken = default)
|
||
{
|
||
var result = new OverrideRevokeResult
|
||
{
|
||
RevokeId = Guid.NewGuid(),
|
||
OverrideId = overrideId,
|
||
RevokeResult = RevokeResult.Success,
|
||
RevokeReason = revokeReason,
|
||
RevokeTimeUtc = DateTime.UtcNow,
|
||
Revoker = operatorId,
|
||
RevokeMessage = "最小实现:撤销成功"
|
||
};
|
||
return Task.FromResult(Result<OverrideRevokeResult>.Success(result));
|
||
}
|
||
|
||
public Task<Result<ManualOverrideStatistics>> GetOverrideStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, CancellationToken cancellationToken = default)
|
||
{
|
||
var statistics = new ManualOverrideStatistics
|
||
{
|
||
TimeRange = new TimeRange { StartTime = startTime, EndTime = endTime },
|
||
ProductTypeCode = productTypeCode ?? string.Empty,
|
||
TotalOverrideCount = 0,
|
||
SuccessfulOverrideCount = 0,
|
||
FailedOverrideCount = 0,
|
||
OverridesByType = new Dictionary<OverrideType, int>(),
|
||
OverridesByOperator = new Dictionary<string, OperatorOverrideStatistics>(),
|
||
ByDate = new Dictionary<DateTime, DailyOverrideStatistics>(),
|
||
AverageOverrideElapsedMs = 0,
|
||
MaxOverrideElapsedMs = 0,
|
||
MinOverrideElapsedMs = 0
|
||
};
|
||
return Task.FromResult(Result<ManualOverrideStatistics>.Success(statistics));
|
||
}
|
||
|
||
public Task<Result<IReadOnlyList<OverrideAuditLog>>> GetOverrideAuditLogsAsync(Guid? sessionId = null, Guid? overrideId = null, DateTime? startTime = null, DateTime? endTime = null, CoreAuditLevel? auditLevel = null, CancellationToken cancellationToken = default)
|
||
{
|
||
IReadOnlyList<OverrideAuditLog> logs = Array.Empty<OverrideAuditLog>();
|
||
return Task.FromResult(Result<IReadOnlyList<OverrideAuditLog>>.Success(logs));
|
||
}
|
||
|
||
public Task<Result<ManualOverrideReport>> GenerateOverrideReportAsync(OverrideReportRequest reportRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
var report = new ManualOverrideReport
|
||
{
|
||
ReportId = Guid.NewGuid(),
|
||
ReportType = reportRequest.ReportType,
|
||
ReportTitle = "最小实现报告",
|
||
TimeRange = reportRequest.TimeRange,
|
||
GeneratedAtUtc = DateTime.UtcNow,
|
||
ExecutiveSummary = new ReportExecutiveSummary(),
|
||
Statistics = new ManualOverrideStatistics(),
|
||
TrendAnalysis = new OverrideTrendAnalysis(),
|
||
ComplianceAnalysis = new OverrideComplianceAnalysis(),
|
||
RiskAnalysis = new OverrideRiskAnalysis(),
|
||
ImprovementSuggestions = Array.Empty<OverrideImprovementSuggestion>()
|
||
};
|
||
return Task.FromResult(Result<ManualOverrideReport>.Success(report));
|
||
}
|
||
|
||
public Task<Result<OverrideComplianceCheck>> CheckOverrideComplianceAsync(Guid sessionId, ManualOverrideRequest overrideRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
var result = new OverrideComplianceCheck
|
||
{
|
||
CheckId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
CheckResult = ComplianceCheckResult.Pass,
|
||
ComplianceScore = 1,
|
||
CheckItems = Array.Empty<ComplianceCheckItem>(),
|
||
Violations = Array.Empty<ComplianceViolation>(),
|
||
CheckTimeUtc = DateTime.UtcNow,
|
||
CheckElapsedMs = 0
|
||
};
|
||
return Task.FromResult(Result<OverrideComplianceCheck>.Success(result));
|
||
}
|
||
|
||
public Task<Result<OverrideTemplate>> GetOverrideTemplateAsync(OverrideTemplateType templateType, CancellationToken cancellationToken = default)
|
||
{
|
||
var template = new OverrideTemplate
|
||
{
|
||
TemplateId = Guid.NewGuid(),
|
||
TemplateType = templateType,
|
||
TemplateName = "最小实现模板",
|
||
TemplateDescription = string.Empty,
|
||
IsEnabled = true,
|
||
CreatedAtUtc = DateTime.UtcNow,
|
||
Creator = string.Empty,
|
||
TemplateContent = string.Empty,
|
||
TemplateParameters = Array.Empty<TemplateParameter>(),
|
||
ApplicableConditions = Array.Empty<TemplateCondition>()
|
||
};
|
||
return Task.FromResult(Result<OverrideTemplate>.Success(template));
|
||
}
|
||
|
||
public Task<Result<OverrideTemplateSaveResult>> SaveOverrideTemplateAsync(OverrideTemplate template, CancellationToken cancellationToken = default)
|
||
{
|
||
var result = new OverrideTemplateSaveResult
|
||
{
|
||
TemplateId = template.TemplateId,
|
||
IsSuccess = true,
|
||
SaveMessage = "最小实现:保存成功",
|
||
SaveTimeUtc = DateTime.UtcNow
|
||
};
|
||
|
||
_logger.LogDebug("最小实现:保存模板 {TemplateId}", template.TemplateId);
|
||
return Task.FromResult(Result<OverrideTemplateSaveResult>.Success(result));
|
||
}
|
||
|
||
#region 辅助方法
|
||
|
||
/// <summary>
|
||
/// 获取操作员权限级别。
|
||
/// </summary>
|
||
private OperatorPermissionLevel GetOperatorPermissionLevel(string operatorId)
|
||
{
|
||
// 这里应该从权限系统获取操作员权限级别
|
||
// 暂时使用硬编码逻辑
|
||
return operatorId.ToLower() switch
|
||
{
|
||
var id when id.Contains("admin") => OperatorPermissionLevel.Administrator,
|
||
var id when id.Contains("supervisor") => OperatorPermissionLevel.Supervisor,
|
||
var id when id.Contains("operator") => OperatorPermissionLevel.Operator,
|
||
_ => OperatorPermissionLevel.Operator
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查覆盖权限。
|
||
/// </summary>
|
||
private bool CheckOverridePermission(Guid sessionId, string operatorId, OperatorPermissionLevel permissionLevel)
|
||
{
|
||
// 管理员和主管拥有所有权限
|
||
if (permissionLevel == OperatorPermissionLevel.Administrator ||
|
||
permissionLevel == OperatorPermissionLevel.Supervisor)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
// 操作员需要特殊权限检查
|
||
if (permissionLevel == OperatorPermissionLevel.Operator)
|
||
{
|
||
// 这里可以添加更复杂的权限检查逻辑
|
||
// 例如:检查会话状态、时间窗口、产品类型等
|
||
return true; // 暂时允许
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取干预结果消息。
|
||
/// </summary>
|
||
private string GetOverrideMessage(OverrideResult result)
|
||
{
|
||
return result switch
|
||
{
|
||
OverrideResult.Success => "干预操作成功",
|
||
OverrideResult.Failed => "干预操作失败",
|
||
OverrideResult.PartialSuccess => "干预操作部分成功",
|
||
OverrideResult.Cancelled => "干预操作已取消",
|
||
_ => "干预操作状态未知"
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取干预后会话状态。
|
||
/// </summary>
|
||
private SessionStatus GetSessionStatusAfterOverride(OverrideType overrideType)
|
||
{
|
||
return overrideType switch
|
||
{
|
||
OverrideType.ResetAndRelease => SessionStatus.Active,
|
||
OverrideType.ForcePass => SessionStatus.Completed,
|
||
OverrideType.SkipInspection => SessionStatus.Active,
|
||
_ => SessionStatus.Active
|
||
};
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
|
||
#if false
|
||
|
||
/// <summary>
|
||
/// 人工复位放行服务实现。
|
||
/// </summary>
|
||
public sealed class ManualOverrideService : IManualOverrideService
|
||
{
|
||
private readonly ILogger<ManualOverrideService> _logger;
|
||
private readonly RuntimeOptions _options;
|
||
private readonly ConcurrentDictionary<string, object> _overrideCache = new();
|
||
private readonly object _lock = new();
|
||
|
||
/// <summary>
|
||
/// 构造函数。
|
||
/// </summary>
|
||
public ManualOverrideService(ILogger<ManualOverrideService> logger, IOptions<RuntimeOptions> options)
|
||
{
|
||
_logger = logger;
|
||
_options = options.Value;
|
||
_logger.LogInformation("人工复位放行服务已初始化");
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<IReadOnlyList<OverrideableSession>>> GetOverrideableSessionsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, OverrideStatus? overrideStatus = null, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("获取可复位放行的会话列表:开始时间={StartTime},结束时间={EndTime},产品类型={ProductTypeCode},复位状态={OverrideStatus}",
|
||
startTime, endTime, productTypeCode, overrideStatus);
|
||
|
||
var cacheKey = $"overrideable_sessions_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{productTypeCode}_{overrideStatus}";
|
||
|
||
if (_options.EnableHistoryTraceCache && _overrideCache.TryGetValue(cacheKey, out var cached))
|
||
{
|
||
_logger.LogDebug("从缓存获取可复位放行的会话列表");
|
||
return Result.Success((IReadOnlyList<OverrideableSession>)cached);
|
||
}
|
||
|
||
var overrideableSessions = await GenerateOverrideableSessionsAsync(startTime, endTime, productTypeCode, overrideStatus, cancellationToken);
|
||
|
||
if (_options.EnableHistoryTraceCache)
|
||
{
|
||
_overrideCache.TryAdd(cacheKey, overrideableSessions);
|
||
}
|
||
|
||
_logger.LogInformation("可复位放行的会话列表获取完成:会话数量={SessionCount}", overrideableSessions.Count);
|
||
return Result.Success(overrideableSessions);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取可复位放行的会话列表失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_OVERRIDABLE_SESSIONS_FAILED", "获取可复位放行的会话列表失败", traceId);
|
||
return Result.FailWithTrace<IReadOnlyList<OverrideableSession>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<OverridePermission>> GetOverridePermissionAsync(Guid sessionId, string operatorId, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("获取会话复位放行权限:会话ID={SessionId},操作员ID={OperatorId}", sessionId, operatorId);
|
||
|
||
var cacheKey = $"override_permission_{sessionId}_{operatorId}";
|
||
|
||
if (_options.EnableHistoryTraceCache && _overrideCache.TryGetValue(cacheKey, out var cached))
|
||
{
|
||
_logger.LogDebug("从缓存获取复位放行权限");
|
||
return Result.Success((OverridePermission)cached);
|
||
}
|
||
|
||
var permission = await GenerateOverridePermissionAsync(sessionId, operatorId, cancellationToken);
|
||
|
||
if (_options.EnableHistoryTraceCache)
|
||
{
|
||
_overrideCache.TryAdd(cacheKey, permission);
|
||
}
|
||
|
||
_logger.LogInformation("复位放行权限获取完成:会话ID={SessionId},操作员ID={OperatorId},是否有权限={HasPermission}",
|
||
sessionId, operatorId, permission.HasPermission);
|
||
|
||
return Result.Success(permission);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取复位放行权限失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_OVERRIDE_PERMISSION_FAILED", "获取复位放行权限失败", traceId);
|
||
return Result.FailWithTrace<OverridePermission>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<OverrideValidationResult>> ValidateOverrideConditionsAsync(Guid sessionId, ManualOverrideRequest overrideRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("验证复位放行条件:会话ID={SessionId},请求ID={RequestId}", sessionId, overrideRequest.RequestId);
|
||
|
||
var validationResult = await GenerateOverrideValidationResultAsync(sessionId, overrideRequest, cancellationToken);
|
||
|
||
_logger.LogInformation("复位放行条件验证完成:会话ID={SessionId},是否通过={IsValid},验证结果={ValidationResult}",
|
||
sessionId, validationResult.IsValid, validationResult.ValidationResult);
|
||
|
||
return Result.Success(validationResult);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "验证复位放行条件失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "VALIDATE_OVERRIDE_CONDITIONS_FAILED", "验证复位放行条件失败", traceId);
|
||
return Result.FailWithTrace<OverrideValidationResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<ManualOverrideResult>> ExecuteManualOverrideAsync(ManualOverrideRequest overrideRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("执行人工复位放行:请求ID={RequestId},会话ID={SessionId},操作员ID={OperatorId}",
|
||
overrideRequest.RequestId, overrideRequest.SessionId, overrideRequest.OperatorId);
|
||
|
||
var startTime = DateTime.UtcNow;
|
||
var overrideResult = await GenerateManualOverrideResultAsync(overrideRequest, cancellationToken);
|
||
var elapsed = DateTime.UtcNow - startTime;
|
||
|
||
// 记录审计日志
|
||
await LogOverrideAuditAsync(overrideRequest, overrideResult, elapsed, cancellationToken);
|
||
|
||
_logger.LogInformation("人工复位放行执行完成:请求ID={RequestId},复位结果={OverrideResult},耗时={ElapsedMs}ms",
|
||
overrideRequest.RequestId, overrideResult.OverrideResult, elapsed.TotalMilliseconds);
|
||
|
||
return Result.Success(overrideResult);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "执行人工复位放行失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "EXECUTE_MANUAL_OVERRIDE_FAILED", "执行人工复位放行失败", traceId);
|
||
return Result.FailWithTrace<ManualOverrideResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<BatchManualOverrideResult>> ExecuteBatchManualOverrideAsync(IReadOnlyList<ManualOverrideRequest> overrideRequests, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("执行批量人工复位放行:请求数量={RequestCount}", overrideRequests.Count);
|
||
|
||
var startTime = DateTime.UtcNow;
|
||
var results = new List<ManualOverrideResult>();
|
||
var successCount = 0;
|
||
var failureCount = 0;
|
||
|
||
foreach (var request in overrideRequests)
|
||
{
|
||
try
|
||
{
|
||
var result = await ExecuteManualOverrideAsync(request, cancellationToken);
|
||
if (result.IsSuccess)
|
||
{
|
||
results.Add(result.Value);
|
||
if (result.Value.OverrideResult == OverrideResult.Success)
|
||
{
|
||
successCount++;
|
||
}
|
||
else
|
||
{
|
||
failureCount++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
failureCount++;
|
||
_logger.LogWarning("批量复位中的单个请求失败:请求ID={RequestId},错误={Error}",
|
||
request.RequestId, result.Message);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
failureCount++;
|
||
_logger.LogError(ex, "批量复位中的单个请求异常:请求ID={RequestId}", request.RequestId);
|
||
}
|
||
}
|
||
|
||
var elapsed = DateTime.UtcNow - startTime;
|
||
var batchResult = new BatchManualOverrideResult
|
||
{
|
||
BatchId = Guid.NewGuid(),
|
||
TotalRequestCount = overrideRequests.Count,
|
||
SuccessCount = successCount,
|
||
FailureCount = failureCount,
|
||
Results = results.AsReadOnly(),
|
||
BatchMessage = $"批量操作完成:成功{successCount}个,失败{failureCount}个",
|
||
BatchExecutionTimeUtc = DateTime.UtcNow,
|
||
BatchExecutionElapsedMs = (long)elapsed.TotalMilliseconds,
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = elapsed.TotalMilliseconds,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
|
||
_logger.LogInformation("批量人工复位放行执行完成:请求数量={RequestCount},成功数={SuccessCount},失败数={FailureCount},耗时={ElapsedMs}ms",
|
||
overrideRequests.Count, successCount, failureCount, elapsed.TotalMilliseconds);
|
||
|
||
return Result.Success(batchResult);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "执行批量人工复位放行失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "EXECUTE_BATCH_MANUAL_OVERRIDE_FAILED", "执行批量人工复位放行失败", traceId);
|
||
return Result.FailWithTrace<BatchManualOverrideResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<IReadOnlyList<ManualOverrideHistory>>> GetOverrideHistoryAsync(DateTime startTime, DateTime endTime, string? operatorId = null, OverrideResult? overrideResult = null, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("获取复位放行历史记录:开始时间={StartTime},结束时间={EndTime},操作员ID={OperatorId},复位结果={OverrideResult}",
|
||
startTime, endTime, operatorId, overrideResult);
|
||
|
||
var cacheKey = $"override_history_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{operatorId}_{overrideResult}";
|
||
|
||
if (_options.EnableHistoryTraceCache && _overrideCache.TryGetValue(cacheKey, out var cached))
|
||
{
|
||
_logger.LogDebug("从缓存获取复位放行历史记录");
|
||
return Result.Success((IReadOnlyList<ManualOverrideHistory>)cached);
|
||
}
|
||
|
||
var overrideHistory = await GenerateOverrideHistoryAsync(startTime, endTime, operatorId, overrideResult, cancellationToken);
|
||
|
||
if (_options.EnableHistoryTraceCache)
|
||
{
|
||
_overrideCache.TryAdd(cacheKey, overrideHistory);
|
||
}
|
||
|
||
_logger.LogInformation("复位放行历史记录获取完成:记录数量={RecordCount}", overrideHistory.Count);
|
||
return Result.Success(overrideHistory);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取复位放行历史记录失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_OVERRIDE_HISTORY_FAILED", "获取复位放行历史记录失败", traceId);
|
||
return Result.FailWithTrace<IReadOnlyList<ManualOverrideHistory>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<ManualOverrideDetail>> GetOverrideDetailAsync(Guid overrideId, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("获取复位放行详细信息:复位ID={OverrideId}", overrideId);
|
||
|
||
var cacheKey = $"override_detail_{overrideId}";
|
||
|
||
if (_options.EnableHistoryTraceCache && _overrideCache.TryGetValue(cacheKey, out var cached))
|
||
{
|
||
_logger.LogDebug("从缓存获取复位放行详细信息");
|
||
return Result.Success((ManualOverrideDetail)cached);
|
||
}
|
||
|
||
var overrideDetail = await GenerateOverrideDetailAsync(overrideId, cancellationToken);
|
||
|
||
if (_options.EnableHistoryTraceCache)
|
||
{
|
||
_overrideCache.TryAdd(cacheKey, overrideDetail);
|
||
}
|
||
|
||
_logger.LogInformation("复位放行详细信息获取完成:复位ID={OverrideId},复位结果={OverrideResult}",
|
||
overrideId, overrideDetail.OverrideResult.OverrideResult);
|
||
|
||
return Result.Success(overrideDetail);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取复位放行详细信息失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_OVERRIDE_DETAIL_FAILED", "获取复位放行详细信息失败", traceId);
|
||
return Result.FailWithTrace<ManualOverrideDetail>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<OverrideRevokeResult>> RevokeManualOverrideAsync(Guid overrideId, string revokeReason, string operatorId, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("撤销人工复位放行:复位ID={OverrideId},撤销原因={RevokeReason},操作员ID={OperatorId}",
|
||
overrideId, revokeReason, operatorId);
|
||
|
||
var revokeResult = await GenerateOverrideRevokeResultAsync(overrideId, revokeReason, operatorId, cancellationToken);
|
||
|
||
// 记录撤销审计日志
|
||
await LogRevokeAuditAsync(overrideId, revokeReason, operatorId, revokeResult, cancellationToken);
|
||
|
||
_logger.LogInformation("人工复位放行撤销完成:复位ID={OverrideId},撤销结果={RevokeResult}",
|
||
overrideId, revokeResult.RevokeResult);
|
||
|
||
return Result.Success(revokeResult);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "撤销人工复位放行失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "REVOKE_MANUAL_OVERRIDE_FAILED", "撤销人工复位放行失败", traceId);
|
||
return Result.FailWithTrace<OverrideRevokeResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<ManualOverrideStatistics>> GetOverrideStatisticsAsync(DateTime startTime, DateTime endTime, string? productTypeCode = null, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("获取复位放行统计信息:开始时间={StartTime},结束时间={EndTime},产品类型={ProductTypeCode}",
|
||
startTime, endTime, productTypeCode);
|
||
|
||
var cacheKey = $"override_statistics_{startTime:yyyyMMddHHmm}_{endTime:yyyyMMddHHmm}_{productTypeCode}";
|
||
|
||
if (_options.EnableHistoryTraceCache && _overrideCache.TryGetValue(cacheKey, out var cached))
|
||
{
|
||
_logger.LogDebug("从缓存获取复位放行统计信息");
|
||
return Result.Success((ManualOverrideStatistics)cached);
|
||
}
|
||
|
||
var statistics = await GenerateOverrideStatisticsAsync(startTime, endTime, productTypeCode, cancellationToken);
|
||
|
||
if (_options.EnableHistoryTraceCache)
|
||
{
|
||
_overrideCache.TryAdd(cacheKey, statistics);
|
||
}
|
||
|
||
_logger.LogInformation("复位放行统计信息获取完成:总复位数={TotalCount},成功率={SuccessRate:F2}%,平均耗时={AvgElapsedMs:F2}ms",
|
||
statistics.TotalOverrideCount, statistics.SuccessRate, statistics.AverageOverrideElapsedMs);
|
||
|
||
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_OVERRIDE_STATISTICS_FAILED", "获取复位放行统计信息失败", traceId);
|
||
return Result.FailWithTrace<ManualOverrideStatistics>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<IReadOnlyList<OverrideAuditLog>>> GetOverrideAuditLogsAsync(Guid? sessionId = null, Guid? overrideId = null, DateTime? startTime = null, DateTime? endTime = null, OrpaonVision.Core.ManualOverride.AuditLevel? auditLevel = null, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("获取复位放行审计日志:会话ID={SessionId},复位ID={OverrideId},开始时间={StartTime},结束时间={EndTime},审计级别={AuditLevel}",
|
||
sessionId, overrideId, startTime, endTime, auditLevel);
|
||
|
||
var auditLogs = await GenerateOverrideAuditLogsAsync(sessionId, overrideId, startTime, endTime, auditLevel, cancellationToken);
|
||
|
||
_logger.LogInformation("复位放行审计日志获取完成:日志数量={LogCount}", auditLogs.Count);
|
||
return Result.Success(auditLogs);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取复位放行审计日志失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_OVERRIDE_AUDIT_LOGS_FAILED", "获取复位放行审计日志失败", traceId);
|
||
return Result.FailWithTrace<IReadOnlyList<OverrideAuditLog>>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<ManualOverrideReport>> GenerateOverrideReportAsync(OverrideReportRequest reportRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("生成复位放行报告:请求ID={RequestId},报告类型={ReportType}",
|
||
reportRequest.RequestId, reportRequest.ReportType);
|
||
|
||
var report = await GenerateManualOverrideReportAsync(reportRequest, 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, "GENERATE_OVERRIDE_REPORT_FAILED", "生成复位放行报告失败", traceId);
|
||
return Result.FailWithTrace<ManualOverrideReport>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<OverrideComplianceCheck>> CheckOverrideComplianceAsync(Guid sessionId, ManualOverrideRequest overrideRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("检查复位放行合规性:会话ID={SessionId},请求ID={RequestId}", sessionId, overrideRequest.RequestId);
|
||
|
||
var complianceCheck = await GenerateOverrideComplianceCheckAsync(sessionId, overrideRequest, cancellationToken);
|
||
|
||
_logger.LogInformation("复位放行合规性检查完成:会话ID={SessionId},检查结果={CheckResult},合规评分={ComplianceScore:F2}",
|
||
sessionId, complianceCheck.CheckResult, complianceCheck.ComplianceScore);
|
||
|
||
return Result.Success(complianceCheck);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "检查复位放行合规性失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "CHECK_OVERRIDE_COMPLIANCE_FAILED", "检查复位放行合规性失败", traceId);
|
||
return Result.FailWithTrace<OverrideComplianceCheck>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<OverrideTemplate>> GetOverrideTemplateAsync(OverrideTemplateType templateType, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("获取复位放行模板:模板类型={TemplateType}", templateType);
|
||
|
||
var template = await GenerateOverrideTemplateAsync(templateType, cancellationToken);
|
||
|
||
_logger.LogInformation("复位放行模板获取完成:模板ID={TemplateId},模板名称={TemplateName}",
|
||
template.TemplateId, template.TemplateName);
|
||
|
||
return Result.Success(template);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取复位放行模板失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_OVERRIDE_TEMPLATE_FAILED", "获取复位放行模板失败", traceId);
|
||
return Result.FailWithTrace<OverrideTemplate>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<Result<OverrideTemplateSaveResult>> SaveOverrideTemplateAsync(OverrideTemplate template, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
_logger.LogInformation("保存复位放行模板:模板ID={TemplateId},模板名称={TemplateName}",
|
||
template.TemplateId, template.TemplateName);
|
||
|
||
var saveResult = await GenerateOverrideTemplateSaveResultAsync(template, cancellationToken);
|
||
|
||
_logger.LogInformation("复位放行模板保存完成:模板ID={TemplateId},保存结果={IsSuccess}",
|
||
template.TemplateId, saveResult.IsSuccess);
|
||
|
||
return Result.Success(saveResult);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "保存复位放行模板失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "SAVE_OVERRIDE_TEMPLATE_FAILED", "保存复位放行模板失败", traceId);
|
||
return Result.FailWithTrace<OverrideTemplateSaveResult>(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
#region 私有方法
|
||
|
||
/// <summary>
|
||
/// 生成可复位放行的会话列表。
|
||
/// </summary>
|
||
private async Task<IReadOnlyList<OverrideableSession>> GenerateOverrideableSessionsAsync(DateTime startTime, DateTime endTime, string? productTypeCode, OverrideStatus? overrideStatus, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var overrideableSessions = new List<OverrideableSession>();
|
||
var current = startTime;
|
||
|
||
while (current <= endTime)
|
||
{
|
||
var sessionCount = random.Next(3, 10);
|
||
|
||
for (int i = 0; i < sessionCount; i++)
|
||
{
|
||
var status = overrideStatus ?? (OverrideStatus)random.Next(0, 6);
|
||
var sessionStartTime = current.AddHours(random.Next(0, 24)).AddMinutes(random.Next(0, 60));
|
||
var sessionEndTime = status == OverrideStatus.Overridden ? sessionStartTime.AddMinutes(random.Next(30, 120)) : null;
|
||
|
||
overrideableSessions.Add(new OverrideableSession
|
||
{
|
||
SessionId = Guid.NewGuid(),
|
||
ProductSerialNumber = $"SN{random.Next(100000, 999999)}",
|
||
ProductTypeCode = productTypeCode ?? $"PT{random.Next(1, 10)}",
|
||
SessionStatus = SessionStatus.Completed,
|
||
FinalJudgmentResult = FinalJudgmentResult.Fail,
|
||
SessionStartTimeUtc = sessionStartTime,
|
||
SessionEndTimeUtc = sessionEndTime,
|
||
OverrideStatus = status,
|
||
OverrideReasons = GenerateOverrideReasons(random),
|
||
OverridePriority = (OverridePriority)random.Next(0, 4),
|
||
RequiredPermissionLevel = (OperatorPermissionLevel)random.Next(1, 6),
|
||
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),
|
||
NGReasons = GenerateNGReasons(random),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 25,
|
||
["data_source"] = "simulated"
|
||
}
|
||
});
|
||
}
|
||
|
||
current = current.AddDays(1);
|
||
}
|
||
|
||
return overrideableSessions.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位权限。
|
||
/// </summary>
|
||
private async Task<OverridePermission> GenerateOverridePermissionAsync(Guid sessionId, string operatorId, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var operatorLevel = (OperatorPermissionLevel)random.Next(0, 6);
|
||
var hasPermission = operatorLevel >= OperatorPermissionLevel.TeamLeader;
|
||
|
||
return new OverridePermission
|
||
{
|
||
PermissionId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
OperatorId = operatorId,
|
||
OperatorName = $"操作员{random.Next(1, 10)}",
|
||
OperatorPermissionLevel = operatorLevel,
|
||
HasPermission = hasPermission,
|
||
PermissionReason = hasPermission ? "权限满足要求" : "权限不足",
|
||
PermissionRestrictions = hasPermission ? new List<string>() : new List<string> { "需要班组长或更高级别权限" },
|
||
PermissionExpiryUtc = hasPermission ? DateTime.UtcNow.AddHours(8) : null,
|
||
RequireSecondaryConfirmation = !hasPermission && operatorLevel == OperatorPermissionLevel.Technician,
|
||
RequireApprovalProcess = !hasPermission,
|
||
RequiredApprovers = !hasPermission ? new List<string> { $"TL{random.Next(1, 3):D3}" } : new List<string>(),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 15,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位验证结果。
|
||
/// </summary>
|
||
private async Task<OverrideValidationResult> GenerateOverrideValidationResultAsync(Guid sessionId, ManualOverrideRequest overrideRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var isValid = random.NextDouble() > 0.2;
|
||
var validationResult = isValid ? ValidationResult.Pass : (random.NextDouble() > 0.5 ? ValidationResult.Warning : ValidationResult.Fail);
|
||
|
||
return new OverrideValidationResult
|
||
{
|
||
ValidationId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
RequestId = overrideRequest.RequestId,
|
||
IsValid = isValid,
|
||
ValidationResult = validationResult,
|
||
ValidationMessage = isValid ? "验证通过" : (validationResult == ValidationResult.Warning ? "验证通过但有警告" : "验证失败"),
|
||
ValidationDetails = GenerateValidationDetails(random),
|
||
ValidationWarnings = validationResult == ValidationResult.Warning ? new List<string> { "警告1", "警告2" } : new List<string>(),
|
||
ValidationErrors = !isValid ? new List<string> { "错误1", "错误2" } : new List<string>(),
|
||
ValidationTimeUtc = DateTime.UtcNow,
|
||
ValidationElapsedMs = random.Next(100, 1000),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 20,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位结果。
|
||
/// </summary>
|
||
private async Task<ManualOverrideResult> GenerateManualOverrideResultAsync(ManualOverrideRequest overrideRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var isSuccess = random.NextDouble() > 0.1;
|
||
var overrideResult = isSuccess ? OverrideResult.Success : (OverrideResult)random.Next(1, 6);
|
||
|
||
return new ManualOverrideResult
|
||
{
|
||
OverrideId = Guid.NewGuid(),
|
||
RequestId = overrideRequest.RequestId,
|
||
SessionId = overrideRequest.SessionId,
|
||
OverrideResult = overrideResult,
|
||
OverrideStatus = isSuccess ? OverrideStatus.Overridden : (overrideResult == OverrideResult.Rejected ? OverrideStatus.Rejected : OverrideStatus.Pending),
|
||
OverrideMessage = isSuccess ? "复位成功" : "复位失败",
|
||
ExecutionTimeUtc = DateTime.UtcNow,
|
||
ExecutionElapsedMs = random.Next(500, 5000),
|
||
Executor = overrideRequest.OperatorName,
|
||
ExecutionDetails = GenerateExecutionDetails(random),
|
||
AffectedSessionStatus = isSuccess ? SessionStatus.Completed : SessionStatus.Failed,
|
||
FollowUpActions = isSuccess ? new List<string> { "记录日志", "通知相关人员" } : new List<string> { "检查失败原因" },
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 30,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位历史记录。
|
||
/// </summary>
|
||
private async Task<IReadOnlyList<ManualOverrideHistory>> GenerateOverrideHistoryAsync(DateTime startTime, DateTime endTime, string? operatorId, OverrideResult? overrideResult, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var overrideHistory = new List<ManualOverrideHistory>();
|
||
var historyCount = random.Next(10, 50);
|
||
|
||
for (int i = 0; i < historyCount; i++)
|
||
{
|
||
var result = overrideResult ?? (OverrideResult)random.Next(0, 6);
|
||
var overrideTime = startTime.AddMinutes(random.Next(0, (int)(endTime - startTime).TotalMinutes));
|
||
|
||
overrideHistory.Add(new ManualOverrideHistory
|
||
{
|
||
HistoryId = Guid.NewGuid(),
|
||
OverrideId = Guid.NewGuid(),
|
||
SessionId = Guid.NewGuid(),
|
||
RequestId = Guid.NewGuid(),
|
||
OverrideType = (OverrideType)random.Next(0, 8),
|
||
OverrideResult = result,
|
||
OverrideStatus = result == OverrideResult.Success ? OverrideStatus.Overridden : OverrideStatus.Pending,
|
||
OperatorId = operatorId ?? $"OP{random.Next(1, 10):D3}",
|
||
OperatorName = $"操作员{random.Next(1, 10)}",
|
||
OverrideReason = $"复位原因{i + 1}",
|
||
OverrideTimeUtc = overrideTime,
|
||
OverrideElapsedMs = random.Next(500, 5000),
|
||
OverrideMessage = result == OverrideResult.Success ? "复位成功" : "复位失败",
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 18,
|
||
["data_source"] = "simulated"
|
||
}
|
||
});
|
||
}
|
||
|
||
return overrideHistory.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位详细信息。
|
||
/// </summary>
|
||
private async Task<ManualOverrideDetail> GenerateOverrideDetailAsync(Guid overrideId, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var overrideResult = new ManualOverrideResult
|
||
{
|
||
OverrideId = overrideId,
|
||
RequestId = Guid.NewGuid(),
|
||
SessionId = Guid.NewGuid(),
|
||
OverrideResult = OverrideResult.Success,
|
||
OverrideStatus = OverrideStatus.Overridden,
|
||
OverrideMessage = "复位成功",
|
||
ExecutionTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 120)),
|
||
ExecutionElapsedMs = random.Next(500, 5000),
|
||
Executor = $"操作员{random.Next(1, 10)}",
|
||
ExecutionDetails = GenerateExecutionDetails(random),
|
||
AffectedSessionStatus = SessionStatus.Completed
|
||
};
|
||
|
||
var overrideRequest = new ManualOverrideRequest
|
||
{
|
||
RequestId = overrideResult.RequestId,
|
||
SessionId = overrideResult.SessionId,
|
||
OperatorId = $"OP{random.Next(1, 10):D3}",
|
||
OperatorName = overrideResult.Executor,
|
||
OverrideType = (OverrideType)random.Next(0, 8),
|
||
OverrideReason = "复位原因",
|
||
OverrideDescription = "复位描述",
|
||
OverridePriority = (OverridePriority)random.Next(0, 4),
|
||
TargetStatus = SessionStatus.Completed,
|
||
RequestTimeUtc = overrideResult.ExecutionTimeUtc.AddMinutes(-random.Next(5, 30)),
|
||
IsUrgent = random.NextDouble() > 0.8,
|
||
RequireApproval = random.NextDouble() > 0.7
|
||
};
|
||
|
||
return new ManualOverrideDetail
|
||
{
|
||
OverrideId = overrideId,
|
||
OverrideResult = overrideResult,
|
||
OverrideRequest = overrideRequest,
|
||
ValidationResult = GenerateOverrideValidationResultAsync(overrideResult.SessionId, overrideRequest, cancellationToken).Result,
|
||
Permission = GenerateOverridePermissionAsync(overrideResult.SessionId, overrideRequest.OperatorId, cancellationToken).Result,
|
||
ApprovalInfos = GenerateApprovalInfos(random),
|
||
ImpactAnalysis = GenerateOverrideImpactAnalysis(random),
|
||
ComplianceCheck = GenerateOverrideComplianceCheckAsync(overrideResult.SessionId, overrideRequest, cancellationToken).Result,
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 40,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位撤销结果。
|
||
/// </summary>
|
||
private async Task<OverrideRevokeResult> GenerateOverrideRevokeResultAsync(Guid overrideId, string revokeReason, string operatorId, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var revokeResult = random.NextDouble() > 0.1 ? RevokeResult.Success : (RevokeResult)random.Next(1, 5);
|
||
|
||
return new OverrideRevokeResult
|
||
{
|
||
RevokeId = Guid.NewGuid(),
|
||
OverrideId = overrideId,
|
||
RevokeResult = revokeResult,
|
||
RevokeReason = revokeReason,
|
||
RevokeTimeUtc = DateTime.UtcNow,
|
||
Revoker = $"操作员{random.Next(1, 10)}",
|
||
RevokeMessage = revokeResult == RevokeResult.Success ? "撤销成功" : "撤销失败",
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 25,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位统计信息。
|
||
/// </summary>
|
||
private async Task<ManualOverrideStatistics> GenerateOverrideStatisticsAsync(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 totalOverrideCount = random.Next(50, 200);
|
||
var successfulOverrideCount = (int)(totalOverrideCount * (0.7 + random.NextDouble() * 0.25));
|
||
|
||
return new ManualOverrideStatistics
|
||
{
|
||
TimeRange = timeRange,
|
||
ProductTypeCode = productTypeCode ?? "default",
|
||
TotalOverrideCount = totalOverrideCount,
|
||
SuccessfulOverrideCount = successfulOverrideCount,
|
||
FailedOverrideCount = totalOverrideCount - successfulOverrideCount,
|
||
OverridesByType = GenerateOverridesByType(random, totalOverrideCount),
|
||
OverridesByOperator = GenerateOverridesByOperator(random),
|
||
ByDate = GenerateDailyOverrideStatistics(startTime, endTime, random),
|
||
AverageOverrideElapsedMs = 1000 + random.NextDouble() * 2000,
|
||
MaxOverrideElapsedMs = 5000 + random.Next(0, 5000),
|
||
MinOverrideElapsedMs = 500 + random.Next(0, 500),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 35,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成审计日志。
|
||
/// </summary>
|
||
private async Task<IReadOnlyList<OverrideAuditLog>> GenerateOverrideAuditLogsAsync(Guid? sessionId, Guid? overrideId, DateTime? startTime, DateTime? endTime, OrpaonVision.Core.ManualOverride.AuditLevel? auditLevel, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var auditLogs = new List<OverrideAuditLog>();
|
||
var logCount = random.Next(20, 100);
|
||
|
||
for (int i = 0; i < logCount; i++)
|
||
{
|
||
var level = auditLevel ?? (OrpaonVision.Core.ManualOverride.AuditLevel)random.Next(0, 5);
|
||
var auditTime = startTime?.AddMinutes(random.Next(0, (int)(endTime - startTime).Value.TotalMinutes)) ?? DateTime.UtcNow.AddMinutes(-random.Next(10, 1440));
|
||
|
||
auditLogs.Add(new OverrideAuditLog
|
||
{
|
||
LogId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
OverrideId = overrideId,
|
||
AuditLevel = level,
|
||
AuditType = (AuditType)random.Next(0, 9),
|
||
AuditMessage = $"审计消息{i + 1}",
|
||
AuditDetails = $"审计详情{i + 1}",
|
||
OperatorId = $"OP{random.Next(1, 10):D3}",
|
||
OperatorName = $"操作员{random.Next(1, 10)}",
|
||
AuditTimeUtc = auditTime,
|
||
ClientIp = $"192.168.1.{random.Next(1, 255)}",
|
||
UserAgent = $"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 12,
|
||
["data_source"] = "simulated"
|
||
}
|
||
});
|
||
}
|
||
|
||
return auditLogs.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位报告。
|
||
/// </summary>
|
||
private async Task<ManualOverrideReport> GenerateManualOverrideReportAsync(OverrideReportRequest reportRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var statistics = await GenerateOverrideStatisticsAsync(reportRequest.TimeRange.StartTimeUtc, reportRequest.TimeRange.EndTimeUtc, reportRequest.ProductTypeCode, cancellationToken);
|
||
|
||
return new ManualOverrideReport
|
||
{
|
||
ReportId = Guid.NewGuid(),
|
||
ReportType = reportRequest.ReportType,
|
||
ReportTitle = $"{reportRequest.ReportType}复位放行报告",
|
||
TimeRange = reportRequest.TimeRange,
|
||
GeneratedAtUtc = DateTime.UtcNow,
|
||
ExecutiveSummary = GenerateReportExecutiveSummary(random),
|
||
Statistics = statistics,
|
||
TrendAnalysis = GenerateOverrideTrendAnalysis(random),
|
||
ComplianceAnalysis = GenerateOverrideComplianceAnalysis(random),
|
||
RiskAnalysis = GenerateOverrideRiskAnalysis(random),
|
||
ImprovementSuggestions = GenerateOverrideImprovementSuggestions(random),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 80,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成合规性检查。
|
||
/// </summary>
|
||
private async Task<OverrideComplianceCheck> GenerateOverrideComplianceCheckAsync(Guid sessionId, ManualOverrideRequest overrideRequest, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var checkResult = random.NextDouble() > 0.2 ? ComplianceCheckResult.Pass : (ComplianceCheckResult)random.Next(1, 4);
|
||
|
||
return new OverrideComplianceCheck
|
||
{
|
||
CheckId = Guid.NewGuid(),
|
||
SessionId = sessionId,
|
||
CheckResult = checkResult,
|
||
ComplianceScore = 70 + random.NextDouble() * 25,
|
||
CheckItems = GenerateComplianceCheckItems(random),
|
||
Violations = checkResult == ComplianceCheckResult.Fail ? GenerateComplianceViolations(random) : new List<ComplianceViolation>(),
|
||
CheckTimeUtc = DateTime.UtcNow,
|
||
CheckElapsedMs = random.Next(200, 2000),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 30,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位模板。
|
||
/// </summary>
|
||
private async Task<OverrideTemplate> GenerateOverrideTemplateAsync(OverrideTemplateType templateType, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
|
||
return new OverrideTemplate
|
||
{
|
||
TemplateId = Guid.NewGuid(),
|
||
TemplateType = templateType,
|
||
TemplateName = $"{templateType}模板",
|
||
TemplateDescription = $"{templateType}复位模板描述",
|
||
TemplateContent = $"{templateType}复位模板内容",
|
||
TemplateParameters = GenerateTemplateParameters(random),
|
||
ApplicableConditions = GenerateTemplateConditions(random),
|
||
CreatedAtUtc = DateTime.UtcNow.AddDays(-random.Next(1, 30)),
|
||
Creator = $"创建者{random.Next(1, 5)}",
|
||
IsEnabled = random.NextDouble() > 0.1,
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 20,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成模板保存结果。
|
||
/// </summary>
|
||
private async Task<OverrideTemplateSaveResult> GenerateOverrideTemplateSaveResultAsync(OverrideTemplate template, CancellationToken cancellationToken = default)
|
||
{
|
||
await Task.Delay(1, cancellationToken);
|
||
|
||
var random = new Random();
|
||
var isSuccess = random.NextDouble() > 0.1;
|
||
|
||
return new OverrideTemplateSaveResult
|
||
{
|
||
IsSuccess = isSuccess,
|
||
TemplateId = template.TemplateId,
|
||
SaveMessage = isSuccess ? "保存成功" : "保存失败",
|
||
SaveTimeUtc = DateTime.UtcNow,
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 15,
|
||
["data_source"] = "simulated"
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 记录复位审计日志。
|
||
/// </summary>
|
||
private async Task LogOverrideAuditAsync(ManualOverrideRequest request, ManualOverrideResult result, TimeSpan elapsed, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var auditLog = new OverrideAuditLog
|
||
{
|
||
LogId = Guid.NewGuid(),
|
||
SessionId = request.SessionId,
|
||
OverrideId = result.OverrideId,
|
||
AuditLevel = result.OverrideResult == OverrideResult.Success ? OrpaonVision.Core.ManualOverride.AuditLevel.Info : OrpaonVision.Core.ManualOverride.AuditLevel.Warning,
|
||
AuditType = AuditType.OverrideExecuted,
|
||
AuditMessage = $"执行复位放行:{result.OverrideResult}",
|
||
AuditDetails = $"请求ID:{request.RequestId},耗时:{elapsed.TotalMilliseconds:F2}ms",
|
||
OperatorId = request.OperatorId,
|
||
OperatorName = request.OperatorName,
|
||
AuditTimeUtc = DateTime.UtcNow,
|
||
ClientIp = "127.0.0.1",
|
||
UserAgent = "ManualOverrideService",
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["request_id"] = request.RequestId,
|
||
["override_type"] = request.OverrideType,
|
||
["elapsed_ms"] = elapsed.TotalMilliseconds
|
||
}
|
||
};
|
||
|
||
// 简化处理:在实际实现中,这里应该将审计日志写入数据库或日志文件
|
||
_logger.LogInformation("记录复位审计日志:{AuditLog}", JsonSerializer.Serialize(auditLog));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "记录复位审计日志失败");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 记录撤销审计日志。
|
||
/// </summary>
|
||
private async Task LogRevokeAuditAsync(Guid overrideId, string revokeReason, string operatorId, OverrideRevokeResult result, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var auditLog = new OverrideAuditLog
|
||
{
|
||
LogId = Guid.NewGuid(),
|
||
OverrideId = overrideId,
|
||
AuditLevel = result.RevokeResult == RevokeResult.Success ? OrpaonVision.Core.ManualOverride.AuditLevel.Info : OrpaonVision.Core.ManualOverride.AuditLevel.Warning,
|
||
AuditType = AuditType.OverrideRevoked,
|
||
AuditMessage = $"撤销复位放行:{result.RevokeResult}",
|
||
AuditDetails = $"撤销原因:{revokeReason}",
|
||
OperatorId = operatorId,
|
||
OperatorName = $"操作员{operatorId}",
|
||
AuditTimeUtc = DateTime.UtcNow,
|
||
ClientIp = "127.0.0.1",
|
||
UserAgent = "ManualOverrideService",
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["override_id"] = overrideId,
|
||
["revoke_reason"] = revokeReason,
|
||
["revoke_result"] = result.RevokeResult
|
||
}
|
||
};
|
||
|
||
// 简化处理:在实际实现中,这里应该将审计日志写入数据库或日志文件
|
||
_logger.LogInformation("记录撤销审计日志:{AuditLog}", JsonSerializer.Serialize(auditLog));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "记录撤销审计日志失败");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 辅助方法
|
||
|
||
/// <summary>
|
||
/// 生成复位原因列表。
|
||
/// </summary>
|
||
private IReadOnlyList<OverrideReason> GenerateOverrideReasons(Random random)
|
||
{
|
||
var reasons = new List<OverrideReason>();
|
||
var reasonCount = random.Next(1, 4);
|
||
|
||
for (int i = 0; i < reasonCount; i++)
|
||
{
|
||
reasons.Add(new OverrideReason
|
||
{
|
||
ReasonId = Guid.NewGuid(),
|
||
ReasonType = (OverrideReasonType)random.Next(0, 8),
|
||
ReasonDescription = $"复位原因{i + 1}",
|
||
ReasonSeverity = (OverrideSeverity)random.Next(0, 4),
|
||
RecommendedAction = $"建议措施{i + 1}",
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["reason_index"] = i
|
||
}
|
||
});
|
||
}
|
||
|
||
return reasons.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成NG原因列表。
|
||
/// </summary>
|
||
private IReadOnlyList<string> GenerateNGReasons(Random random)
|
||
{
|
||
var reasons = new List<string>();
|
||
var reasonCount = random.Next(0, 5);
|
||
|
||
for (int i = 0; i < reasonCount; i++)
|
||
{
|
||
reasons.Add($"NG原因{i + 1}");
|
||
}
|
||
|
||
return reasons.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成验证详情列表。
|
||
/// </summary>
|
||
private IReadOnlyList<ValidationDetail> GenerateValidationDetails(Random random)
|
||
{
|
||
var details = new List<ValidationDetail>();
|
||
var detailCount = random.Next(3, 8);
|
||
|
||
for (int i = 0; i < detailCount; i++)
|
||
{
|
||
details.Add(new ValidationDetail
|
||
{
|
||
DetailId = Guid.NewGuid(),
|
||
ValidationItem = $"验证项{i + 1}",
|
||
ValidationResult = random.NextDouble() > 0.2 ? ValidationResult.Pass : ValidationResult.Fail,
|
||
ValidationMessage = $"验证消息{i + 1}",
|
||
ValidationValue = random.Next(1, 100),
|
||
ExpectedValue = random.Next(1, 100),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["detail_index"] = i
|
||
}
|
||
});
|
||
}
|
||
|
||
return details.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成执行详情列表。
|
||
/// </summary>
|
||
private IReadOnlyList<ExecutionDetail> GenerateExecutionDetails(Random random)
|
||
{
|
||
var details = new List<ExecutionDetail>();
|
||
var detailCount = random.Next(3, 10);
|
||
|
||
for (int i = 0; i < detailCount; i++)
|
||
{
|
||
details.Add(new ExecutionDetail
|
||
{
|
||
DetailId = Guid.NewGuid(),
|
||
ExecutionStep = $"执行步骤{i + 1}",
|
||
ExecutionResult = random.NextDouble() > 0.1,
|
||
ExecutionMessage = $"执行消息{i + 1}",
|
||
ExecutionTimeUtc = DateTime.UtcNow.AddSeconds(-random.Next(1, 60)),
|
||
ExecutionElapsedMs = random.Next(50, 500),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["step_index"] = i
|
||
}
|
||
});
|
||
}
|
||
|
||
return details.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成审批信息列表。
|
||
/// </summary>
|
||
private IReadOnlyList<ApprovalInfo> GenerateApprovalInfos(Random random)
|
||
{
|
||
var approvals = new List<ApprovalInfo>();
|
||
var approvalCount = random.Next(0, 3);
|
||
|
||
for (int i = 0; i < approvalCount; i++)
|
||
{
|
||
approvals.Add(new ApprovalInfo
|
||
{
|
||
ApprovalId = Guid.NewGuid(),
|
||
ApproverId = $"AP{random.Next(1, 5):D3}",
|
||
ApproverName = $"审批人{random.Next(1, 5)}",
|
||
ApprovalResult = (ApprovalResult)random.Next(0, 4),
|
||
ApprovalComment = $"审批意见{i + 1}",
|
||
ApprovalTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 120)),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["approval_index"] = i
|
||
}
|
||
});
|
||
}
|
||
|
||
return approvals.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位影响分析。
|
||
/// </summary>
|
||
private OverrideImpactAnalysis GenerateOverrideImpactAnalysis(Random random)
|
||
{
|
||
return new OverrideImpactAnalysis
|
||
{
|
||
AnalysisId = Guid.NewGuid(),
|
||
ImpactLevel = (ImpactLevel)random.Next(0, 5),
|
||
ImpactDescription = "影响分析描述",
|
||
AffectedSessionCount = random.Next(1, 5),
|
||
AffectedLayerCount = random.Next(3, 20),
|
||
AffectedDetectionCount = random.Next(10, 100),
|
||
RiskAssessment = new RiskAssessment
|
||
{
|
||
RiskLevel = (RiskLevel)random.Next(0, 5),
|
||
RiskDescription = "风险评估描述",
|
||
RiskProbability = random.NextDouble(),
|
||
RiskImpact = random.NextDouble(),
|
||
MitigationMeasures = new List<string> { "缓解措施1", "缓解措施2" },
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 10
|
||
}
|
||
},
|
||
RecommendedActions = new List<string> { "建议措施1", "建议措施2", "建议措施3" },
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 15
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成按类型分组的复位统计。
|
||
/// </summary>
|
||
private Dictionary<OverrideType, int> GenerateOverridesByType(Random random, int totalCount)
|
||
{
|
||
var overridesByType = new Dictionary<OverrideType, int>();
|
||
var remainingCount = totalCount;
|
||
|
||
foreach (OverrideType type in Enum.GetValues<OverrideType>())
|
||
{
|
||
if (remainingCount <= 0) break;
|
||
|
||
var count = random.Next(0, remainingCount / 2 + 1);
|
||
overridesByType[type] = count;
|
||
remainingCount -= count;
|
||
}
|
||
|
||
return overridesByType;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成按操作员分组的复位统计。
|
||
/// </summary>
|
||
private Dictionary<string, OperatorOverrideStatistics> GenerateOverridesByOperator(Random random)
|
||
{
|
||
var operatorStats = new Dictionary<string, OperatorOverrideStatistics>();
|
||
|
||
for (int i = 1; i <= 5; i++)
|
||
{
|
||
var overrideCount = random.Next(5, 30);
|
||
var successCount = (int)(overrideCount * (0.7 + random.NextDouble() * 0.25));
|
||
|
||
operatorStats[$"OP{i:D3}"] = new OperatorOverrideStatistics
|
||
{
|
||
OperatorId = $"OP{i:D3}",
|
||
OperatorName = $"操作员{i}",
|
||
OverrideCount = overrideCount,
|
||
SuccessCount = successCount,
|
||
FailureCount = overrideCount - successCount,
|
||
AverageElapsedMs = 1000 + random.NextDouble() * 2000,
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 8
|
||
}
|
||
};
|
||
}
|
||
|
||
return operatorStats;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成每日复位统计。
|
||
/// </summary>
|
||
private Dictionary<DateTime, DailyOverrideStatistics> GenerateDailyOverrideStatistics(DateTime startTime, DateTime endTime, Random random)
|
||
{
|
||
var dailyStats = new Dictionary<DateTime, DailyOverrideStatistics>();
|
||
var current = startTime.Date;
|
||
|
||
while (current <= endTime.Date)
|
||
{
|
||
var overrideCount = random.Next(5, 20);
|
||
var successCount = (int)(overrideCount * (0.7 + random.NextDouble() * 0.25));
|
||
|
||
dailyStats[current] = new DailyOverrideStatistics
|
||
{
|
||
Date = current,
|
||
OverrideCount = overrideCount,
|
||
SuccessCount = successCount,
|
||
FailureCount = overrideCount - successCount,
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 6
|
||
}
|
||
};
|
||
|
||
current = current.AddDays(1);
|
||
}
|
||
|
||
return dailyStats;
|
||
}
|
||
|
||
/// <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"] = 12
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位趋势分析。
|
||
/// </summary>
|
||
private OverrideTrendAnalysis GenerateOverrideTrendAnalysis(Random random)
|
||
{
|
||
return new OverrideTrendAnalysis
|
||
{
|
||
TrendDirection = (TrendDirection)random.Next(0, 4),
|
||
ChangeRate = random.NextDouble() * 10 - 5,
|
||
TrendDescription = "复位趋势分析",
|
||
PredictedNextOverrideCount = random.Next(10, 50),
|
||
Confidence = 0.6 + random.NextDouble() * 0.3,
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 10
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位合规性分析。
|
||
/// </summary>
|
||
private OverrideComplianceAnalysis GenerateOverrideComplianceAnalysis(Random random)
|
||
{
|
||
return new OverrideComplianceAnalysis
|
||
{
|
||
ComplianceScore = 75 + random.NextDouble() * 20,
|
||
ComplianceViolationCount = random.Next(0, 10),
|
||
Violations = GenerateComplianceViolations(random),
|
||
ComplianceRecommendations = new[] { "合规建议1", "合规建议2" },
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 15
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位风险分析。
|
||
/// </summary>
|
||
private OverrideRiskAnalysis GenerateOverrideRiskAnalysis(Random random)
|
||
{
|
||
return new OverrideRiskAnalysis
|
||
{
|
||
RiskScore = 20 + random.NextDouble() * 60,
|
||
HighRiskOverrideCount = random.Next(0, 5),
|
||
RiskFactors = new List<RiskFactor>
|
||
{
|
||
new RiskFactor
|
||
{
|
||
FactorId = Guid.NewGuid(),
|
||
FactorName = "风险因素1",
|
||
FactorDescription = "风险因素描述1",
|
||
RiskLevel = (RiskLevel)random.Next(0, 5),
|
||
ImpactLevel = random.NextDouble(),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["factor_index"] = 0
|
||
}
|
||
}
|
||
},
|
||
RiskMitigationRecommendations = new[] { "风险缓解建议1", "风险缓解建议2" },
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["generation_time_ms"] = 12
|
||
}
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成复位改进建议。
|
||
/// </summary>
|
||
private IReadOnlyList<OverrideImprovementSuggestion> GenerateOverrideImprovementSuggestions(Random random)
|
||
{
|
||
var suggestions = new List<OverrideImprovementSuggestion>();
|
||
|
||
for (int i = 0; i < random.Next(3, 8); i++)
|
||
{
|
||
suggestions.Add(new OverrideImprovementSuggestion
|
||
{
|
||
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),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["suggestion_index"] = i
|
||
}
|
||
});
|
||
}
|
||
|
||
return suggestions.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成合规性检查项。
|
||
/// </summary>
|
||
private IReadOnlyList<ComplianceCheckItem> GenerateComplianceCheckItems(Random random)
|
||
{
|
||
var items = new List<ComplianceCheckItem>();
|
||
var itemCount = random.Next(5, 15);
|
||
|
||
for (int i = 0; i < itemCount; i++)
|
||
{
|
||
items.Add(new ComplianceCheckItem
|
||
{
|
||
ItemId = Guid.NewGuid(),
|
||
ItemName = $"检查项{i + 1}",
|
||
ItemDescription = $"检查项描述{i + 1}",
|
||
CheckResult = random.NextDouble() > 0.2 ? ComplianceCheckResult.Pass : ComplianceCheckResult.Fail,
|
||
CheckValue = random.Next(1, 100),
|
||
StandardValue = random.Next(1, 100),
|
||
CheckMessage = $"检查消息{i + 1}",
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["item_index"] = i
|
||
}
|
||
});
|
||
}
|
||
|
||
return items.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成合规违规。
|
||
/// </summary>
|
||
private IReadOnlyList<ComplianceViolation> GenerateComplianceViolations(Random random)
|
||
{
|
||
var violations = new List<ComplianceViolation>();
|
||
var violationCount = random.Next(0, 5);
|
||
|
||
for (int i = 0; i < violationCount; i++)
|
||
{
|
||
violations.Add(new ComplianceViolation
|
||
{
|
||
ViolationId = Guid.NewGuid(),
|
||
ViolationType = $"违规类型{i + 1}",
|
||
ViolationDescription = $"违规描述{i + 1}",
|
||
ViolationSeverity = (ViolationSeverity)random.Next(0, 4),
|
||
ViolationTimeUtc = DateTime.UtcNow.AddMinutes(-random.Next(10, 120)),
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["violation_index"] = i
|
||
}
|
||
});
|
||
}
|
||
|
||
return violations.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成模板参数。
|
||
/// </summary>
|
||
private IReadOnlyList<TemplateParameter> GenerateTemplateParameters(Random random)
|
||
{
|
||
var parameters = new List<TemplateParameter>();
|
||
var parameterCount = random.Next(3, 8);
|
||
|
||
for (int i = 0; i < parameterCount; i++)
|
||
{
|
||
parameters.Add(new TemplateParameter
|
||
{
|
||
ParameterId = Guid.NewGuid(),
|
||
ParameterName = $"参数{i + 1}",
|
||
ParameterType = "string",
|
||
ParameterDescription = $"参数描述{i + 1}",
|
||
IsRequired = random.NextDouble() > 0.5,
|
||
DefaultValue = $"默认值{i + 1}",
|
||
ValidationRule = "required",
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["parameter_index"] = i
|
||
}
|
||
});
|
||
}
|
||
|
||
return parameters.AsReadOnly();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成模板条件。
|
||
/// </summary>
|
||
private IReadOnlyList<TemplateCondition> GenerateTemplateConditions(Random random)
|
||
{
|
||
var conditions = new List<TemplateCondition>();
|
||
var conditionCount = random.Next(0, 3);
|
||
|
||
for (int i = 0; i < conditionCount; i++)
|
||
{
|
||
conditions.Add(new TemplateCondition
|
||
{
|
||
ConditionId = Guid.NewGuid(),
|
||
ConditionName = $"条件{i + 1}",
|
||
ConditionExpression = $"condition{i + 1} == true",
|
||
ConditionDescription = $"条件描述{i + 1}",
|
||
ExtendedProperties = new Dictionary<string, object>
|
||
{
|
||
["condition_index"] = i
|
||
}
|
||
});
|
||
}
|
||
|
||
return conditions.AsReadOnly();
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
|
||
#endif
|