Asoka.Wang aac34433fa 123
2025-09-04 19:14:24 +08:00

2153 lines
98 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using 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
{
/// <summary>
/// 全局优化引擎 - 专门负责遗传算法优化和结果处理
/// 设计原则:高内聚、低耦合、单一职责、易维护
/// 核心价值:为智能调度提供高性能的全局优化能力
/// </summary>
public class GlobalOptimizationEngine
{
#region
private readonly GeneticAlgorithmEngine _geneticEngine;
private readonly LinearProgrammingEngine _linearProgrammingEngine;
private readonly ILogger<GlobalOptimizationEngine> _logger;
// 人员名称缓存
private readonly Dictionary<long, string> _personnelNameCache = new();
#endregion
#region
/// <summary>
/// 构造函数 - 依赖注入模式
/// </summary>
public GlobalOptimizationEngine(
GeneticAlgorithmEngine geneticEngine,
LinearProgrammingEngine linearProgrammingEngine,
ILogger<GlobalOptimizationEngine> logger)
{
_geneticEngine = geneticEngine ?? throw new ArgumentNullException(nameof(geneticEngine));
_linearProgrammingEngine = linearProgrammingEngine ?? throw new ArgumentNullException(nameof(linearProgrammingEngine));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
#endregion
#region
/// <summary>
/// 执行全局优化算法 - 主入口方法
/// 业务流程:预筛选验证 → 遗传算法优化 → 公平性分析 → 智能协商 → 业务规则验证 → 结果构建
/// 核心流程:遗传算法优化 → 基尼系数计算 → 智能协商 → 结果封装
/// 性能目标:通过精英策略和收敛检测控制计算复杂度
/// </summary>
/// <param name="context">全局分配上下文,包含任务、人员、配置等所有必需信息</param>
/// <returns>优化后的分配结果,包含成功匹配、失败项、性能指标</returns>
public async Task<GlobalAllocationResult> 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
/// <summary>
/// 验证预筛选结果的有效性
/// </summary>
private bool ValidatePrefilterResults(GlobalAllocationContext context, GlobalAllocationResult result)
{
if (!context.PrefilterResults.Any())
{
_logger.LogError("❌ 无预筛选结果!无法进行遗传算法优化");
result.IsSuccess = false;
result.AllocationSummary = "预筛选阶段未找到可行的任务-人员组合";
return false;
}
return true;
}
/// <summary>
/// 记录预筛选统计信息
/// </summary>
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);
}
/// <summary>
/// 记录优化结果统计
/// </summary>
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
/// <summary>
/// 执行优化后的处理流程
/// 包括:公平性分析 → 智能协商 → 业务规则验证
/// </summary>
private async Task ExecutePostOptimizationProcessingAsync(
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
GlobalAllocationResult result)
{
// 公平性分析
await ExecuteFairnessAnalysisAsync(optimizedSolution, result);
// 智能协商
//await ExecuteIntelligentNegotiationAsync(optimizedSolution, context, result);
// 最终业务规则验证
//await ExecuteFinalValidationAsync(optimizedSolution, context, result);
}
/// <summary>
/// 执行公平性分析
/// </summary>
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;
}
/// <summary>
/// 执行智能协商 - 完整的冲突检测与解决方案引擎
/// 【业务价值】:通过智能冲突检测和多策略协商,确保遗传算法结果符合业务规则
/// 【核心逻辑】:分层优先级处理、多维度冲突检测、智能决策选择最优解决方案
/// 【深度思考】:协商成功率直接影响最终分配质量,必须兼顾效率和准确性
/// 【技术特色】:利用预加载数据、并行检测、缓存优化实现高性能智能协商
/// </summary>
/// <param name="optimizedSolution">遗传算法优化后的解决方案</param>
/// <param name="context">全局分配上下文,包含所有必要的缓存数据</param>
/// <param name="result">最终分配结果,用于存储协商操作和冲突检测信息</param>
/// <returns>异步任务</returns>
private async Task ExecuteIntelligentNegotiationAsync(
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
GlobalAllocationResult result)
{
var negotiationStartTime = DateTime.Now;
var negotiationActions = new List<GlobalNegotiationAction>();
var conflictDetections = new List<GlobalConflictDetectionInfo>();
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);
}
}
/// <summary>
/// 执行全面冲突检测 - 多维度并行检测所有潜在冲突
/// 【业务逻辑】:整合班次规则、资质匹配、时间约束、负载均衡等多个维度进行全面检测
/// 【性能优化】:利用预加载缓存和并行检测提升检测效率
/// 【深度思考】:每种冲突类型都有其业务优先级,必须确保检测的完整性和准确性
/// </summary>
/// <param name="optimizedSolution">遗传算法优化解决方案</param>
/// <param name="context">全局分配上下文</param>
/// <param name="conflictDetections">冲突检测结果列表</param>
private async Task ExecuteComprehensiveConflictDetectionAsync(
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalConflictDetectionInfo> conflictDetections)
{
var detectionTasks = new List<Task>();
// 【并行检测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);
}
/// <summary>
/// 检测班次规则冲突 - 利用ShiftRuleValidationEngine进行深度验证
/// 【业务关键】:班次规则是最重要的硬约束,违反会导致排班不可执行
/// 【深度整合】调用现有的ShiftRuleValidationEngine确保验证逻辑的一致性
/// </summary>
private async Task DetectShiftRuleConflictsAsync(
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalConflictDetectionInfo> 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, "💥 班次规则冲突检测整体异常");
}
}
/// <summary>
/// 模拟班次规则验证 - 临时实现后续需要完整整合ShiftRuleValidationEngine
/// 【临时方案】:由于依赖注入的复杂性,先提供基础的规则检测逻辑
/// 【TODO】完整整合ShiftRuleValidationEngine的依赖注入
/// </summary>
private async Task<List<string>> SimulateShiftRuleValidation(
long personnelId,
WorkOrderEntity currentTask,
List<WorkOrderEntity> batchContext,
GlobalAllocationContext context)
{
var violations = new List<string>();
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<string> { $"班次规则验证异常: {ex.Message}" };
}
}
/// <summary>
/// 检测资质匹配冲突 - 确保人员技能符合任务要求
/// 【业务逻辑】:利用预加载的人员资质缓存,快速验证技能匹配度
/// </summary>
private async Task DetectQualificationMismatchesAsync(
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalConflictDetectionInfo> 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, "💥 资质匹配冲突检测异常");
}
}
/// <summary>
/// 检测时间不可用冲突 - 人员请假、培训等不可用时间冲突
/// 【业务逻辑】:利用班次不可用性缓存,快速识别时间冲突
/// </summary>
private async Task DetectTimeUnavailabilityConflictsAsync(
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalConflictDetectionInfo> 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, "💥 时间不可用冲突检测异常");
}
}
/// <summary>
/// 检测工作限制超出冲突 - 人员工作量、连续工作天数等限制
/// </summary>
private async Task DetectWorkLimitExceededConflictsAsync(
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalConflictDetectionInfo> 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, "💥 工作限制超出冲突检测异常");
}
}
/// <summary>
/// 检测负载不均衡冲突 - 基于公平性分析识别负载分配问题
/// </summary>
private async Task DetectLoadImbalanceConflictsAsync(
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalConflictDetectionInfo> 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, "💥 负载不均衡冲突检测异常");
}
}
/// <summary>
/// 业务规则验证
/// </summary>
private async Task ExecuteFinalValidationAsync(
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
GlobalAllocationResult result)
{
_logger.LogInformation("✅ 第5步执行最终业务规则验证");
// 这里应该调用实际的验证逻辑
// 为了保持代码整洁,这里创建一个默认通过的结果
var finalValidationResult = new FinalValidationResult
{
IsValid = true,
ErrorMessage = null,
Violations = new List<GlobalConflictDetectionInfo>()
};
if (!finalValidationResult.IsValid)
{
await HandleValidationFailureAsync(finalValidationResult, result);
}
else
{
_logger.LogInformation("✅ 最终业务规则验证通过");
}
}
/// <summary>
/// 处理验证失败的情况
/// </summary>
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<GlobalConflictDetectionInfo>();
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<GlobalConflictDetectionInfo>();
result.ConflictDetections.AddRange(validationResult.Violations);
}
#endregion
#region
/// <summary>
/// 构建最终分配结果
/// </summary>
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);
}
/// <summary>
/// 设置性能指标
/// </summary>
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
/// <summary>
/// 计算工作负载公平性 - 基尼系数计算
/// 业务逻辑深度思考:
/// 1. 公平性是智能调度的核心目标之一,必须确保没有个别人员承担过重或过轻的工作负载
/// 2. 基尼系数是衡量分配不均匀程度的标准经济学指标值越接近0表示分配越均匀
/// 3. 需要综合考虑任务数量、预估工时、任务复杂度等多个维度的负载分布
/// 4. 边界情况处理:无分配方案、单一人员、所有人员负载相同等场景
/// 5. 业务场景覆盖:不同技能等级人员的负载能力差异、特殊时段的工作强度调整
/// </summary>
/// <param name="optimizedSolution">遗传算法优化后的解决方案,包含任务-人员分配映射和人员负载分布</param>
/// <returns>完整的工作负载公平性分析结果,包括基尼系数、人员负载详情、公平性等级</returns>
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}");
}
}
/// <summary>
/// 构建人员工作负载分布数据
/// 业务思考:需要综合考虑任务数量、工时、复杂度等多维度因素
/// </summary>
private Dictionary<long, GlobalPersonnelWorkloadInfo> BuildPersonnelWorkloadDistribution(
GlobalOptimizedSolution optimizedSolution)
{
var personnelWorkloads = new Dictionary<long, GlobalPersonnelWorkloadInfo>();
// 方案一:优先使用遗传算法已计算的负载分布(性能最优)
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;
}
/// <summary>
/// 提取工作负载数值用于统计计算
/// </summary>
private List<decimal> ExtractWorkloadValues(Dictionary<long, GlobalPersonnelWorkloadInfo> personnelWorkloads)
{
return personnelWorkloads.Values
.Select(p => p.EstimatedTotalHours)
.OrderBy(x => x)
.ToList();
}
/// <summary>
/// 计算基尼系数 - 标准经济学算法实现
/// 数学原理:基尼系数 = (2 * Σ(i * Xi)) / (n * Σ(Xi)) - (n+1) / n
/// 其中 Xi 为排序后的第i个数值i为排序位置n为总数量
/// 业务意义0表示完全均匀分配1表示完全不均匀分配所有负载集中在一个人
/// </summary>
private double CalculateGiniCoefficient(List<decimal> 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;
}
/// <summary>
/// 计算工作负载统计指标
/// </summary>
private (double StandardDeviation, decimal MaxDifference) CalculateWorkloadStatistics(List<decimal> 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);
}
/// <summary>
/// 根据基尼系数确定公平性等级
/// 业务规则:基于经济学中收入分配不平等程度的标准划分
/// </summary>
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 // 很不公平
};
}
/// <summary>
/// 创建默认公平性分析结果(用于异常情况)
/// </summary>
private GlobalWorkloadFairnessAnalysis CreateDefaultFairnessAnalysis(string reason)
{
_logger.LogWarning("🔄 创建默认公平性分析,原因:{Reason}", reason);
return new GlobalWorkloadFairnessAnalysis
{
GiniCoefficient = 0.0, // 默认为完全公平
PersonnelWorkloads = new Dictionary<long, GlobalPersonnelWorkloadInfo>(),
FairnessLevel = GlobalFairnessLevel.VeryFair,
WorkloadStandardDeviation = 0.0,
MaxWorkloadDifference = 0.0m
};
}
/// <summary>
/// 记录公平性分析结果的详细日志
/// </summary>
private void LogFairnessAnalysisResults(
GlobalWorkloadFairnessAnalysis result,
int personnelCount,
List<decimal> 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("⚠️ 工作负载分配不够公平,建议调整分配策略或增加人员资源");
}
}
/// <summary>
/// 转换为任务人员匹配列表 - 基于字典格式的解决方案
/// </summary>
private List<GlobalTaskPersonnelMatch> ConvertToTaskPersonnelMatches(Dictionary<long, long> solution)
{
if (solution == null) return new List<GlobalTaskPersonnelMatch>();
return solution.Select(kvp => new GlobalTaskPersonnelMatch
{
TaskId = kvp.Key,
PersonnelId = kvp.Value,
MatchScore = 85, // 默认匹配分数
PersonnelName = GetPersonnelName(kvp.Value),
MatchReason = "遗传算法全局优化结果"
}).ToList();
}
/// <summary>
/// 转换为失败分配列表 - 基于任务ID列表
/// </summary>
private List<GlobalFailedAllocation> ConvertToFailedAllocations(List<long> failedTaskIds)
{
if (failedTaskIds == null) return new List<GlobalFailedAllocation>();
return failedTaskIds.Select(taskId => new GlobalFailedAllocation
{
TaskId = taskId,
TaskCode = $"WO_{taskId}",
FailureReason = "遗传算法无法找到合适的人员分配",
ConflictDetails = new List<string>
{
"检查人员资质匹配度",
"验证任务时间冲突",
"考虑增加人员池",
"调整任务优先级"
}
}).ToList();
}
/// <summary>
/// 转换为失败分配列表 - 基于工作任务实体列表
/// </summary>
private List<GlobalFailedAllocation> ConvertToFailedAllocations(List<WorkOrderEntity> failedTasks)
{
if (failedTasks == null) return new List<GlobalFailedAllocation>();
return failedTasks.Select(task => new GlobalFailedAllocation
{
TaskId = task.Id,
TaskCode = task.ProjectNumber ?? $"WO_{task.Id}",
FailureReason = "无法找到合适的人员分配",
ConflictDetails = new List<string> { "检查人员资质要求", "考虑调整任务时间" }
}).ToList();
}
/// <summary>
/// 获取人员姓名 - 带缓存的人员姓名获取
/// </summary>
private string GetPersonnelName(long personnelId)
{
if (_personnelNameCache.TryGetValue(personnelId, out var cachedName))
{
return cachedName;
}
// 如果缓存中没有,返回默认格式
var defaultName = $"人员_{personnelId}";
_personnelNameCache[personnelId] = defaultName;
return defaultName;
}
/// <summary>
/// 设置人员名称缓存
/// </summary>
public void SetPersonnelNameCache(Dictionary<long, string> nameMapping)
{
if (nameMapping != null)
{
foreach (var kvp in nameMapping)
{
_personnelNameCache[kvp.Key] = kvp.Value;
}
}
}
/// <summary>
/// 生成成功分配摘要
/// </summary>
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}";
}
/// <summary>
/// 生成失败分配摘要
/// </summary>
private string GenerateFailedAllocationSummary(GlobalAllocationResult result)
{
return result.AllocationSummary ?? "全局优化分配未能成功完成,请检查任务和人员配置";
}
/// <summary>
/// 创建错误结果
/// </summary>
private GlobalAllocationResult CreateErrorResult(string errorMessage)
{
return new GlobalAllocationResult
{
IsSuccess = false,
AllocationSummary = $"系统异常:{errorMessage}",
SuccessfulMatches = new List<GlobalTaskPersonnelMatch>(),
FailedAllocations = new List<GlobalFailedAllocation>(),
ConflictDetections = new List<GlobalConflictDetectionInfo>()
};
}
#region
/// <summary>
/// 分析和优先级排序冲突 - 基于业务影响程度对冲突进行分类排序
/// 【业务逻辑】:将检测到的冲突按照严重程度和业务影响进行分层处理
/// 【深度思考】:不同冲突类型有不同的解决优先级,合理排序有助于提高协商成功率
/// </summary>
/// <param name="conflictDetections">原始冲突检测列表</param>
/// <returns>按优先级排序的冲突分组</returns>
private Dictionary<GlobalConflictSeverity, List<GlobalConflictDetectionInfo>> AnalyzeAndPrioritizeConflicts(
List<GlobalConflictDetectionInfo> 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<GlobalConflictSeverity, List<GlobalConflictDetectionInfo>>();
}
}
/// <summary>
/// 执行智能解决方案策略 - 多策略并行尝试解决冲突
/// 【核心算法】:基于冲突类型和严重程度选择最合适的解决策略
/// 【智能决策】:从人员替换、任务重分配、时间调整等策略中选择最优方案
/// </summary>
private async Task ExecuteIntelligentResolutionStrategiesAsync(
Dictionary<GlobalConflictSeverity, List<GlobalConflictDetectionInfo>> prioritizedConflicts,
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalNegotiationAction> negotiationActions,
List<GlobalConflictDetectionInfo> 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, "智能解决方案策略执行异常");
}
}
/// <summary>
/// 尝试解决单个冲突 - 核心的冲突解决逻辑
/// 【策略选择】:根据冲突类型智能选择最适合的解决策略
/// 【深度思考】:每种冲突类型都有其特定的最优解决方案,需要针对性处理
/// </summary>
private async Task<bool> AttemptConflictResolutionAsync(
GlobalConflictDetectionInfo conflict,
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalNegotiationAction> 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;
}
}
/// <summary>
/// 解决休息规则冲突 - 次日休息规则的专门处理策略
/// </summary>
private async Task<bool> ResolveRestViolationConflictAsync(
GlobalConflictDetectionInfo conflict,
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalNegotiationAction> 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; // 无法找到合适的替代方案
}
/// <summary>
/// 解决班次连续性冲突 - 同天班次冲突的处理策略
/// </summary>
private async Task<bool> ResolveShiftContinuityConflictAsync(
GlobalConflictDetectionInfo conflict,
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalNegotiationAction> 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;
}
/// <summary>
/// 解决资质不匹配冲突 - 找到具备合适资质的人员
/// </summary>
private async Task<bool> ResolveQualificationMismatchAsync(
GlobalConflictDetectionInfo conflict,
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalNegotiationAction> 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;
}
/// <summary>
/// 解决时间不可用冲突 - 找到该时间段可用的人员
/// </summary>
private async Task<bool> ResolveTimeUnavailableConflictAsync(
GlobalConflictDetectionInfo conflict,
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalNegotiationAction> 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;
}
/// <summary>
/// 解决工作限制超出冲突 - 重新分配任务以满足工作量限制
/// </summary>
private async Task<bool> ResolveWorkLimitExceededAsync(
GlobalConflictDetectionInfo conflict,
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalNegotiationAction> 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;
}
/// <summary>
/// 解决负载不均衡冲突 - 通过任务重分配实现负载平衡
/// </summary>
private async Task<bool> ResolveLoadImbalanceAsync(
GlobalConflictDetectionInfo conflict,
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalNegotiationAction> 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;
}
/// <summary>
/// 解决通用冲突 - 其他类型冲突的通用处理策略
/// </summary>
private async Task<bool> ResolveGenericConflictAsync(
GlobalConflictDetectionInfo conflict,
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalNegotiationAction> 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;
}
/// <summary>
/// 验证协商结果 - 确保协商后的方案仍然满足基本约束
/// </summary>
private async Task ValidateNegotiationResultsAsync(
GlobalOptimizedSolution optimizedSolution,
GlobalAllocationContext context,
List<GlobalNegotiationAction> negotiationActions,
List<GlobalConflictDetectionInfo> 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, "协商结果验证异常");
}
}
/// <summary>
/// 记录协商结果日志 - 详细的协商过程和效果统计
/// </summary>
private void LogNegotiationResults(
List<GlobalNegotiationAction> negotiationActions,
List<GlobalConflictDetectionInfo> 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, "协商结果日志记录异常");
}
}
/// <summary>
/// 完成协商并设置空结果 - 无冲突或无有效方案时的处理
/// </summary>
private async Task CompleteNegotiationWithEmptyResult(
GlobalAllocationResult result,
List<GlobalNegotiationAction> negotiationActions,
List<GlobalConflictDetectionInfo> conflictDetections)
{
await Task.CompletedTask;
result.NegotiationActions = negotiationActions;
if (result.ConflictDetections == null)
result.ConflictDetections = new List<GlobalConflictDetectionInfo>();
result.ConflictDetections.AddRange(conflictDetections);
_logger.LogInformation("🔧 智能协商完成 - 空结果处理");
}
/// <summary>
/// 完成协商并设置结果 - 正常协商流程完成后的结果设置
/// </summary>
private async Task CompleteNegotiationWithResults(
GlobalAllocationResult result,
List<GlobalNegotiationAction> negotiationActions,
List<GlobalConflictDetectionInfo> conflictDetections)
{
await Task.CompletedTask;
result.NegotiationActions = negotiationActions;
if (result.ConflictDetections == null)
result.ConflictDetections = new List<GlobalConflictDetectionInfo>();
result.ConflictDetections.AddRange(conflictDetections);
_logger.LogInformation("🔧 智能协商完成 - 执行操作:{ActionCount}个,冲突检测:{ConflictCount}个",
negotiationActions?.Count ?? 0, conflictDetections?.Count ?? 0);
}
#endregion
#region
/// <summary>
/// 根据违规信息确定冲突类型
/// </summary>
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;
}
/// <summary>
/// 根据违规信息确定冲突严重程度
/// </summary>
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;
}
/// <summary>
/// 验证人员资质是否满足任务要求
/// </summary>
private bool ValidatePersonnelQualifications(
List<PersonnelQualificationCacheItem> 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();
}
/// <summary>
/// 获取不可用性原因文本描述
/// </summary>
private string GetUnavailabilityReasonText(int reasonType)
{
return reasonType switch
{
1 => "个人意愿",
2 => "培训任务",
3 => "会议任务",
4 => "设备维护",
7 => "临时请假",
8 => "计划请假",
9 => "医疗原因",
10 => "家庭事务",
11 => "轮岗安排",
12 => "技能认证",
_ => "其他原因"
};
}
/// <summary>
/// 根据不可用原因确定冲突严重程度
/// </summary>
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 // 其他较低重要性
};
}
/// <summary>
/// 获取冲突类型的处理优先级顺序
/// </summary>
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 // 其他未知类型
};
}
/// <summary>
/// 查找任务的替代人员 - 核心的人员替换算法
/// 【业务逻辑】:在可用人员池中找到能够胜任该任务且无冲突的人员
/// </summary>
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;
}
}
/// <summary>
/// 查找具备资质的人员 - 基于资质匹配的人员查找
/// </summary>
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;
}
}
/// <summary>
/// 查找时间可用的人员 - 基于时间可用性的人员查找
/// </summary>
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<long>());
// 【查找可用人员】从全部人员中排除不可用的人员
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;
}
}
/// <summary>
/// 查找工作负载较轻的人员 - 用于负载均衡
/// </summary>
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;
}
}
/// <summary>
/// 尝试负载均衡 - 通过任务重分配优化负载分布
/// </summary>
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;
}
}
/// <summary>
/// 检查人员是否可用于特定任务 - 综合可用性检查
/// </summary>
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
}
}