using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using NPP.SmartSchedue.Api.Contracts.Domain.Work; using NPP.SmartSchedue.Api.Contracts.Services.Integration.Internal; using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output; using NPP.SmartSchedue.Api.Services.Integration.Algorithms; namespace NPP.SmartSchedue.Api.Services.Integration.Algorithms { /// /// 全局优化引擎 - 专门负责遗传算法优化和结果处理 /// 设计原则:高内聚、低耦合、单一职责、易维护 /// 核心价值:为智能调度提供高性能的全局优化能力 /// public class GlobalOptimizationEngine { #region 私有字段 private readonly GeneticAlgorithmEngine _geneticEngine; private readonly LinearProgrammingEngine _linearProgrammingEngine; private readonly ILogger _logger; // 人员名称缓存 private readonly Dictionary _personnelNameCache = new(); #endregion #region 构造函数 /// /// 构造函数 - 依赖注入模式 /// public GlobalOptimizationEngine( GeneticAlgorithmEngine geneticEngine, LinearProgrammingEngine linearProgrammingEngine, ILogger logger) { _geneticEngine = geneticEngine ?? throw new ArgumentNullException(nameof(geneticEngine)); _linearProgrammingEngine = linearProgrammingEngine ?? throw new ArgumentNullException(nameof(linearProgrammingEngine)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } #endregion #region 公共方法 /// /// 执行全局优化算法 - 主入口方法 /// 业务流程:预筛选验证 → 遗传算法优化 → 公平性分析 → 智能协商 → 业务规则验证 → 结果构建 /// 核心流程:遗传算法优化 → 基尼系数计算 → 智能协商 → 结果封装 /// 性能目标:通过精英策略和收敛检测控制计算复杂度 /// /// 全局分配上下文,包含任务、人员、配置等所有必需信息 /// 优化后的分配结果,包含成功匹配、失败项、性能指标 public async Task ExecuteOptimizationAsync(GlobalAllocationContext context) { var result = new GlobalAllocationResult(); var metrics = new GlobalOptimizationMetrics(); var executionStopwatch = Stopwatch.StartNew(); try { _logger.LogInformation("🧬 开始全局优化执行"); // 第一步:验证预筛选结果 if (!ValidatePrefilterResults(context, result)) { return result; } LogPrefilterStatistics(context); // 第二步:智能选择优化算法 GlobalOptimizedSolution optimizedSolution; var taskCount = context.Tasks.Count; var personnelCount = context.AvailablePersonnel.Count; // 根据问题规模选择最优算法:小规模用线性规划,大规模用遗传算法 _logger.LogInformation("🎯 第2步:执行线性规划优化 - 任务数:{TaskCount},人员数:{PersonnelCount}", taskCount, personnelCount); optimizedSolution = await _linearProgrammingEngine.OptimizeAsync(context); executionStopwatch.Stop(); LogOptimizationResults(optimizedSolution, executionStopwatch.ElapsedMilliseconds, context, taskCount <= 20 && personnelCount <= 10); // 第三步:执行后续处理流程 await ExecutePostOptimizationProcessingAsync(optimizedSolution, context, result); // 第四步:构建最终结果 BuildFinalResult(optimizedSolution, result, metrics, executionStopwatch.ElapsedMilliseconds); return result; } catch (Exception ex) { executionStopwatch.Stop(); _logger.LogError(ex, "💥 全局优化执行异常,耗时:{ElapsedMs}ms", executionStopwatch.ElapsedMilliseconds); return CreateErrorResult(ex.Message); } } #endregion #region 验证和统计方法 /// /// 验证预筛选结果的有效性 /// private bool ValidatePrefilterResults(GlobalAllocationContext context, GlobalAllocationResult result) { if (!context.PrefilterResults.Any()) { _logger.LogError("❌ 无预筛选结果!无法进行遗传算法优化"); result.IsSuccess = false; result.AllocationSummary = "预筛选阶段未找到可行的任务-人员组合"; return false; } return true; } /// /// 记录预筛选统计信息 /// private void LogPrefilterStatistics(GlobalAllocationContext context) { var totalCombinations = context.Tasks.Count * context.AvailablePersonnel.Count; var feasibleCount = context.PrefilterResults.Count(p => p.Value.IsFeasible); var feasibilityRate = feasibleCount / (double)Math.Max(context.PrefilterResults.Count, 1); _logger.LogInformation("📊 预筛选统计 - 总组合:{TotalCombinations},可行组合:{FeasibleCount},可行率:{FeasibilityRate:P2}", totalCombinations, feasibleCount, feasibilityRate); } /// /// 记录优化结果统计 /// private void LogOptimizationResults(GlobalOptimizedSolution optimizedSolution, long elapsedMs, GlobalAllocationContext context, bool isLinearProgramming = false) { if (isLinearProgramming) { _logger.LogInformation("🎯 线性规划完成 - 耗时:{ElapsedMs}ms,目标函数值:{BestFitness:F2},约束满足率:{ConstraintRate:P2}", elapsedMs, optimizedSolution.BestFitness, optimizedSolution.ConstraintSatisfactionRate); } else { _logger.LogInformation("🎯 遗传算法完成 - 耗时:{ElapsedMs}ms,执行代数:{ActualGens}/{MaxGens},最佳适应度:{BestFitness:F2},约束满足率:{ConstraintRate:P2}", elapsedMs, optimizedSolution.ActualGenerations, context.Config.MaxGenerations, optimizedSolution.BestFitness, optimizedSolution.ConstraintSatisfactionRate); } } #endregion #region 后续处理流程 /// /// 执行优化后的处理流程 /// 包括:公平性分析 → 智能协商 → 业务规则验证 /// private async Task ExecutePostOptimizationProcessingAsync( GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, GlobalAllocationResult result) { // 公平性分析 await ExecuteFairnessAnalysisAsync(optimizedSolution, result); // 智能协商 //await ExecuteIntelligentNegotiationAsync(optimizedSolution, context, result); // 最终业务规则验证 //await ExecuteFinalValidationAsync(optimizedSolution, context, result); } /// /// 执行公平性分析 /// private async Task ExecuteFairnessAnalysisAsync(GlobalOptimizedSolution optimizedSolution, GlobalAllocationResult result) { await Task.CompletedTask; // 保持异步接口 _logger.LogInformation("📈 第3步:计算公平性分析"); var fairnessAnalysis = CalculateWorkloadFairness(optimizedSolution); _logger.LogInformation("📊 公平性分析完成 - 基尼系数:{GiniCoeff:F3}", fairnessAnalysis.GiniCoefficient); result.FairnessAnalysis = fairnessAnalysis; } /// /// 执行智能协商 - 完整的冲突检测与解决方案引擎 /// 【业务价值】:通过智能冲突检测和多策略协商,确保遗传算法结果符合业务规则 /// 【核心逻辑】:分层优先级处理、多维度冲突检测、智能决策选择最优解决方案 /// 【深度思考】:协商成功率直接影响最终分配质量,必须兼顾效率和准确性 /// 【技术特色】:利用预加载数据、并行检测、缓存优化实现高性能智能协商 /// /// 遗传算法优化后的解决方案 /// 全局分配上下文,包含所有必要的缓存数据 /// 最终分配结果,用于存储协商操作和冲突检测信息 /// 异步任务 private async Task ExecuteIntelligentNegotiationAsync( GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, GlobalAllocationResult result) { var negotiationStartTime = DateTime.Now; var negotiationActions = new List(); var conflictDetections = new List(); try { _logger.LogInformation("🤝 第4步:执行智能协商处理冲突 - 分析{TaskCount}个任务分配", optimizedSolution.BestSolution?.Count ?? 0); // 【前置验证】检查输入数据有效性 if (optimizedSolution?.BestSolution == null || !optimizedSolution.BestSolution.Any()) { _logger.LogWarning("⚠️ 智能协商跳过 - 无有效的遗传算法分配方案"); await CompleteNegotiationWithEmptyResult(result, negotiationActions, conflictDetections); return; } // 【第一阶段】全面冲突检测 - 识别所有类型的约束冲突 _logger.LogInformation("🔍 阶段1:全面冲突检测"); await ExecuteComprehensiveConflictDetectionAsync(optimizedSolution, context, conflictDetections); // 【第二阶段】冲突分析与优先级排序 _logger.LogInformation("📊 阶段2:冲突分析与优先级排序"); var prioritizedConflicts = AnalyzeAndPrioritizeConflicts(conflictDetections); // 【第三阶段】智能解决方案生成与执行 _logger.LogInformation("💡 阶段3:智能解决方案生成"); await ExecuteIntelligentResolutionStrategiesAsync( prioritizedConflicts, optimizedSolution, context, negotiationActions, conflictDetections); // 【第四阶段】协商结果验证与优化 _logger.LogInformation("✅ 阶段4:协商结果验证"); await ValidateNegotiationResultsAsync(optimizedSolution, context, negotiationActions, conflictDetections); // 【结果统计与性能分析】 var negotiationDuration = DateTime.Now - negotiationStartTime; LogNegotiationResults(negotiationActions, conflictDetections, negotiationDuration); // 【最终结果封装】 await CompleteNegotiationWithResults(result, negotiationActions, conflictDetections); } catch (Exception ex) { var negotiationDuration = DateTime.Now - negotiationStartTime; _logger.LogError(ex, "💥 智能协商异常 - 执行时间:{Duration}ms", negotiationDuration.TotalMilliseconds); // 【异常处理】创建异常信息记录,确保系统稳定性 var errorConflict = new GlobalConflictDetectionInfo { ConflictType = GlobalConflictType.LoadImbalance, // 使用通用冲突类型 TaskId = 0, PersonnelId = 0, Severity = GlobalConflictSeverity.High, Description = $"智能协商执行异常: {ex.Message}", IsResolved = false }; conflictDetections.Add(errorConflict); await CompleteNegotiationWithResults(result, negotiationActions, conflictDetections); } } /// /// 执行全面冲突检测 - 多维度并行检测所有潜在冲突 /// 【业务逻辑】:整合班次规则、资质匹配、时间约束、负载均衡等多个维度进行全面检测 /// 【性能优化】:利用预加载缓存和并行检测提升检测效率 /// 【深度思考】:每种冲突类型都有其业务优先级,必须确保检测的完整性和准确性 /// /// 遗传算法优化解决方案 /// 全局分配上下文 /// 冲突检测结果列表 private async Task ExecuteComprehensiveConflictDetectionAsync( GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List conflictDetections) { var detectionTasks = new List(); // 【并行检测1】班次规则冲突检测 - 最重要的约束检测 detectionTasks.Add(DetectShiftRuleConflictsAsync(optimizedSolution, context, conflictDetections)); // 【并行检测2】资质匹配冲突检测 - 确保人员技能符合任务要求 detectionTasks.Add(DetectQualificationMismatchesAsync(optimizedSolution, context, conflictDetections)); // 【并行检测3】时间不可用冲突检测 - 人员请假、不可用时间冲突 detectionTasks.Add(DetectTimeUnavailabilityConflictsAsync(optimizedSolution, context, conflictDetections)); // 【并行检测4】工作负载超限检测 - 防止人员工作量过载 detectionTasks.Add(DetectWorkLimitExceededConflictsAsync(optimizedSolution, context, conflictDetections)); // 【并行检测5】负载不均衡检测 - 基于公平性分析的负载平衡检查 detectionTasks.Add(DetectLoadImbalanceConflictsAsync(optimizedSolution, context, conflictDetections)); // 【等待所有检测完成】确保所有维度的冲突都被识别 await Task.WhenAll(detectionTasks); _logger.LogInformation("🔍 全面冲突检测完成 - 共发现{ConflictCount}个冲突", conflictDetections.Count); } /// /// 检测班次规则冲突 - 利用ShiftRuleValidationEngine进行深度验证 /// 【业务关键】:班次规则是最重要的硬约束,违反会导致排班不可执行 /// 【深度整合】:调用现有的ShiftRuleValidationEngine,确保验证逻辑的一致性 /// private async Task DetectShiftRuleConflictsAsync( GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List conflictDetections) { try { _logger.LogDebug("🔍 开始班次规则冲突检测"); // 【创建班次规则验证引擎】使用现有的成熟验证逻辑 // 注意:由于Logger类型不匹配,这里先注释掉实际的引擎调用 // var shiftRuleEngine = new ShiftRuleValidationEngine(_logger, null, context); var shiftRuleConflictCount = 0; // 【逐个任务验证】对每个分配的任务进行班次规则验证 foreach (var allocation in optimizedSolution.BestSolution) { var taskId = allocation.Key; var personnelId = allocation.Value; // 【获取任务信息】从上下文中获取任务详情 var currentTask = context.Tasks.FirstOrDefault(t => t.Id == taskId); if (currentTask == null) { _logger.LogWarning("⚠️ 任务{TaskId}信息不存在,跳过班次规则检测", taskId); continue; } // 【构建批次上下文】创建其他相关任务的上下文(排除当前任务) var batchContext = optimizedSolution.BestSolution .Where(kvp => kvp.Value == personnelId && kvp.Key != taskId) .Select(kvp => context.Tasks.FirstOrDefault(t => t.Id == kvp.Key)) .Where(t => t != null) .ToList(); // 【执行班次规则验证】调用成熟的验证引擎 try { // 注意:这里简化处理,实际应该传入IShiftService实例 // var ruleViolations = await shiftRuleEngine.ValidateShiftRulesWithEnhancedBatchContextAsync( // personnelId, currentTask, batchContext); // 【临时实现】创建模拟的规则冲突检测,后续需要完整整合 var ruleViolations = await SimulateShiftRuleValidation(personnelId, currentTask, batchContext, context); // 【转换冲突格式】将规则违规转换为标准冲突检测格式 foreach (var violation in ruleViolations) { var conflictInfo = new GlobalConflictDetectionInfo { ConflictType = DetermineConflictTypeFromViolation(violation), TaskId = taskId, PersonnelId = personnelId, Severity = DetermineConflictSeverity(violation), Description = $"班次规则冲突: {violation}", IsResolved = false }; conflictDetections.Add(conflictInfo); shiftRuleConflictCount++; } } catch (Exception ex) { _logger.LogError(ex, "⚠️ 任务{TaskId}人员{PersonnelId}班次规则检测异常", taskId, personnelId); // 【异常处理】创建异常冲突记录 var errorConflict = new GlobalConflictDetectionInfo { ConflictType = GlobalConflictType.NextDayRestViolation, TaskId = taskId, PersonnelId = personnelId, Severity = GlobalConflictSeverity.Medium, Description = $"班次规则验证异常: {ex.Message}", IsResolved = false }; conflictDetections.Add(errorConflict); } } _logger.LogInformation("🔍 班次规则冲突检测完成 - 发现{ConflictCount}个冲突", shiftRuleConflictCount); } catch (Exception ex) { _logger.LogError(ex, "💥 班次规则冲突检测整体异常"); } } /// /// 模拟班次规则验证 - 临时实现,后续需要完整整合ShiftRuleValidationEngine /// 【临时方案】:由于依赖注入的复杂性,先提供基础的规则检测逻辑 /// 【TODO】:完整整合ShiftRuleValidationEngine的依赖注入 /// private async Task> SimulateShiftRuleValidation( long personnelId, WorkOrderEntity currentTask, List batchContext, GlobalAllocationContext context) { var violations = new List(); await Task.CompletedTask; // 保持异步接口 try { // 【基础检查】班次ID有效性 if (!currentTask.ShiftId.HasValue) { violations.Add($"任务{currentTask.WorkOrderCode}缺少班次ID"); return violations; } var currentDate = currentTask.WorkOrderDate.Date; var currentShiftId = currentTask.ShiftId.Value; // 【简化的班次规则检查】检查同一天是否有冲突的班次安排 var sameDayTasks = batchContext .Where(t => t.WorkOrderDate.Date == currentDate) .Where(t => t.ShiftId.HasValue) .ToList(); if (sameDayTasks.Any()) { // 【模拟冲突】假设存在班次冲突的情况 var conflictTasks = sameDayTasks.Where(t => t.ShiftId != currentShiftId).ToList(); foreach (var conflictTask in conflictTasks) { violations.Add($"同日班次冲突: 任务{currentTask.WorkOrderCode}与{conflictTask.WorkOrderCode}存在班次安排冲突"); } } // 【连续工作天数检查】简化版本的连续天数计算 var personnelTasks = batchContext .Where(t => Math.Abs((t.WorkOrderDate.Date - currentDate).Days) <= 7) .OrderBy(t => t.WorkOrderDate) .ToList(); if (personnelTasks.Count >= 7) { violations.Add($"连续工作天数超限: 人员{personnelId}在7天内安排了{personnelTasks.Count + 1}个任务"); } return violations; } catch (Exception ex) { _logger.LogError(ex, "模拟班次规则验证异常"); return new List { $"班次规则验证异常: {ex.Message}" }; } } /// /// 检测资质匹配冲突 - 确保人员技能符合任务要求 /// 【业务逻辑】:利用预加载的人员资质缓存,快速验证技能匹配度 /// private async Task DetectQualificationMismatchesAsync( GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List conflictDetections) { await Task.CompletedTask; // 保持异步接口 try { _logger.LogDebug("🔍 开始资质匹配冲突检测"); var qualificationConflictCount = 0; foreach (var allocation in optimizedSolution.BestSolution) { var taskId = allocation.Key; var personnelId = allocation.Value; // 【获取任务资质要求】从上下文获取任务信息 var currentTask = context.Tasks.FirstOrDefault(t => t.Id == taskId); if (currentTask == null) continue; // 【获取人员资质】从缓存获取人员资质信息 if (context.PersonnelQualificationsCache.TryGetValue(personnelId, out var personnelQualifications)) { // 【资质匹配检查】检查人员是否具备任务所需的基本资质 var hasRequiredQualifications = ValidatePersonnelQualifications( personnelQualifications, currentTask); if (!hasRequiredQualifications) { var conflictInfo = new GlobalConflictDetectionInfo { ConflictType = GlobalConflictType.QualificationMismatch, TaskId = taskId, PersonnelId = personnelId, Severity = GlobalConflictSeverity.Critical, // 资质不匹配是严重问题 Description = $"人员资质不匹配: 人员{personnelId}不具备任务{currentTask.WorkOrderCode}所需的基本资质", IsResolved = false }; conflictDetections.Add(conflictInfo); qualificationConflictCount++; } } else { // 【缓存未命中】记录为资质信息缺失 var conflictInfo = new GlobalConflictDetectionInfo { ConflictType = GlobalConflictType.QualificationMismatch, TaskId = taskId, PersonnelId = personnelId, Severity = GlobalConflictSeverity.High, Description = $"人员资质信息缺失: 无法验证人员{personnelId}的资质情况", IsResolved = false }; conflictDetections.Add(conflictInfo); qualificationConflictCount++; } } _logger.LogInformation("🔍 资质匹配冲突检测完成 - 发现{ConflictCount}个冲突", qualificationConflictCount); } catch (Exception ex) { _logger.LogError(ex, "💥 资质匹配冲突检测异常"); } } /// /// 检测时间不可用冲突 - 人员请假、培训等不可用时间冲突 /// 【业务逻辑】:利用班次不可用性缓存,快速识别时间冲突 /// private async Task DetectTimeUnavailabilityConflictsAsync( GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List conflictDetections) { await Task.CompletedTask; // 保持异步接口 try { _logger.LogDebug("🔍 开始时间不可用冲突检测"); var timeConflictCount = 0; foreach (var allocation in optimizedSolution.BestSolution) { var taskId = allocation.Key; var personnelId = allocation.Value; var currentTask = context.Tasks.FirstOrDefault(t => t.Id == taskId); if (currentTask?.ShiftId == null) continue; // 【构建不可用性检查键】 var dateShiftKey = $"{currentTask.WorkOrderDate:yyyy-MM-dd}_{currentTask.ShiftId}"; // 【检查不可用性缓存】 if (context.DateShiftUnavailablePersonnel.TryGetValue(dateShiftKey, out var unavailablePersonnel)) { if (unavailablePersonnel.Contains(personnelId)) { // 【获取详细不可用信息】 var detailKey = $"{currentTask.WorkOrderDate:yyyy-MM-dd}_{currentTask.ShiftId}_{personnelId}"; var unavailabilityReason = "时间不可用"; if (context.UnavailabilityDetails.TryGetValue(detailKey, out var detailInfo)) { unavailabilityReason = GetUnavailabilityReasonText(detailInfo.ReasonType); } var conflictInfo = new GlobalConflictDetectionInfo { ConflictType = GlobalConflictType.TimeUnavailable, TaskId = taskId, PersonnelId = personnelId, Severity = DetermineUnavailabilitySeverity(detailInfo?.ReasonType ?? 1), Description = $"时间不可用冲突: 人员{personnelId}在{currentTask.WorkOrderDate:yyyy-MM-dd}班次{currentTask.ShiftId}不可用({unavailabilityReason})", IsResolved = false }; conflictDetections.Add(conflictInfo); timeConflictCount++; } } } _logger.LogInformation("🔍 时间不可用冲突检测完成 - 发现{ConflictCount}个冲突", timeConflictCount); } catch (Exception ex) { _logger.LogError(ex, "💥 时间不可用冲突检测异常"); } } /// /// 检测工作限制超出冲突 - 人员工作量、连续工作天数等限制 /// private async Task DetectWorkLimitExceededConflictsAsync( GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List conflictDetections) { await Task.CompletedTask; // 保持异步接口 try { _logger.LogDebug("🔍 开始工作限制超出冲突检测"); var workLimitConflictCount = 0; // 【按人员分组检查】统计每个人员的工作安排 var personnelWorkloads = optimizedSolution.BestSolution.GroupBy(kvp => kvp.Value); foreach (var personnelGroup in personnelWorkloads) { var personnelId = personnelGroup.Key; var assignedTasks = personnelGroup.Select(g => g.Key).ToList(); // 【获取人员工作限制】 if (context.PersonnelWorkLimitsRuleCache.TryGetValue(personnelId, out var workLimit)) { // 【检查周任务限制】 if (workLimit.MaxShiftsPerWeek.HasValue && assignedTasks.Count > workLimit.MaxShiftsPerWeek.Value) { var conflictInfo = new GlobalConflictDetectionInfo { ConflictType = GlobalConflictType.WorkLimitExceeded, TaskId = assignedTasks.First(), // 使用第一个任务ID作为代表 PersonnelId = personnelId, Severity = GlobalConflictSeverity.High, Description = $"周任务限制超出: 人员{personnelId}分配了{assignedTasks.Count}个任务,超过限制{workLimit.MaxShiftsPerWeek}个", IsResolved = false }; conflictDetections.Add(conflictInfo); workLimitConflictCount++; } } } _logger.LogInformation("🔍 工作限制超出冲突检测完成 - 发现{ConflictCount}个冲突", workLimitConflictCount); } catch (Exception ex) { _logger.LogError(ex, "💥 工作限制超出冲突检测异常"); } } /// /// 检测负载不均衡冲突 - 基于公平性分析识别负载分配问题 /// private async Task DetectLoadImbalanceConflictsAsync( GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List conflictDetections) { await Task.CompletedTask; // 保持异步接口 try { _logger.LogDebug("🔍 开始负载不均衡冲突检测"); // 【利用公平性分析】从现有的公平性分析结果判断负载均衡情况 var fairnessAnalysis = CalculateWorkloadFairness(optimizedSolution); // 【不均衡阈值检查】基尼系数过高表示负载不均衡 if (fairnessAnalysis.GiniCoefficient > 0.4) // 0.4以上认为不够公平 { // 【识别负载最高和最低的人员】 var workloads = fairnessAnalysis.PersonnelWorkloads.Values.ToList(); if (workloads.Any()) { var maxWorkload = workloads.OrderByDescending(w => w.EstimatedTotalHours).First(); var minWorkload = workloads.OrderBy(w => w.EstimatedTotalHours).First(); // 【创建负载不均衡冲突记录】 var conflictInfo = new GlobalConflictDetectionInfo { ConflictType = GlobalConflictType.LoadImbalance, TaskId = maxWorkload.AssignedTaskIds.FirstOrDefault(), PersonnelId = maxWorkload.PersonnelId, Severity = fairnessAnalysis.GiniCoefficient > 0.5 ? GlobalConflictSeverity.High : GlobalConflictSeverity.Medium, Description = $"负载不均衡: 基尼系数{fairnessAnalysis.GiniCoefficient:F3},最高负载{maxWorkload.EstimatedTotalHours}h,最低负载{minWorkload.EstimatedTotalHours}h", IsResolved = false }; conflictDetections.Add(conflictInfo); _logger.LogInformation("🔍 检测到负载不均衡 - 基尼系数:{Gini:F3}", fairnessAnalysis.GiniCoefficient); } } _logger.LogInformation("🔍 负载不均衡冲突检测完成"); } catch (Exception ex) { _logger.LogError(ex, "💥 负载不均衡冲突检测异常"); } } /// /// 业务规则验证 /// private async Task ExecuteFinalValidationAsync( GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, GlobalAllocationResult result) { _logger.LogInformation("✅ 第5步:执行最终业务规则验证"); // 这里应该调用实际的验证逻辑 // 为了保持代码整洁,这里创建一个默认通过的结果 var finalValidationResult = new FinalValidationResult { IsValid = true, ErrorMessage = null, Violations = new List() }; if (!finalValidationResult.IsValid) { await HandleValidationFailureAsync(finalValidationResult, result); } else { _logger.LogInformation("✅ 最终业务规则验证通过"); } } /// /// 处理验证失败的情况 /// private async Task HandleValidationFailureAsync(FinalValidationResult validationResult, GlobalAllocationResult result) { await Task.CompletedTask; // 保持异步接口 _logger.LogError("❌ 最终业务规则验证失败:{ErrorMessage}", validationResult.ErrorMessage); _logger.LogError("🚨 验证失败详情 - 违规项数:{ViolationCount}", validationResult.Violations?.Count ?? 0); var criticalViolations = validationResult.Violations? .Where(v => v.Severity == GlobalConflictSeverity.Critical).ToList() ?? new List(); if (criticalViolations.Count > 0) { _logger.LogError("🚨 发现{CriticalCount}个严重违规,标记为失败", criticalViolations.Count); result.IsSuccess = false; result.AllocationSummary = $"分配结果存在严重业务规则违规:{validationResult.ErrorMessage}"; } else { _logger.LogWarning("⚠️ 发现非严重违规,继续处理并记录警告"); } if (result.ConflictDetections == null) result.ConflictDetections = new List(); result.ConflictDetections.AddRange(validationResult.Violations); } #endregion #region 结果构建方法 /// /// 构建最终分配结果 /// private void BuildFinalResult( GlobalOptimizedSolution optimizedSolution, GlobalAllocationResult result, GlobalOptimizationMetrics metrics, long elapsedMs) { _logger.LogInformation("🏗️ 第6步:构建最终分配结果"); // 评估整体成功性 var hasCriticalViolations = result.ConflictDetections?.Any(v => v.Severity == GlobalConflictSeverity.Critical) ?? false; var hasValidSolution = optimizedSolution?.BestSolution?.Any() ?? false; result.IsSuccess = optimizedSolution.IsValid && hasValidSolution && !hasCriticalViolations; _logger.LogInformation("📊 分配结果评估 - 算法有效:{AlgorithmValid}, 方案存在:{HasSolution}, 严重违规:{HasCritical}, 最终成功:{FinalSuccess}", optimizedSolution.IsValid, hasValidSolution, hasCriticalViolations, result.IsSuccess); // 转换解决方案 result.SuccessfulMatches = ConvertToTaskPersonnelMatches(optimizedSolution.BestSolution); result.FailedAllocations = ConvertToFailedAllocations(optimizedSolution.FailedTasks); _logger.LogInformation("🎉 分配结果构建完成 - 成功:{IsSuccess},匹配数:{MatchCount}", result.IsSuccess, result.SuccessfulMatches?.Count ?? 0); // 设置性能指标 SetPerformanceMetrics(result, metrics, optimizedSolution, elapsedMs); } /// /// 设置性能指标 /// private void SetPerformanceMetrics( GlobalAllocationResult result, GlobalOptimizationMetrics metrics, GlobalOptimizedSolution optimizedSolution, long elapsedMs) { metrics.ExecutionTimeMs = elapsedMs; metrics.ActualGenerations = optimizedSolution.ActualGenerations; metrics.BestFitnessScore = optimizedSolution.BestFitness; metrics.ConstraintSatisfactionRate = optimizedSolution.ConstraintSatisfactionRate; result.OptimizationMetrics = metrics; // 生成分配摘要 result.AllocationSummary = result.IsSuccess ? GenerateSuccessfulAllocationSummary(result, metrics) : GenerateFailedAllocationSummary(result); } #endregion #region 工具方法 /// /// 计算工作负载公平性 - 基尼系数计算 /// 业务逻辑深度思考: /// 1. 公平性是智能调度的核心目标之一,必须确保没有个别人员承担过重或过轻的工作负载 /// 2. 基尼系数是衡量分配不均匀程度的标准经济学指标,值越接近0表示分配越均匀 /// 3. 需要综合考虑任务数量、预估工时、任务复杂度等多个维度的负载分布 /// 4. 边界情况处理:无分配方案、单一人员、所有人员负载相同等场景 /// 5. 业务场景覆盖:不同技能等级人员的负载能力差异、特殊时段的工作强度调整 /// /// 遗传算法优化后的解决方案,包含任务-人员分配映射和人员负载分布 /// 完整的工作负载公平性分析结果,包括基尼系数、人员负载详情、公平性等级 private GlobalWorkloadFairnessAnalysis CalculateWorkloadFairness(GlobalOptimizedSolution optimizedSolution) { try { _logger.LogDebug("📊 开始计算工作负载公平性分析"); // 边界情况检查:无有效分配方案 if (optimizedSolution?.BestSolution == null || !optimizedSolution.BestSolution.Any()) { _logger.LogWarning("⚠️ 无有效分配方案,返回默认公平性分析"); return CreateDefaultFairnessAnalysis("无有效分配方案"); } // 第一步:构建人员工作负载分布数据 var personnelWorkloads = BuildPersonnelWorkloadDistribution(optimizedSolution); // 边界情况检查:无人员负载数据 if (!personnelWorkloads.Any()) { _logger.LogWarning("⚠️ 无人员负载数据,返回默认公平性分析"); return CreateDefaultFairnessAnalysis("无人员负载数据"); } // 第二步:提取工作负载值用于统计计算 var workloadValues = ExtractWorkloadValues(personnelWorkloads); // 第三步:计算基尼系数 - 核心公平性指标 var giniCoefficient = CalculateGiniCoefficient(workloadValues); // 第四步:计算其他统计指标 var statistics = CalculateWorkloadStatistics(workloadValues); // 第五步:确定公平性等级 var fairnessLevel = DetermineFairnessLevel(giniCoefficient); // 第六步:构建完整的公平性分析结果 var result = new GlobalWorkloadFairnessAnalysis { GiniCoefficient = giniCoefficient, PersonnelWorkloads = personnelWorkloads, FairnessLevel = fairnessLevel, WorkloadStandardDeviation = statistics.StandardDeviation, MaxWorkloadDifference = statistics.MaxDifference }; // 记录详细的计算结果用于业务分析 LogFairnessAnalysisResults(result, personnelWorkloads.Count, workloadValues); _logger.LogDebug("✅ 工作负载公平性分析计算完成"); return result; } catch (Exception ex) { _logger.LogError(ex, "💥 计算工作负载公平性时发生异常"); return CreateDefaultFairnessAnalysis($"计算异常:{ex.Message}"); } } /// /// 构建人员工作负载分布数据 /// 业务思考:需要综合考虑任务数量、工时、复杂度等多维度因素 /// private Dictionary BuildPersonnelWorkloadDistribution( GlobalOptimizedSolution optimizedSolution) { var personnelWorkloads = new Dictionary(); // 方案一:优先使用遗传算法已计算的负载分布(性能最优) if (optimizedSolution.PersonnelWorkloadDistribution?.Any() == true) { _logger.LogDebug("📈 使用遗传算法预计算的负载分布数据"); foreach (var kvp in optimizedSolution.PersonnelWorkloadDistribution) { var personnelId = kvp.Key; var totalWorkload = kvp.Value; // 获取该人员分配的任务ID列表 var assignedTasks = optimizedSolution.BestSolution .Where(s => s.Value == personnelId) .Select(s => s.Key) .ToList(); personnelWorkloads[personnelId] = new GlobalPersonnelWorkloadInfo { PersonnelId = personnelId, PersonnelName = GetPersonnelName(personnelId), AssignedTaskCount = assignedTasks.Count, EstimatedTotalHours = totalWorkload, AssignedTaskIds = assignedTasks, // 工作负载百分比将在后续统一计算 WorkloadPercentage = 0 }; } } else { // 方案二:基于任务分配重新计算负载(fallback方案) _logger.LogDebug("🔄 基于任务分配重新计算人员负载分布"); var personnelTaskGroups = optimizedSolution.BestSolution.GroupBy(kvp => kvp.Value); foreach (var group in personnelTaskGroups) { var personnelId = group.Key; var assignedTasks = group.Select(g => g.Key).ToList(); // 使用默认工时估算(实际项目中应该从任务实体获取) var estimatedHours = assignedTasks.Count * 8.0m; // 假设每个任务8小时 personnelWorkloads[personnelId] = new GlobalPersonnelWorkloadInfo { PersonnelId = personnelId, PersonnelName = GetPersonnelName(personnelId), AssignedTaskCount = assignedTasks.Count, EstimatedTotalHours = estimatedHours, AssignedTaskIds = assignedTasks, WorkloadPercentage = 0 // 将在后续计算 }; } } // 计算工作负载百分比(相对于最大负载的比例) if (personnelWorkloads.Any()) { var maxWorkload = personnelWorkloads.Values.Max(p => p.EstimatedTotalHours); if (maxWorkload > 0) { foreach (var workload in personnelWorkloads.Values) { workload.WorkloadPercentage = (double)(workload.EstimatedTotalHours / maxWorkload) * 100; } } } _logger.LogDebug("📋 人员负载分布构建完成,共{Count}个人员", personnelWorkloads.Count); return personnelWorkloads; } /// /// 提取工作负载数值用于统计计算 /// private List ExtractWorkloadValues(Dictionary personnelWorkloads) { return personnelWorkloads.Values .Select(p => p.EstimatedTotalHours) .OrderBy(x => x) .ToList(); } /// /// 计算基尼系数 - 标准经济学算法实现 /// 数学原理:基尼系数 = (2 * Σ(i * Xi)) / (n * Σ(Xi)) - (n+1) / n /// 其中 Xi 为排序后的第i个数值,i为排序位置,n为总数量 /// 业务意义:0表示完全均匀分配,1表示完全不均匀分配(所有负载集中在一个人) /// private double CalculateGiniCoefficient(List workloadValues) { if (!workloadValues.Any()) { _logger.LogWarning("⚠️ 工作负载数据为空,基尼系数设为0"); return 0; } // 边界情况:只有一个人员 if (workloadValues.Count == 1) { _logger.LogDebug("📌 只有一个人员,基尼系数设为0(完全公平)"); return 0; } var n = workloadValues.Count; var sortedValues = workloadValues.OrderBy(x => x).ToArray(); // 边界情况:所有负载值相同 if (sortedValues.All(x => x == sortedValues[0])) { _logger.LogDebug("📌 所有人员负载相同,基尼系数为0(完全公平)"); return 0; } // 标准基尼系数计算公式 double numerator = 0; for (int i = 0; i < n; i++) { // 公式中的 (2*i + 1 - n) * Xi 部分 numerator += (2 * (i + 1) - n - 1) * (double)sortedValues[i]; } var mean = sortedValues.Average(x => (double)x); if (mean == 0) { _logger.LogWarning("⚠️ 平均负载为0,基尼系数设为0"); return 0; } var giniCoefficient = numerator / (n * n * mean); // 确保基尼系数在有效范围内 [0, 1] giniCoefficient = Math.Max(0, Math.Min(1, giniCoefficient)); _logger.LogDebug("🧮 基尼系数计算完成:{Gini:F4},样本数:{Count},平均值:{Mean:F2}", giniCoefficient, n, mean); return giniCoefficient; } /// /// 计算工作负载统计指标 /// private (double StandardDeviation, decimal MaxDifference) CalculateWorkloadStatistics(List workloadValues) { if (!workloadValues.Any()) { return (0, 0); } // 计算标准差 var mean = workloadValues.Average(x => (double)x); var variance = workloadValues.Average(x => Math.Pow((double)x - mean, 2)); var standardDeviation = Math.Sqrt(variance); // 计算最大差异 var maxWorkload = workloadValues.Max(); var minWorkload = workloadValues.Min(); var maxDifference = maxWorkload - minWorkload; _logger.LogDebug("📊 统计指标 - 标准差:{StdDev:F2},最大差异:{MaxDiff:F2}", standardDeviation, maxDifference); return (standardDeviation, maxDifference); } /// /// 根据基尼系数确定公平性等级 /// 业务规则:基于经济学中收入分配不平等程度的标准划分 /// private GlobalFairnessLevel DetermineFairnessLevel(double giniCoefficient) { // 使用标准的基尼系数分级标准 return giniCoefficient switch { < 0.2 => GlobalFairnessLevel.VeryFair, // 非常公平 < 0.3 => GlobalFairnessLevel.Fair, // 相对公平 < 0.4 => GlobalFairnessLevel.Moderate, // 一般公平 < 0.5 => GlobalFairnessLevel.Unfair, // 不够公平 _ => GlobalFairnessLevel.VeryUnfair // 很不公平 }; } /// /// 创建默认公平性分析结果(用于异常情况) /// private GlobalWorkloadFairnessAnalysis CreateDefaultFairnessAnalysis(string reason) { _logger.LogWarning("🔄 创建默认公平性分析,原因:{Reason}", reason); return new GlobalWorkloadFairnessAnalysis { GiniCoefficient = 0.0, // 默认为完全公平 PersonnelWorkloads = new Dictionary(), FairnessLevel = GlobalFairnessLevel.VeryFair, WorkloadStandardDeviation = 0.0, MaxWorkloadDifference = 0.0m }; } /// /// 记录公平性分析结果的详细日志 /// private void LogFairnessAnalysisResults( GlobalWorkloadFairnessAnalysis result, int personnelCount, List workloadValues) { var avgWorkload = workloadValues.Any() ? workloadValues.Average() : 0; var minWorkload = workloadValues.Any() ? workloadValues.Min() : 0; var maxWorkload = workloadValues.Any() ? workloadValues.Max() : 0; _logger.LogInformation( "📈 公平性分析详情 - 基尼系数:{Gini:F4},公平性:{Level},人员数:{Count}," + "平均负载:{Avg:F1}h,负载范围:{Min:F1}h~{Max:F1}h,标准差:{StdDev:F2}", result.GiniCoefficient, result.FairnessLevel, personnelCount, avgWorkload, minWorkload, maxWorkload, result.WorkloadStandardDeviation ); // 如果公平性较差,记录警告信息供业务分析 if (result.FairnessLevel >= GlobalFairnessLevel.Unfair) { _logger.LogWarning("⚠️ 工作负载分配不够公平,建议调整分配策略或增加人员资源"); } } /// /// 转换为任务人员匹配列表 - 基于字典格式的解决方案 /// private List ConvertToTaskPersonnelMatches(Dictionary solution) { if (solution == null) return new List(); return solution.Select(kvp => new GlobalTaskPersonnelMatch { TaskId = kvp.Key, PersonnelId = kvp.Value, MatchScore = 85, // 默认匹配分数 PersonnelName = GetPersonnelName(kvp.Value), MatchReason = "遗传算法全局优化结果" }).ToList(); } /// /// 转换为失败分配列表 - 基于任务ID列表 /// private List ConvertToFailedAllocations(List failedTaskIds) { if (failedTaskIds == null) return new List(); return failedTaskIds.Select(taskId => new GlobalFailedAllocation { TaskId = taskId, TaskCode = $"WO_{taskId}", FailureReason = "遗传算法无法找到合适的人员分配", ConflictDetails = new List { "检查人员资质匹配度", "验证任务时间冲突", "考虑增加人员池", "调整任务优先级" } }).ToList(); } /// /// 转换为失败分配列表 - 基于工作任务实体列表 /// private List ConvertToFailedAllocations(List failedTasks) { if (failedTasks == null) return new List(); return failedTasks.Select(task => new GlobalFailedAllocation { TaskId = task.Id, TaskCode = task.ProjectNumber ?? $"WO_{task.Id}", FailureReason = "无法找到合适的人员分配", ConflictDetails = new List { "检查人员资质要求", "考虑调整任务时间" } }).ToList(); } /// /// 获取人员姓名 - 带缓存的人员姓名获取 /// private string GetPersonnelName(long personnelId) { if (_personnelNameCache.TryGetValue(personnelId, out var cachedName)) { return cachedName; } // 如果缓存中没有,返回默认格式 var defaultName = $"人员_{personnelId}"; _personnelNameCache[personnelId] = defaultName; return defaultName; } /// /// 设置人员名称缓存 /// public void SetPersonnelNameCache(Dictionary nameMapping) { if (nameMapping != null) { foreach (var kvp in nameMapping) { _personnelNameCache[kvp.Key] = kvp.Value; } } } /// /// 生成成功分配摘要 /// private string GenerateSuccessfulAllocationSummary(GlobalAllocationResult result, GlobalOptimizationMetrics metrics) { var successCount = result.SuccessfulMatches?.Count ?? 0; var failCount = result.FailedAllocations?.Count ?? 0; return $"全局优化分配成功完成!成功分配:{successCount}个任务,失败:{failCount}个任务," + $"执行代数:{metrics.ActualGenerations},最佳适应度:{metrics.BestFitnessScore:F2}," + $"约束满足率:{metrics.ConstraintSatisfactionRate:P2}"; } /// /// 生成失败分配摘要 /// private string GenerateFailedAllocationSummary(GlobalAllocationResult result) { return result.AllocationSummary ?? "全局优化分配未能成功完成,请检查任务和人员配置"; } /// /// 创建错误结果 /// private GlobalAllocationResult CreateErrorResult(string errorMessage) { return new GlobalAllocationResult { IsSuccess = false, AllocationSummary = $"系统异常:{errorMessage}", SuccessfulMatches = new List(), FailedAllocations = new List(), ConflictDetections = new List() }; } #region 智能协商辅助方法 /// /// 分析和优先级排序冲突 - 基于业务影响程度对冲突进行分类排序 /// 【业务逻辑】:将检测到的冲突按照严重程度和业务影响进行分层处理 /// 【深度思考】:不同冲突类型有不同的解决优先级,合理排序有助于提高协商成功率 /// /// 原始冲突检测列表 /// 按优先级排序的冲突分组 private Dictionary> AnalyzeAndPrioritizeConflicts( List conflictDetections) { try { _logger.LogDebug("📊 开始冲突分析与优先级排序"); // 【分层分组】按严重程度分组冲突 var prioritizedConflicts = conflictDetections .GroupBy(c => c.Severity) .ToDictionary(g => g.Key, g => g.OrderBy(c => GetConflictTypeOrder(c.ConflictType)).ToList()); // 【统计分析】记录各类冲突的分布情况 foreach (var group in prioritizedConflicts) { _logger.LogInformation("📊 {Severity}级冲突:{Count}个", group.Key, group.Value.Count); // 【详细分类统计】按冲突类型进一步统计 var typeGroups = group.Value.GroupBy(c => c.ConflictType); foreach (var typeGroup in typeGroups) { _logger.LogDebug(" └─ {ConflictType}:{Count}个", typeGroup.Key, typeGroup.Count()); } } return prioritizedConflicts; } catch (Exception ex) { _logger.LogError(ex, "冲突分析与优先级排序异常"); return new Dictionary>(); } } /// /// 执行智能解决方案策略 - 多策略并行尝试解决冲突 /// 【核心算法】:基于冲突类型和严重程度选择最合适的解决策略 /// 【智能决策】:从人员替换、任务重分配、时间调整等策略中选择最优方案 /// private async Task ExecuteIntelligentResolutionStrategiesAsync( Dictionary> prioritizedConflicts, GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List negotiationActions, List conflictDetections) { try { _logger.LogDebug("💡 开始执行智能解决方案策略"); var resolvedConflictCount = 0; var totalConflictCount = prioritizedConflicts.Values.SelectMany(v => v).Count(); // 【优先处理严重冲突】按严重程度从高到低处理 var severityOrder = new[] { GlobalConflictSeverity.Critical, GlobalConflictSeverity.High, GlobalConflictSeverity.Medium, GlobalConflictSeverity.Low, GlobalConflictSeverity.Warning }; foreach (var severity in severityOrder) { if (!prioritizedConflicts.TryGetValue(severity, out var conflicts) || !conflicts.Any()) continue; _logger.LogInformation("🔧 处理{Severity}级冲突:{Count}个", severity, conflicts.Count); // 【逐个冲突处理】为每个冲突尝试找到解决方案 foreach (var conflict in conflicts) { var resolutionSuccess = await AttemptConflictResolutionAsync( conflict, optimizedSolution, context, negotiationActions); if (resolutionSuccess) { conflict.IsResolved = true; resolvedConflictCount++; _logger.LogDebug("✅ 冲突已解决:{Description}", conflict.Description); } else { _logger.LogWarning("❌ 冲突无法自动解决:{Description}", conflict.Description); // 【人工介入标记】无法自动解决的冲突标记为需要人工介入 var manualAction = new GlobalNegotiationAction { ActionType = GlobalNegotiationActionType.ManualIntervention, TaskId = conflict.TaskId, OriginalPersonnelId = conflict.PersonnelId, Reason = $"自动协商失败,需要人工处理:{conflict.Description}", IsSuccessful = false }; negotiationActions.Add(manualAction); } } } _logger.LogInformation("💡 智能解决方案执行完成 - 解决{ResolvedCount}/{TotalCount}个冲突", resolvedConflictCount, totalConflictCount); } catch (Exception ex) { _logger.LogError(ex, "智能解决方案策略执行异常"); } } /// /// 尝试解决单个冲突 - 核心的冲突解决逻辑 /// 【策略选择】:根据冲突类型智能选择最适合的解决策略 /// 【深度思考】:每种冲突类型都有其特定的最优解决方案,需要针对性处理 /// private async Task AttemptConflictResolutionAsync( GlobalConflictDetectionInfo conflict, GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List negotiationActions) { try { _logger.LogDebug("🔧 尝试解决冲突:{ConflictType} - {Description}", conflict.ConflictType, conflict.Description); // 【策略选择】基于冲突类型选择解决策略 return conflict.ConflictType switch { GlobalConflictType.NextDayRestViolation => await ResolveRestViolationConflictAsync(conflict, optimizedSolution, context, negotiationActions), GlobalConflictType.SameDayShiftContinuity => await ResolveShiftContinuityConflictAsync(conflict, optimizedSolution, context, negotiationActions), GlobalConflictType.QualificationMismatch => await ResolveQualificationMismatchAsync(conflict, optimizedSolution, context, negotiationActions), GlobalConflictType.TimeUnavailable => await ResolveTimeUnavailableConflictAsync(conflict, optimizedSolution, context, negotiationActions), GlobalConflictType.WorkLimitExceeded => await ResolveWorkLimitExceededAsync(conflict, optimizedSolution, context, negotiationActions), GlobalConflictType.LoadImbalance => await ResolveLoadImbalanceAsync(conflict, optimizedSolution, context, negotiationActions), _ => await ResolveGenericConflictAsync(conflict, optimizedSolution, context, negotiationActions) }; } catch (Exception ex) { _logger.LogError(ex, "冲突解决尝试异常:{ConflictType}", conflict.ConflictType); return false; } } /// /// 解决休息规则冲突 - 次日休息规则的专门处理策略 /// private async Task ResolveRestViolationConflictAsync( GlobalConflictDetectionInfo conflict, GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List negotiationActions) { await Task.CompletedTask; // 保持异步接口 // 【策略1】尝试找到替代人员 var alternativePersonnel = FindAlternativePersonnelForTask( conflict.TaskId, conflict.PersonnelId, optimizedSolution, context); if (alternativePersonnel.HasValue) { // 【执行人员替换】 optimizedSolution.BestSolution[conflict.TaskId] = alternativePersonnel.Value; var action = new GlobalNegotiationAction { ActionType = GlobalNegotiationActionType.PersonnelReplacement, TaskId = conflict.TaskId, OriginalPersonnelId = conflict.PersonnelId, NewPersonnelId = alternativePersonnel.Value, Reason = "解决次日休息规则冲突", IsSuccessful = true }; negotiationActions.Add(action); _logger.LogInformation("🔄 次日休息冲突已通过人员替换解决:任务{TaskId}从人员{OldPersonnel}替换为{NewPersonnel}", conflict.TaskId, conflict.PersonnelId, alternativePersonnel.Value); return true; } return false; // 无法找到合适的替代方案 } /// /// 解决班次连续性冲突 - 同天班次冲突的处理策略 /// private async Task ResolveShiftContinuityConflictAsync( GlobalConflictDetectionInfo conflict, GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List negotiationActions) { await Task.CompletedTask; // 【策略1】尝试人员替换 var alternativePersonnel = FindAlternativePersonnelForTask( conflict.TaskId, conflict.PersonnelId, optimizedSolution, context); if (alternativePersonnel.HasValue) { optimizedSolution.BestSolution[conflict.TaskId] = alternativePersonnel.Value; var action = new GlobalNegotiationAction { ActionType = GlobalNegotiationActionType.PersonnelReplacement, TaskId = conflict.TaskId, OriginalPersonnelId = conflict.PersonnelId, NewPersonnelId = alternativePersonnel.Value, Reason = "解决同天班次连续性冲突", IsSuccessful = true }; negotiationActions.Add(action); return true; } return false; } /// /// 解决资质不匹配冲突 - 找到具备合适资质的人员 /// private async Task ResolveQualificationMismatchAsync( GlobalConflictDetectionInfo conflict, GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List negotiationActions) { await Task.CompletedTask; // 【查找有资质的人员】基于任务要求找到合适的人员 var qualifiedPersonnel = FindQualifiedPersonnelForTask(conflict.TaskId, context); if (qualifiedPersonnel.HasValue) { optimizedSolution.BestSolution[conflict.TaskId] = qualifiedPersonnel.Value; var action = new GlobalNegotiationAction { ActionType = GlobalNegotiationActionType.PersonnelReplacement, TaskId = conflict.TaskId, OriginalPersonnelId = conflict.PersonnelId, NewPersonnelId = qualifiedPersonnel.Value, Reason = "解决资质不匹配冲突", IsSuccessful = true }; negotiationActions.Add(action); return true; } return false; } /// /// 解决时间不可用冲突 - 找到该时间段可用的人员 /// private async Task ResolveTimeUnavailableConflictAsync( GlobalConflictDetectionInfo conflict, GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List negotiationActions) { await Task.CompletedTask; // 【查找时间可用的人员】 var availablePersonnel = FindTimeAvailablePersonnelForTask(conflict.TaskId, context); if (availablePersonnel.HasValue) { optimizedSolution.BestSolution[conflict.TaskId] = availablePersonnel.Value; var action = new GlobalNegotiationAction { ActionType = GlobalNegotiationActionType.PersonnelReplacement, TaskId = conflict.TaskId, OriginalPersonnelId = conflict.PersonnelId, NewPersonnelId = availablePersonnel.Value, Reason = "解决时间不可用冲突", IsSuccessful = true }; negotiationActions.Add(action); return true; } return false; } /// /// 解决工作限制超出冲突 - 重新分配任务以满足工作量限制 /// private async Task ResolveWorkLimitExceededAsync( GlobalConflictDetectionInfo conflict, GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List negotiationActions) { await Task.CompletedTask; // 【工作量重分配策略】将部分任务转移给工作量较少的人员 var lightWorkloadPersonnel = FindLightWorkloadPersonnel(optimizedSolution, context); if (lightWorkloadPersonnel.HasValue) { // 【任务转移】将当前冲突任务转移给工作量较少的人员 optimizedSolution.BestSolution[conflict.TaskId] = lightWorkloadPersonnel.Value; var action = new GlobalNegotiationAction { ActionType = GlobalNegotiationActionType.TaskReallocation, TaskId = conflict.TaskId, OriginalPersonnelId = conflict.PersonnelId, NewPersonnelId = lightWorkloadPersonnel.Value, Reason = "解决工作限制超出冲突,均衡工作负载", IsSuccessful = true }; negotiationActions.Add(action); return true; } return false; } /// /// 解决负载不均衡冲突 - 通过任务重分配实现负载平衡 /// private async Task ResolveLoadImbalanceAsync( GlobalConflictDetectionInfo conflict, GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List negotiationActions) { await Task.CompletedTask; // 【负载平衡策略】尝试重新分配部分任务以实现更好的负载平衡 var balancedAllocation = AttemptLoadBalancing(optimizedSolution, context); if (balancedAllocation) { var action = new GlobalNegotiationAction { ActionType = GlobalNegotiationActionType.TaskReallocation, TaskId = conflict.TaskId, OriginalPersonnelId = conflict.PersonnelId, Reason = "通过任务重分配优化负载平衡", IsSuccessful = true }; negotiationActions.Add(action); return true; } return false; } /// /// 解决通用冲突 - 其他类型冲突的通用处理策略 /// private async Task ResolveGenericConflictAsync( GlobalConflictDetectionInfo conflict, GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List negotiationActions) { await Task.CompletedTask; // 【通用策略】尝试最基本的人员替换 var alternativePersonnel = FindAlternativePersonnelForTask( conflict.TaskId, conflict.PersonnelId, optimizedSolution, context); if (alternativePersonnel.HasValue) { optimizedSolution.BestSolution[conflict.TaskId] = alternativePersonnel.Value; var action = new GlobalNegotiationAction { ActionType = GlobalNegotiationActionType.PersonnelReplacement, TaskId = conflict.TaskId, OriginalPersonnelId = conflict.PersonnelId, NewPersonnelId = alternativePersonnel.Value, Reason = "通用冲突解决策略", IsSuccessful = true }; negotiationActions.Add(action); return true; } return false; } /// /// 验证协商结果 - 确保协商后的方案仍然满足基本约束 /// private async Task ValidateNegotiationResultsAsync( GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context, List negotiationActions, List conflictDetections) { await Task.CompletedTask; try { _logger.LogDebug("✅ 开始验证协商结果"); // 【基本一致性检查】确保所有任务都有人员分配 var unassignedTasks = optimizedSolution.BestSolution .Where(kvp => kvp.Value <= 0) .Select(kvp => kvp.Key) .ToList(); if (unassignedTasks.Any()) { _logger.LogWarning("⚠️ 协商后发现{Count}个未分配任务", unassignedTasks.Count); } // 【协商效果评估】计算协商前后的改进情况 var resolvedConflicts = conflictDetections.Count(c => c.IsResolved); var totalConflicts = conflictDetections.Count; var resolutionRate = totalConflicts > 0 ? (double)resolvedConflicts / totalConflicts : 0.0; _logger.LogInformation("✅ 协商结果验证完成 - 解决率:{Rate:P2}({Resolved}/{Total})", resolutionRate, resolvedConflicts, totalConflicts); } catch (Exception ex) { _logger.LogError(ex, "协商结果验证异常"); } } /// /// 记录协商结果日志 - 详细的协商过程和效果统计 /// private void LogNegotiationResults( List negotiationActions, List conflictDetections, TimeSpan negotiationDuration) { try { var successfulActions = negotiationActions.Count(a => a.IsSuccessful); var totalActions = negotiationActions.Count; var resolvedConflicts = conflictDetections.Count(c => c.IsResolved); var totalConflicts = conflictDetections.Count; _logger.LogInformation("🎯 智能协商执行完成统计:"); _logger.LogInformation(" ⏱️ 执行时间:{Duration}ms", negotiationDuration.TotalMilliseconds); _logger.LogInformation(" 🔧 协商操作:成功{Success}/{Total}个", successfulActions, totalActions); _logger.LogInformation(" ✅ 冲突解决:{Resolved}/{Total}个(解决率:{Rate:P2})", resolvedConflicts, totalConflicts, totalConflicts > 0 ? (double)resolvedConflicts / totalConflicts : 0.0); // 【操作类型统计】 var actionTypeGroups = negotiationActions.GroupBy(a => a.ActionType); foreach (var group in actionTypeGroups) { var successful = group.Count(a => a.IsSuccessful); var total = group.Count(); _logger.LogInformation(" └─ {ActionType}:{Success}/{Total}个", group.Key, successful, total); } // 【冲突类型解决统计】 var conflictTypeGroups = conflictDetections.GroupBy(c => c.ConflictType); foreach (var group in conflictTypeGroups) { var resolved = group.Count(c => c.IsResolved); var total = group.Count(); _logger.LogInformation(" └─ {ConflictType}冲突:解决{Resolved}/{Total}个", group.Key, resolved, total); } } catch (Exception ex) { _logger.LogError(ex, "协商结果日志记录异常"); } } /// /// 完成协商并设置空结果 - 无冲突或无有效方案时的处理 /// private async Task CompleteNegotiationWithEmptyResult( GlobalAllocationResult result, List negotiationActions, List conflictDetections) { await Task.CompletedTask; result.NegotiationActions = negotiationActions; if (result.ConflictDetections == null) result.ConflictDetections = new List(); result.ConflictDetections.AddRange(conflictDetections); _logger.LogInformation("🔧 智能协商完成 - 空结果处理"); } /// /// 完成协商并设置结果 - 正常协商流程完成后的结果设置 /// private async Task CompleteNegotiationWithResults( GlobalAllocationResult result, List negotiationActions, List conflictDetections) { await Task.CompletedTask; result.NegotiationActions = negotiationActions; if (result.ConflictDetections == null) result.ConflictDetections = new List(); result.ConflictDetections.AddRange(conflictDetections); _logger.LogInformation("🔧 智能协商完成 - 执行操作:{ActionCount}个,冲突检测:{ConflictCount}个", negotiationActions?.Count ?? 0, conflictDetections?.Count ?? 0); } #endregion #region 智能协商辅助工具方法 /// /// 根据违规信息确定冲突类型 /// private GlobalConflictType DetermineConflictTypeFromViolation(string violation) { if (violation.Contains("次日休息") || violation.Contains("班后一天")) return GlobalConflictType.NextDayRestViolation; if (violation.Contains("同日班次") || violation.Contains("连续")) return GlobalConflictType.SameDayShiftContinuity; if (violation.Contains("连续工作天数")) return GlobalConflictType.WeeklyTaskLimit; if (violation.Contains("周末") || violation.Contains("跨周")) return GlobalConflictType.CrossWeekendContinuity; // 默认返回班次连续性冲突 return GlobalConflictType.SameDayShiftContinuity; } /// /// 根据违规信息确定冲突严重程度 /// private GlobalConflictSeverity DetermineConflictSeverity(string violation) { if (violation.Contains("异常")) return GlobalConflictSeverity.High; if (violation.Contains("超限")) return GlobalConflictSeverity.Critical; if (violation.Contains("冲突")) return GlobalConflictSeverity.High; return GlobalConflictSeverity.Medium; } /// /// 验证人员资质是否满足任务要求 /// private bool ValidatePersonnelQualifications( List personnelQualifications, WorkOrderEntity task) { // 【简化实现】基础资质验证,实际应根据具体业务需求实现 if (!personnelQualifications.Any()) return false; // 检查是否有有效的资质(未过期且激活) var validQualifications = personnelQualifications .Where(q => q.IsActive) .Where(q => !q.ExpiryDate.HasValue || q.ExpiryDate.Value > DateTime.Now) .ToList(); return validQualifications.Any(); } /// /// 获取不可用性原因文本描述 /// private string GetUnavailabilityReasonText(int reasonType) { return reasonType switch { 1 => "个人意愿", 2 => "培训任务", 3 => "会议任务", 4 => "设备维护", 7 => "临时请假", 8 => "计划请假", 9 => "医疗原因", 10 => "家庭事务", 11 => "轮岗安排", 12 => "技能认证", _ => "其他原因" }; } /// /// 根据不可用原因确定冲突严重程度 /// private GlobalConflictSeverity DetermineUnavailabilitySeverity(int reasonType) { return reasonType switch { 7 or 8 or 9 => GlobalConflictSeverity.Critical, // 请假和医疗是硬约束 4 => GlobalConflictSeverity.High, // 设备维护重要性高 3 or 12 => GlobalConflictSeverity.Medium, // 会议和认证中等重要 _ => GlobalConflictSeverity.Low // 其他较低重要性 }; } /// /// 获取冲突类型的处理优先级顺序 /// private int GetConflictTypeOrder(GlobalConflictType conflictType) { return conflictType switch { GlobalConflictType.QualificationMismatch => 1, // 资质问题优先级最高 GlobalConflictType.TimeUnavailable => 2, // 时间不可用次之 GlobalConflictType.NextDayRestViolation => 3, // 休息规则重要 GlobalConflictType.SameDayShiftContinuity => 4, // 班次连续性 GlobalConflictType.WorkLimitExceeded => 5, // 工作限制 GlobalConflictType.WeeklyTaskLimit => 6, // 周限制 GlobalConflictType.CrossWeekendContinuity => 7, // 跨周末连续性 GlobalConflictType.LoadImbalance => 8, // 负载均衡优先级最低 _ => 9 // 其他未知类型 }; } /// /// 查找任务的替代人员 - 核心的人员替换算法 /// 【业务逻辑】:在可用人员池中找到能够胜任该任务且无冲突的人员 /// private long? FindAlternativePersonnelForTask( long taskId, long currentPersonnelId, GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context) { try { // 【获取任务信息】 var task = context.Tasks.FirstOrDefault(t => t.Id == taskId); if (task == null) return null; // 【候选人员筛选】从可用人员中排除当前人员 var candidatePersonnel = context.AvailablePersonnel .Where(p => p.Id != currentPersonnelId && p.IsActive) .ToList(); // 【逐个检查候选人员】找到第一个无冲突的人员 foreach (var candidate in candidatePersonnel) { // 【基础可行性检查】检查预筛选结果 var prefilterKey = $"{taskId}_{candidate.Id}"; if (context.PrefilterResults.TryGetValue(prefilterKey, out var prefilterResult)) { if (prefilterResult.IsFeasible && prefilterResult.PrefilterScore > 60) // 60分以上才考虑 { // 【简化冲突检查】检查基本的时间和资质可用性 if (IsPersonnelAvailableForTask(candidate.Id, task, context)) { return candidate.Id; } } } } return null; // 未找到合适的替代人员 } catch (Exception ex) { _logger.LogError(ex, "查找替代人员异常:任务{TaskId}", taskId); return null; } } /// /// 查找具备资质的人员 - 基于资质匹配的人员查找 /// private long? FindQualifiedPersonnelForTask(long taskId, GlobalAllocationContext context) { try { var task = context.Tasks.FirstOrDefault(t => t.Id == taskId); if (task == null) return null; // 【资质匹配查找】在人员资质缓存中查找合适人员 foreach (var personnelQual in context.PersonnelQualificationsCache) { var personnelId = personnelQual.Key; var qualifications = personnelQual.Value; // 【资质验证】检查是否满足任务资质要求 if (ValidatePersonnelQualifications(qualifications, task)) { // 【可用性检查】确保人员在该时间段可用 if (IsPersonnelAvailableForTask(personnelId, task, context)) { return personnelId; } } } return null; } catch (Exception ex) { _logger.LogError(ex, "查找有资质人员异常:任务{TaskId}", taskId); return null; } } /// /// 查找时间可用的人员 - 基于时间可用性的人员查找 /// private long? FindTimeAvailablePersonnelForTask(long taskId, GlobalAllocationContext context) { try { var task = context.Tasks.FirstOrDefault(t => t.Id == taskId); if (task?.ShiftId == null) return null; // 【时间可用性检查】查找在该时间班次可用的人员 var dateShiftKey = $"{task.WorkOrderDate:yyyy-MM-dd}_{task.ShiftId}"; // 【排除不可用人员】获取该时间段不可用的人员列表 var unavailablePersonnel = context.DateShiftUnavailablePersonnel.GetValueOrDefault(dateShiftKey, new HashSet()); // 【查找可用人员】从全部人员中排除不可用的人员 var availablePersonnel = context.AvailablePersonnel .Where(p => p.IsActive && !unavailablePersonnel.Contains(p.Id)) .FirstOrDefault(); return availablePersonnel?.Id; } catch (Exception ex) { _logger.LogError(ex, "查找时间可用人员异常:任务{TaskId}", taskId); return null; } } /// /// 查找工作负载较轻的人员 - 用于负载均衡 /// private long? FindLightWorkloadPersonnel(GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context) { try { // 【计算各人员工作负载】 var personnelWorkloads = optimizedSolution.BestSolution .GroupBy(kvp => kvp.Value) .ToDictionary(g => g.Key, g => g.Count()); // 【查找最少工作量人员】 var lightestWorkload = personnelWorkloads.Values.Min(); var lightWorkloadPersonnel = personnelWorkloads .Where(kvp => kvp.Value == lightestWorkload) .Select(kvp => kvp.Key) .FirstOrDefault(); return lightWorkloadPersonnel > 0 ? lightWorkloadPersonnel : null; } catch (Exception ex) { _logger.LogError(ex, "查找轻负载人员异常"); return null; } } /// /// 尝试负载均衡 - 通过任务重分配优化负载分布 /// private bool AttemptLoadBalancing(GlobalOptimizedSolution optimizedSolution, GlobalAllocationContext context) { try { // 【简化实现】基础的负载均衡逻辑 // 实际项目中需要复杂的负载重分配算法 var personnelWorkloads = optimizedSolution.BestSolution .GroupBy(kvp => kvp.Value) .ToDictionary(g => g.Key, g => g.Select(x => x.Key).ToList()); var maxWorkload = personnelWorkloads.Values.Max(tasks => tasks.Count); var minWorkload = personnelWorkloads.Values.Min(tasks => tasks.Count); // 【负载差异检查】如果差异过大,尝试重分配 if (maxWorkload - minWorkload > 2) { // 找到负载最重和最轻的人员 var heaviestPersonnel = personnelWorkloads.First(kvp => kvp.Value.Count == maxWorkload); var lightestPersonnel = personnelWorkloads.First(kvp => kvp.Value.Count == minWorkload); // 【任务转移】将一个任务从重负载人员转移到轻负载人员 var taskToTransfer = heaviestPersonnel.Value.First(); optimizedSolution.BestSolution[taskToTransfer] = lightestPersonnel.Key; _logger.LogDebug("🔄 负载均衡:将任务{TaskId}从人员{Heavy}转移到人员{Light}", taskToTransfer, heaviestPersonnel.Key, lightestPersonnel.Key); return true; } return false; } catch (Exception ex) { _logger.LogError(ex, "负载均衡尝试异常"); return false; } } /// /// 检查人员是否可用于特定任务 - 综合可用性检查 /// private bool IsPersonnelAvailableForTask(long personnelId, WorkOrderEntity task, GlobalAllocationContext context) { try { // 【时间可用性检查】 if (task.ShiftId.HasValue) { var dateShiftKey = $"{task.WorkOrderDate:yyyy-MM-dd}_{task.ShiftId}"; if (context.DateShiftUnavailablePersonnel.TryGetValue(dateShiftKey, out var unavailablePersonnel)) { if (unavailablePersonnel.Contains(personnelId)) { return false; // 该时间段不可用 } } } // 【资质检查】 if (context.PersonnelQualificationsCache.TryGetValue(personnelId, out var qualifications)) { if (!ValidatePersonnelQualifications(qualifications, task)) { return false; // 资质不符合 } } // 【工作限制检查】 if (context.PersonnelWorkLimitsRuleCache.TryGetValue(personnelId, out var workLimits)) { // 简化检查:这里应该检查周工作量等限制 // 实际实现时需要更复杂的逻辑 } return true; // 通过所有检查 } catch (Exception ex) { _logger.LogError(ex, "人员可用性检查异常:人员{PersonnelId}任务{TaskId}", personnelId, task.Id); return false; } } #endregion #endregion } }