using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NPP.SmartSchedue.Api.Contracts;
using ZhonTai.Admin.Services;
using ZhonTai.DynamicApi;
using ZhonTai.DynamicApi.Attributes;
using NPP.SmartSchedue.Api.Contracts.Services.Integration;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
using NPP.SmartSchedue.Api.Contracts.Core.Enums;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
using NPP.SmartSchedue.Api.Contracts.Domain.Equipment;
using NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
using NPP.SmartSchedue.Api.Contracts.Domain.Time;
using NPP.SmartSchedue.Api.Repositories.Work;
namespace NPP.SmartSchedue.Api.Services.Integration
{
///
/// 任务验证服务
/// 职责:专门负责任务数据完整性验证、业务规则检查和需求分析
/// 架构思考:集中处理所有验证逻辑,确保数据质量和业务规则一致性
///
[DynamicApi(Area = "app")]
public class TaskValidationService : BaseService, ITaskValidationService
{
private readonly WorkOrderRepository _workOrderRepository;
private readonly IShiftRuleMappingRepository _shiftRuleMappingRepository;
private readonly IShiftRepository _shiftRepository;
private readonly IEquipmentRepository _equipmentRepository;
private readonly ILogger _logger;
public TaskValidationService(
WorkOrderRepository workOrderRepository,
IShiftRuleMappingRepository shiftRuleMappingRepository,
IShiftRepository shiftRepository,
IEquipmentRepository equipmentRepository,
ILogger logger)
{
_workOrderRepository = workOrderRepository;
_shiftRuleMappingRepository = shiftRuleMappingRepository ?? throw new ArgumentNullException(nameof(shiftRuleMappingRepository));
_shiftRepository = shiftRepository ?? throw new ArgumentNullException(nameof(shiftRepository));
_equipmentRepository = equipmentRepository ?? throw new ArgumentNullException(nameof(equipmentRepository));
_logger = logger;
}
///
/// 分析任务需求
/// 深度业务思考:按照文档1.1步骤进行完整的任务需求分析
///
[HttpPost]
public async Task AnalyzeTaskRequirementsAsync(List tasks)
{
var result = new TaskRequirementAnalysisResult
{
ProcessRequirements = new List(),
ResourceRequirements = new ResourceRequirement(),
TimeDistribution = new TimeDistribution(),
AnalysisSummary = ""
};
try
{
// 1.1.1 工序需求提取
var processReqs = ExtractProcessRequirements(tasks);
result.ProcessRequirements = processReqs.Select(p => new TaskProcessRequirement
{
TaskId = p.TaskId,
ProcessId = p.ProcessId,
RequiredQualifications = p.RequiredQualifications,
EstimatedDuration = p.EstimatedDuration,
EquipmentTypeId = p.EquipmentTypeId
}).ToList();
// 1.1.2 资源需求统计
result.ResourceRequirements = await StatisticalResourceRequirementsAsync(tasks);
// 生成分析摘要
result.AnalysisSummary = GenerateRequirementAnalysisSummary(result, tasks.Count);
_logger.LogInformation("任务需求分析完成: 总任务数={TaskCount}, 工序类型数={ProcessTypes}",
tasks.Count, result.ProcessRequirements.Select(p => p.ProcessId).Distinct().Count());
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "任务需求分析失败: {Message}", ex.Message);
result.AnalysisSummary = $"需求分析异常: {ex.Message}";
return result;
}
}
///
/// 验证任务数据完整性
/// 深度业务思考:按照文档1.2步骤进行全面的数据完整性检查
///
[HttpPost]
public async Task ValidateTaskDataIntegrityAsync(List tasks)
{
var result = new TaskDataValidationResult
{
IsValid = true,
ValidationIssues = new List(),
BusinessRuleViolations = new List(),
ValidationSummary = ""
};
try
{
// 1.2.1 基础数据完整性检查
var dataIntegrityIssues = await ValidateBasicDataIntegrityAsync(tasks);
result.ValidationIssues.AddRange(dataIntegrityIssues);
// 1.2.2 业务规则预检查
var businessRuleViolations = await ValidateBusinessRulesAsync(tasks);
result.BusinessRuleViolations.AddRange(businessRuleViolations);
// 确定整体验证结果
result.IsValid = !result.ValidationIssues.Any() && !result.BusinessRuleViolations.Any();
result.ValidationSummary = GenerateValidationSummary(result, tasks.Count);
if (!result.IsValid)
{
_logger.LogWarning("任务数据验证发现问题: 完整性问题={IntegrityIssues}, 业务规则违反={BusinessRuleViolations}",
result.ValidationIssues.Count, result.BusinessRuleViolations.Count);
}
else
{
_logger.LogInformation("任务数据验证通过: 总任务数={TaskCount}", tasks.Count);
}
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "任务数据验证失败: {Message}", ex.Message);
result.IsValid = false;
result.ValidationSummary = $"验证过程异常: {ex.Message}";
return result;
}
}
///
/// 加载任务详细信息
/// 深度业务思考:按照文档1.3步骤优化关联数据加载和结构化处理
///
[HttpPost]
public async Task LoadTaskDetailedInfoAsync(List tasks)
{
var result = new TaskDetailLoadResult
{
TaskDetails = new List(),
LoadedDataStatistics = new LoadedDataStatistics(),
OptimizationSummary = ""
};
try
{
var taskIds = tasks.Select(t => t.Id).ToList();
// 1.3.1 关联数据加载策略
var taskDetails = await LoadTaskAssociatedDataAsync(taskIds);
// 1.3.2 数据结构优化
var optimizedData = await OptimizeDataStructuresAsync(taskDetails);
result.TaskDetails = optimizedData.TaskDetails;
result.LoadedDataStatistics = optimizedData.Statistics;
result.OptimizationSummary = GenerateLoadingSummary(result, tasks.Count);
_logger.LogInformation("任务详细信息加载完成: 任务数={TaskCount}, 关联数据项={AssociatedDataCount}",
tasks.Count, result.LoadedDataStatistics.TotalAssociatedRecords);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "任务详细信息加载失败: {Message}", ex.Message);
result.OptimizationSummary = $"加载过程异常: {ex.Message}";
return result;
}
}
#region 1.1 任务需求分析
///
/// 内部工序需求结构
///
private class InternalProcessRequirement
{
public long TaskId { get; set; }
public long ProcessId { get; set; }
public List RequiredQualifications { get; set; } = new List();
public TimeSpan? EstimatedDuration { get; set; }
public long? EquipmentTypeId { get; set; }
}
///
/// 提取工序需求
/// 高级工程师修复:正确解析字符串格式的资质要求
/// ProcessEntity.QualificationRequirements 是逗号分隔的资质ID字符串
///
private List ExtractProcessRequirements(List tasks)
{
var result = new List(tasks.Count);
foreach (var task in tasks)
{
var requirement = new InternalProcessRequirement
{
TaskId = task.Id,
ProcessId = task.ProcessId,
RequiredQualifications = ParseQualificationIds(task.ProcessEntity?.QualificationRequirements),
EstimatedDuration = task.ProcessEntity?.EstimatedDuration,
EquipmentTypeId = task.ProcessEntity?.EquipmentTypeId
};
result.Add(requirement);
}
return result;
}
///
/// 解析资质ID字符串
/// 高级工程师实现:严格的字符串解析和验证
///
/// 逗号分隔的资质ID字符串,如 "1,2,3"
/// 资质ID列表(转换为字符串以保持兼容性)
private List ParseQualificationIds(string qualificationRequirements)
{
if (string.IsNullOrWhiteSpace(qualificationRequirements))
return new List();
try
{
return qualificationRequirements
.Split(QualificationIdSeparators, StringSplitOptions.RemoveEmptyEntries)
.Select(id => id.Trim())
.Where(id => !string.IsNullOrWhiteSpace(id) && long.TryParse(id, out var numId) && numId > 0)
.ToList();
}
catch (Exception ex)
{
_logger.LogWarning(ex, "解析工序资质要求字符串失败: {QualificationRequirements}", qualificationRequirements);
return new List();
}
}
/// 资质ID分隔符数组
private static readonly char[] QualificationIdSeparators = { ',', ';', '|' };
///
/// 统计资源需求
/// 高级工程师修复:正确解析字符串格式的资质要求进行统计
/// 修复异步警告:改为同步方法,因为没有异步操作
///
private Task StatisticalResourceRequirementsAsync(List tasks)
{
var qualificationStats = new Dictionary();
var equipmentTypeStats = new Dictionary();
foreach (var task in tasks)
{
// 人员资质需求统计 - 修复:从字符串解析资质ID
if (!string.IsNullOrWhiteSpace(task.ProcessEntity?.QualificationRequirements))
{
var qualificationIds = ParseQualificationIds(task.ProcessEntity.QualificationRequirements);
foreach (var qualificationIdStr in qualificationIds)
{
if (long.TryParse(qualificationIdStr, out var qualificationId))
{
qualificationStats[qualificationId] =
qualificationStats.GetValueOrDefault(qualificationId, 0) + 1;
}
}
}
// 设备类型需求统计
if (!string.IsNullOrWhiteSpace(task.ProcessEntity?.EquipmentType) )
{
var equipmentType = task.ProcessEntity.EquipmentType;
var duration = (double)(task.ProcessEntity?.TheoreticalDuration ?? (decimal)DefaultTaskDurationHours);
equipmentTypeStats[equipmentType] =
equipmentTypeStats.GetValueOrDefault(equipmentType, 0) + duration;
}
}
_logger.LogDebug("资源需求统计完成: 资质类型 {QualificationCount} 个,设备类型 {EquipmentCount} 个",
qualificationStats.Count, equipmentTypeStats.Count);
return Task.FromResult(new ResourceRequirement
{
QualificationRequirements = qualificationStats,
EquipmentTypeRequirements = equipmentTypeStats
});
}
/// 默认任务持续时间(小时)
private const double DefaultTaskDurationHours = 8.0;
#endregion
#region 1.2 任务数据完整性验证
///
/// 验证基础数据完整性
///
private async Task> ValidateBasicDataIntegrityAsync(List tasks)
{
var validationIssues = new List();
foreach (var task in tasks)
{
// 检查工序信息完整性
if (task.ProcessEntity == null)
{
validationIssues.Add(new ValidationIssue
{
TaskId = task.Id,
IssueType = ValidationIssueType.MissingProcess,
Description = "工序信息缺失",
Severity = ValidationSeverity.Error
});
}
// 检查班次信息
if (!task.ShiftId.HasValue || task.ShiftId == 0)
{
validationIssues.Add(new ValidationIssue
{
TaskId = task.Id,
IssueType = ValidationIssueType.MissingShift,
Description = "班次信息缺失",
Severity = ValidationSeverity.Error
});
}
// 检查项目编号
if (string.IsNullOrWhiteSpace(task.ProjectNumber))
{
validationIssues.Add(new ValidationIssue
{
TaskId = task.Id,
IssueType = ValidationIssueType.MissingProjectNumber,
Description = "项目编号缺失",
Severity = ValidationSeverity.Warning
});
}
}
return validationIssues;
}
///
/// 验证业务规则
///
private async Task> ValidateBusinessRulesAsync(List tasks)
{
var violations = new List();
foreach (var task in tasks)
{
// 资质要求验证
if (!string.IsNullOrWhiteSpace(task.ProcessEntity?.QualificationRequirements))
{
var qualificationViolations = await ValidateQualificationRequirementsAsync(task);
violations.AddRange(qualificationViolations);
}
// 设备可用性预检
if (!string.IsNullOrWhiteSpace(task.ProcessEntity?.EquipmentType))
{
var equipmentViolations = await ValidateEquipmentAvailabilityAsync(task);
violations.AddRange(equipmentViolations);
}
}
return violations;
}
///
/// 验证班次规则
///
private async Task> ValidateShiftRulesAsync(WorkOrderEntity task)
{
var violations = new List();
// 暂时注释班次规则验证,需要完善ShiftEntity导航属性
// if (task.ShiftEntity?.ShiftRules?.Any() == true)
// {
// foreach (var rule in task.ShiftEntity.ShiftRules)
// {
// // 检查任务时间是否符合班次规则
// if (rule.Type == ShiftRuleTypeEnum.WorkingHours)
// {
// var taskStartHour = task.PlannedStartTime.Hour;
// var taskEndHour = task.PlannedEndTime.Hour;
//
// if (taskStartHour < 6 || taskEndHour > 22) // 示例规则
// {
// violations.Add(new BusinessRuleViolation
// {
// TaskId = task.Id,
// RuleType = BusinessRuleType.ShiftRule,
// RuleDescription = $"任务时间超出班次工作时间范围",
// ViolationDetails = $"任务时间: {task.PlannedStartTime:HH:mm}-{task.PlannedEndTime:HH:mm}"
// });
// }
// }
// }
// }
return violations;
}
///
/// 验证资质要求
///
private async Task> ValidateQualificationRequirementsAsync(WorkOrderEntity task)
{
var violations = new List();
if (!string.IsNullOrWhiteSpace(task.ProcessEntity?.QualificationRequirements))
{
// 解析资质ID字符串并验证
var qualificationIds = ParseQualificationIds(task.ProcessEntity.QualificationRequirements);
foreach (var qualificationIdStr in qualificationIds)
{
if (!long.TryParse(qualificationIdStr, out var qualificationId) || qualificationId <= 0)
{
violations.Add(new BusinessRuleViolation
{
TaskId = task.Id,
RuleType = BusinessRuleType.QualificationRequirement,
RuleDescription = "无效的资质要求配置",
ViolationDetails = $"资质ID: {qualificationIdStr}"
});
}
}
}
return violations;
}
///
/// 验证设备可用性
///
private async Task> ValidateEquipmentAvailabilityAsync(WorkOrderEntity task)
{
var violations = new List();
if (!string.IsNullOrWhiteSpace(task.ProcessEntity?.EquipmentType))
{
// 使用 EquipmentRepository 检查指定设备类型是否有可用设备
var hasAvailableEquipment = await _equipmentRepository.HasAvailableEquipmentByTypeAsync(task.ProcessEntity.EquipmentType);
if (!hasAvailableEquipment)
{
violations.Add(new BusinessRuleViolation
{
TaskId = task.Id,
RuleType = BusinessRuleType.EquipmentAvailability,
RuleDescription = "所需设备类型暂无可用设备",
ViolationDetails = $"设备类型: {task.ProcessEntity.EquipmentType}"
});
}
}
return violations;
}
#endregion
#region 1.3 任务详细信息加载
///
/// 加载任务关联数据
/// 批量加载优化查询性能
///
private async Task> LoadTaskAssociatedDataAsync(List taskIds)
{
var taskDetails = await _workOrderRepository.Select
.Where(w => taskIds.Contains(w.Id))
.IncludeMany(w => w.WorkOrderFLPersonnels)
.Include(w => w.ShiftEntity)
.Include(w => w.ProcessEntity)
.ToListAsync();
// 批量获取班次规则数据
var shiftIds = taskDetails.Where(t => t.ShiftId.HasValue).Select(t => t.ShiftId.Value).Distinct().ToList();
var shiftRulesMap = await _shiftRuleMappingRepository.GetBatchShiftRulesAsync(shiftIds);
return taskDetails.Select(task => new TaskDetailInfo
{
TaskId = task.Id,
TaskCode = task.Code,
ShiftRules = task.ShiftId.HasValue && shiftRulesMap.ContainsKey(task.ShiftId.Value)
? shiftRulesMap[task.ShiftId.Value]
: new List(),
QualificationRequirements = ConvertQualificationRequirements(task.ProcessEntity?.QualificationRequirements),
FLPersonnelRelations = task.WorkOrderFLPersonnels?.ToList() ?? new List()
}).ToList();
}
///
/// 优化数据结构
///
private async Task<(List TaskDetails, LoadedDataStatistics Statistics)> OptimizeDataStructuresAsync(
List taskDetails)
{
var statistics = new LoadedDataStatistics
{
TotalTasks = taskDetails.Count,
TotalAssociatedRecords = 0,
ShiftRulesCount = 0,
QualificationRequirementsCount = 0,
FLPersonnelRelationsCount = 0,
SpecifiedConstraintsCount = 0
};
// 构建快速查询索引
var shiftRuleIndex = new Dictionary>();
var qualificationIndex = new Dictionary>();
foreach (var detail in taskDetails)
{
// 班次规则解析和索引
if (detail.ShiftRules.Any())
{
shiftRuleIndex[detail.TaskId] = detail.ShiftRules;
statistics.ShiftRulesCount += detail.ShiftRules.Count;
}
// 资质要求映射和索引
if (detail.QualificationRequirements.Any())
{
qualificationIndex[detail.TaskId] = detail.QualificationRequirements;
statistics.QualificationRequirementsCount += detail.QualificationRequirements.Count;
}
// FL人员关系计数
if (detail.FLPersonnelRelations.Any())
{
statistics.FLPersonnelRelationsCount += detail.FLPersonnelRelations.Count;
}
// 指定约束计数(暂时不统计,因为没有指定约束)
statistics.SpecifiedConstraintsCount = 0;
}
statistics.TotalAssociatedRecords = statistics.ShiftRulesCount +
statistics.QualificationRequirementsCount +
statistics.FLPersonnelRelationsCount +
statistics.SpecifiedConstraintsCount;
return (taskDetails, statistics);
}
///
/// 转换资质要求为输出格式
/// 深度业务思考:统一资质要求的数据格式,便于后续验证和分配使用
/// 高级工程师优化:
/// 1. 正确解析字符串格式的资质ID(逗号分隔)
/// 2. 严格的空值和异常处理
/// 3. 业务规则验证
/// 4. 性能优化
/// 5. 常量化硬编码值
///
private List ConvertQualificationRequirements(
string qualificationRequirementsStr)
{
// 防御性编程:空字符串处理
if (string.IsNullOrWhiteSpace(qualificationRequirementsStr))
{
_logger.LogDebug("工序资质要求字符串为空,返回空结果");
return new List();
}
try
{
// 解析资质ID字符串
var qualificationIds = ParseQualificationIds(qualificationRequirementsStr);
if (!qualificationIds.Any())
{
_logger.LogDebug("工序资质要求字符串解析后为空: {QualificationRequirements}", qualificationRequirementsStr);
return new List();
}
var result = new List(qualificationIds.Count);
foreach (var qualificationIdStr in qualificationIds)
{
if (!long.TryParse(qualificationIdStr, out var qualificationId) || qualificationId <= 0)
{
_logger.LogWarning("发现无效的资质ID字符串: {QualificationId},已跳过", qualificationIdStr);
continue;
}
var qualification = new QualificationRequirement
{
QualificationId = qualificationId,
QualificationName = $"资质{qualificationId}", // 临时名称,实际应用中需要查询资质表
};
result.Add(qualification);
}
_logger.LogDebug("成功转换 {Count} 个工序资质要求", result.Count);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "转换工序资质要求时发生异常: {QualificationRequirements}", qualificationRequirementsStr);
return new List();
}
}
#region 资质转换常量定义
/// 默认资质等级
private const int DefaultQualificationLevel = 1;
#endregion
#endregion
#region 辅助方法和摘要生成
///
/// 生成需求分析摘要
///
private string GenerateRequirementAnalysisSummary(TaskRequirementAnalysisResult result, int totalTasks)
{
var processTypeCount = result.ProcessRequirements.Select(p => p.ProcessId).Distinct().Count();
var qualificationTypeCount = result.ResourceRequirements.QualificationRequirements.Count;
var equipmentTypeCount = result.ResourceRequirements.EquipmentTypeRequirements.Count;
return $"需求分析完成: 总任务{totalTasks}个, 涉及{processTypeCount}种工序, " +
$"{qualificationTypeCount}种资质需求, {equipmentTypeCount}种设备类型需求。";
}
///
/// 生成验证摘要
///
private string GenerateValidationSummary(TaskDataValidationResult result, int totalTasks)
{
if (result.IsValid)
{
return $"数据验证通过: 总任务{totalTasks}个, 数据完整性和业务规则均符合要求。";
}
else
{
return $"数据验证发现问题: 总任务{totalTasks}个, " +
$"完整性问题{result.ValidationIssues.Count}个, " +
$"业务规则违反{result.BusinessRuleViolations.Count}个。";
}
}
///
/// 生成加载摘要
///
private string GenerateLoadingSummary(TaskDetailLoadResult result, int totalTasks)
{
return $"详细信息加载完成: 任务{totalTasks}个, " +
$"关联数据{result.LoadedDataStatistics.TotalAssociatedRecords}条, " +
$"包含班次规则{result.LoadedDataStatistics.ShiftRulesCount}条, " +
$"资质要求{result.LoadedDataStatistics.QualificationRequirementsCount}条。";
}
#endregion
}
}