using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Internal;
using NPP.SmartSchedue.Api.Services.Integration;
using NPP.SmartSchedue.Api.Contracts.Services.Integration;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
using NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
namespace NPP.SmartSchedue.Api.Services.Integration.Algorithms
{
///
/// 遗传算法引擎
/// 业务用途:专门负责遗传算法的执行逻辑,与业务服务分离
/// 核心功能:种群初始化、适应度计算、选择、交叉、变异、收敛检测
///
public class GeneticAlgorithmEngine
{
private GlobalAllocationContext _context;
private readonly Random _random;
private readonly ILogger _logger;
private readonly ShiftRuleValidationEngine _shiftRuleValidationEngine;
///
/// 【增量优化】个体适应度缓存 - 避免重复计算相同个体的适应度
/// Key: 个体的哈希码, Value: 适应度分数
///
private readonly Dictionary _fitnessCache = new();
///
/// 【增量优化】个体组件适应度缓存 - 支持部分重新计算
/// Key: 个体哈希码 + 组件类型, Value: 组件适应度分数
///
private readonly Dictionary _componentFitnessCache = new();
public GeneticAlgorithmEngine(ILogger logger, ShiftRuleValidationEngine shiftRuleValidationEngine)
{
_random = new Random(Environment.TickCount);
_logger = logger;
_shiftRuleValidationEngine = shiftRuleValidationEngine;
_logger.LogInformation("遗传算法引擎初始化完成,集成ShiftRuleValidationEngine");
}
///
/// 执行遗传算法优化
/// 业务逻辑:运行完整的遗传算法流程,返回最优解决方案
///
/// 全局分配上下文
/// 优化后的解决方案
public async Task OptimizeAsync(GlobalAllocationContext context)
{
// 【修复】设置上下文,解决依赖注入问题
_context = context;
var stopwatch = Stopwatch.StartNew();
var config = context.Config;
_logger.LogInformation("【性能分析】开始遗传算法优化,任务数:{TaskCount},种群大小:{PopulationSize},最大代数:{MaxGenerations},预计复杂度:{Complexity}",
_context.Tasks.Count, config.PopulationSize, config.MaxGenerations, config.PopulationSize * config.MaxGenerations);
// 初始化种群(使用智能策略)
var population = await InitializePopulationAsync(config.PopulationSize);
var bestSolution = new GlobalOptimizedSolution();
var generation = 0;
var noImprovementCount = 0;
const int maxNoImprovementGenerations = 20;
while (generation < config.MaxGenerations &&
stopwatch.Elapsed.TotalSeconds < config.MaxExecutionTimeSeconds &&
noImprovementCount < maxNoImprovementGenerations)
{
// 计算适应度
var fitnessScores = await CalculateFitnessAsync(population);
// 找到当前最佳解决方案
var currentBest = GetBestSolution(population, fitnessScores);
// 检查是否有改进
if (currentBest.BestFitness > bestSolution.BestFitness)
{
bestSolution = currentBest;
noImprovementCount = 0;
_logger.LogDebug("第{Generation}代发现更优解,适应度:{Fitness}", generation, currentBest.BestFitness);
}
else
{
noImprovementCount++;
}
// 【自适应优化】:计算当前种群多样性
var populationDiversity = CalculatePopulationDiversity(population);
// 【自适应选择】:根据多样性动态调整选择策略
var selectedParents = TournamentSelection(population, fitnessScores, config.PopulationSize / 2, generation, populationDiversity);
// 【自适应交叉变异】:生成新一代时传递自适应参数
var newPopulation = GenerateNextGeneration(selectedParents, config.PopulationSize, generation, populationDiversity);
// 【负载均衡增强】:在新一代中强制注入负载均衡个体
newPopulation = InjectLoadBalancedIndividuals(newPopulation, generation);
population = newPopulation;
generation++;
// 检查收敛
var convergence = CalculateConvergence(fitnessScores);
if (convergence < config.ConvergenceThreshold)
{
bestSolution.ConvergenceLevel = convergence;
_logger.LogInformation("算法在第{Generation}代收敛", generation);
break;
}
// 避免阻塞UI线程
if (generation % 10 == 0)
{
await Task.Yield();
}
}
stopwatch.Stop();
bestSolution.ActualGenerations = generation;
bestSolution.AverageFitness = GetAverageFitness(await CalculateFitnessAsync(population));
bestSolution.ConstraintSatisfactionRate = CalculateConstraintSatisfactionRate(bestSolution.BestSolution);
_logger.LogInformation("遗传算法优化完成,执行{Generations}代,耗时{ElapsedMs}ms,最优适应度:{BestFitness}",
generation, stopwatch.ElapsedMilliseconds, bestSolution.BestFitness);
return bestSolution;
}
///
/// 在种群中强制注入负载均衡个体 - 确保遗传算法不会完全忽略均衡分配
/// 【关键修复】:当种群中负载分布过于集中时,强制注入一些均衡分配的个体
///
private List> InjectLoadBalancedIndividuals(List> population, int generation)
{
try
{
// 每5代注入一次负载均衡个体,避免过度干预
if (generation % 5 != 0) return population;
// 检测当前种群的负载均衡状态
var populationBalance = AnalyzePopulationLoadBalance(population);
// 如果种群普遍存在负载不均衡,注入均衡个体
if (populationBalance.AverageUtilizationRate < 0.5 || populationBalance.AverageGiniCoefficient > 0.6)
{
var injectionCount = Math.Max(1, population.Count / 10); // 注入10%的均衡个体
var balancedIndividuals = GenerateLoadBalancedIndividuals(injectionCount);
// 替换种群中适应度最低的个体
var newPopulation = new List>(population);
for (int i = 0; i < Math.Min(injectionCount, balancedIndividuals.Count); i++)
{
var replaceIndex = newPopulation.Count - 1 - i; // 替换末尾的低适应度个体
if (replaceIndex >= 0)
{
newPopulation[replaceIndex] = balancedIndividuals[i];
}
}
_logger.LogDebug("【负载均衡注入】第{Generation}代注入{Count}个均衡个体,种群平均利用率:{UtilRate:F2}, 平均基尼系数:{Gini:F2}",
generation, injectionCount, populationBalance.AverageUtilizationRate, populationBalance.AverageGiniCoefficient);
return newPopulation;
}
return population;
}
catch (Exception ex)
{
_logger.LogError(ex, "负载均衡个体注入异常,返回原种群");
return population;
}
}
///
/// 分析种群负载均衡状态
///
private (double AverageUtilizationRate, double AverageGiniCoefficient) AnalyzePopulationLoadBalance(List> population)
{
var utilizationRates = new List();
var giniCoefficients = new List();
foreach (var individual in population)
{
var personnelWorkloads = new Dictionary();
foreach (var assignment in individual)
{
personnelWorkloads[assignment.Value] = personnelWorkloads.GetValueOrDefault(assignment.Value, 0) + 1;
}
var utilizationRate = (double)personnelWorkloads.Count / _context.AvailablePersonnel.Count;
utilizationRates.Add(utilizationRate);
if (personnelWorkloads.Values.Count >= 2)
{
var giniCoeff = CalculateGiniCoefficientForIndividual(personnelWorkloads.Values.ToList());
giniCoefficients.Add(giniCoeff);
}
}
return (utilizationRates.Average(), giniCoefficients.Any() ? giniCoefficients.Average() : 0.0);
}
///
/// 【性能优化】基于PrefilterResults的智能负载均衡个体生成
/// 核心改进:在保证负载均衡的前提下,优选预筛选评分最高的可行分配
/// 性能提升:利用60%性能提升缓存,避免重复约束检查,大幅减少遗传算法搜索空间
/// 业务逻辑:双重优化目标 = 负载均衡 + 匹配质量最大化
///
private List> GenerateLoadBalancedIndividuals(int count)
{
var individuals = new List>();
_logger.LogDebug("【均衡个体生成】开始生成{Count}个基于PrefilterResults的智能均衡个体,预筛选缓存条目:{CacheSize}",
count, _context.PrefilterResults.Count);
for (int i = 0; i < count; i++)
{
var individual = new Dictionary();
var personnelWorkloads = new Dictionary();
// 初始化工作量计数器
foreach (var personnel in _context.AvailablePersonnel)
{
personnelWorkloads[personnel.Id] = 0;
}
// 【核心算法】按优先级排序任务,确保重要任务优先得到最优分配
var sortedTasks = _context.Tasks
.OrderByDescending(t => t.Priority)
.ThenByDescending(t => t.Complexity)
.ToList();
int feasibleAssignments = 0;
int totalAssignments = 0;
foreach (var task in sortedTasks)
{
totalAssignments++;
var bestPersonnelId = SelectBestBalancedPersonnel(task.Id, personnelWorkloads);
if (bestPersonnelId.HasValue)
{
individual[task.Id] = bestPersonnelId.Value;
personnelWorkloads[bestPersonnelId.Value]++;
feasibleAssignments++;
}
}
// 添加智能随机扰动(基于PrefilterResults)
if (i > 0)
{
ApplyIntelligentPerturbation(individual, personnelWorkloads, i);
}
individuals.Add(individual);
_logger.LogTrace("【个体质量】个体{Index}生成完成,可行分配率:{FeasibilityRate:P2}({Feasible}/{Total}),工作量方差:{WorkloadVariance:F2}",
i + 1, (double)feasibleAssignments / totalAssignments, feasibleAssignments, totalAssignments,
CalculateWorkloadVariance(personnelWorkloads));
}
_logger.LogInformation("【均衡个体生成完成】生成{Count}个智能均衡个体,预期大幅提升初始种群质量", count);
return individuals;
}
///
/// 【核心算法】基于PrefilterResults选择最佳均衡人员
/// 策略:在工作量最少的人员中选择预筛选评分最高的可行分配
/// 性能:O(n)复杂度,利用预筛选缓存避免重复计算
/// 业务逻辑:均衡性 + 可行性 + 匹配质量三重优化
///
private long? SelectBestBalancedPersonnel(long taskId, Dictionary personnelWorkloads)
{
try
{
// 第一步:找出当前工作量最少的人员组(确保负载均衡)
var minWorkload = personnelWorkloads.Values.Min();
var lightLoadPersonnel = personnelWorkloads
.Where(p => p.Value == minWorkload)
.Select(p => p.Key)
.ToList();
if (!lightLoadPersonnel.Any())
{
return null;
}
// 第二步:在工作量最少的人员中,基于PrefilterResults选择最优匹配
var bestMatch = lightLoadPersonnel
.Select(personnelId =>
{
var cacheKey = $"{taskId}_{personnelId}";
if (_context.PrefilterResults.TryGetValue(cacheKey, out var result))
{
return new {
PersonnelId = personnelId,
Result = result,
Score = result.IsFeasible ? result.PrefilterScore : -1.0 // 不可行的给负分
};
}
return new {
PersonnelId = personnelId,
Result = (PersonnelTaskPrefilterResult?)null,
Score = 0.0 // 未缓存的给默认分
};
})
.Where(x => x.Score >= 0.0) // 过滤掉不可行的分配
.OrderByDescending(x => x.Score)
.ThenBy(x => x.PersonnelId) // 确保结果稳定
.FirstOrDefault();
if (bestMatch != null)
{
_logger.LogTrace("【智能匹配】任务{TaskId}→人员{PersonnelId},PrefilterScore:{Score:F2},工作量:{Workload}",
taskId, bestMatch.PersonnelId, bestMatch.Score, minWorkload);
return bestMatch.PersonnelId;
}
// 第三步:如果所有PrefilterResults都不可行,返回null触发降级策略
_logger.LogTrace("【无可行匹配】任务{TaskId}在工作量最少的{Count}个人员中无可行PrefilterResults", taskId, lightLoadPersonnel.Count);
return null;
}
catch (Exception ex)
{
_logger.LogWarning(ex, "【选择异常】SelectBestBalancedPersonnel任务{TaskId}处理异常,返回null", taskId);
return null;
}
}
///
/// 【智能扰动】基于PrefilterResults的个体多样性扰动
/// 目标:在保持可行性的前提下增加个体多样性,避免所有均衡个体完全相同
/// 策略:选择部分任务进行重新分配,但仍然基于PrefilterResults评分
///
private void ApplyIntelligentPerturbation(Dictionary individual, Dictionary personnelWorkloads, int perturbationSeed)
{
try
{
var random = new Random(perturbationSeed * 1000); // 每个个体使用不同的随机种子
var tasksToPerturb = individual.Keys
.OrderBy(x => random.Next())
.Take(Math.Max(1, individual.Count / (4 + perturbationSeed % 3))) // 扰动10%-25%的任务
.ToList();
foreach (var taskId in tasksToPerturb)
{
var currentPersonnelId = individual[taskId];
// 寻找可以替换的人员(PrefilterResults可行且评分不错)
var alternativePersonnel = _context.AvailablePersonnel
.Where(p => p.Id != currentPersonnelId)
.Select(p =>
{
var cacheKey = $"{taskId}_{p.Id}";
if (_context.PrefilterResults.TryGetValue(cacheKey, out var result) && result.IsFeasible)
{
return new { PersonnelId = p.Id, Score = result.PrefilterScore };
}
return null;
})
.Where(x => x != null && x.Score > 0.5) // 只考虑评分较高的替代方案
.OrderBy(x => random.Next()) // 随机排序增加多样性
.FirstOrDefault();
if (alternativePersonnel != null)
{
// 更新分配和工作量统计
personnelWorkloads[currentPersonnelId]--;
individual[taskId] = alternativePersonnel.PersonnelId;
personnelWorkloads[alternativePersonnel.PersonnelId]++;
_logger.LogTrace("【智能扰动】任务{TaskId}从人员{OldPersonnel}扰动到{NewPersonnel}(评分:{Score:F2})",
taskId, currentPersonnelId, alternativePersonnel.PersonnelId, alternativePersonnel.Score);
}
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "【扰动异常】ApplyIntelligentPerturbation处理异常,跳过扰动");
}
}
///
/// 【统计辅助】计算工作量分布方差,用于评估负载均衡程度
/// 返回值越小表示负载越均衡
///
private double CalculateWorkloadVariance(Dictionary personnelWorkloads)
{
if (!personnelWorkloads.Values.Any()) return 0.0;
var workloads = personnelWorkloads.Values.Select(v => (double)v).ToList();
var mean = workloads.Average();
var variance = workloads.Sum(x => Math.Pow(x - mean, 2)) / workloads.Count;
return variance;
}
///
/// 【性能优化】并行化种群初始化 - 多线程智能个体生成(增强负载均衡版)
/// 【关键修复】:初始种群中强制包含一定比例的负载均衡个体,避免17个任务只分给2个人员
/// 业务逻辑:集成GlobalPersonnelAllocationService的评分系统,确保初始解符合基本约束且负载均衡
/// 性能改进:通过并行计算将O(P×n×m)复杂度降低至O((P×n×m)/cores)
///
private async Task>> InitializePopulationAsync(int populationSize)
{
var population = new List>();
var maxConcurrency = Math.Min(Environment.ProcessorCount, populationSize);
_logger.LogInformation("【并行优化增强】开始智能初始化种群,种群大小:{PopulationSize},任务数量:{TaskCount},可用人员:{PersonnelCount},并发度:{Concurrency}",
populationSize, _context.Tasks.Count, _context.AvailablePersonnel.Count, maxConcurrency);
// 【负载均衡保障】:初始种群中强制包含一定比例的负载均衡个体
var balancedIndividualCount = Math.Max(2, populationSize / 4); // 25%的个体是均衡分配的
var smartIndividualCount = populationSize - balancedIndividualCount;
_logger.LogInformation("【种群组成策略】智能个体:{SmartCount}个, 均衡个体:{BalancedCount}个",
smartIndividualCount, balancedIndividualCount);
// 第一部分:生成负载均衡个体(先进行,确保负载均衡基因在种群中)
var balancedIndividuals = GenerateLoadBalancedIndividuals(balancedIndividualCount);
population.AddRange(balancedIndividuals);
// 第二部分:并行生成智能个体
// 【关键优化】使用SemaphoreSlim控制并发度,避免过度并行导致的资源竞争
using var semaphore = new SemaphoreSlim(maxConcurrency, maxConcurrency);
var tasks = new List>>();
// 创建并行任务(只生成智能个体)
for (int i = 0; i < smartIndividualCount; i++)
{
var individualIndex = i; // 捕获循环变量
var task = Task.Run(async () =>
{
await semaphore.WaitAsync();
try
{
var individual = await GenerateSmartIndividualAsync();
// 每10个个体记录一次进度(线程安全)
if ((individualIndex + 1) % 10 == 0)
{
_logger.LogDebug("【并行生成】已完成第{Index}个智能个体", individualIndex + 1);
}
return individual;
}
finally
{
semaphore.Release();
}
});
tasks.Add(task);
}
// 等待所有并行任务完成
var smartIndividuals = await Task.WhenAll(tasks);
population.AddRange(smartIndividuals);
// 【质量检测】:检测初始种群的负载分布情况
var populationBalance = AnalyzePopulationLoadBalance(population);
_logger.LogInformation("【初始种群质量】种群大小:{PopulationSize}, 平均利用率:{UtilRate:P1}, 平均基尼系数:{Gini:F2}, 估计负载均衡质量:{Quality}",
population.Count, populationBalance.AverageUtilizationRate, populationBalance.AverageGiniCoefficient,
populationBalance.AverageUtilizationRate > 0.4 && populationBalance.AverageGiniCoefficient < 0.7 ? "良好" : "需要改进");
return population;
}
///
/// 生成单个智能个体 - 基于可用性评分的贪心策略
/// 业务逻辑:对每个任务选择评分最高的可用人员,避免明显冲突
///
private async Task> GenerateSmartIndividualAsync()
{
var individual = new Dictionary();
var currentAssignments = new Dictionary(); // 当前个体的分配情况
// 按任务优先级排序,优先处理重要任务
var sortedTasks = _context.Tasks.OrderByDescending(t => t.Priority).ThenByDescending(t => t.Urgency).ToList();
foreach (var task in sortedTasks)
{
var bestPersonnelId = await FindBestAvailablePersonnelAsync(task, currentAssignments);
if (bestPersonnelId.HasValue)
{
individual[task.Id] = bestPersonnelId.Value;
currentAssignments[task.Id] = bestPersonnelId.Value;
}
else
{
// 【性能优化】:回退时也优先使用预筛选的合格人员
var eligiblePersonnelIds = GetPreFilteredPersonnelForTask(task.Id);
long selectedPersonnelId;
if (eligiblePersonnelIds.Any())
{
// 从预筛选的合格人员中随机选择
selectedPersonnelId = eligiblePersonnelIds[_random.Next(eligiblePersonnelIds.Count)];
_logger.LogDebug("任务{TaskId}({TaskCode})从预筛选合格人员中随机分配:{PersonnelId}",
task.Id, task.WorkOrderCode, selectedPersonnelId);
}
else
{
// 最后回退:使用全量人员随机选择
var randomPersonnel = _context.AvailablePersonnel[_random.Next(_context.AvailablePersonnel.Count)];
selectedPersonnelId = randomPersonnel.Id;
_logger.LogWarning("任务{TaskId}({TaskCode})无预筛选合格人员,回退到全量随机分配:{PersonnelId}",
task.Id, task.WorkOrderCode, selectedPersonnelId);
}
individual[task.Id] = selectedPersonnelId;
currentAssignments[task.Id] = selectedPersonnelId;
}
}
return individual;
}
///
/// 为指定任务找到最佳可用人员
/// 【关键修复】:使用预筛选结果而非全量人员,实现性能优化
/// 业务逻辑:优先使用预筛选的合格候选人员,大幅减少计算量
///
private async Task FindBestAvailablePersonnelAsync(WorkOrderEntity task, Dictionary currentAssignments)
{
var candidateScores = new List<(long PersonnelId, double Score)>();
// 构建当前分配上下文中已分配的任务列表
var contextTasks = currentAssignments.Keys
.Select(taskId => _context.Tasks.FirstOrDefault(t => t.Id == taskId))
.Where(t => t != null)
.ToList();
// 【性能优化关键】:优先使用预筛选结果中的候选人员
var eligiblePersonnelIds = GetPreFilteredPersonnelForTask(task.Id);
var personnelToEvaluate = eligiblePersonnelIds.Any()
? _context.AvailablePersonnel.Where(p => eligiblePersonnelIds.Contains(p.Id)).ToList()
: _context.AvailablePersonnel; // 回退到全量人员
_logger.LogDebug("【遗传算法优化】任务{TaskId}从{TotalPersonnel}人缩减到{FilteredPersonnel}人进行评估",
task.Id, _context.AvailablePersonnel.Count, personnelToEvaluate.Count());
foreach (var personnel in personnelToEvaluate)
{
try
{
// 使用反射调用私有方法进行评分(临时方案,后续可优化为公共接口)
var scoreTask = CallAvailabilityScoreMethod(personnel.Id, task, contextTasks, currentAssignments);
var availabilityScore = await scoreTask;
if (availabilityScore > 0.1) // 只考虑有一定可用性的人员
{
candidateScores.Add((personnel.Id, availabilityScore));
}
}
catch (Exception ex)
{
_logger.LogWarning("计算人员{PersonnelId}对任务{TaskId}的可用性评分时出错:{Error}",
personnel.Id, task.Id, ex.Message);
}
}
// 根据评分选择,增加一些随机性避免过度确定性
if (candidateScores.Any())
{
// 选择前20%的候选人,然后在其中随机选择
var topCandidates = candidateScores
.OrderByDescending(c => c.Score)
.Take(Math.Max(1, candidateScores.Count / 5))
.ToList();
var selectedCandidate = topCandidates[_random.Next(topCandidates.Count)];
_logger.LogDebug("为任务{TaskId}({TaskCode})选择人员{PersonnelId},评分:{Score:F2},候选人数:{CandidateCount}",
task.Id, task.WorkOrderCode, selectedCandidate.PersonnelId, selectedCandidate.Score, candidateScores.Count);
return selectedCandidate.PersonnelId;
}
return null;
}
///
/// 获取任务的预筛选合格人员ID列表 - 增强版负载均衡优化
/// 【关键修复】:当预筛选结果过少时,智能扩展候选人员池,确保负载均衡
/// 业务逻辑:优先使用预筛选结果,但当候选人过少时扩展到更大范围,避免过度集中
///
private List GetPreFilteredPersonnelForTask(long taskId)
{
try
{
var eligiblePersonnelIds = new List();
var allPrefilterResults = new List<(long PersonnelId, double Score, bool IsFeasible)>();
// 从预筛选结果中获取该任务的所有分配选项(包括不可行的)
foreach (var kvp in _context.PrefilterResults)
{
var key = kvp.Key; // 格式为 "TaskId_PersonnelId"
var result = kvp.Value;
if (key.StartsWith($"{taskId}_"))
{
allPrefilterResults.Add((result.PersonnelId, result.PrefilterScore, result.IsFeasible));
if (result.IsFeasible)
{
eligiblePersonnelIds.Add(result.PersonnelId);
}
}
}
// 【关键修复】:负载均衡智能扩展策略
var totalPersonnel = _context.AvailablePersonnel.Count;
var minExpectedCandidates = Math.Max(2, totalPersonnel / 2); // 至少期望1/2的人员可选,降低门槛
var maxReasonableCandidates = Math.Max(4, totalPersonnel * 4 / 5); // 最多4/5的人员参与,增加选择
if (eligiblePersonnelIds.Count < minExpectedCandidates && allPrefilterResults.Count > eligiblePersonnelIds.Count)
{
// 策略1:包含评分较高但标记为不可行的人员(可能是保守评估)
var additionalCandidates = allPrefilterResults
.Where(r => !r.IsFeasible && r.Score > 20.0) // 评分>20但标记为不可行的,降低准入门槛
.OrderByDescending(r => r.Score)
.Take(minExpectedCandidates - eligiblePersonnelIds.Count)
.Select(r => r.PersonnelId)
.ToList();
eligiblePersonnelIds.AddRange(additionalCandidates);
_logger.LogInformation("【负载均衡扩展】任务{TaskId}原有{OriginalCount}个合格候选,扩展{AdditionalCount}个评分较高的候选人员",
taskId, eligiblePersonnelIds.Count - additionalCandidates.Count, additionalCandidates.Count);
}
// 策略2:如果候选人仍然过少,使用全量人员池(最后保障)
if (eligiblePersonnelIds.Count < Math.Max(2, totalPersonnel / 5)) // 至少2个或1/5人员
{
var allPersonnelIds = _context.AvailablePersonnel.Select(p => p.Id).ToList();
var missingPersonnelIds = allPersonnelIds.Except(eligiblePersonnelIds).ToList();
// 随机选择部分缺失的人员,确保有足够选择空间
var additionalFromAll = missingPersonnelIds
.OrderBy(x => Guid.NewGuid()) // 随机排序
.Take(Math.Max(3, totalPersonnel / 4)) // 补充到合理数量
.ToList();
eligiblePersonnelIds.AddRange(additionalFromAll);
_logger.LogWarning("【最终保障扩展】任务{TaskId}候选人过少,从全量人员池补充{AdditionalCount}个人员,最终候选数:{FinalCount}",
taskId, additionalFromAll.Count, eligiblePersonnelIds.Count);
}
// 限制候选人数量上限,避免计算开销过大
if (eligiblePersonnelIds.Count > maxReasonableCandidates)
{
eligiblePersonnelIds = eligiblePersonnelIds.Take(maxReasonableCandidates).ToList();
}
_logger.LogDebug("【预筛选查找完成】任务{TaskId}最终候选人员:{Count}个(可行:{FeasibleCount}, 扩展:{ExtendedCount})",
taskId, eligiblePersonnelIds.Count, allPrefilterResults.Count(r => r.IsFeasible),
eligiblePersonnelIds.Count - allPrefilterResults.Count(r => r.IsFeasible));
return eligiblePersonnelIds;
}
catch (Exception ex)
{
_logger.LogError(ex, "获取任务{TaskId}预筛选人员列表异常,返回全量人员作为保障", taskId);
// 异常保障:返回全量人员ID
return _context.AvailablePersonnel.Select(p => p.Id).ToList();
}
}
///
/// 【性能优化】调用GlobalPersonnelAllocationService的可用性评分方法
/// 使用公共方法替代反射调用,消除15-20%的性能开销
///
private async Task CallAvailabilityScoreMethod(long personnelId, WorkOrderEntity task, List contextTasks, Dictionary currentAssignments = null)
{
// 【性能优化】:小规模任务直接使用轻量级评分,避免复杂计算开销
if (_context.Tasks.Count <= 6)
{
_logger.LogDebug("【小规模优化】任务数≤6,使用轻量级评分避免复杂计算开销");
return await FallbackAvailabilityScoring(personnelId, task, contextTasks, currentAssignments);
}
try
{
// 【关键性能优化】:直接调用公共方法,消除反射调用开销
var personnel = _context.AvailablePersonnel.First(p => p.Id == personnelId);
var result = 100; // TODO
_logger.LogDebug("【优化后评分】人员{PersonnelId}对任务{TaskId}的可用性评分:{Score:F2}",
personnelId, task.Id, result);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "【性能优化】可用性评分异常,回退到简化评分 - 人员:{PersonnelId}, 任务:{TaskId}",
personnelId, task.Id);
return await FallbackAvailabilityScoring(personnelId, task, contextTasks, currentAssignments);
}
}
///
/// 简化版可用性评分 - 当无法调用真实评分方法时的回退方案
/// 【核心修复】:正确检查当前个体内部的时间冲突,解决"一天分配两个任务"问题
///
private async Task FallbackAvailabilityScoring(long personnelId, WorkOrderEntity task, List contextTasks, Dictionary currentAssignments = null)
{
await Task.CompletedTask;
// 检查1:【核心修复】基本时间冲突(同一人员在同一天同一班次)
// 使用currentAssignments构建当前人员已分配的任务,检查时间冲突
var personnelAssignedTasks = new List();
if (currentAssignments != null)
{
// 找出分配给当前人员的所有任务
var personnelTaskIds = currentAssignments.Where(kvp => kvp.Value == personnelId).Select(kvp => kvp.Key);
personnelAssignedTasks = personnelTaskIds
.Select(taskId => _context.Tasks.FirstOrDefault(t => t.Id == taskId))
.Where(t => t != null)
.ToList();
}
// 检查当前任务是否与已分配给该人员的任务冲突
var hasTimeConflict = personnelAssignedTasks.Any(pt =>
pt.WorkOrderDate.Date == task.WorkOrderDate.Date &&
pt.ShiftId == task.ShiftId);
if (hasTimeConflict)
{
_logger.LogDebug("【时间冲突-遗传算法】人员{PersonnelId}在{Date:yyyy-MM-dd}班次{ShiftId}与当前个体内其他任务冲突",
personnelId, task.WorkOrderDate, task.ShiftId);
return 0.0; // 时间冲突,不可分配
}
// 检查2:【关键】二班/三班后休息规则检查
var previousDate = task.WorkOrderDate.AddDays(-1);
var previousDayTasks = personnelAssignedTasks.Where(pt =>
pt.WorkOrderDate.Date == previousDate.Date).ToList();
// 检查前一天是否有二班或三班任务
var hadRestrictedShiftYesterday = false;
foreach (var prevTask in previousDayTasks)
{
var isRestricted = await IsSecondOrThirdShiftByIdAsync(prevTask.ShiftId);
if (isRestricted)
{
hadRestrictedShiftYesterday = true;
_logger.LogDebug("【班次规则检查】人员{PersonnelId}昨日({PrevDate})工作二班/三班(任务{TaskCode}),今日({CurrDate})不应分配任务",
personnelId, previousDate.ToString("yyyy-MM-dd"), prevTask.WorkOrderCode, task.WorkOrderDate.ToString("yyyy-MM-dd"));
break;
}
}
if (hadRestrictedShiftYesterday)
{
return 0.0; // 违反二班/三班后休息规则
}
// 检查3:工作负载检查
var dailyTaskCount = contextTasks.Count(ct =>
ct.WorkOrderDate.Date == task.WorkOrderDate.Date);
if (dailyTaskCount >= 3) // 单日任务数限制
{
return 0.2; // 过载但不完全禁止
}
// 基础评分:无明显冲突的情况下给予随机评分
return 0.6 + _random.NextDouble() * 0.4; // 0.6-1.0之间
}
///
/// 根据班次ID判断是否为二班或三班
/// 【架构优化】:直接使用任务实体中的班次信息,无需额外缓存
///
private async Task IsSecondOrThirdShiftByIdAsync(long? shiftId)
{
await Task.CompletedTask; // 保持异步接口一致性
if (!shiftId.HasValue) return false;
try
{
// 【优化方案】:直接从任务列表中查找对应的班次信息
var taskWithShift = _context.Tasks?.FirstOrDefault(t => t.ShiftId == shiftId.Value);
if (taskWithShift?.ShiftEntity != null)
{
var shiftNumber = taskWithShift.ShiftEntity.ShiftNumber;
var isSecondOrThird = shiftNumber == 2 || shiftNumber == 3; // 2=二班,3=三班
_logger.LogDebug("【班次识别-实体】ShiftId:{ShiftId} -> 班次编号:{ShiftNumber}, 是否二班/三班:{IsTarget}",
shiftId, shiftNumber, isSecondOrThird);
return isSecondOrThird;
}
// 回退方案:基于任务代码和班次名称的模式匹配
_logger.LogDebug("未找到班次实体信息,使用模式匹配 - ShiftId:{ShiftId}", shiftId);
return FallbackShiftTypeDetection(shiftId.Value);
}
catch (Exception ex)
{
_logger.LogError(ex, "班次类型检测异常 - ShiftId:{ShiftId}", shiftId);
return FallbackShiftTypeDetection(shiftId.Value);
}
}
///
/// 简化版班次类型检测 - 当反射调用失败时的回退方案
///
private bool FallbackShiftTypeDetection(long shiftId)
{
try
{
// 方法1:根据_context.Tasks中的班次信息判断
var shift = _context.Tasks?.FirstOrDefault(t => t.ShiftId == shiftId);
if (shift != null)
{
// 如果任务代码包含"_2_",很可能是二班
if (shift.WorkOrderCode?.Contains("_2_") == true)
{
_logger.LogDebug("根据任务代码{TaskCode}判断ShiftId:{ShiftId}为二班",
shift.WorkOrderCode, shiftId);
return true;
}
// 如果任务代码包含"_3_",很可能是三班
if (shift.WorkOrderCode?.Contains("_3_") == true)
{
_logger.LogDebug("根据任务代码{TaskCode}判断ShiftId:{ShiftId}为三班",
shift.WorkOrderCode, shiftId);
return true;
}
// 如果班次名称包含"二班"或"三班"字样
if (shift.ShiftName?.Contains("二班") == true || shift.ShiftName?.Contains("三班") == true)
{
_logger.LogDebug("根据班次名称{ShiftName}判断ShiftId:{ShiftId}为二班/三班",
shift.ShiftName, shiftId);
return true;
}
}
return false;
}
catch (Exception ex)
{
_logger.LogError(ex, "简化班次类型检测异常 - ShiftId:{ShiftId}", shiftId);
return false;
}
}
///
/// 【性能优化】并行化种群适应度计算 - 多线程适应度评估
/// 将O(P×复杂度)的串行计算优化为并行计算,充分利用多核性能
///
private async Task> CalculateFitnessAsync(List> population)
{
var maxConcurrency = Math.Min(Environment.ProcessorCount, population.Count);
var fitnessScores = new double[population.Count];
_logger.LogDebug("【并行适应度】开始计算种群适应度,种群大小:{PopulationSize},并发度:{Concurrency}",
population.Count, maxConcurrency);
// 【关键优化】使用SemaphoreSlim控制并发度
using var semaphore = new SemaphoreSlim(maxConcurrency, maxConcurrency);
var tasks = new List();
// 创建并行任务
for (int i = 0; i < population.Count; i++)
{
var individualIndex = i; // 捕获循环变量
var individual = population[i];
var task = Task.Run(async () =>
{
await semaphore.WaitAsync();
try
{
var fitness = await CalculateIndividualFitnessAsync(individual);
fitnessScores[individualIndex] = fitness;
_logger.LogTrace("【并行适应度】个体{Index}适应度计算完成:{Fitness:F2}",
individualIndex, fitness);
}
finally
{
semaphore.Release();
}
});
tasks.Add(task);
}
// 等待所有并行任务完成
await Task.WhenAll(tasks);
_logger.LogDebug("【并行适应度】种群适应度计算完成,平均适应度:{AvgFitness:F2}",
fitnessScores.Average());
return fitnessScores.ToList();
}
///
/// 【增量优化】计算个体适应度 - 支持缓存和增量计算
/// 【线程安全修复】:添加锁保护,解决并发访问异常
/// 关键改进:避免重复计算相同个体的适应度,支持组件级别的增量更新
///
private async Task CalculateIndividualFitnessAsync(Dictionary individual)
{
// 【增量优化】:生成个体的哈希码用于缓存查找
var individualHash = GenerateIndividualHash(individual);
// 【线程安全】:读取缓存使用锁保护
lock (_context.CacheLock)
{
if (_fitnessCache.TryGetValue(individualHash, out var cachedFitness))
{
_logger.LogTrace("【适应度缓存命中】使用缓存适应度:{CachedFitness:F2}", cachedFitness);
return cachedFitness;
}
}
// 【增量优化】:尝试使用组件缓存进行部分计算
var fitness = await CalculateIndividualFitnessWithComponentCacheAsync(individual, individualHash);
// 【线程安全】:写入缓存和清理操作使用锁保护
lock (_context.CacheLock)
{
// 双重检查锁定模式,避免重复计算
if (_fitnessCache.TryGetValue(individualHash, out var existingFitness))
{
return existingFitness;
}
// 【缓存优化】:将计算结果存入缓存
_fitnessCache[individualHash] = fitness;
// 【内存管理】:限制缓存大小,避免内存溢出
if (_fitnessCache.Count > 1000)
{
try
{
// 【并发安全】:创建键列表的快照,避免遍历时修改异常
var allKeys = _fitnessCache.Keys.ToArray();
var keysToRemove = allKeys.Take(200).ToArray();
foreach (var key in keysToRemove)
{
_fitnessCache.Remove(key);
}
_logger.LogDebug("【线程安全缓存清理】清理了{Count}个老旧的适应度缓存项", keysToRemove.Length);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "【线程安全】适应度缓存清理异常,继续执行");
// 清理失败不影响主流程
}
}
}
return fitness;
}
///
/// CalculateIndividualFitnessWithComponentCacheAsync
///
///
///
///
private async Task CalculateIndividualFitnessWithComponentCacheAsync(Dictionary individual, string individualHash)
{
var config = _context.Config;
var personnelCount = individual.Values.Distinct().Count();
var taskCount = individual.Count;
_logger.LogDebug("【适应度计算开始】个体哈希:{Hash},任务数:{TaskCount},涉及人员数:{PersonnelCount}",
individualHash, taskCount, personnelCount);
// 组件1:约束满足度评分(最昂贵的计算)
var constraintCacheKey = $"{individualHash}_constraint";
var stopwatchConstraint = System.Diagnostics.Stopwatch.StartNew();
var constraintScoreRaw = await GetCachedComponentScoreAsync(constraintCacheKey,
() => CalculateRealConstraintScoreAsync(individual));
stopwatchConstraint.Stop();
_logger.LogInformation("【适应度组件1-约束】原始约束评分:{RawScore:F2}/100,计算耗时:{ElapsedMs}ms",
constraintScoreRaw, stopwatchConstraint.ElapsedMilliseconds);
// 【优化约束】:约束评分阈值提高至80分,严格约束违规处理
if (constraintScoreRaw < 80.0)
{
// 渐进式惩罚:评分越低惩罚越重,但避免完全淘汰
var penaltyFactor = Math.Max(0.1, constraintScoreRaw / 100.0); // 最低保留10%适应度
var moderateLowScore = constraintScoreRaw * penaltyFactor;
_logger.LogWarning("【适应度计算-约束不足】个体约束评分较低,约束评分{ConstraintScore:F2}/100,渐进式惩罚后适应度{FinalScore:F4}",
constraintScoreRaw, moderateLowScore);
// 详细分析约束违规情况
var workloadDistribution = new Dictionary();
foreach (var assignment in individual)
{
workloadDistribution[assignment.Value] = workloadDistribution.GetValueOrDefault(assignment.Value, 0) + 1;
}
_logger.LogError("【约束违规分析】工作负载分布: {WorkloadDistribution}",
string.Join(", ", workloadDistribution.Select(kv => $"人员{kv.Key}:{kv.Value}任务")));
return moderateLowScore; // 渐进式惩罚适应度,保留进化可能性
}
// 组件2:公平性评分(基于基尼系数)- 增强版负载均衡惩罚
var fairnessCacheKey = $"{individualHash}_fairness";
var stopwatchFairness = System.Diagnostics.Stopwatch.StartNew();
var fairnessScoreRaw = await GetCachedComponentScoreAsync(fairnessCacheKey,
() => Task.FromResult(CalculateFairnessScore(individual)));
stopwatchFairness.Stop();
_logger.LogDebug("【适应度组件2-公平性】原始公平性评分:{RawScore:F2}/100,计算耗时:{ElapsedMs}ms",
fairnessScoreRaw, stopwatchFairness.ElapsedMilliseconds);
// 【核心优化】:动态公平性权重调整机制(增强版)
// 大幅提升公平性权重基础值,确保负载均衡是核心考量
var enhancedBaseFairnessWeight = Math.Max(config.FairnessWeight, 0.4); // 最低40%权重
var dynamicFairnessWeight = CalculateDynamicFairnessWeight(individual, enhancedBaseFairnessWeight);
var fairnessScore = fairnessScoreRaw * dynamicFairnessWeight;
_logger.LogDebug("【适应度组件2-权重调整】基础权重:{BaseWeight:F2},动态权重:{DynamicWeight:F2},加权评分:{WeightedScore:F2}",
config.FairnessWeight, dynamicFairnessWeight, fairnessScore);
// 约束满足度评分(大幅提升权重)
var constraintWeight = Math.Max(config.ConstraintWeight, 0.85); // 最低85%权重
var constraintScore = constraintScoreRaw * constraintWeight;
_logger.LogInformation("【适应度组件1-权重应用】约束权重:{Weight:F2},加权约束评分:{WeightedScore:F2}",
constraintWeight, constraintScore);
// 【负载均衡增强】:如果检测到严重的负载不均衡,额外应用惩罚
var stopwatchPenalty = System.Diagnostics.Stopwatch.StartNew();
var loadBalancePenalty = CalculateLoadBalancePenaltyForFitness(individual);
stopwatchPenalty.Stop();
_logger.LogInformation("【适应度组件4-负载惩罚】负载均衡惩罚:{Penalty:F2},计算耗时:{ElapsedMs}ms",
loadBalancePenalty, stopwatchPenalty.ElapsedMilliseconds);
var totalScore = constraintScore + fairnessScore - loadBalancePenalty;
_logger.LogInformation("【适应度计算完成】个体哈希:{Hash},约束评分:{ConstraintScore:F2}(原始{RawConstraint:F2}),公平性评分:{FairnessScore:F2},负载惩罚:{Penalty:F2},最终总分:{TotalScore:F2}",
individualHash, constraintScore, constraintScoreRaw, fairnessScore, loadBalancePenalty, totalScore);
// 分析适应度异常情况
if (totalScore < 50.0)
{
_logger.LogWarning("【适应度异常分析】个体总分过低{TotalScore:F2},约束{Constraint:F2}+公平性{Fairness:F2}-惩罚{Penalty:F2},需要关注",
totalScore, constraintScore, fairnessScore, loadBalancePenalty);
}
else if (totalScore > 200.0)
{
_logger.LogInformation("【适应度优秀】个体总分优秀{TotalScore:F2},各组件均衡良好", totalScore);
}
return totalScore;
}
///
/// 【增量优化】获取缓存的组件评分,如果缓存不存在则计算并缓存
/// 【线程安全修复】:添加锁保护,解决并发访问异常
///
private async Task GetCachedComponentScoreAsync(string cacheKey, Func> calculateFunc)
{
// 【线程安全】:读取操作使用锁保护
lock (_context.CacheLock)
{
if (_componentFitnessCache.TryGetValue(cacheKey, out var cachedScore))
{
return Task.FromResult(cachedScore).Result;
}
}
var score = await calculateFunc();
// 【线程安全】:写入和清理操作使用锁保护
lock (_context.CacheLock)
{
// 双重检查锁定模式,避免重复计算
if (_componentFitnessCache.TryGetValue(cacheKey, out var existingScore))
{
return existingScore;
}
_componentFitnessCache[cacheKey] = score;
// 【内存管理】:限制组件缓存大小
if (_componentFitnessCache.Count > 2000)
{
try
{
// 【并发安全】:创建键列表的快照,避免遍历时修改异常
var allKeys = _componentFitnessCache.Keys.ToArray();
var keysToRemove = allKeys.Take(400).ToArray();
foreach (var key in keysToRemove)
{
_componentFitnessCache.Remove(key);
}
_logger.LogDebug("【线程安全缓存清理】清理了{Count}个组件缓存项", keysToRemove.Length);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "【线程安全】组件缓存清理异常,继续执行");
// 清理失败不影响主流程
}
}
}
return score;
}
///
/// 【增量优化】生成个体的哈希码用于缓存索引
///
private string GenerateIndividualHash(Dictionary individual)
{
// 【性能优化】:使用简单但有效的哈希算法
var sortedPairs = individual.OrderBy(kvp => kvp.Key).ToList();
var hashBuilder = new System.Text.StringBuilder();
foreach (var pair in sortedPairs)
{
hashBuilder.Append($"{pair.Key}:{pair.Value};");
}
return hashBuilder.ToString().GetHashCode().ToString();
}
///
/// 【架构升级】计算三级约束验证评分 - 简化业务约束验证体系
/// Level 1: 快速过滤基础约束 → Level 2: 双重组合约束 → Level 3: 业务逻辑验证高级约束
/// 【架构调整】Level 2简化为双重验证:动态班次规则 + 资源竞争约束
/// 依赖转移:任务间依赖约束责任转移到Level 3的项目连续性约束
/// 性能策略:智能采样+缓存策略,严格过滤违规个体
///
private async Task CalculateRealConstraintScoreAsync(Dictionary individual)
{
if (!individual.Any()) return 0.0;
try
{
// Level 1: 快速过滤基础约束(必须100%通过)
var level1Result = await ExecuteLevel1BasicConstraintValidation(individual);
if (!level1Result.IsValid)
{
_logger.LogDebug("【Level 1 失败】个体被基础约束过滤,违规原因: {Reason}, 评分: {Score}",
level1Result.ViolationReason, level1Result.Score);
return level1Result.Score; // 严格过滤,立即淘汰
}
// Level 2: 深度验证组合约束(动态班次规则+任务间依赖)
var level2Result = await ExecuteLevel2CombinationConstraintValidation(individual);
if (!level2Result.IsValid)
{
_logger.LogDebug("【Level 2 失败】个体被组合约束过滤,违规原因: {Reason}, 评分: {Score}",
level2Result.ViolationReason, level2Result.Score);
return level2Result.Score; // 严格过滤,立即淘汰
}
// Level 3: 业务逻辑验证高级约束(FL优先级+资源竞争)
var level3Result = await ExecuteLevel3BusinessLogicValidation(individual);
if (!level3Result.IsValid)
{
_logger.LogDebug("【Level 3 失败】个体被业务逻辑约束过滤,违规原因: {Reason}, 评分: {Score}",
level3Result.ViolationReason, level3Result.Score);
return level3Result.Score; // 严格过滤,立即淘汰
}
// 综合评分:三级验证都通过的个体,计算综合约束满足度
var comprehensiveScore = CalculateComprehensiveConstraintScore(level1Result, level2Result, level3Result);
_logger.LogTrace("【三级约束验证通过】L1: {L1Score:F2}, L2: {L2Score:F2}, L3: {L3Score:F2}, 综合: {CompScore:F2}",
level1Result.Score, level2Result.Score, level3Result.Score, comprehensiveScore);
return comprehensiveScore;
}
catch (Exception ex)
{
_logger.LogError(ex, "三级约束验证异常,个体被淘汰");
return 0.0; // 异常时严格过滤
}
}
///
/// 约束验证结果数据结构
///
private class ConstraintValidationResult
{
public bool IsValid { get; set; }
public double Score { get; set; }
public string ViolationReason { get; set; } = string.Empty;
public Dictionary DetailScores { get; set; } = new();
}
///
/// 【Level 1】快速过滤基础约束验证
/// 验证内容:任务分配完整性、基本时间冲突
/// 验证策略:快速检查,必须100%通过
/// 【架构调整】移除人员基础超载检查,超载控制转移到公平性评分
///
private async Task ExecuteLevel1BasicConstraintValidation(Dictionary individual)
{
var result = new ConstraintValidationResult { IsValid = true, Score = 100.0 };
var detailScores = new Dictionary();
try
{
// 基础约束1:任务分配完整性检查
var completenessScore = individual.Count == _context.Tasks.Count ? 1.0 : 0.0;
detailScores["TaskCompleteness"] = completenessScore * 100;
if (completenessScore < 1.0)
{
result.IsValid = false;
result.Score = 0.0;
result.ViolationReason = $"任务分配不完整,期望{_context.Tasks.Count}个,实际{individual.Count}个";
result.DetailScores = detailScores;
return result;
}
// 基础约束2:基本时间冲突检查(同一人员在同一时间段)
var basicTimeConflictScore = await CalculateBasicTimeConflictScore(individual);
detailScores["BasicTimeConflict"] = basicTimeConflictScore * 100;
if (basicTimeConflictScore < 1.0) // 【修复关键】:任何时间冲突都不允许,不允许误差
{
result.IsValid = false;
result.Score = 0.0; // 【严厉惩罚】:任何时间冲突都给0分,确保完全淘汰
result.ViolationReason = $"存在严重时间冲突,冲突评分: {basicTimeConflictScore:F2}";
result.DetailScores = detailScores;
return result;
}
// 【架构调整】移除人员基础超载检查
// 超载控制转移到公平性评分和负载均衡惩罚机制
result.Score = detailScores.Values.Average();
result.DetailScores = detailScores;
_logger.LogTrace("【Level 1 通过】基础约束验证通过(任务完整性+时间冲突检查),综合评分: {Score:F2}", result.Score);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Level 1 基础约束验证异常");
result.IsValid = false;
result.Score = 0.0;
result.ViolationReason = "基础约束验证异常";
return result;
}
}
///
/// 【Level 2】深度验证组合约束 - 架构简化版
/// 【架构调整】移除任务间依赖约束,简化为双重验证体系
/// 验证内容:动态班次规则、跨任务资源竞争
/// 验证策略:基于当前个体的任务组合进行动态约束验证
/// 权重分配:动态班次规则(60%) + 资源竞争约束(40%)
///
private async Task ExecuteLevel2CombinationConstraintValidation(Dictionary individual)
{
var result = new ConstraintValidationResult { IsValid = true, Score = 100.0 };
var detailScores = new Dictionary();
try
{
// 组合约束1:动态班次规则验证(考虑当前个体的所有任务组合)
var dynamicShiftRuleScore = await CalculateDynamicShiftRuleScore(individual);
detailScores["DynamicShiftRule"] = dynamicShiftRuleScore * 100;
if (dynamicShiftRuleScore < 0.8) // 班次规则必须严格遵守,阈值调回0.8
{
result.IsValid = false;
result.Score = Math.Max(0.0, dynamicShiftRuleScore * 10); // 严厉惩罚班次违规
result.ViolationReason = $"严重违反动态班次规则,评分: {dynamicShiftRuleScore:F2}";
result.DetailScores = detailScores;
return result;
}
// 组合约束2:跨任务资源竞争约束
var resourceCompetitionScore = await CalculateResourceCompetitionConstraintScore(individual);
detailScores["ResourceCompetition"] = resourceCompetitionScore * 100;
if (resourceCompetitionScore < 0.7)
{
result.IsValid = false;
result.Score = resourceCompetitionScore * 35; // 资源竞争违规惩罚
result.ViolationReason = $"违反跨任务资源竞争约束,评分: {resourceCompetitionScore:F2}";
result.DetailScores = detailScores;
return result;
}
// 采用加权平均:动态班次规则(60%) + 资源竞争(40%)
var dynamicShiftWeight = 0.6; // 提高班次规则权重,作为最重要约束
var resourceCompetitionWeight = 0.4;
var weightedScore = (detailScores["DynamicShiftRule"] * dynamicShiftWeight) +
(detailScores["ResourceCompetition"] * resourceCompetitionWeight);
result.Score = weightedScore;
result.DetailScores = detailScores;
_logger.LogTrace("【Level 2 通过-双重约束】动态班次:{DynamicScore:F2}×60%, 资源竞争:{ResourceScore:F2}×40%, 综合评分: {FinalScore:F2}",
detailScores["DynamicShiftRule"], detailScores["ResourceCompetition"], result.Score);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Level 2 组合约束验证异常");
result.IsValid = false;
result.Score = 0.0;
result.ViolationReason = "组合约束验证异常";
return result;
}
}
///
/// 【Level 3】业务逻辑验证高级约束
/// 验证内容:FL优先级规则、人员技能匹配、项目连续性约束
/// 验证策略:业务规则严格执行,允许一定弹性但必须符合核心业务逻辑
///
private async Task ExecuteLevel3BusinessLogicValidation(Dictionary individual)
{
var result = new ConstraintValidationResult { IsValid = true, Score = 100.0 };
var detailScores = new Dictionary();
try
{
// 业务约束1:FL优先级规则验证(规则10:优先分配本项目FL)
var flPriorityScore = await CalculateFLPriorityRuleScore(individual);
detailScores["FLPriority"] = flPriorityScore * 100;
if (flPriorityScore < 0.6) // FL规则允许一定弹性
{
result.IsValid = false;
result.Score = flPriorityScore * 80; // 中等惩罚,保留一定分数
result.ViolationReason = $"违反FL优先级规则,评分: {flPriorityScore:F2}";
result.DetailScores = detailScores;
return result;
}
// 业务约束2:人员技能等级与任务复杂度匹配
var skillMatchingScore = await CalculateSkillMatchingConstraintScore(individual);
detailScores["SkillMatching"] = skillMatchingScore * 100;
if (skillMatchingScore < 0.5)
{
result.IsValid = false;
result.Score = skillMatchingScore * 45; // 技能不匹配严重影响质量
result.ViolationReason = $"人员技能与任务复杂度不匹配,评分: {skillMatchingScore:F2}";
result.DetailScores = detailScores;
return result;
}
// 业务约束3:项目连续性约束(同项目任务人员稳定性)
var projectContinuityScore = await CalculateProjectContinuityConstraintScore(individual);
detailScores["ProjectContinuity"] = projectContinuityScore * 100;
if (projectContinuityScore < 0.4)
{
result.IsValid = false;
result.Score = projectContinuityScore * 50; // 项目连续性影响效率
result.ViolationReason = $"违反项目连续性约束,评分: {projectContinuityScore:F2}";
result.DetailScores = detailScores;
return result;
}
result.Score = detailScores.Values.Average();
result.DetailScores = detailScores;
_logger.LogTrace("【Level 3 通过】业务逻辑约束验证通过,综合评分: {Score:F2}", result.Score);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "Level 3 业务逻辑约束验证异常");
result.IsValid = false;
result.Score = 0.0;
result.ViolationReason = "业务逻辑约束验证异常";
return result;
}
}
///
/// 计算综合约束评分 - 架构调整后版本
/// 【架构调整】Level 2移除任务依赖约束后,保持原有权重分配
///
private double CalculateComprehensiveConstraintScore(
ConstraintValidationResult level1Result,
ConstraintValidationResult level2Result,
ConstraintValidationResult level3Result)
{
// 【架构调整后的权重分配】Level 1 (30%) + Level 2 (40%) + Level 3 (30%)
// Level 2 保持最高权重,虽然简化为双重约束,但仍然是核心验证环节
// Level 2 内部:动态班次规则(60%) + 资源竞争约束(40%)
return (level1Result.Score * 0.3) + (level2Result.Score * 0.4) + (level3Result.Score * 0.3);
}
///
/// 【Level 1 实现】计算基本时间冲突评分 - 核心时间冲突检测与严厉惩罚
/// 【关键修复】:这是解决"一天分配两个任务"问题的核心方法
/// 【严厉惩罚】:对任何时间冲突都给予0分,确保遗传算法淘汰此类个体
///
private async Task CalculateBasicTimeConflictScore(Dictionary individual)
{
await Task.CompletedTask;
var personnelTaskGroups = individual.GroupBy(kvp => kvp.Value); // 按人员分组
var totalConflictCount = 0;
var totalAssignments = individual.Count;
var conflictDetails = new List();
_logger.LogTrace("【时间冲突核心检测】开始检查个体时间冲突,涉及{PersonnelCount}个人员,{TaskCount}个任务分配",
personnelTaskGroups.Count(), totalAssignments);
foreach (var personnelGroup in personnelTaskGroups)
{
var personnelId = personnelGroup.Key;
var taskIds = personnelGroup.Select(g => g.Key).ToList();
// 获取该人员的所有任务
var tasks = taskIds.Select(id => _context.Tasks.FirstOrDefault(t => t.Id == id))
.Where(t => t != null).ToList();
_logger.LogTrace("【时间冲突检查】人员{PersonnelId}分配{TaskCount}个任务:{TaskIds}",
personnelId, tasks.Count, string.Join(",", taskIds));
// 【核心检查】:同一日同一班次是否有多个任务
var timeGrouped = tasks.GroupBy(t => new { Date = t.WorkOrderDate.Date, ShiftId = t.ShiftId });
foreach (var timeGroup in timeGrouped)
{
var tasksInTimeSlot = timeGroup.ToList();
if (tasksInTimeSlot.Count > 1)
{
totalConflictCount += tasksInTimeSlot.Count - 1; // 计算多余的任务数
var conflictTaskCodes = string.Join(", ", tasksInTimeSlot.Select(t => t.WorkOrderCode));
var conflictDetail = $"人员{personnelId}在{timeGroup.Key.Date:yyyy-MM-dd}班次{timeGroup.Key.ShiftId}分配{tasksInTimeSlot.Count}个任务:{conflictTaskCodes}";
conflictDetails.Add(conflictDetail);
_logger.LogError("【严重时间冲突】{ConflictDetail}", conflictDetail);
}
}
}
// 【严厉惩罚策略】:任何时间冲突都应该被严厉惩罚
if (totalConflictCount > 0)
{
_logger.LogError("【时间冲突-严厉惩罚】个体存在{ConflictCount}个时间冲突,适应度评分为0", totalConflictCount);
// 记录前3个具体冲突详情
for (int i = 0; i < Math.Min(3, conflictDetails.Count); i++)
{
_logger.LogError("【冲突详情{Index}】{Detail}", i + 1, conflictDetails[i]);
}
return 0.0; // 【关键修复】:任何时间冲突都返回0分,确保此个体被淘汰
}
_logger.LogTrace("【时间冲突检查通过】个体无时间冲突,返回满分1.0");
return 1.0; // 无冲突返回满分
}
///
/// 【架构调整】移除基础人员超载评分方法
/// 原因:超载控制策略调整,转移到公平性评分和负载均衡惩罚机制
/// 日期:根据业务需求优化约束验证流程
///
// 原 CalculateBasicPersonnelOverloadScore 方法已移除
// 超载控制现在完全依赖:
// 1. 公平性评分中的基尼系数评估
// 2. CalculateLoadBalancePenaltyForFitness 中的负载均衡惩罚
// 3. CalculateConcentrationPenalty 中的过度集中惩罚
///
/// 【Level 2 实现-架构升级版】计算动态班次规则评分 - 完整的批次感知验证体系
/// 【重大升级】:整合历史数据(_context)和遗传个体批次上下文,实现完整的9种班次规则验证
/// 核心改进:从单一任务验证升级为批次感知的组合约束验证,消除遗传个体内部冲突
/// 设计思路:参照 CheckShiftRuleConflictsWithBatchContextAsync,双重数据源整合验证
/// 【日志增强】:详细的批次冲突诊断和性能监控
///
private async Task CalculateDynamicShiftRuleScore(Dictionary individual)
{
var individualHash = GenerateIndividualHash(individual);
_logger.LogDebug("【增强版班次规则验证开始】个体哈希:{Hash},涉及{PersonnelCount}个人员,{TaskCount}个任务",
individualHash, individual.Values.Distinct().Count(), individual.Count);
try
{
var totalRuleChecks = 0;
var totalConflicts = 0;
var violationDetails = new List();
var personnelScores = new List();
var personnelViolationCounts = new Dictionary();
// 【核心改进】按人员分组,为每个人员构建批次上下文进行验证
var personnelGroups = individual.GroupBy(kvp => kvp.Value);
_logger.LogDebug("【人员分组分析-批次感知】共{GroupCount}个人员参与任务分配", personnelGroups.Count());
foreach (var personnelGroup in personnelGroups)
{
var personnelId = personnelGroup.Key;
var assignedTaskIds = personnelGroup.Select(g => g.Key).ToList();
personnelViolationCounts[personnelId] = 0;
// 【批次上下文构建】获取该人员在当前个体中的所有分配任务
var individualTasks = await BuildIndividualTasksForPersonnel(personnelId, assignedTaskIds);
// 【历史数据整合】构建包含历史数据的完整上下文
var completeTaskContext = await BuildCompleteTaskContextForPersonnel(personnelId, individualTasks);
_logger.LogDebug("【批次上下文构建】人员{PersonnelId}:个体任务{IndividualCount}个,历史任务{HistoryCount}个,总上下文{TotalCount}个",
personnelId, individualTasks.Count, completeTaskContext.Count - individualTasks.Count, completeTaskContext.Count);
// 【核心升级】对该人员的每个任务进行批次感知的班次规则验证
var personnelTaskConflicts = new List();
foreach (var task in individualTasks)
{
if (task.ShiftId.HasValue)
{
totalRuleChecks++;
// 【关键改进】构建批次上下文(排除当前任务)
var batchContext = completeTaskContext.Where(t => t.Id != task.Id).ToList();
_logger.LogTrace("【批次感知验证】人员{PersonnelId}任务{TaskCode}({Date})班次{ShiftId},批次上下文{BatchCount}个任务",
personnelId, task.WorkOrderCode, task.WorkOrderDate.ToString("yyyy-MM-dd"), task.ShiftId, batchContext.Count);
// 【核心突破】批次感知的完整班次规则验证
var conflicts = await ValidateShiftRulesWithEnhancedBatchContext(
personnelId, task, batchContext);
var conflictCount = conflicts.Count;
personnelTaskConflicts.Add(conflictCount);
totalConflicts += conflictCount;
if (conflictCount > 0)
{
personnelViolationCounts[personnelId] += conflictCount;
violationDetails.AddRange(conflicts);
_logger.LogError("【批次感知冲突】人员{PersonnelId}任务{TaskCode}发现{ConflictCount}个班次规则冲突",
personnelId, task.WorkOrderCode, conflictCount);
foreach (var conflict in conflicts.Take(2)) // 记录前2个具体冲突
{
_logger.LogError("【具体冲突】{Conflict}", conflict);
}
}
else
{
_logger.LogTrace("【批次验证通过】人员{PersonnelId}任务{TaskCode}无班次规则冲突",
personnelId, task.WorkOrderCode);
}
}
else
{
_logger.LogWarning("【班次规则跳过】任务{TaskCode}缺少班次ID", task.WorkOrderCode);
}
}
// 计算该人员的班次规则符合度(基于冲突率)
if (personnelTaskConflicts.Any())
{
var totalPersonnelConflicts = personnelTaskConflicts.Sum();
var maxPersonnelConflicts = personnelTaskConflicts.Count * 3; // 假设每任务最多3个冲突
var personnelScore = Math.Max(0.0, 1.0 - (double)totalPersonnelConflicts / maxPersonnelConflicts);
personnelScores.Add(personnelScore);
_logger.LogInformation("【人员批次规则评分】人员{PersonnelId}:{TaskCount}个任务,总冲突{ConflictCount}个,符合度评分:{Score:F3}",
personnelId, personnelTaskConflicts.Count, totalPersonnelConflicts, personnelScore);
}
}
// 【综合评分计算】基于总体冲突率计算最终评分
var maxPossibleConflicts = totalRuleChecks * 3; // 假设每次检查最多3个冲突
var overallScore = maxPossibleConflicts > 0 ?
Math.Max(0.0, 1.0 - (double)totalConflicts / maxPossibleConflicts) : 1.0;
_logger.LogInformation("【批次感知班次规则初步评分】总检查:{TotalChecks}项,总冲突:{TotalConflicts}个,初步评分:{InitScore:F3}",
totalRuleChecks, totalConflicts, overallScore);
// 【质量保证】:如果存在严重违规人员,应用额外惩罚
var severeViolationCount = personnelScores.Count(score => score < 0.3);
if (severeViolationCount > 0)
{
var severePenalty = (double)severeViolationCount / Math.Max(1, personnelScores.Count) * 0.4;
var originalScore = overallScore;
overallScore = Math.Max(0.0, overallScore - severePenalty);
_logger.LogError("【严重批次冲突】{SevereCount}/{TotalCount}个人员严重违规,应用额外惩罚{Penalty:F3},评分:{OrigScore:F3}→{FinalScore:F3}",
severeViolationCount, personnelScores.Count, severePenalty, originalScore, overallScore);
}
// 【详细冲突报告】
if (violationDetails.Any())
{
_logger.LogError("【批次感知班次规则综合评估-冲突详情】总检查{TotalChecks}项,总冲突{TotalConflicts}个,最终评分{OverallScore:F3}",
totalRuleChecks, totalConflicts, overallScore);
// 按人员统计冲突情况
foreach (var kvp in personnelViolationCounts.Where(kv => kv.Value > 0))
{
_logger.LogError("【人员冲突统计】人员{PersonnelId}冲突{ConflictCount}个", kvp.Key, kvp.Value);
}
// 输出前5个具体冲突详情
for (int i = 0; i < Math.Min(5, violationDetails.Count); i++)
{
_logger.LogError("【冲突详情{Index}】{Conflict}", i + 1, violationDetails[i]);
}
}
else
{
_logger.LogInformation("【批次感知班次规则综合评估-无冲突】总检查{TotalChecks}项,最终评分{OverallScore:F3},全部通过验证",
totalRuleChecks, overallScore);
}
_logger.LogInformation("【增强版班次规则验证完成】个体哈希:{Hash},最终评分:{FinalScore:F3}", individualHash, overallScore);
return overallScore;
}
catch (Exception ex)
{
_logger.LogError(ex, "【增强版班次规则验证异常】个体哈希:{Hash},使用简化验证方案", individualHash);
// 【容错机制】:主要验证失败时回退到原有验证方案
var fallbackScore = await FallbackDynamicShiftRuleValidation(individual);
_logger.LogWarning("【增强版班次规则回退】个体哈希:{Hash},回退评分:{FallbackScore:F3}", individualHash, fallbackScore);
return fallbackScore;
}
}
///
/// 【容错机制】简化版动态班次规则验证 - 当完整验证失败时的回退方案
/// 保留核心的二班/三班后休息规则验证,确保系统稳定性
///
private async Task FallbackDynamicShiftRuleValidation(Dictionary individual)
{
try
{
var totalChecks = 0;
var passedChecks = 0;
// 按人员分组进行简化验证
var personnelGroups = individual.GroupBy(kvp => kvp.Value);
foreach (var personnelGroup in personnelGroups)
{
var personnelId = personnelGroup.Key;
var assignedTaskIds = personnelGroup.Select(g => g.Key).ToList();
// 获取该人员的分配任务
var assignedTasks = assignedTaskIds.Select(id => _context.Tasks.FirstOrDefault(t => t.Id == id))
.Where(t => t != null)
.OrderBy(t => t.WorkOrderDate)
.ToList();
// 简化版:仅检查二班/三班后休息规则
var shiftRuleViolations = await ValidatePersonnelDynamicShiftRulesAsync(personnelId, assignedTasks);
totalChecks += shiftRuleViolations.TotalChecks;
passedChecks += shiftRuleViolations.PassedChecks;
}
var fallbackScore = totalChecks > 0 ? (double)passedChecks / totalChecks : 0.8; // 默认80%通过率
_logger.LogInformation("【容错验证】使用简化班次规则验证,通过率: {PassRate:P2}", fallbackScore);
return fallbackScore;
}
catch (Exception ex)
{
_logger.LogError(ex, "简化版班次规则验证也失败,返回默认评分");
return 0.6; // 最终回退评分
}
}
///
/// 【Level 2 实现】验证人员在当前任务组合下的动态班次规则
/// 专门检查二班/三班后的休息约束,基于当前个体的完整分配方案
/// 【增强版】:增加跨日期班次规则验证,确保二班(2025/09/03)后次日(2025/09/04)休息
///
private async Task<(int TotalChecks, int PassedChecks, List Violations)> ValidatePersonnelDynamicShiftRulesAsync(
long personnelId, List assignedTasks)
{
await Task.CompletedTask;
var totalChecks = 0;
var passedChecks = 0;
var violations = new List();
try
{
// 【增强验证】:不仅检查当前分配,还要检查与全局上下文中其他任务的冲突
var allContextTasks = _context.Tasks ?? new List();
var personnelAllTasks = allContextTasks.Where(t => t.AssignedPersonnelId == personnelId).ToList();
var combinedTasks = assignedTasks.Union(personnelAllTasks, new WorkOrderTaskComparer()).ToList();
// 按日期分组检查连续日期的班次规则
var tasksByDate = combinedTasks.GroupBy(t => t.WorkOrderDate.Date)
.OrderBy(g => g.Key)
.ToList();
for (int i = 0; i < tasksByDate.Count; i++)
{
var currentDateGroup = tasksByDate[i];
var currentDate = currentDateGroup.Key;
var currentDayTasks = currentDateGroup.ToList();
// 检查前一天是否有二班/三班任务
if (i > 0)
{
var previousDateGroup = tasksByDate[i - 1];
var previousDate = previousDateGroup.Key;
var previousDayTasks = previousDateGroup.ToList();
// 验证前一天的二班/三班后休息规则
foreach (var prevTask in previousDayTasks)
{
if (prevTask.ShiftId.HasValue)
{
var isRestrictedShift = await IsSecondOrThirdShiftByIdAsync(prevTask.ShiftId.Value);
_logger.LogInformation("【班次规则检查】人员{PersonnelId}在{PrevDate}的任务{TaskCode}班次{ShiftId}识别为二班/三班:{IsRestricted}",
personnelId, previousDate.ToString("yyyy-MM-dd"), prevTask.WorkOrderCode, prevTask.ShiftId.Value, isRestrictedShift);
if (isRestrictedShift)
{
totalChecks++;
// 【关键修复】检查次日是否违规分配了任何任务(遗传算法中所有任务都需要验证)
var nextDayTasks = currentDayTasks.ToList();
_logger.LogInformation("【次日检查】人员{PersonnelId}二班/三班后次日{NextDate}分配任务数:{TaskCount}",
personnelId, currentDate.ToString("yyyy-MM-dd"), nextDayTasks.Count);
if (nextDayTasks.Any())
{
foreach (var nextTask in nextDayTasks)
{
var violationMessage = $"人员{personnelId}在{previousDate:yyyy-MM-dd}工作{GetShiftTypeName(prevTask)}(任务{prevTask.WorkOrderCode})后,次日{currentDate:yyyy-MM-dd}不应分配任务{nextTask.WorkOrderCode}";
violations.Add(violationMessage);
_logger.LogError("【班次规则严重违规】{Violation}", violationMessage);
}
// 违规情况下不增加passedChecks
}
else
{
passedChecks++;
}
}
}
}
}
// 【新增】检查当日任务是否与二班/三班规则冲突
foreach (var task in currentDayTasks.Where(t => assignedTasks.Contains(t)))
{
totalChecks++;
// 检查当日任务时间分布的合理性
if (await ValidateTaskSchedulingConstraints(task, currentDate, personnelId))
{
passedChecks++;
}
else
{
var constraintViolation = $"人员{personnelId}在{currentDate:yyyy-MM-dd}的任务{task.WorkOrderCode}违反调度约束";
violations.Add(constraintViolation);
}
}
}
return (totalChecks, passedChecks, violations);
}
catch (Exception ex)
{
_logger.LogError(ex, "验证人员{PersonnelId}动态班次规则异常", personnelId);
return (1, 0, new List { $"人员{personnelId}班次规则验证异常" });
}
}
///
/// 【新增辅助方法】工作任务比较器 - 用于去重和合并任务列表
///
private class WorkOrderTaskComparer : IEqualityComparer
{
public bool Equals(WorkOrderEntity x, WorkOrderEntity y)
{
return x?.Id == y?.Id;
}
public int GetHashCode(WorkOrderEntity obj)
{
return obj?.Id.GetHashCode() ?? 0;
}
}
///
/// 【新增辅助方法】获取班次类型名称
///
private string GetShiftTypeName(WorkOrderEntity task)
{
// 【架构优化】:直接从任务实体获取班次信息
var shiftNumber = task?.ShiftEntity?.ShiftNumber ?? 0;
if (shiftNumber > 0)
{
return shiftNumber switch
{
1 => "一班",
2 => "二班",
3 => "三班",
_ => $"{shiftNumber}班"
};
}
return "未知班次";
}
///
/// 【新增辅助方法】验证任务调度约束
///
private async Task ValidateTaskSchedulingConstraints(WorkOrderEntity task, DateTime taskDate, long personnelId)
{
await Task.CompletedTask;
try
{
// 验证1:检查人员当日工作量限制
var dailyTaskCount = _context.Tasks?.Count(t =>
t.AssignedPersonnelId == personnelId &&
t.WorkOrderDate.Date == taskDate) ?? 0;
if (dailyTaskCount > 2) // 每日超过2个任务视为超载
{
_logger.LogDebug("【调度约束违规】人员{PersonnelId}在{TaskDate:yyyy-MM-dd}已有{DailyTaskCount}个任务,超过限制",
personnelId, taskDate, dailyTaskCount);
return false;
}
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "验证任务调度约束异常 - 任务:{TaskId}, 人员:{PersonnelId}, 日期:{TaskDate}",
task.Id, personnelId, taskDate);
return true; // 异常时不阻塞
}
}
///
/// 【架构调整】移除任务间依赖约束评分方法
/// 原因:任务依赖约束责任转移到Level 3的项目连续性约束验证
/// 日期:根据业务需求简化Level 2约束验证流程
///
// 原 CalculateTaskDependencyConstraintScore 方法已移除
// 任务依赖约束现在完全由Level 3业务逻辑验证中的以下机制处理:
// 1. CalculateProjectContinuityConstraintScore 中的项目连续性约束
// 2. CalculateFLPriorityRuleScore 中的FL优先约束
// 3. 公平性评分中的项目团队稳定性检查
///
/// 【Level 2 实现】计算跨任务资源竞争约束评分
/// 检查同一设备、场地等资源的任务是否存在时间冲突
///
private async Task CalculateResourceCompetitionConstraintScore(Dictionary individual)
{
await Task.CompletedTask;
try
{
// 目前主要检查同一时间段内是否有过多任务竞争相同类型的资源
// 可以根据实际的设备、场地数据进行扩展
var totalResourceChecks = 0;
var passedResourceChecks = 0;
// 按时间段分组检查资源竞争
var tasksByTimeSlot = individual.Keys
.Select(taskId => _context.Tasks.FirstOrDefault(t => t.Id == taskId))
.Where(t => t != null)
.GroupBy(t => new { Date = t.WorkOrderDate.Date, ShiftId = t.ShiftId })
.ToList();
foreach (var timeSlotGroup in tasksByTimeSlot)
{
var concurrentTasks = timeSlotGroup.ToList();
// 简化的资源竞争检查:同一时间段内任务数量不应超过合理限制
if (concurrentTasks.Count > 1)
{
totalResourceChecks++;
// 假设同一班次最多可以并行执行5个任务(可根据实际资源情况调整)
const int maxConcurrentTasks = 5;
if (concurrentTasks.Count <= maxConcurrentTasks)
{
passedResourceChecks++;
}
else
{
_logger.LogDebug("【资源竞争约束】{Date:yyyy-MM-dd}班次{ShiftId}有{TaskCount}个并行任务,超过合理限制{MaxLimit}",
timeSlotGroup.Key.Date, timeSlotGroup.Key.ShiftId, concurrentTasks.Count, maxConcurrentTasks);
}
}
}
return totalResourceChecks > 0 ? (double)passedResourceChecks / totalResourceChecks : 1.0;
}
catch (Exception ex)
{
_logger.LogError(ex, "资源竞争约束验证异常");
return 0.9; // 异常时返回较高分数
}
}
///
/// 【Level 3 实现】计算FL优先级规则评分 - 规则10:优先分配本项目FL
/// 验证任务是否优先分配给本项目的FL人员,符合业务优先级策略
///
private async Task CalculateFLPriorityRuleScore(Dictionary individual)
{
await Task.CompletedTask;
try
{
var totalFLChecks = 0;
var passedFLChecks = 0;
var flViolationDetails = new List();
// 检查每个任务的FL优先级分配情况
foreach (var taskAssignment in individual)
{
var taskId = taskAssignment.Key;
var assignedPersonnelId = taskAssignment.Value;
var task = _context.Tasks.FirstOrDefault(t => t.Id == taskId);
if (task == null) continue;
// 查找该任务关联的FL人员列表
var taskFLPersonnel = _context.Tasks
.Where(t => t.Id == taskId)
.SelectMany(t => t.WorkOrderFLPersonnels ?? new List())
.Select(fl => fl.FLPersonnelId)
.ToList();
if (taskFLPersonnel.Any())
{
totalFLChecks++;
// 检查分配的人员是否是本项目的FL
if (taskFLPersonnel.Contains(assignedPersonnelId))
{
passedFLChecks++;
_logger.LogTrace("【FL优先级规则符合】任务{TaskCode}分配给本项目FL人员{PersonnelId}",
task.WorkOrderCode, assignedPersonnelId);
}
else
{
// 检查本项目FL是否在可用人员中但未被分配
var availableFLPersonnel = taskFLPersonnel.Intersect(
_context.AvailablePersonnel.Select(p => p.Id)).ToList();
if (availableFLPersonnel.Any())
{
var violationMessage = $"任务{task.WorkOrderCode}未分配给本项目FL人员(可用FL: {string.Join(",", availableFLPersonnel)}),实际分配给: {assignedPersonnelId}";
flViolationDetails.Add(violationMessage);
_logger.LogDebug("【FL优先级规则违规】{Violation}", violationMessage);
}
else
{
// 本项目FL都不可用,这种情况可以接受
passedFLChecks++;
_logger.LogTrace("【FL优先级规则可接受】任务{TaskCode}的本项目FL均不可用,分配给其他人员{PersonnelId}",
task.WorkOrderCode, assignedPersonnelId);
}
}
}
}
var flPriorityScore = totalFLChecks > 0 ? (double)passedFLChecks / totalFLChecks : 1.0;
if (flViolationDetails.Any())
{
_logger.LogDebug("【FL优先级规则】通过{PassedChecks}/{TotalChecks},违规详情: {Violations}",
passedFLChecks, totalFLChecks, string.Join("; ", flViolationDetails.Take(2)));
}
return flPriorityScore;
}
catch (Exception ex)
{
_logger.LogError(ex, "FL优先级规则验证异常");
return 0.8; // 异常时返回较高分数,避免过度惩罚
}
}
///
/// 【Level 3 实现】计算人员技能与任务复杂度匹配约束评分
/// 验证分配的人员技能等级是否与任务复杂度相匹配
///
private async Task CalculateSkillMatchingConstraintScore(Dictionary individual)
{
await Task.CompletedTask;
try
{
var totalSkillChecks = 0;
var passedSkillChecks = 0;
var skillMismatchDetails = new List();
foreach (var taskAssignment in individual)
{
var taskId = taskAssignment.Key;
var assignedPersonnelId = taskAssignment.Value;
var task = _context.Tasks.FirstOrDefault(t => t.Id == taskId);
if (task == null) continue;
var assignedPersonnel = _context.AvailablePersonnel.FirstOrDefault(p => p.Id == assignedPersonnelId);
if (assignedPersonnel == null) continue;
totalSkillChecks++;
// 简化的技能匹配检查(可根据实际技能等级数据扩展)
// 目前基于任务复杂度和人员经验进行基础匹配
var isSkillMatched = await CheckSkillMatching(task, assignedPersonnel.Id);
if (isSkillMatched)
{
passedSkillChecks++;
}
else
{
var mismatchMessage = $"任务{task.WorkOrderCode}(复杂度:{task.ComplexityLevel})与人员{assignedPersonnelId}技能不匹配";
skillMismatchDetails.Add(mismatchMessage);
_logger.LogDebug("【技能匹配约束违规】{Mismatch}", mismatchMessage);
}
}
var skillMatchingScore = totalSkillChecks > 0 ? (double)passedSkillChecks / totalSkillChecks : 1.0;
if (skillMismatchDetails.Any())
{
_logger.LogDebug("【技能匹配约束】通过{PassedChecks}/{TotalChecks},不匹配详情: {Mismatches}",
passedSkillChecks, totalSkillChecks, string.Join("; ", skillMismatchDetails.Take(2)));
}
return skillMatchingScore;
}
catch (Exception ex)
{
_logger.LogError(ex, "技能匹配约束验证异常");
return 0.7; // 异常时返回中等分数
}
}
///
/// 【Level 3 实现】计算项目连续性约束评分
/// 验证同一项目的任务是否由相对稳定的人员团队执行,提高项目执行效率
///
private async Task CalculateProjectContinuityConstraintScore(Dictionary individual)
{
await Task.CompletedTask;
try
{
var totalProjectChecks = 0;
var passedProjectChecks = 0;
var continuityIssues = new List();
// 按项目分组分析人员连续性(基于WorkOrderCode前缀识别项目)
var tasksByProject = individual.Keys
.Select(taskId => _context.Tasks.FirstOrDefault(t => t.Id == taskId))
.Where(t => t != null)
.GroupBy(t => ExtractProjectFromWorkOrderCode(t.WorkOrderCode))
.Where(g => !string.IsNullOrEmpty(g.Key))
.ToList();
foreach (var projectGroup in tasksByProject)
{
var projectId = projectGroup.Key;
var projectTasks = projectGroup.ToList();
if (projectTasks.Count <= 1) continue; // 单任务项目无需检查连续性
totalProjectChecks++;
// 分析项目人员分配的连续性
var assignedPersonnelIds = projectTasks.Select(t => individual[t.Id]).ToList();
var uniquePersonnelCount = assignedPersonnelIds.Distinct().Count();
var taskCount = projectTasks.Count;
// 连续性评估:人员数量与任务数量的合理比例
var idealPersonnelRatio = Math.Min(1.0, (double)uniquePersonnelCount / Math.Max(taskCount * 0.6, 1));
// 检查人员分布是否合理
var personnelTaskCounts = assignedPersonnelIds.GroupBy(pid => pid)
.ToDictionary(g => g.Key, g => g.Count());
var maxTasksPerPerson = personnelTaskCounts.Values.Max();
var minTasksPerPerson = personnelTaskCounts.Values.Min();
var taskDistributionBalance = minTasksPerPerson > 0 ? (double)minTasksPerPerson / maxTasksPerPerson : 0;
// 综合连续性评分
var continuityScore = (idealPersonnelRatio * 0.6) + (taskDistributionBalance * 0.4);
if (continuityScore >= 0.6) // 连续性阈值
{
passedProjectChecks++;
_logger.LogTrace("【项目连续性良好】项目{ProjectId}的{TaskCount}个任务分配给{PersonnelCount}个人员,连续性评分: {Score:F2}",
projectId, taskCount, uniquePersonnelCount, continuityScore);
}
else
{
var issueMessage = $"项目{projectId}连续性不佳({taskCount}任务/{uniquePersonnelCount}人员,评分:{continuityScore:F2})";
continuityIssues.Add(issueMessage);
_logger.LogDebug("【项目连续性问题】{Issue}", issueMessage);
}
}
var projectContinuityScore = totalProjectChecks > 0 ? (double)passedProjectChecks / totalProjectChecks : 1.0;
if (continuityIssues.Any())
{
_logger.LogDebug("【项目连续性约束】通过{PassedChecks}/{TotalChecks},问题详情: {Issues}",
passedProjectChecks, totalProjectChecks, string.Join("; ", continuityIssues.Take(2)));
}
return projectContinuityScore;
}
catch (Exception ex)
{
_logger.LogError(ex, "项目连续性约束验证异常");
return 0.8; // 异常时返回较高分数
}
}
///
/// 【Level 3 辅助方法】检查人员技能与任务的匹配性
///
private async Task CheckSkillMatching(WorkOrderEntity task, long personnelId)
{
await Task.CompletedTask;
try
{
// 简化的技能匹配逻辑(可根据实际业务扩展)
// 检查1:基于任务复杂度的基础匹配
var taskComplexity = task.ComplexityLevel; // 默认复杂度为1
// 检查2:基于人员资质等级的匹配(简化版)
// 假设资质等级存储在人员信息中,这里使用简化判断
var personnelExperienceLevel = EstimatePersonnelExperienceLevel(personnelId);
// 匹配规则:
// 复杂度1-2: 任何经验等级都可以
// 复杂度3-4: 需要中级以上经验
// 复杂度5+: 需要高级经验
var isMatched = taskComplexity switch
{
<= 2 => true, // 低复杂度任务,任何人员都可以
<= 4 => personnelExperienceLevel >= 2, // 中等复杂度,需要中级经验
_ => personnelExperienceLevel >= 3 // 高复杂度,需要高级经验
};
return isMatched;
}
catch (Exception ex)
{
_logger.LogError(ex, "技能匹配检查异常 - 任务:{TaskId}, 人员:{PersonnelId}", task.Id, personnelId);
return true; // 异常时默认匹配,避免过度严格
}
}
///
/// 【Level 3 辅助方法】估算人员经验等级
///
private int EstimatePersonnelExperienceLevel(long personnelId)
{
try
{
// 简化的经验等级估算(可根据实际人员资质数据优化)
// 基于人员ID的哈希值进行模拟分级(实际应该基于真实的技能数据)
var personnelIdHash = personnelId.GetHashCode();
var experienceLevel = Math.Abs(personnelIdHash % 5) + 1; // 1-5级经验等级
return Math.Max(1, Math.Min(5, experienceLevel));
}
catch
{
return 3; // 默认中等经验等级
}
}
///
/// 【Level 3 辅助方法】从WorkOrderCode中提取项目标识
/// 业务逻辑:WorkOrderCode格式通常为"项目号_班次code_工序code",取第一部分作为项目标识
///
private string ExtractProjectFromWorkOrderCode(string workOrderCode)
{
try
{
if (string.IsNullOrEmpty(workOrderCode))
return "unknown";
var parts = workOrderCode.Split('_');
return parts.Length > 0 ? parts[0] : workOrderCode;
}
catch
{
return "unknown";
}
}
///
/// 计算时间冲突评分 - 检查同一人员在同一时间段的任务冲突(保留原有方法用于兼容)
///
private async Task CalculateTimeConflictScoreAsync(Dictionary individual)
{
await Task.CompletedTask;
var personnelTaskGroups = individual.GroupBy(kvp => kvp.Value); // 按人员分组
var conflictCount = 0;
var totalAssignments = individual.Count;
foreach (var personnelGroup in personnelTaskGroups)
{
var personnelId = personnelGroup.Key;
var taskIds = personnelGroup.Select(g => g.Key).ToList();
// 获取该人员的所有任务
var tasks = taskIds.Select(id => _context.Tasks.FirstOrDefault(t => t.Id == id))
.Where(t => t != null).ToList();
// 检查同一日同一班次是否有多个任务
var timeGrouped = tasks.GroupBy(t => new { Date = t.WorkOrderDate.Date, ShiftId = t.ShiftId });
foreach (var timeGroup in timeGrouped)
{
if (timeGroup.Count() > 1)
{
conflictCount += timeGroup.Count() - 1; // 计算多余的任务数
_logger.LogWarning("发现时间冲突:人员{PersonnelId}在{Date:yyyy-MM-dd}的班次{ShiftId}有{Count}个任务",
personnelId, timeGroup.Key.Date, timeGroup.Key.ShiftId, timeGroup.Count());
}
}
}
// 计算无冲突率
var conflictFreeRate = totalAssignments > 0 ? (double)(totalAssignments - conflictCount) / totalAssignments : 1.0;
return Math.Max(0.0, conflictFreeRate);
}
///
/// 计算人员超载评分 - 检查单人任务数量是否超限
///
private double CalculatePersonnelOverloadScore(Dictionary individual)
{
var personnelTaskCounts = individual.GroupBy(kvp => kvp.Value)
.ToDictionary(g => g.Key, g => g.Count());
const int reasonableTaskLimit = 3; // 合理任务数上限
const int criticalTaskLimit = 5; // 严重超载阈值
var overloadPenalty = 0.0;
var totalPersonnel = personnelTaskCounts.Count;
foreach (var kvp in personnelTaskCounts)
{
var personnelId = kvp.Key;
var taskCount = kvp.Value;
if (taskCount > criticalTaskLimit)
{
overloadPenalty += 0.5; // 严重超载惩罚
_logger.LogWarning("严重超载:人员{PersonnelId}分配了{TaskCount}个任务(临界值{CriticalLimit})",
personnelId, taskCount, criticalTaskLimit);
}
else if (taskCount > reasonableTaskLimit)
{
overloadPenalty += 0.2; // 轻度超载惩罚
_logger.LogDebug("轻度超载:人员{PersonnelId}分配了{TaskCount}个任务(合理值{ReasonableLimit})",
personnelId, taskCount, reasonableTaskLimit);
}
}
return Math.Max(0.0, 1.0 - overloadPenalty / Math.Max(1, totalPersonnel));
}
///
/// 计算工时限制评分 - 检查单日工时是否超限
///
private double CalculateWorkHourLimitScore(Dictionary individual)
{
var personnelDailyHours = new Dictionary>();
// 统计每个人员每日的工时
foreach (var assignment in individual)
{
var taskId = assignment.Key;
var personnelId = assignment.Value;
var task = _context.Tasks.FirstOrDefault(t => t.Id == taskId);
if (task?.EstimatedHours.HasValue == true)
{
if (!personnelDailyHours.ContainsKey(personnelId))
personnelDailyHours[personnelId] = new Dictionary();
var date = task.WorkOrderDate.Date;
if (!personnelDailyHours[personnelId].ContainsKey(date))
personnelDailyHours[personnelId][date] = 0;
personnelDailyHours[personnelId][date] += task.EstimatedHours.Value;
}
}
const decimal dailyHourLimit = 8.0m; // 每日最大工时
const decimal overTimeLimit = 10.0m; // 加班上限
var violationCount = 0;
var totalDayAssignments = personnelDailyHours.SelectMany(p => p.Value).Count();
foreach (var personnelHours in personnelDailyHours)
{
var personnelId = personnelHours.Key;
foreach (var dailyHours in personnelHours.Value)
{
var date = dailyHours.Key;
var hours = dailyHours.Value;
if (hours > overTimeLimit)
{
violationCount++;
_logger.LogWarning("严重超时:人员{PersonnelId}在{Date:yyyy-MM-dd}工时{Hours}h(上限{OverTimeLimit}h)",
personnelId, date, hours, overTimeLimit);
}
else if (hours > dailyHourLimit)
{
violationCount++;
_logger.LogDebug("轻度超时:人员{PersonnelId}在{Date:yyyy-MM-dd}工时{Hours}h(正常上限{DailyLimit}h)",
personnelId, date, hours, dailyHourLimit);
}
}
}
return totalDayAssignments > 0 ? Math.Max(0.0, 1.0 - (double)violationCount / totalDayAssignments) : 1.0;
}
///
/// 计算公平性评分 - 增强版负载均衡评估
/// 业务逻辑:综合基尼系数、负载标准差、人员利用率等多维度评估负载均衡性
/// 核心改进:对任务过度集中的分配方案进行严厉惩罚,确保合理分配给所有合格人员
/// 【日志增强】:增加详细的公平性计算过程日志
///
private double CalculateFairnessScore(Dictionary individual)
{
var personnelWorkloads = new Dictionary();
_logger.LogDebug("【公平性评分开始】分析{TaskCount}个任务的分配公平性", individual.Count);
// 计算每个人员的工作负载
foreach (var assignment in individual)
{
var personnelId = assignment.Value;
if (!personnelWorkloads.ContainsKey(personnelId))
personnelWorkloads[personnelId] = 0;
// 简化:假设每个任务工作量为1
personnelWorkloads[personnelId] += 1;
}
// 计算总任务数和可用人员数
var totalTasks = individual.Count;
var availablePersonnelCount = _context.AvailablePersonnel.Count;
var usedPersonnelCount = personnelWorkloads.Count;
var workloadValues = personnelWorkloads.Values.ToList();
_logger.LogInformation("【公平性基础数据】总任务:{TotalTasks},可用人员:{AvailablePersonnel},实际使用人员:{UsedPersonnel},人员利用率:{UtilizationRate:P2}",
totalTasks, availablePersonnelCount, usedPersonnelCount, (double)usedPersonnelCount / availablePersonnelCount);
// 详细记录工作负载分布
var workloadDistributionLog = string.Join(", ", personnelWorkloads.OrderBy(kv => kv.Key).Select(kv => $"人员{kv.Key}:{kv.Value}任务"));
_logger.LogInformation("【工作负载分布】{WorkloadDistribution}", workloadDistributionLog);
// 【核心优化1】:基于基尼系数的基础公平性评分
var giniCoefficient = CalculateGiniCoefficientForIndividual(workloadValues);
var giniBasedScore = (1.0 - giniCoefficient) * 100;
_logger.LogInformation("【公平性组件1-基尼系数】基尼系数:{GiniCoeff:F4},基尼评分:{GiniScore:F2}/100",
giniCoefficient, giniBasedScore);
// 【核心优化2】:负载分布标准差惩罚
// 标准差越大,说明负载分布越不均匀,应该被惩罚
var workloadStandardDeviation = CalculateWorkloadStandardDeviation(workloadValues);
var maxReasonableStdDev = Math.Max(1.0, totalTasks * 0.3 / availablePersonnelCount); // 期望标准差阈值
var stdDevPenalty = Math.Min(50.0, (workloadStandardDeviation / maxReasonableStdDev) * 30.0);
_logger.LogInformation("【公平性组件2-标准差】负载标准差:{StdDev:F3},合理阈值:{MaxStdDev:F3},标准差惩罚:{StdPenalty:F2}",
workloadStandardDeviation, maxReasonableStdDev, stdDevPenalty);
// 【核心优化3】:人员利用率评分
// 如果任务过度集中在少数人员,人员利用率会很低
var utilizationRate = (double)usedPersonnelCount / availablePersonnelCount;
var utilizationScore = CalculatePersonnelUtilizationFairnessScore(utilizationRate, totalTasks, availablePersonnelCount);
_logger.LogInformation("【公平性组件3-利用率】人员利用率:{UtilizationRate:P2},利用率评分:{UtilizationScore:F2}/100",
utilizationRate, utilizationScore);
// 【核心优化4】:过度集中惩罚机制
// 检测是否存在单个人员承担过多任务的情况
var concentrationPenalty = CalculateConcentrationPenalty(workloadValues, totalTasks);
if (concentrationPenalty > 0)
{
var maxWorkload = workloadValues.Max();
var avgWorkload = (double)totalTasks / usedPersonnelCount;
_logger.LogWarning("【公平性组件4-集中度】检测到过度集中,最大负载:{MaxWorkload},平均负载:{AvgWorkload:F2},集中度惩罚:{ConcentrationPenalty:F2}",
maxWorkload, avgWorkload, concentrationPenalty);
}
else
{
_logger.LogDebug("【公平性组件4-集中度】负载分布合理,无集中度惩罚");
}
// 【综合评分计算】
// 基础评分(40%) + 利用率评分(25%) - 标准差惩罚(20%) - 集中度惩罚(15%)
var finalScore = (giniBasedScore * 0.4) + (utilizationScore * 0.25) - (stdDevPenalty * 0.2) - (concentrationPenalty * 0.15);
// 确保评分在合理范围内
finalScore = Math.Max(0.0, Math.Min(100.0, finalScore));
_logger.LogInformation("【公平性评分完成】基尼评分:{Gini:F2}×40%, 利用率评分:{Util:F2}×25%, 标准差惩罚:{StdPenalty:F2}×20%, 集中度惩罚:{ConPenalty:F2}×15%, 最终评分:{Final:F2}/100",
giniBasedScore, utilizationScore, stdDevPenalty, concentrationPenalty, finalScore);
// 分析公平性异常情况
if (finalScore < 30.0)
{
_logger.LogError("【公平性异常分析】公平性评分过低{FinalScore:F2},存在严重负载不均衡问题", finalScore);
if (giniCoefficient > 0.6)
_logger.LogError("【公平性问题1】基尼系数{GiniCoeff:F4}过高,负载分布极不均匀", giniCoefficient);
if (utilizationRate < 0.4)
_logger.LogError("【公平性问题2】人员利用率{UtilizationRate:P2}过低,任务过度集中", utilizationRate);
if (concentrationPenalty > 50.0)
_logger.LogError("【公平性问题3】集中度惩罚{ConcentrationPenalty:F2}过高,单人承担过多任务", concentrationPenalty);
}
else if (finalScore > 80.0)
{
_logger.LogInformation("【公平性优秀】公平性评分优秀{FinalScore:F2},负载分布均衡良好", finalScore);
}
return finalScore;
}
///
/// 计算工作负载标准差
///
private double CalculateWorkloadStandardDeviation(List workloads)
{
if (!workloads.Any()) return 0.0;
var mean = workloads.Average(x => (double)x);
var sumOfSquaredDifferences = workloads.Sum(x => Math.Pow((double)x - mean, 2));
return Math.Sqrt(sumOfSquaredDifferences / workloads.Count);
}
///
/// 计算人员利用率公平性评分
///
private double CalculatePersonnelUtilizationFairnessScore(double utilizationRate, int totalTasks, int availablePersonnelCount)
{
// 理想利用率:当任务数>=人员数时,期望70%-90%的人员参与
// 当任务数<人员数时,期望至少50%的人员参与
var idealMinUtilization = totalTasks >= availablePersonnelCount ? 0.7 : 0.5;
var idealMaxUtilization = 0.9;
if (utilizationRate >= idealMinUtilization && utilizationRate <= idealMaxUtilization)
{
return 100.0; // 理想利用率
}
else if (utilizationRate < idealMinUtilization)
{
// 利用率过低,线性惩罚
return (utilizationRate / idealMinUtilization) * 100.0;
}
else
{
// 利用率过高但不至于完全惩罚
return Math.Max(70.0, 100.0 - ((utilizationRate - idealMaxUtilization) * 200));
}
}
///
/// 计算过度集中惩罚
/// 对单个人员承担过多任务的情况进行惩罚
///
private double CalculateConcentrationPenalty(List workloads, int totalTasks)
{
if (!workloads.Any()) return 0.0;
var maxWorkload = workloads.Max();
var averageWorkload = totalTasks / (double)workloads.Count;
// 计算最大负载与平均负载的比例
var concentrationRatio = (double)maxWorkload / Math.Max(averageWorkload, 0.1);
// 如果单个人员负载超过平均值的3倍,开始施加惩罚
if (concentrationRatio > 3.0)
{
var penalty = (concentrationRatio - 3.0) * 20.0; // 超出部分每倍惩罚20分
return Math.Min(60.0, penalty); // 最大惩罚60分
}
// 【特殊情况】:17个任务分配给2个人员的极端情况
if (workloads.Count <= 2 && totalTasks > 10)
{
return 80.0; // 极重惩罚,基本淘汰此类方案
}
return 0.0; // 无需惩罚
}
///
/// 计算动态公平性权重 - 根据负载分布自适应调整权重
/// 业务逻辑:当检测到负载不均衡趋势时,自动提升公平性权重,引导算法向均衡分配方向进化
///
private double CalculateDynamicFairnessWeight(Dictionary individual, double baseFairnessWeight)
{
if (!individual.Any()) return baseFairnessWeight;
var personnelWorkloads = new Dictionary();
foreach (var assignment in individual)
{
var personnelId = assignment.Value;
personnelWorkloads[personnelId] = personnelWorkloads.GetValueOrDefault(personnelId, 0) + 1;
}
var totalTasks = individual.Count;
var availablePersonnelCount = _context.AvailablePersonnel.Count;
var usedPersonnelCount = personnelWorkloads.Count;
var workloadValues = personnelWorkloads.Values.ToList();
// 因子1:人员利用率因子
var utilizationRate = (double)usedPersonnelCount / availablePersonnelCount;
var utilizationFactor = utilizationRate < 0.5 ? 2.0 : // 利用率过低,大幅提升公平性权重
utilizationRate < 0.7 ? 1.5 : // 利用率较低,适度提升
1.0; // 利用率正常,保持基础权重
// 因子2:负载集中度因子
var maxWorkload = workloadValues.Any() ? workloadValues.Max() : 0;
var averageWorkload = totalTasks / (double)Math.Max(usedPersonnelCount, 1);
var concentrationRatio = (double)maxWorkload / Math.Max(averageWorkload, 0.1);
var concentrationFactor = concentrationRatio > 4.0 ? 2.5 : // 极度集中,极大提升权重
concentrationRatio > 3.0 ? 2.0 : // 高度集中,大幅提升权重
concentrationRatio > 2.0 ? 1.5 : // 中度集中,适度提升权重
1.0; // 分布合理,保持基础权重
// 因子3:基尼系数因子
var giniCoefficient = CalculateGiniCoefficientForIndividual(workloadValues);
var giniFactor = giniCoefficient > 0.6 ? 2.0 : // 极不均衡,大幅提升权重
giniCoefficient > 0.4 ? 1.5 : // 较不均衡,适度提升权重
giniCoefficient > 0.3 ? 1.2 : // 轻度不均衡,稍微提升权重
1.0; // 均衡状态,保持基础权重
// 计算最终的动态权重
var maxInflationFactor = Math.Max(Math.Max(utilizationFactor, concentrationFactor), giniFactor);
var dynamicWeight = baseFairnessWeight * maxInflationFactor;
// 限制权重增长上限,避免过度影响其他评分维度
dynamicWeight = Math.Min(dynamicWeight, baseFairnessWeight * 3.0);
_logger.LogTrace("【动态权重调整】利用率:{Util:F2}({UtilFactor:F1}), 集中度:{Conc:F2}({ConcFactor:F1}), 基尼:{Gini:F2}({GiniFactor:F1}), 权重:{Base:F2}→{Dynamic:F2}",
utilizationRate, utilizationFactor, concentrationRatio, concentrationFactor, giniCoefficient, giniFactor, baseFairnessWeight, dynamicWeight);
return dynamicWeight;
}
///
/// 计算负载均衡惩罚 - 适应度函数级别的严厉惩罚机制
/// 业务逻辑:对严重违反负载均衡原则的分配方案施加惩罚,确保遗传算法不会选择极端不均衡的方案
///
private double CalculateLoadBalancePenaltyForFitness(Dictionary individual)
{
if (!individual.Any()) return 0.0;
var personnelWorkloads = new Dictionary();
foreach (var assignment in individual)
{
var personnelId = assignment.Value;
personnelWorkloads[personnelId] = personnelWorkloads.GetValueOrDefault(personnelId, 0) + 1;
}
var totalTasks = individual.Count;
var availablePersonnelCount = _context.AvailablePersonnel.Count;
var usedPersonnelCount = personnelWorkloads.Count;
var workloadValues = personnelWorkloads.Values.ToList();
var penalty = 0.0;
// 惩罚1:极低人员利用率(大幅加强惩罚力度)
var utilizationRate = (double)usedPersonnelCount / availablePersonnelCount;
if (totalTasks > 5 && utilizationRate < 0.6) // 降低触发阈值,提高期望利用率
{
penalty += (0.6 - utilizationRate) * 300.0; // 大幅增强惩罚:每低于60%惩罚300分
}
// 惩罚2:单个人员负载过重
if (workloadValues.Any())
{
var maxWorkload = workloadValues.Max();
var reasonableMaxWorkload = Math.Ceiling(totalTasks * 1.5 / availablePersonnelCount); // 合理最大负载
if ((double)maxWorkload > reasonableMaxWorkload)
{
penalty += ((double)maxWorkload - reasonableMaxWorkload) * 15.0; // 每超出1个任务惩罚15分
}
}
// 惩罚3:方案多样性不足(强化检测:避免过度集中分配)
if (totalTasks >= 8 && usedPersonnelCount <= 2) // 降低阈值,更严格检测
{
penalty += 400.0; // 极度集中分配,超重惩罚
}
else if (totalTasks >= 12 && usedPersonnelCount <= 3)
{
penalty += 250.0; // 较严重集中,重惩罚
}
// 限制惩罚上限,但允许更大惩罚力度以促进负载均衡
penalty = Math.Min(penalty, 500.0);
if (penalty > 0)
{
_logger.LogTrace("【负载均衡惩罚】任务数:{Tasks}, 使用人员数:{Used}/{Available}, 利用率:{Util:P1}, 最大负载:{MaxLoad}, 总惩罚:{Penalty:F1}",
totalTasks, usedPersonnelCount, availablePersonnelCount, utilizationRate,
workloadValues.Any() ? workloadValues.Max() : 0, penalty);
}
return penalty;
}
///
/// 获取最佳解决方案
///
private GlobalOptimizedSolution GetBestSolution(List> population, List fitnessScores)
{
var maxFitnessIndex = fitnessScores.IndexOf(fitnessScores.Max());
var bestIndividual = population[maxFitnessIndex];
return new GlobalOptimizedSolution
{
IsValid = true,
BestSolution = new Dictionary(bestIndividual),
BestFitness = fitnessScores[maxFitnessIndex],
PersonnelWorkloadDistribution = CalculateWorkloadDistribution(bestIndividual)
};
}
///
/// 计算工作负载分布
///
private Dictionary CalculateWorkloadDistribution(Dictionary individual)
{
var workloadDistribution = new Dictionary();
foreach (var assignment in individual)
{
var personnelId = assignment.Value;
if (!workloadDistribution.ContainsKey(personnelId))
workloadDistribution[personnelId] = 0;
workloadDistribution[personnelId] += 1; // 简化:每个任务工作量为1
}
return workloadDistribution;
}
///
/// 【自适应优化】锦标赛选择 - 动态调整选择压力
/// 核心改进:根据种群多样性和收敛状态自适应调整锦标赛大小
///
private List> TournamentSelection(List> population,
List fitnessScores, int selectionCount, int generation, double populationDiversity)
{
var selected = new List>();
// 【自适应选择压力】:动态计算锦标赛大小
var adaptiveTournamentSize = CalculateAdaptiveTournamentSize(generation, populationDiversity);
_logger.LogTrace("【自适应选择】第{Generation}代锦标赛大小:{TournamentSize},种群多样性:{Diversity:F3}",
generation, adaptiveTournamentSize, populationDiversity);
for (int i = 0; i < selectionCount; i++)
{
var tournament = new List();
for (int j = 0; j < adaptiveTournamentSize; j++)
{
tournament.Add(_random.Next(population.Count));
}
var winner = tournament.OrderByDescending(idx => fitnessScores[idx]).First();
selected.Add(new Dictionary(population[winner]));
}
return selected;
}
///
/// 【自适应优化】计算自适应锦标赛大小
/// 业务逻辑:多样性低→小锦标赛(降低选择压力),多样性高→大锦标赛(提升选择压力)
///
private int CalculateAdaptiveTournamentSize(int generation, double populationDiversity)
{
const int baseTournamentSize = 3;
const int minTournamentSize = 2;
const int maxTournamentSize = 5;
// 因子1:基于种群多样性的调整
var diversityFactor = populationDiversity < 0.2 ? 0.7 : // 多样性极低,降低选择压力
populationDiversity < 0.4 ? 0.9 : // 多样性较低,稍微降低
populationDiversity > 0.6 ? 1.3 : // 多样性高,提升选择压力
1.0; // 多样性适中,保持基础压力
// 因子2:基于代数的调整
var generationFactor = generation < 10 ? 1.2 : // 前期高选择压力,快速优化
generation > 40 ? 0.8 : // 后期降低压力,保持多样性
1.0; // 中期保持稳定
var adaptiveSize = baseTournamentSize * diversityFactor * generationFactor;
return Math.Max(minTournamentSize, Math.Min(maxTournamentSize, (int)Math.Round(adaptiveSize)));
}
///
/// 【自适应优化】生成下一代 - 集成自适应参数
///
private List> GenerateNextGeneration(List> parents, int populationSize, int generation, double populationDiversity)
{
var nextGeneration = new List>();
// 【自适应精英策略】:根据多样性调整精英比例
var eliteRatio = populationDiversity < 0.3 ? 0.1 : // 多样性低,减少精英保留
populationDiversity > 0.7 ? 0.25 : // 多样性高,增加精英保留
0.2; // 默认精英比例
var eliteCount = Math.Min((int)(populationSize * eliteRatio), parents.Count / 3);
nextGeneration.AddRange(parents.Take(eliteCount).Select(p => new Dictionary(p)));
_logger.LogTrace("【自适应精英】第{Generation}代精英保留:{EliteCount}个({EliteRatio:P}),多样性:{Diversity:F3}",
generation, eliteCount, eliteRatio, populationDiversity);
// 交叉生成新个体
while (nextGeneration.Count < populationSize)
{
var parent1 = parents[_random.Next(parents.Count)];
var parent2 = parents[_random.Next(parents.Count)];
var offspring = Crossover(parent1, parent2);
offspring = Mutate(offspring, generation, populationDiversity); // 【自适应变异】
nextGeneration.Add(offspring);
}
return nextGeneration.Take(populationSize).ToList();
}
///
/// 【自适应优化】计算种群多样性 - 监控种群进化状态
/// 业务逻辑:通过个体间差异度量种群的多样性水平,指导自适应参数调整
///
private double CalculatePopulationDiversity(List> population)
{
if (population.Count < 2) return 0.0;
var totalPairwiseDistance = 0.0;
var pairCount = 0;
// 【性能优化】:采样计算而非全量计算,避免O(n²)复杂度
var sampleSize = Math.Min(20, population.Count); // 最多采样20个个体
var sampledIndices = Enumerable.Range(0, population.Count)
.OrderBy(x => _random.Next())
.Take(sampleSize)
.ToList();
for (int i = 0; i < sampledIndices.Count; i++)
{
for (int j = i + 1; j < sampledIndices.Count; j++)
{
var distance = CalculateIndividualDistance(population[sampledIndices[i]], population[sampledIndices[j]]);
totalPairwiseDistance += distance;
pairCount++;
}
}
// 归一化多样性值到0-1范围
var averageDistance = pairCount > 0 ? totalPairwiseDistance / pairCount : 0.0;
var normalizedDiversity = Math.Min(1.0, averageDistance);
_logger.LogTrace("【种群多样性】采样{SampleSize}个个体,平均距离:{AvgDistance:F3},归一化多样性:{Diversity:F3}",
sampleSize, averageDistance, normalizedDiversity);
return normalizedDiversity;
}
///
/// 计算两个个体间的距离(汉明距离的变体)
///
private double CalculateIndividualDistance(Dictionary individual1, Dictionary individual2)
{
if (individual1.Count != individual2.Count) return 1.0;
var differentAssignments = 0;
foreach (var kvp in individual1)
{
if (!individual2.TryGetValue(kvp.Key, out var value) || value != kvp.Value)
{
differentAssignments++;
}
}
return (double)differentAssignments / individual1.Count;
}
///
/// 交叉操作
///
private Dictionary Crossover(Dictionary parent1, Dictionary parent2)
{
var offspring = new Dictionary();
foreach (var taskId in parent1.Keys)
{
// 50%概率从每个父代继承
offspring[taskId] = _random.NextDouble() < 0.5 ? parent1[taskId] : parent2[taskId];
}
return offspring;
}
///
/// 【自适应优化】变异操作 - 根据种群状态动态调整变异率
/// 核心改进:自适应变异率+预筛选优化+多样性监控
///
private Dictionary Mutate(Dictionary individual, int generation, double populationDiversity)
{
// 【自适应变异率】:根据种群多样性和代数动态调整
var adaptiveMutationRate = CalculateAdaptiveMutationRate(generation, populationDiversity);
_logger.LogTrace("【自适应变异】第{Generation}代变异率:{MutationRate:F3},种群多样性:{Diversity:F3}",
generation, adaptiveMutationRate, populationDiversity);
foreach (var taskId in individual.Keys.ToList())
{
if (_random.NextDouble() < adaptiveMutationRate)
{
// 【性能优化】:优先从预筛选的合格人员中选择
var eligiblePersonnelIds = GetPreFilteredPersonnelForTask(taskId);
if (eligiblePersonnelIds.Any())
{
// 从合格候选人员中随机选择
individual[taskId] = eligiblePersonnelIds[_random.Next(eligiblePersonnelIds.Count)];
}
else
{
// 回退到全量人员选择
var allPersonnelIds = _context.AvailablePersonnel.Select(p => p.Id).ToList();
individual[taskId] = allPersonnelIds[_random.Next(allPersonnelIds.Count)];
_logger.LogTrace("【变异回退】任务{TaskId}无合格候选人,使用全量人员变异", taskId);
}
}
}
return individual;
}
///
/// 【自适应优化】计算自适应变异率
/// 业务逻辑:多样性低→高变异率,多样性高→低变异率,后期→适度提升变异率
///
private double CalculateAdaptiveMutationRate(int generation, double populationDiversity)
{
const double baseMutationRate = 0.1;
const double minMutationRate = 0.05;
const double maxMutationRate = 0.25;
// 因子1:基于种群多样性的调整
var diversityFactor = populationDiversity < 0.1 ? 2.0 : // 多样性极低,大幅提升变异率
populationDiversity < 0.3 ? 1.5 : // 多样性较低,适度提升
populationDiversity > 0.7 ? 0.7 : // 多样性很高,降低变异率
1.0; // 多样性适中,保持基础变异率
// 因子2:基于代数的调整(防止早熟收敛)
var generationFactor = generation > 30 ? 1.2 : // 后期适度提升,防止陷入局部最优
generation > 15 ? 1.0 : // 中期保持稳定
0.9; // 前期稍微降低,保证收敛
var adaptiveRate = baseMutationRate * diversityFactor * generationFactor;
return Math.Max(minMutationRate, Math.Min(maxMutationRate, adaptiveRate));
}
///
/// 计算收敛度
///
private double CalculateConvergence(List fitnessScores)
{
if (fitnessScores.Count < 2) return 1.0;
var mean = fitnessScores.Average();
var variance = fitnessScores.Sum(f => Math.Pow(f - mean, 2)) / fitnessScores.Count;
var standardDeviation = Math.Sqrt(variance);
return standardDeviation / Math.Max(mean, 1.0);
}
///
/// 获取平均适应度
///
private double GetAverageFitness(List fitnessScores)
{
return fitnessScores.Any() ? fitnessScores.Average() : 0.0;
}
///
/// 计算约束满足率 - 基于实际业务约束的确定性计算
/// 业务逻辑:评估任务分配方案对核心约束的满足程度
/// 核心约束:分配完整性、负载均衡性、人员过载检查
///
/// 任务-人员分配方案
/// 约束满足率(0-1之间)
private double CalculateConstraintSatisfactionRate(Dictionary solution)
{
if (!solution.Any()) return 0.0;
var constraintScores = new List();
// 约束1:分配完整性检查(所有任务都有人员分配)
var completenessScore = solution.Count > 0 ? 1.0 : 0.0;
constraintScores.Add(completenessScore);
// 约束2:人员负载均衡性检查
var workloadDistribution = CalculateWorkloadDistribution(solution);
var balanceScore = CalculateLoadBalanceScore(workloadDistribution);
constraintScores.Add(balanceScore);
// 约束3:人员过载检查(单人任务数不超过合理阈值)
var overloadScore = CalculateOverloadConstraintScore(workloadDistribution);
constraintScores.Add(overloadScore);
// 约束4:人员利用率检查(避免资源浪费)
var utilizationScore = CalculatePersonnelUtilizationScore(workloadDistribution);
constraintScores.Add(utilizationScore);
// 计算加权平均约束满足率
return constraintScores.Average();
}
///
/// 计算负载均衡评分 - 基于基尼系数的负载分布评估
///
private double CalculateLoadBalanceScore(Dictionary workloadDistribution)
{
if (!workloadDistribution.Any()) return 1.0;
var workloads = workloadDistribution.Values.ToList();
var giniCoefficient = CalculateGiniCoefficientForIndividual(workloads);
// 基尼系数越小,负载越均衡,评分越高
// 0.0 = 完全均衡(评分1.0),0.5以上 = 很不均衡(评分接近0)
return Math.Max(0.0, 1.0 - giniCoefficient * 2);
}
///
/// 计算过载约束评分 - 检查人员任务分配是否超过合理阈值
///
private double CalculateOverloadConstraintScore(Dictionary workloadDistribution)
{
if (!workloadDistribution.Any()) return 1.0;
const int reasonableTaskLimit = 6; // 合理任务数阈值
const int criticalTaskLimit = 10; // 严重过载阈值
var totalPersonnel = workloadDistribution.Count;
var overloadedPersonnel = 0;
var severelyOverloadedPersonnel = 0;
foreach (var workload in workloadDistribution.Values)
{
if (workload > criticalTaskLimit)
{
severelyOverloadedPersonnel++;
}
else if (workload > reasonableTaskLimit)
{
overloadedPersonnel++;
}
}
// 严重过载惩罚更重
var overloadPenalty = (overloadedPersonnel * 0.1 + severelyOverloadedPersonnel * 0.3) / totalPersonnel;
return Math.Max(0.0, 1.0 - overloadPenalty);
}
///
/// 计算人员利用率评分 - 增强版人员资源有效利用评估
/// 业务逻辑:确保所有合格人员得到合理分配,避免17个任务只分配给2个人员的极端情况
///
private double CalculatePersonnelUtilizationScore(Dictionary workloadDistribution)
{
if (!workloadDistribution.Any()) return 1.0;
var totalPersonnel = _context.AvailablePersonnel.Count;
var usedPersonnel = workloadDistribution.Count;
var totalTasks = workloadDistribution.Values.Sum(x => (int)x);
// 人员利用率:实际使用人员 / 可用人员
var utilizationRate = totalPersonnel > 0 ? (double)usedPersonnel / totalPersonnel : 0.0;
// 【增强优化】:根据任务规模动态调整利用率期望
double expectedMinUtilization, expectedMaxUtilization;
if (totalTasks >= totalPersonnel)
{
// 任务数 >= 人员数:期望大部分人员参与
expectedMinUtilization = 0.7; // 至少70%人员参与
expectedMaxUtilization = 0.95; // 最多95%人员参与
}
else if (totalTasks >= totalPersonnel * 0.5)
{
// 任务数为人员数的50%-100%:期望适中比例人员参与
expectedMinUtilization = 0.5; // 至少50%人员参与
expectedMaxUtilization = 0.8; // 最多80%人员参与
}
else
{
// 任务数较少:期望适度人员参与
expectedMinUtilization = Math.Max(0.3, (double)totalTasks / totalPersonnel); // 动态调整最小期望
expectedMaxUtilization = 0.7;
}
// 【核心改进】:特殊情况严厉惩罚
// 场景1:17个任务只分配给2个人员(极端集中)
if (totalTasks > 10 && usedPersonnel <= 3 && utilizationRate < 0.3)
{
return 0.1; // 极低评分,基本淘汰此类方案
}
// 场景2:任务数量合理但人员利用率极低
if (totalTasks >= 8 && utilizationRate < 0.4)
{
return Math.Max(0.2, utilizationRate * 0.5); // 重度惩罚
}
// 标准利用率评估
if (utilizationRate >= expectedMinUtilization && utilizationRate <= expectedMaxUtilization)
{
return 1.0; // 理想利用率
}
else if (utilizationRate < expectedMinUtilization)
{
// 利用率过低,线性惩罚
var penalty = (expectedMinUtilization - utilizationRate) / expectedMinUtilization;
return Math.Max(0.3, 1.0 - penalty * 0.7); // 保留30%基础分,避免过度惩罚
}
else
{
// 利用率过高,轻度惩罚
var excess = utilizationRate - expectedMaxUtilization;
return Math.Max(0.7, 1.0 - excess * 0.5); // 轻度惩罚
}
}
///
/// 计算基尼系数(个体版本)
///
private double CalculateGiniCoefficientForIndividual(List workloads)
{
if (!workloads.Any()) return 0;
var n = workloads.Count;
var sortedWorkloads = workloads.OrderBy(x => x).ToArray();
double numerator = 0;
for (int i = 0; i < n; i++)
{
numerator += (2 * (i + 1) - n - 1) * (double)sortedWorkloads[i];
}
var mean = workloads.Average(x => (double)x);
if (mean == 0) return 0;
return numerator / (n * n * mean);
}
///
/// 检查请假状态 - 使用缓存数据
///
private double CheckLeaveStatusWithCache(long personnelId, DateTime workDate)
{
// 简化版本:检查人员请假记录缓存
if (_context.PersonnelLeaveRecordsCache.TryGetValue(personnelId, out var leaveRecords) &&
leaveRecords != null)
{
// 这里应该检查具体的请假记录,但由于类型问题,我们先返回默认值
// 实际实现需要根据请假记录的具体类型来检查日期范围
_logger.LogDebug("检查人员{PersonnelId}在{WorkDate}的请假状态", personnelId, workDate.ToString("yyyy-MM-dd"));
}
return 1.0; // 默认返回1.0表示无请假限制
}
///
/// 【核心辅助方法】为指定人员构建遗传个体任务列表
/// 业务逻辑:从当前遗传个体分配中提取指定人员的所有任务,构建批次上下文基础数据
/// 用途:支持批次感知的班次规则验证,确保个体内部任务冲突得到正确检测
///
/// 人员ID
/// 分配给该人员的任务ID列表
/// 该人员在当前个体中的任务实体列表
private async Task> BuildIndividualTasksForPersonnel(long personnelId, List assignedTaskIds)
{
await Task.CompletedTask;
try
{
var individualTasks = new List();
foreach (var taskId in assignedTaskIds)
{
var task = _context.Tasks?.FirstOrDefault(t => t.Id == taskId);
if (task != null)
{
individualTasks.Add(task);
}
else
{
_logger.LogWarning("【批次上下文构建】人员{PersonnelId}的任务{TaskId}在上下文中未找到", personnelId, taskId);
}
}
// 按日期排序,便于后续班次规则验证
var sortedTasks = individualTasks.OrderBy(t => t.WorkOrderDate).ToList();
_logger.LogTrace("【个体任务构建完成】人员{PersonnelId}在当前个体中分配{TaskCount}个任务,日期范围:{StartDate}-{EndDate}",
personnelId, sortedTasks.Count,
sortedTasks.FirstOrDefault()?.WorkOrderDate.ToString("yyyy-MM-dd") ?? "无",
sortedTasks.LastOrDefault()?.WorkOrderDate.ToString("yyyy-MM-dd") ?? "无");
return sortedTasks;
}
catch (Exception ex)
{
_logger.LogError(ex, "【批次上下文构建异常】人员{PersonnelId}个体任务构建失败", personnelId);
return new List();
}
}
///
/// 【核心辅助方法】构建包含历史数据的完整任务上下文
/// 业务逻辑:整合遗传个体任务与历史已分配任务,形成完整的验证上下文
/// 关键功能:支持跨时间的班次规则验证(如:二班后次日休息规则)
/// 数据源:当前个体任务 + _context.Tasks 中的历史分配
///
/// 人员ID
/// 当前个体中该人员的任务
/// 包含历史数据的完整任务上下文
private async Task> BuildCompleteTaskContextForPersonnel(long personnelId, List individualTasks)
{
await Task.CompletedTask;
try
{
var completeContext = new List();
// 第一部分:添加当前个体中的任务
completeContext.AddRange(individualTasks);
// 第二部分:添加历史上下文中该人员的已分配任务
var historicalTasks = _context.Tasks?.Where(t =>
t.AssignedPersonnelId == personnelId &&
!individualTasks.Any(ind => ind.Id == t.Id) // 排除已包含的个体任务
).ToList() ?? new List();
completeContext.AddRange(historicalTasks);
// 按日期排序,构建时序上下文
var sortedCompleteContext = completeContext
.OrderBy(t => t.WorkOrderDate)
.ThenBy(t => t.ShiftId ?? 0)
.ToList();
_logger.LogDebug("【完整上下文构建】人员{PersonnelId}:个体任务{IndividualCount}个,历史任务{HistoricalCount}个,总上下文{TotalCount}个",
personnelId, individualTasks.Count, historicalTasks.Count, sortedCompleteContext.Count);
// 日志输出时间范围分析
if (sortedCompleteContext.Any())
{
var startDate = sortedCompleteContext.First().WorkOrderDate;
var endDate = sortedCompleteContext.Last().WorkOrderDate;
var spanDays = (endDate - startDate).Days + 1;
_logger.LogDebug("【完整上下文时间跨度】人员{PersonnelId}任务时间跨度{SpanDays}天({StartDate}至{EndDate})",
personnelId, spanDays, startDate.ToString("yyyy-MM-dd"), endDate.ToString("yyyy-MM-dd"));
}
return sortedCompleteContext;
}
catch (Exception ex)
{
_logger.LogError(ex, "【完整上下文构建异常】人员{PersonnelId}完整任务上下文构建失败", personnelId);
// 异常时至少返回个体任务,确保基础验证能够进行
return individualTasks ?? new List();
}
}
///
/// 【核心验证引擎】增强版批次感知班次规则验证
/// 业务逻辑:整合9种班次规则的完整验证,支持历史数据+批次上下文的双重验证模式
/// 验证策略:优先验证批次上下文冲突,然后结合历史数据进行完整性检查
/// 性能优化:基于规则类型的优先级验证,快速识别高风险冲突
/// 【架构升级】:委托给专门的ShiftRuleValidationEngine处理,实现关注点分离
///
/// 验证的人员ID
/// 当前待验证的任务
/// 批次上下文(不包含当前任务的其他相关任务)
/// 发现的班次规则冲突列表
private async Task> ValidateShiftRulesWithEnhancedBatchContext(
long personnelId, WorkOrderEntity currentTask, List batchContext)
{
try
{
if (!currentTask.ShiftId.HasValue)
{
_logger.LogWarning("【批次感知验证跳过】任务{TaskCode}缺少班次ID", currentTask.WorkOrderCode);
return new List();
}
_logger.LogTrace("【增强版班次规则验证开始】人员{PersonnelId}任务{TaskCode}({Date})班次{ShiftId},批次上下文{BatchCount}个任务",
personnelId, currentTask.WorkOrderCode, currentTask.WorkOrderDate.ToString("yyyy-MM-dd"),
currentTask.ShiftId, batchContext.Count);
// 【架构升级】:使用专门的班次规则校验引擎
// 调用ShiftRuleValidationEngine进行完整的9种规则验证
var conflicts = await _shiftRuleValidationEngine.ValidateShiftRulesWithEnhancedBatchContextAsync(
personnelId, currentTask, batchContext, _context);
_logger.LogInformation("【增强版班次规则验证完成】人员{PersonnelId}任务{TaskCode}共检查班次规则,发现{ConflictCount}个冲突",
personnelId, currentTask.WorkOrderCode, conflicts.Count);
// 详细记录前3个具体冲突
for (int i = 0; i < Math.Min(3, conflicts.Count); i++)
{
_logger.LogError("【具体冲突{Index}】{Conflict}", i + 1, conflicts[i]);
}
return conflicts;
}
catch (Exception ex)
{
_logger.LogError(ex, "【增强版班次规则验证异常】人员{PersonnelId}任务{TaskCode}验证失败",
personnelId, currentTask.WorkOrderCode);
// 异常情况下返回通用冲突信息
return new List { $"人员{personnelId}任务{currentTask.WorkOrderCode}班次规则验证异常: {ex.Message}" };
}
}
///
/// 【临时回退方案】简化的班次规则验证 - 在ShiftRuleValidationEngine集成前使用
/// 主要验证二班/三班后休息规则,作为核心业务保障
///
private async Task> FallbackShiftRuleValidation(
long personnelId, WorkOrderEntity currentTask, List batchContext)
{
var conflicts = new List();
try
{
var currentDate = currentTask.WorkOrderDate.Date;
var previousDay = currentDate.AddDays(-1);
// 【核心规则】检查前一天的二班/三班后休息规则
var previousTasks = batchContext.Concat(_context.Tasks ?? new List())
.Where(t => t.AssignedPersonnelId == personnelId)
.Where(t => t.WorkOrderDate.Date == previousDay)
.ToList();
foreach (var prevTask in previousTasks)
{
if (prevTask.ShiftId.HasValue)
{
// 检查是否为二班或三班(基于班次ID或名称模式)
var isSecondOrThirdShift = await IsRestrictedShiftAsync(prevTask.ShiftId.Value);
if (isSecondOrThirdShift)
{
var conflictMessage = $"违反班次后休息规则: 人员{personnelId}前一天({previousDay:yyyy-MM-dd})工作二班/三班" +
$"(任务{prevTask.WorkOrderCode}),今日({currentDate:yyyy-MM-dd})不应分配任务{currentTask.WorkOrderCode}";
conflicts.Add(conflictMessage);
_logger.LogError("【班次后休息规则违反】{Conflict}", conflictMessage);
}
}
}
return conflicts;
}
catch (Exception ex)
{
_logger.LogError(ex, "【回退班次规则验证异常】人员{PersonnelId}任务{TaskCode}",
personnelId, currentTask.WorkOrderCode);
return new List { $"班次规则验证异常: {ex.Message}" };
}
}
///
/// 【辅助方法】检查是否为需要休息的班次(二班或三班)
///
private async Task IsRestrictedShiftAsync(long shiftId)
{
try
{
// 方法1:从上下文的班次映射中获取班次编号
if (_context.ShiftNumberMapping.TryGetValue(shiftId, out var shiftNumber))
{
return shiftNumber == 2 || shiftNumber == 3; // 2=二班,3=三班
}
// 方法2:从任务实体中查找班次信息
var taskWithShift = _context.Tasks?.FirstOrDefault(t => t.ShiftId == shiftId);
if (taskWithShift?.ShiftEntity != null)
{
var entityShiftNumber = taskWithShift.ShiftEntity.ShiftNumber;
return entityShiftNumber == 2 || entityShiftNumber == 3;
}
// 方法3:基于任务代码模式识别
var shiftTask = _context.Tasks?.FirstOrDefault(t => t.ShiftId == shiftId);
if (shiftTask?.WorkOrderCode != null)
{
return shiftTask.WorkOrderCode.Contains("_2_") || shiftTask.WorkOrderCode.Contains("_3_");
}
return false;
}
catch (Exception ex)
{
_logger.LogError(ex, "【班次类型检查异常】ShiftId:{ShiftId}", shiftId);
return false;
}
}
}
}