paiban/NPP.SmartSchedue.Api/Services/Integration/IntegrationRecordService.cs
Asoka.Wang 2b3f9acdce 123
2025-09-22 19:09:47 +08:00

1495 lines
65 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

using FreeSql;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NPP.SmartSchedue.Api.Contracts.Core.Enums;
using NPP.SmartSchedue.Api.Contracts.Domain.Integration;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
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.Repositories.Work;
using NPP.SmartSchedue.Api.Repositories.Equipment;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using ZhonTai.Admin.Services;
using ZhonTai.DynamicApi;
using ZhonTai.DynamicApi.Attributes;
namespace NPP.SmartSchedue.Api.Services.Integration
{
/// <summary>
/// 整合记录服务
/// </summary>
[DynamicApi(Area = "app")]
public partial class IntegrationRecordService : BaseService, IIntegrationRecordService, IDynamicApi
{
private readonly IIntegrationRecordRepository _integrationRecordRepository;
private readonly WorkOrderRepository _workOrderRepository;
private readonly EquipmentRepository _equipmentRepository;
private readonly ILogger<IntegrationRecordService> _logger;
public IntegrationRecordService(
IIntegrationRecordRepository integrationRecordRepository,
WorkOrderRepository workOrderRepository,
EquipmentRepository equipmentRepository,
ILogger<IntegrationRecordService> logger)
{
_integrationRecordRepository = integrationRecordRepository;
_workOrderRepository = workOrderRepository;
_equipmentRepository = equipmentRepository;
_logger = logger;
}
/// <summary>
/// 生成整合记录核心方法
/// 深度业务思考按照文档5.1-5.5步骤实现完整的记录生成流程
/// </summary>
[HttpPost]
public async Task<IntegrationRecord> GenerateIntegrationRecordAsync(IntegrationRecordInput input)
{
try
{
// 5.1 整合记录数据准备
var batchCode = await GenerateUniqueBatchCodeAsync();
var taskEntities = await GetTaskEntitiesForRecordAsync(input.TaskIds);
var projectNumbers = ExtractProjectNumbers(taskEntities);
// 5.2 分配结果序列化
var strategyConfigJson = SerializeStrategyConfig(input.Strategy);
var personnelAllocationJson = SerializePersonnelAllocationResult(input.PersonnelAllocation);
var equipmentAllocationJson = SerializeEquipmentAllocationResult(input.EquipmentAllocation);
// 5.3 统计信息计算与记录
var statistics = await CalculateIntegrationStatisticsAsync(input);
var failureAnalysis = await GenerateFailureAnalysisAsync(input);
// 构建整合记录实体
var integrationRecord = new IntegrationRecordEntity
{
IntegrationBatchCode = batchCode,
IntegrationTime = DateTime.Now,
ProjectNumbers = string.Join(",", projectNumbers),
OriginalTaskCount = taskEntities.Count,
SuccessTaskCount = input.PersonnelAllocation?.SuccessfulMatches?.Count ?? 0,
FailedTaskCount = statistics.FailedTaskCount,
// SuccessRate is a calculated property
// 序列化结果存储
StrategyConfigJson = strategyConfigJson,
PersonnelAllocationResultJson = personnelAllocationJson,
EquipmentAllocationResultJson = equipmentAllocationJson,
TaskIdsJson = JsonSerializer.Serialize(input.TaskIds),
// 统计分析数据
ElapsedMilliseconds = statistics.ExecutionTimeMs,
PersonnelFairnessScore = input.PersonnelAllocation?.FairnessScore ?? 0,
EquipmentUtilizationRate = (decimal)(input.EquipmentAllocation?.OverallUtilizationRate ?? 0),
// 失败分析
FailureReasonStats = JsonSerializer.Serialize(failureAnalysis),
// 操作员信息
OperatorUserId = input.OperatorUserId,
OperatorUserName = input.OperatorName,
OperatorRealName = input.OperatorName,
Remarks = input.Remarks ?? "",
CreatedTime = DateTime.Now,
CreatedUserId = input.OperatorUserId,
CreatedUserName = input.OperatorName
};
// 5.4 数据库持久化与事务管理
var record = await _integrationRecordRepository.InsertAsync(integrationRecord);
// 创建关联数据
await CreateTaskIntegrationRelationsAsync(record.Id, taskEntities);
// 生成索引数据
await GenerateSearchIndexDataAsync(record.Id, taskEntities);
// 记录审计信息
await RecordAuditInfoAsync(record.Id, input.OperatorUserId);
// Transaction handled by UnitOfWork
_logger.LogInformation("整合记录生成成功: BatchCode={BatchCode}, RecordId={RecordId}",
batchCode, record.Id);
// 5.5 记录转换与API返回
return ConvertToIntegrationRecord(record);
}
catch (Exception ex)
{
// Transaction handled by UnitOfWork
_logger.LogError(ex, "整合记录生成失败: {Message}", ex.Message);
throw new IntegrationRecordException($"记录生成失败: {ex.Message}", ex);
}
}
#region 5.1
/// <summary>
/// 生成唯一批次编码
/// 格式INT + yyyyMMddHHmmss + XXX总长度23字符符合数据库30字符限制
/// 业务思考:确保编码唯一性和数据库兼容性,与编排服务保持一致
/// </summary>
private async Task<string> GenerateUniqueBatchCodeAsync()
{
var timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
var random = new Random().Next(100, 999);
var batchCode = $"INT{timestamp}{random}";
// 唯一性验证
var exists = await _integrationRecordRepository
.Where(r => r.IntegrationBatchCode == batchCode)
.AnyAsync();
if (exists)
{
// 递归重新生成,增加延时避免时间戳冲突
await Task.Delay(1);
return await GenerateUniqueBatchCodeAsync();
}
return batchCode;
}
/// <summary>
/// 获取任务实体数据
/// 包含关联数据的批量获取
/// </summary>
private async Task<List<WorkOrderEntity>> GetTaskEntitiesForRecordAsync(List<long> taskIds)
{
return await _workOrderRepository.Select
.Where(w => taskIds.Contains(w.Id))
.IncludeMany(w => w.WorkOrderFLPersonnels)
.Include(w => w.ShiftEntity)
.Include(w => w.ProcessEntity)
.ToListAsync();
}
/// <summary>
/// 提取项目编号
/// 去重并格式化处理
/// </summary>
private List<string> ExtractProjectNumbers(List<WorkOrderEntity> tasks)
{
return tasks.Select(t => t.ProjectNumber)
.Where(pn => !string.IsNullOrEmpty(pn))
.Distinct()
.OrderBy(pn => pn)
.ToList();
}
#endregion
#region 5.2
/// <summary>
/// 策略配置序列化
/// 深度业务思考:保存完整的策略配置以便后续分析和重现
/// </summary>
private string SerializeStrategyConfig(IntegrationStrategy strategy)
{
if (strategy == null) return "{}";
var config = new
{
PersonnelStrategy = strategy.PersonnelStrategy.ToString() ?? "FairDistribution",
EquipmentStrategy = strategy.EquipmentStrategy.ToString() ?? "UtilizationBalance",
EnforceShiftRules = strategy.EnforceShiftRules,
TargetEquipmentUtilization = strategy.TargetEquipmentUtilization,
AllowCrossShiftAllocation = true,
PreferredPersonnelWeighting = 0.3,
FairnessWeighting = 0.4,
EfficiencyWeighting = 0.3
};
return JsonSerializer.Serialize(config, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
});
}
/// <summary>
/// 人员分配结果序列化
/// 包含详细的匹配信息和分析数据
/// </summary>
private string SerializePersonnelAllocationResult(PersonnelAllocationResult result)
{
if (result == null) return "{}";
var serializedResult = new
{
SuccessfulMatches = (result.SuccessfulMatches?.Select(m => new
{
TaskId = m.TaskId,
TaskCode = m.TaskCode,
AssignedPersonnelId = m.PersonnelId,
PersonnelName = m.PersonnelName ?? "未知",
MatchScore = m.MatchScore,
MatchReason = m.MatchReason ?? "智能分配",
AllocationStrategy = "智能匹配"
}).ToList() as IEnumerable<object>) ?? new List<object>(),
FailedTasks = (result.FailedTasks?.Select(f => new
{
TaskId = f.TaskId,
TaskCode = f.TaskCode,
FailureReason = f.FailureReason,
FailureType = f.FailureType.ToString(),
ConflictDetails = f.ConflictDetails ?? new List<string>()
}).ToList() as IEnumerable<object>) ?? new List<object>(),
FairnessScore = result.FairnessScore,
WorkloadAnalysis = result.WorkloadAnalysis?.Cast<object>().ToList() ?? new List<object>(),
AllocationSummary = result.AllocationSummary ?? "人员分配完成"
};
return JsonSerializer.Serialize(serializedResult, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
});
}
/// <summary>
/// 设备分配结果序列化
/// 包含利用率分析和冲突解决信息
/// </summary>
private string SerializeEquipmentAllocationResult(EquipmentAllocationResult result)
{
if (result == null) return "{}";
var serializedResult = new
{
SuccessfulAllocations = (result.SuccessfulMatches?.Select(a => new
{
TaskId = a.TaskId,
EquipmentId = a.EquipmentId,
EquipmentCode = a.EquipmentCode ?? $"EQP-{a.EquipmentId}",
UtilizationRate = 0.75, // 示例值,实际需要计算
AllocationReason = a.AllocationReason ?? "利用率均衡分配"
}).ToList() as IEnumerable<object>) ?? new List<object>(),
FailedAllocations = (result.FailedAllocations?.Select(f => new
{
TaskId = f.TaskId,
TaskCode = f.TaskCode,
EquipmentType = "未知类型",
FailureReason = f.FailureReason,
SuggestedActions = f.ConflictDetails ?? new List<string>()
}).ToList() as IEnumerable<object>) ?? new List<object>(),
OverallUtilizationRate = result.OverallUtilizationRate,
EquipmentLoadBalance = new { /* 负载均衡数据 */ },
UtilizationReport = result.AllocationSummary ?? $"平均设备利用率{result.OverallUtilizationRate:F1}%"
};
return JsonSerializer.Serialize(serializedResult, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
});
}
#endregion
#region 5.3
/// <summary>
/// 统计信息结构
/// </summary>
private class IntegrationStatistics
{
public int FailedTaskCount { get; set; }
public double SuccessRate { get; set; }
public long ExecutionTimeMs { get; set; }
}
/// <summary>
/// 计算整合统计信息
/// </summary>
private async Task<IntegrationStatistics> CalculateIntegrationStatisticsAsync(IntegrationRecordInput input)
{
var successfulCount = input.PersonnelAllocation?.SuccessfulMatches?.Count ?? 0;
var totalTasks = input.TaskIds.Count;
var failedCount = totalTasks - successfulCount;
return new IntegrationStatistics
{
FailedTaskCount = failedCount,
SuccessRate = totalTasks > 0 ? (double)successfulCount / totalTasks : 0,
ExecutionTimeMs = 0 // 由调用方传入或计算
};
}
/// <summary>
/// 生成失败分析数据
/// 深度业务思考:详细分析失败原因,为系统优化提供数据支持
/// </summary>
private async Task<Dictionary<string, object>> GenerateFailureAnalysisAsync(IntegrationRecordInput input)
{
var failureAnalysis = new Dictionary<string, object>();
// 人员分配失败分析
if (input.PersonnelAllocation?.FailedTasks?.Any() == true)
{
var personnelFailures = input.PersonnelAllocation.FailedTasks
.GroupBy(f => f.FailureType)
.ToDictionary(g => g.Key.ToString(), g => g.Count());
failureAnalysis["PersonnelAllocationFailures"] = personnelFailures;
}
// 设备分配失败分析
if (input.EquipmentAllocation?.FailedAllocations?.Any() == true)
{
var equipmentFailures = input.EquipmentAllocation.FailedAllocations
.GroupBy(f => f.FailureReason)
.ToDictionary(g => g.Key ?? "未知", g => g.Count());
failureAnalysis["EquipmentAllocationFailures"] = equipmentFailures;
}
// 改进建议生成
failureAnalysis["ImprovementSuggestions"] = await GenerateImprovementSuggestionsAsync(input);
return failureAnalysis;
}
/// <summary>
/// 生成改进建议
/// </summary>
private async Task<List<string>> GenerateImprovementSuggestionsAsync(IntegrationRecordInput input)
{
var suggestions = new List<string>();
var successRate = input.TaskIds.Count > 0 ?
(double)(input.PersonnelAllocation?.SuccessfulMatches?.Count ?? 0) / input.TaskIds.Count : 0;
if (successRate < 0.8)
{
suggestions.Add("建议增加人员培训以提高资质匹配率");
suggestions.Add("考虑优化任务时间安排以减少冲突");
}
if (input.EquipmentAllocation?.FailedAllocations?.Any() == true)
{
suggestions.Add("建议评估设备维护计划以提高可用性");
suggestions.Add("考虑增加关键设备的数量配置");
}
return suggestions;
}
#endregion
#region 5.4
/// <summary>
/// 创建任务整合关联数据
/// </summary>
private async Task CreateTaskIntegrationRelationsAsync(long recordId, List<WorkOrderEntity> tasks)
{
// 创建任务-记录关联表数据(如果需要)
foreach (var task in tasks)
{
// 更新任务的整合记录ID
task.IntegrationRecordId = recordId;
}
if (tasks.Any())
{
await _workOrderRepository.UpdateAsync(tasks);
}
}
/// <summary>
/// 生成搜索索引数据
/// 优化后续查询性能
/// </summary>
private async Task GenerateSearchIndexDataAsync(long recordId, List<WorkOrderEntity> tasks)
{
// 生成项目编号索引
var projectNumbers = tasks.Select(t => t.ProjectNumber).Distinct().ToList();
// 生成时间范围索引
var dateRange = new
{
StartDate = tasks.Min(t => t.PlannedStartTime),
EndDate = tasks.Max(t => t.PlannedEndTime)
};
// 这里可以创建专门的索引表或使用全文搜索引擎
await Task.CompletedTask; // 占位实现
}
/// <summary>
/// 记录审计信息
/// </summary>
private async Task RecordAuditInfoAsync(long recordId, long operatorUserId)
{
// 记录操作审计日志
_logger.LogInformation("整合记录创建审计: RecordId={RecordId}, OperatorUserId={OperatorUserId}",
recordId, operatorUserId);
// 这里可以创建专门的审计日志记录
await Task.CompletedTask; // 占位实现
}
#endregion
#region 5.5 API返回
/// <summary>
/// 转换为API返回格式
/// 深度业务思考:提供用户友好的数据格式,隐藏内部技术细节
/// </summary>
private IntegrationRecord ConvertToIntegrationRecord(IntegrationRecordEntity entity)
{
return new IntegrationRecord
{
Id = entity.Id,
IntegrationBatchCode = entity.IntegrationBatchCode,
IntegrationTime = entity.IntegrationTime,
ProjectNumbers = entity.ProjectNumbers ?? "",
TaskCount = entity.OriginalTaskCount,
SuccessTaskCount = entity.SuccessTaskCount,
FailedTaskCount = entity.FailedTaskCount,
SuccessRate = entity.SuccessRate,
ElapsedMilliseconds = entity.ElapsedMilliseconds,
PersonnelFairnessScore = entity.PersonnelFairnessScore,
EquipmentUtilizationRate = entity.EquipmentUtilizationRate,
OperatorUserId = entity.OperatorUserId,
OperatorName = entity.OperatorUserName,
Remarks = entity.Remarks,
CreatedTime = entity.CreatedTime ?? DateTime.Now
};
}
#endregion
/// <summary>
/// 根据记录ID查询整合记录信息并附加任务集
/// </summary>
/// <param name="recordId">整合记录ID</param>
/// <returns>包含任务集的整合记录信息</returns>
[HttpGet]
public async Task<IntegrationRecordWithTasksOutput> GetIntegrationRecordWithTasksAsync(long recordId)
{
try
{
// 查询整合记录
var integrationRecord = await _integrationRecordRepository.GetAsync(recordId);
if (integrationRecord == null)
{
throw new IntegrationRecordException($"未找到ID为{recordId}的整合记录");
}
// 获取任务ID列表
var taskIds = integrationRecord.GetTaskIds();
if (!taskIds.Any())
{
// 如果没有任务,返回基本记录信息
return ConvertToIntegrationRecordWithTasks(integrationRecord, new List<WorkOrderEntity>());
}
// 查询任务详细信息
var taskEntities = await GetTaskEntitiesForRecordAsync(taskIds);
// 转换为输出格式
var result = ConvertToIntegrationRecordWithTasks(integrationRecord, taskEntities);
_logger.LogInformation("成功查询整合记录及任务集: RecordId={RecordId}, TaskCount={TaskCount}",
recordId, taskEntities.Count);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "查询整合记录及任务集失败: RecordId={RecordId}, Error={Message}",
recordId, ex.Message);
throw new IntegrationRecordException($"查询整合记录及任务集失败: {ex.Message}", ex);
}
}
/// <summary>
/// 转换为包含任务集的整合记录输出格式
/// </summary>
private IntegrationRecordWithTasksOutput ConvertToIntegrationRecordWithTasks(
IntegrationRecordEntity entity,
List<WorkOrderEntity> tasks)
{
var result = new IntegrationRecordWithTasksOutput
{
Id = entity.Id,
IntegrationBatchCode = entity.IntegrationBatchCode,
IntegrationTime = entity.IntegrationTime,
OperatorUserId = entity.OperatorUserId,
OperatorUserName = entity.OperatorUserName,
OperatorRealName = entity.OperatorRealName,
SuccessTaskCount = entity.SuccessTaskCount,
FailedTaskCount = entity.FailedTaskCount,
ElapsedMilliseconds = entity.ElapsedMilliseconds,
FairnessScore = entity.PersonnelFairnessScore,
UtilizationRate = entity.EquipmentUtilizationRate,
Remarks = entity.Remarks,
CreatedTime = entity.CreatedTime ?? DateTime.Now,
ProjectNumbers = entity.GetProjectNumbers(),
IntegrationType = entity.IntegrationType,
PublishStatus = entity.PublishStatus,
TaskDetails = ConvertToTaskDetails(tasks)
};
// 解析策略配置
try
{
if (!string.IsNullOrEmpty(entity.StrategyConfigJson))
{
var strategyConfig = JsonSerializer.Deserialize<IntegrationStrategyConfig>(
entity.StrategyConfigJson,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
if (strategyConfig != null)
{
result.StrategyConfig = strategyConfig;
}
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "解析策略配置失败: RecordId={RecordId}", entity.Id);
}
// 解析人员分配结果
try
{
if (!string.IsNullOrEmpty(entity.PersonnelAllocationResultJson))
{
var personnelResult = JsonSerializer.Deserialize<PersonnelAllocationResult>(
entity.PersonnelAllocationResultJson,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
result.PersonnelAllocationResult = personnelResult;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "解析人员分配结果失败: RecordId={RecordId}", entity.Id);
}
// 解析设备分配结果
try
{
if (!string.IsNullOrEmpty(entity.EquipmentAllocationResultJson))
{
var equipmentResult = JsonSerializer.Deserialize<EquipmentAllocationResult>(
entity.EquipmentAllocationResultJson,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
result.EquipmentAllocationResult = equipmentResult;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "解析设备分配结果失败: RecordId={RecordId}", entity.Id);
}
// 解析失败原因统计
try
{
if (!string.IsNullOrEmpty(entity.FailureReasonStats))
{
var failureStats = JsonSerializer.Deserialize<Dictionary<string, object>>(
entity.FailureReasonStats,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
if (failureStats != null)
{
result.FailureReasonStats = failureStats;
}
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "解析失败原因统计失败: RecordId={RecordId}", entity.Id);
}
return result;
}
/// <summary>
/// 转换为任务详细信息列表
/// </summary>
private List<TaskDetailForRecord> ConvertToTaskDetails(List<WorkOrderEntity> tasks)
{
return tasks.Select(task => new TaskDetailForRecord
{
TaskId = task.Id,
TaskCode = task.WorkOrderCode ?? task.Code ?? $"TASK-{task.Id}",
ProjectNumber = task.ProjectNumber,
ProjectCategory = task.ProjectCategory,
ShiftId = task.ShiftId,
ShiftName = task.ShiftName,
ProcessId = task.ProcessId,
ProcessName = task.ProcessName,
WorkOrderDate = task.WorkOrderDate,
Priority = task.Priority,
Urgency = task.Urgency,
Complexity = task.Complexity,
EstimatedHours = task.EstimatedHours,
Status = task.Status,
AssignedPersonnelId = task.AssignedPersonnelId,
AssignedPersonnelName = task.AssignedPersonnelName ?? "",
AssignedEquipmentId = task.AssignedEquipmentId,
AssignedEquipmentName = task.AssignedEquipmentName ?? "",
WeightFactor = task.WeightFactor,
Remarks = task.Remarks ?? ""
}).ToList();
}
/// <summary>
/// 查询所有整合记录列表
/// 深度业务思考:提供完整的记录列表查询,支持筛选和排序
/// </summary>
/// <param name="input">查询条件</param>
/// <returns>整合记录列表</returns>
[HttpGet]
public async Task<List<IntegrationRecordListOutput>> GetIntegrationRecordsAsync(IntegrationRecordGetListInput input)
{
try
{
// 构建查询条件
var query = _integrationRecordRepository.Select;
// 批次编码筛选
if (!string.IsNullOrWhiteSpace(input.IntegrationBatchCode))
{
query = query.Where(r => r.IntegrationBatchCode.Contains(input.IntegrationBatchCode));
}
// 项目编号筛选
if (!string.IsNullOrWhiteSpace(input.ProjectNumber))
{
query = query.Where(r => r.ProjectNumbers.Contains(input.ProjectNumber));
}
// 操作员用户名筛选
if (!string.IsNullOrWhiteSpace(input.OperatorUserName))
{
query = query.Where(r => r.OperatorUserName.Contains(input.OperatorUserName));
}
// 操作员真实姓名筛选
if (!string.IsNullOrWhiteSpace(input.OperatorRealName))
{
query = query.Where(r => r.OperatorRealName.Contains(input.OperatorRealName));
}
// 时间范围筛选
if (input.StartDate.HasValue)
{
query = query.Where(r => r.IntegrationTime >= input.StartDate.Value);
}
if (input.EndDate.HasValue)
{
query = query.Where(r => r.IntegrationTime <= input.EndDate.Value.AddDays(1).AddSeconds(-1));
}
// 按创建时间降序排序(最新的在前面)
query = query.OrderByDescending(r => r.CreatedTime);
// 执行查询并转换为列表
var entities = await query.ToListAsync();
var result = entities.Select(ConvertToIntegrationRecordListOutput).ToList();
_logger.LogInformation("成功查询整合记录列表: Count={Count}", result.Count);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "查询整合记录列表失败: {Message}", ex.Message);
throw new IntegrationRecordException($"查询整合记录列表失败: {ex.Message}", ex);
}
}
#region
/// <summary>
/// 发布整合记录
/// 深度业务思考:执行完整的发布流程,包括验证、状态更新、任务发布和后处理
/// </summary>
[HttpPost]
public async Task<PublishIntegrationRecordResult> PublishIntegrationRecordAsync(PublishIntegrationRecordInput input)
{
var result = new PublishIntegrationRecordResult
{
IntegrationRecordId = input.IntegrationRecordId,
PublishedTime = DateTime.Now
};
try
{
// 第一步:获取整合记录并验证状态
var integrationRecord = await _integrationRecordRepository.GetAsync(input.IntegrationRecordId);
if (integrationRecord == null)
{
result.IsSuccess = false;
result.ErrorMessage = $"未找到ID为{input.IntegrationRecordId}的整合记录";
return result;
}
result.IntegrationBatchCode = integrationRecord.IntegrationBatchCode;
// 第二步:发布前验证
var validationResult = await ValidateBeforePublishAsync(integrationRecord, input);
result.ValidationResult = validationResult;
if (!validationResult.IsValid && !input.ForcePublish)
{
result.IsSuccess = false;
result.ErrorMessage = "发布前验证失败,存在阻塞性错误";
result.WarningMessages.AddRange(validationResult.BlockingErrors.Select(e => e.Message));
return result;
}
// 第三步:获取相关任务
var taskIds = integrationRecord.GetTaskIds();
if (!taskIds.Any())
{
result.IsSuccess = false;
result.ErrorMessage = "整合记录中没有关联的任务";
return result;
}
var taskEntities = await GetTaskEntitiesForRecordAsync(taskIds);
// 第四步:执行任务发布
var publishTasksResult = await ExecuteTaskPublishAsync(taskEntities, integrationRecord, input);
result.PublishedTasks = publishTasksResult.PublishedTasks;
result.FailedPublishTasks = publishTasksResult.FailedPublishTasks;
// 第五步:更新整合记录状态
await UpdateIntegrationRecordStatusInternalAsync(integrationRecord, "Published", input.PublishedByUserId, input.PublishedByUserName, input.PublishRemarks);
// 第六步:任务状态同步
result.TaskStatusSyncResult = await SynchronizeTaskStatusesAsync(taskEntities, integrationRecord);
// 第七步:发送通知(如果需要)
if (input.NotifyRelatedPersonnel)
{
result.NotificationResults = await SendPublishNotificationsAsync(integrationRecord, input);
}
// 第八步:生成统计信息
result.Statistics = GeneratePublishStatistics(result);
// 设置最终结果
result.IsSuccess = result.FailedPublishTasks.Count == 0;
result.SuccessMessage = result.IsSuccess ?
$"整合记录发布成功,共发布{result.PublishedTasks.Count}个任务" :
$"整合记录部分发布成功,{result.PublishedTasks.Count}个任务成功,{result.FailedPublishTasks.Count}个任务失败";
_logger.LogInformation("整合记录发布完成: RecordId={RecordId}, Success={IsSuccess}, PublishedCount={PublishedCount}",
input.IntegrationRecordId, result.IsSuccess, result.PublishedTasks.Count);
return result;
}
catch (Exception ex)
{
result.IsSuccess = false;
result.ErrorMessage = $"发布过程中发生异常: {ex.Message}";
_logger.LogError(ex, "整合记录发布失败: RecordId={RecordId}, Error={Message}", input.IntegrationRecordId, ex.Message);
return result;
}
}
/// <summary>
/// 更新整合记录状态
/// 深度业务思考:实现状态转换的完整业务逻辑,包括状态验证和审计
/// </summary>
[HttpPost]
public async Task<bool> UpdateIntegrationRecordStatusAsync(long recordId, string newStatus, long operatorUserId, string operatorName, string remarks = "")
{
try
{
var integrationRecord = await _integrationRecordRepository.GetAsync(recordId);
if (integrationRecord == null)
{
_logger.LogWarning("尝试更新不存在的整合记录状态: RecordId={RecordId}", recordId);
return false;
}
// 验证状态转换的合法性
if (!IsValidStatusTransition(integrationRecord.PublishStatus ?? "草稿", newStatus))
{
_logger.LogWarning("非法的状态转换: RecordId={RecordId}, From={OldStatus}, To={NewStatus}",
recordId, integrationRecord.PublishStatus, newStatus);
return false;
}
await UpdateIntegrationRecordStatusInternalAsync(integrationRecord, newStatus, operatorUserId, operatorName, remarks);
_logger.LogInformation("整合记录状态更新成功: RecordId={RecordId}, NewStatus={NewStatus}", recordId, newStatus);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "更新整合记录状态失败: RecordId={RecordId}, NewStatus={NewStatus}, Error={Message}",
recordId, newStatus, ex.Message);
return false;
}
}
/// <summary>
/// 发布修改后的任务
/// 深度业务思考:支持增量发布,只发布有变更的任务
/// </summary>
[HttpPost]
public async Task<PublishIntegrationRecordResult> PublishTaskModificationsAsync(long recordId, List<long> modifiedTaskIds, long operatorUserId, string operatorName, string publishRemarks = "")
{
var result = new PublishIntegrationRecordResult
{
IntegrationRecordId = recordId,
PublishedTime = DateTime.Now
};
try
{
// 获取整合记录
var integrationRecord = await _integrationRecordRepository.GetAsync(recordId);
if (integrationRecord == null)
{
result.IsSuccess = false;
result.ErrorMessage = $"未找到ID为{recordId}的整合记录";
return result;
}
result.IntegrationBatchCode = integrationRecord.IntegrationBatchCode;
// 获取修改的任务
var modifiedTasks = await GetTaskEntitiesForRecordAsync(modifiedTaskIds);
if (!modifiedTasks.Any())
{
result.IsSuccess = false;
result.ErrorMessage = "未找到需要发布的修改任务";
return result;
}
// 创建增量发布输入
var incrementalInput = new PublishIntegrationRecordInput
{
IntegrationRecordId = recordId,
PublishedByUserId = operatorUserId,
PublishedByUserName = operatorName,
PublishRemarks = publishRemarks ?? "增量任务修改发布",
ForcePublish = true, // 增量发布通常跳过完整验证
NotifyRelatedPersonnel = true
};
// 执行增量任务发布
var publishTasksResult = await ExecuteTaskPublishAsync(modifiedTasks, integrationRecord, incrementalInput);
result.PublishedTasks = publishTasksResult.PublishedTasks;
result.FailedPublishTasks = publishTasksResult.FailedPublishTasks;
// 更新记录备注
integrationRecord.Remarks = $"{integrationRecord.Remarks ?? ""}\n[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 增量发布{modifiedTaskIds.Count}个任务修改";
await _integrationRecordRepository.UpdateAsync(integrationRecord);
// 生成统计信息
result.Statistics = GeneratePublishStatistics(result);
result.IsSuccess = result.FailedPublishTasks.Count == 0;
result.SuccessMessage = result.IsSuccess ?
$"任务修改发布成功,共发布{result.PublishedTasks.Count}个任务" :
$"任务修改部分发布成功,{result.PublishedTasks.Count}个成功,{result.FailedPublishTasks.Count}个失败";
_logger.LogInformation("增量任务发布完成: RecordId={RecordId}, ModifiedTaskCount={TaskCount}, Success={IsSuccess}",
recordId, modifiedTaskIds.Count, result.IsSuccess);
return result;
}
catch (Exception ex)
{
result.IsSuccess = false;
result.ErrorMessage = $"发布任务修改时发生异常: {ex.Message}";
_logger.LogError(ex, "发布任务修改失败: RecordId={RecordId}, Error={Message}", recordId, ex.Message);
return result;
}
}
#endregion
#region
/// <summary>
/// 修改整合记录中的任务分配
/// 根据选中的人员修改任务的指定人员ID和姓名并更新整合记录
/// </summary>
[HttpPost]
public async Task<bool> ModifyIntegrationRecordTaskAsync(IntegrationRecordTaskModifyInput input)
{
try
{
_logger.LogInformation("开始修改整合记录任务: RecordId={RecordId}, ModificationsCount={Count}",
input.IntegrationRecordId, input.TaskModifications.Count);
// 获取整合记录
var integrationRecord = await _integrationRecordRepository.GetAsync(input.IntegrationRecordId);
if (integrationRecord == null)
{
_logger.LogWarning("未找到整合记录: RecordId={RecordId}", input.IntegrationRecordId);
return false;
}
// 获取需要修改的任务
var taskIds = input.TaskModifications.Select(m => m.TaskId).ToList();
var tasks = await _workOrderRepository.Select
.Where(t => taskIds.Contains(t.Id))
.ToListAsync();
if (!tasks.Any())
{
_logger.LogWarning("未找到需要修改的任务: RecordId={RecordId}", input.IntegrationRecordId);
return false;
}
// 执行任务修改
foreach (var modification in input.TaskModifications)
{
var task = tasks.FirstOrDefault(t => t.Id == modification.TaskId);
if (task == null) continue;
_logger.LogInformation("修改任务分配: TaskId={TaskId}, TaskCode={TaskCode}",
modification.TaskId, modification.TaskCode ?? "N/A");
// 修改人员分配
if (modification.NewPersonnelId.HasValue)
{
task.AssignedPersonnelId = modification.NewPersonnelId.Value;
task.AssignedPersonnelName = modification.NewPersonnelName ?? string.Empty;
_logger.LogInformation(" 更新人员分配: PersonnelId={PersonnelId}, PersonnelName={PersonnelName}",
modification.NewPersonnelId.Value, modification.NewPersonnelName ?? "N/A");
}
// 修改设备分配
if (modification.NewEquipmentId.HasValue)
{
task.AssignedEquipmentId = modification.NewEquipmentId.Value;
task.AssignedEquipmentName = modification.NewEquipmentName ?? string.Empty;
_logger.LogInformation(" 更新设备分配: EquipmentId={EquipmentId}, EquipmentName={EquipmentName}",
modification.NewEquipmentId.Value, modification.NewEquipmentName ?? "N/A");
}
// 更新任务备注
if (!string.IsNullOrWhiteSpace(modification.ModificationNote))
{
task.Remarks = string.IsNullOrWhiteSpace(task.Remarks)
? $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {modification.ModificationNote}"
: $"{task.Remarks}\n[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {modification.ModificationNote}";
}
task.ModifiedTime = DateTime.Now;
task.ModifiedUserId = input.OperatorUserId;
task.ModifiedUserName = input.OperatorUserName;
}
// 批量更新任务
await _workOrderRepository.UpdateAsync(tasks);
// 更新整合记录备注
if (!string.IsNullOrWhiteSpace(input.ModificationReason))
{
integrationRecord.Remarks = string.IsNullOrWhiteSpace(integrationRecord.Remarks)
? $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {input.ModificationReason}"
: $"{integrationRecord.Remarks}\n[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {input.ModificationReason}";
integrationRecord.ModifiedTime = DateTime.Now;
integrationRecord.ModifiedUserId = input.OperatorUserId;
integrationRecord.ModifiedUserName = input.OperatorUserName;
await _integrationRecordRepository.UpdateAsync(integrationRecord);
}
_logger.LogInformation("整合记录任务修改完成: RecordId={RecordId}, SuccessCount={Count}",
input.IntegrationRecordId, input.TaskModifications.Count);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "修改整合记录任务失败: RecordId={RecordId}, Error={Message}",
input.IntegrationRecordId, ex.Message);
return false;
}
}
#endregion
#region
/// <summary>
/// 发送发布通知(预留接口实现)
/// 深度业务思考:为未来的通知系统集成预留完整的接口结构
/// </summary>
[HttpPost]
public async Task<IntegrationNotificationResult> SendPublishNotificationAsync(long recordId, string notificationType, List<long> targetPersonnelIds, string customMessage = "")
{
// 预留实现:当前返回模拟结果,未来集成真实通知服务
var result = new IntegrationNotificationResult
{
NotificationType = notificationType,
IsSent = true, // 预留:假设发送成功
SentTime = DateTime.Now,
RecipientId = targetPersonnelIds.FirstOrDefault(),
RecipientName = "待集成通知服务", // 预留:需要从人员服务获取
FailureReason = ""
};
try
{
_logger.LogInformation("预留通知接口调用: RecordId={RecordId}, Type={NotificationType}, TargetCount={TargetCount}",
recordId, notificationType, targetPersonnelIds.Count);
// 预留:未来在此处集成实际的通知服务
// var notificationService = serviceProvider.GetService<INotificationService>();
// result = await notificationService.SendPublishNotificationAsync(...);
await Task.CompletedTask;
return result;
}
catch (Exception ex)
{
result.IsSent = false;
result.FailureReason = $"通知发送异常: {ex.Message}";
_logger.LogError(ex, "发送发布通知失败: RecordId={RecordId}, Error={Message}", recordId, ex.Message);
return result;
}
}
/// <summary>
/// 创建发布相关待办任务(预留接口实现)
/// 深度业务思考:为待办任务系统预留完整的集成接口
/// </summary>
[HttpPost]
public async Task<CreateTodoResult> CreatePublishRelatedTodoAsync(long recordId, string todoType, List<long> assigneeIds, string title, string description, DateTime? dueDate = null)
{
// 预留实现:当前返回模拟结果,未来集成真实待办服务
var result = new CreateTodoResult
{
IsSuccess = true, // 预留:假设创建成功
TodoType = todoType,
Title = title,
CreatedTime = DateTime.Now,
CreatedTodoCount = assigneeIds.Count,
DueDate = dueDate ?? DateTime.Now.AddDays(7),
ResultSummary = "待办任务创建成功(预留接口)"
};
// 模拟成功创建的待办ID
result.SuccessfulTodoIds = assigneeIds.Select(_ => (long)new Random().Next(10000, 99999)).ToList();
try
{
_logger.LogInformation("预留待办接口调用: RecordId={RecordId}, Type={TodoType}, AssigneeCount={AssigneeCount}",
recordId, todoType, assigneeIds.Count);
// 预留:未来在此处集成实际的待办任务服务
// var todoService = serviceProvider.GetService<ITodoTaskService>();
// result = await todoService.CreatePublishRelatedTodoAsync(...);
await Task.CompletedTask;
return result;
}
catch (Exception ex)
{
result.IsSuccess = false;
result.ErrorMessages.Add($"创建待办任务异常: {ex.Message}");
result.ResultSummary = "创建待办任务失败";
_logger.LogError(ex, "创建发布相关待办失败: RecordId={RecordId}, Error={Message}", recordId, ex.Message);
return result;
}
}
#endregion
#region
/// <summary>
/// 发布前验证
/// </summary>
private async Task<PublishValidationResult> ValidateBeforePublishAsync(IntegrationRecordEntity record, PublishIntegrationRecordInput input)
{
var result = new PublishValidationResult
{
ValidationTime = DateTime.Now,
IsValid = true
};
// 状态验证
if (!string.IsNullOrEmpty(record.PublishStatus) && record.PublishStatus != "Draft")
{
result.BlockingErrors.Add(new IntegrationValidationError
{
ErrorType = "状态错误",
Message = $"记录状态为'{record.PublishStatus}',无法发布",
RelatedFieldName = "PublishStatus"
});
result.IsValid = false;
}
// 任务数量验证
var taskIds = record.GetTaskIds();
if (!taskIds.Any())
{
result.BlockingErrors.Add(new IntegrationValidationError
{
ErrorType = "数据错误",
Message = "记录中没有关联的任务",
RelatedFieldName = "TaskIds"
});
result.IsValid = false;
}
// 其他业务验证...
await Task.CompletedTask;
result.ValidationDetails = $"验证完成,发现{result.BlockingErrors.Count}个阻塞性错误,{result.Warnings.Count}个警告";
return result;
}
/// <summary>
/// 执行任务发布
/// 业务思考:
/// 1. 批量处理任务发布,但每个任务独立处理避免相互影响
/// 2. 详细记录发布过程和结果,便于问题排查和审计
/// 3. 支持部分成功的发布场景,返回成功和失败的详细信息
/// 4. 在发布失败时提供具体的失败原因和建议
/// </summary>
private async Task<(List<PublishedTaskDetail> PublishedTasks, List<FailedPublishTaskDetail> FailedPublishTasks)> ExecuteTaskPublishAsync(
List<WorkOrderEntity> tasks,
IntegrationRecordEntity integrationRecord,
PublishIntegrationRecordInput input)
{
var publishedTasks = new List<PublishedTaskDetail>();
var failedTasks = new List<FailedPublishTaskDetail>();
_logger.LogInformation("开始执行任务批量发布: RecordId={RecordId}, TaskCount={Count}, AutoStart={AutoStart}",
integrationRecord.Id, tasks.Count, input.AutoStartTasksAfterPublish);
foreach (var task in tasks)
{
try
{
// 记录发布前状态
var previousStatus = (WorkOrderStatusEnum)task.Status;
var previousStatusName = previousStatus.ToString();
_logger.LogDebug("开始发布任务: TaskId={TaskId}, TaskCode={Code}, CurrentStatus={Status}",
task.Id, task.WorkOrderCode, previousStatusName);
// 执行任务发布逻辑
var publishSuccess = await PublishSingleTaskAsync(task, integrationRecord, input);
if (publishSuccess)
{
// 重新获取更新后的状态
var currentStatus = (WorkOrderStatusEnum)task.Status;
var currentStatusName = currentStatus.ToString();
publishedTasks.Add(new PublishedTaskDetail
{
TaskId = task.Id,
TaskCode = task.WorkOrderCode ?? $"TASK-{task.Id}",
AssignedPersonnelId = task.AssignedPersonnelId,
AssignedPersonnelName = task.AssignedPersonnelName ?? "",
AssignedEquipmentId = task.AssignedEquipmentId,
AssignedEquipmentName = task.AssignedEquipmentName ?? "",
PreviousStatus = previousStatusName,
CurrentStatus = currentStatusName,
PublishTime = DateTime.Now
});
_logger.LogInformation("任务发布成功: TaskId={TaskId}, StatusChange={Previous}->{Current}",
task.Id, previousStatusName, currentStatusName);
}
else
{
// 分析发布失败的具体原因
var failureReasons = new List<string>();
if (previousStatus != WorkOrderStatusEnum.PendingIntegration)
{
failureReasons.Add($"任务状态不正确,当前状态:{previousStatusName}期望状态PendingIntegration");
}
if (task.AssignedPersonnelId == null || task.AssignedPersonnelId <= 0)
{
failureReasons.Add("任务未分配人员");
}
if (string.IsNullOrEmpty(task.WorkOrderCode))
{
failureReasons.Add("任务编号为空");
}
failedTasks.Add(new FailedPublishTaskDetail
{
TaskId = task.Id,
TaskCode = task.WorkOrderCode ?? $"TASK-{task.Id}",
FailureReason = "任务发布失败",
DetailedErrors = failureReasons.Any() ? failureReasons : new List<string> { "发布过程中遇到未知问题" }
});
_logger.LogWarning("任务发布失败: TaskId={TaskId}, Reasons={Reasons}",
task.Id, string.Join("; ", failureReasons));
}
}
catch (Exception ex)
{
failedTasks.Add(new FailedPublishTaskDetail
{
TaskId = task.Id,
TaskCode = task.WorkOrderCode ?? $"TASK-{task.Id}",
FailureReason = "发布异常",
DetailedErrors = new List<string> { ex.Message, ex.StackTrace ?? "" }
});
_logger.LogError(ex, "任务发布异常: TaskId={TaskId}, TaskCode={Code}, Error={Message}",
task.Id, task.WorkOrderCode, ex.Message);
}
}
_logger.LogInformation("任务批量发布完成: RecordId={RecordId}, Success={Success}, Failed={Failed}",
integrationRecord.Id, publishedTasks.Count, failedTasks.Count);
return (publishedTasks, failedTasks);
}
/// <summary>
/// 发布单个任务
/// 深度业务思考:
/// 1. 验证任务状态转换的合法性只有PendingIntegration状态的任务可以发布
/// 2. 支持AutoStartTasksAfterPublish选项发布后可直接开始任务
/// 3. 完整的异常处理和日志记录
/// 4. 原子性操作确保数据一致性
/// </summary>
private async Task<bool> PublishSingleTaskAsync(WorkOrderEntity task, IntegrationRecordEntity integrationRecord, PublishIntegrationRecordInput input)
{
try
{
// 验证任务当前状态是否可以发布
var currentStatus = (WorkOrderStatusEnum)task.Status;
if (currentStatus != WorkOrderStatusEnum.PendingIntegration)
{
_logger.LogWarning("任务状态不允许发布: TaskId={TaskId}, CurrentStatus={Status}",
task.Id, currentStatus);
return false;
}
// 确定发布后的目标状态
WorkOrderStatusEnum targetStatus;
if (input.AutoStartTasksAfterPublish)
{
// 自动开始任务PendingIntegration -> Assigned -> InProgress
targetStatus = WorkOrderStatusEnum.InProgress;
_logger.LogInformation("任务将发布并自动开始: TaskId={TaskId}", task.Id);
}
else
{
// 常规发布PendingIntegration -> Assigned
targetStatus = WorkOrderStatusEnum.Assigned;
_logger.LogInformation("任务将发布为已分配状态: TaskId={TaskId}", task.Id);
}
// 更新任务状态和相关字段
task.Status = (int)targetStatus;
task.ModifiedTime = DateTime.Now;
task.ModifiedUserId = input.PublishedByUserId;
task.ModifiedUserName = input.PublishedByUserName;
// 如果是自动开始任务,设置开始时间
if (input.AutoStartTasksAfterPublish)
{
task.ActualStartTime = DateTime.Now;
}
// 设置发布时间(如果是定时发布)
if (input.ScheduledPublishTime.HasValue)
{
task.PlannedStartTime = input.ScheduledPublishTime.Value;
}
// 保存任务更新(原子操作)
await _workOrderRepository.UpdateAsync(task);
// 验证更新结果
var updatedTask = await _workOrderRepository.GetAsync(task.Id);
if (updatedTask == null || updatedTask.Status != (int)targetStatus)
{
_logger.LogError("任务状态更新验证失败: TaskId={TaskId}, ExpectedStatus={Expected}, ActualStatus={Actual}",
task.Id, targetStatus, updatedTask?.Status);
return false;
}
_logger.LogInformation("任务发布成功: TaskId={TaskId}, OldStatus={OldStatus}, NewStatus={NewStatus}",
task.Id, currentStatus, targetStatus);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "任务发布失败: TaskId={TaskId}, IntegrationRecordId={RecordId}, Error={Message}",
task.Id, integrationRecord.Id, ex.Message);
return false;
}
}
/// <summary>
/// 同步任务状态
/// </summary>
private async Task<TaskStatusSyncResult> SynchronizeTaskStatusesAsync(List<WorkOrderEntity> tasks, IntegrationRecordEntity integrationRecord)
{
var result = new TaskStatusSyncResult
{
SuccessfulSyncCount = tasks.Count,
FailedSyncCount = 0,
IsFullySuccessful = true,
SyncElapsedMilliseconds = 0
};
// 预留:未来可以在此处添加与外部系统的状态同步逻辑
await Task.CompletedTask;
return result;
}
/// <summary>
/// 发送发布通知
/// </summary>
private async Task<List<IntegrationNotificationResult>> SendPublishNotificationsAsync(IntegrationRecordEntity integrationRecord, PublishIntegrationRecordInput input)
{
var results = new List<IntegrationNotificationResult>();
// 预留:根据发布规则确定通知对象和内容
var targetPersonnelIds = new List<long>(); // 从业务规则中获取
if (targetPersonnelIds.Any())
{
var notificationResult = await SendPublishNotificationAsync(
integrationRecord.Id,
"发布通知",
targetPersonnelIds,
$"整合记录 {integrationRecord.IntegrationBatchCode} 已发布生效");
results.Add(notificationResult);
}
return results;
}
/// <summary>
/// 生成发布统计信息
/// </summary>
private PublishStatistics GeneratePublishStatistics(PublishIntegrationRecordResult result)
{
return new PublishStatistics
{
TotalTaskCount = result.PublishedTasks.Count + result.FailedPublishTasks.Count,
SuccessfulPublishCount = result.PublishedTasks.Count,
FailedPublishCount = result.FailedPublishTasks.Count,
PublishSuccessRate = result.PublishedTasks.Count + result.FailedPublishTasks.Count > 0 ?
(decimal)result.PublishedTasks.Count / (result.PublishedTasks.Count + result.FailedPublishTasks.Count) * 100 : 0,
InvolvedPersonnelCount = result.PublishedTasks.Select(t => t.AssignedPersonnelId).Where(id => id.HasValue).Distinct().Count(),
InvolvedEquipmentCount = result.PublishedTasks.Select(t => t.AssignedEquipmentId).Where(id => id.HasValue).Distinct().Count(),
TotalElapsedMilliseconds = 0 // 预留:记录实际执行时间
};
}
/// <summary>
/// 内部状态更新方法
/// </summary>
private async Task UpdateIntegrationRecordStatusInternalAsync(IntegrationRecordEntity integrationRecord, string newStatus, long operatorUserId, string operatorName, string remarks)
{
integrationRecord.PublishStatus = newStatus;
integrationRecord.PublishedTime = DateTime.Now;
integrationRecord.PublishedByUserId = operatorUserId;
integrationRecord.PublishedByUserName = operatorName;
if (!string.IsNullOrWhiteSpace(remarks))
{
integrationRecord.Remarks = $"{integrationRecord.Remarks ?? ""}\n[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {remarks}";
}
integrationRecord.ModifiedTime = DateTime.Now;
integrationRecord.ModifiedUserId = operatorUserId;
integrationRecord.ModifiedUserName = operatorName;
await _integrationRecordRepository.UpdateAsync(integrationRecord);
}
/// <summary>
/// 验证状态转换的合法性
/// </summary>
private bool IsValidStatusTransition(string currentStatus, string newStatus)
{
var validTransitions = new Dictionary<string, List<string>>
{
["草稿"] = new List<string> { "已发布", "已撤销" },
["已发布"] = new List<string> { "已完成", "已撤销" },
["已完成"] = new List<string> { "已归档" },
["已撤销"] = new List<string> { "草稿" }
};
return validTransitions.ContainsKey(currentStatus) && validTransitions[currentStatus].Contains(newStatus);
}
#endregion
/// <summary>
/// 转换为整合记录列表输出格式
/// </summary>
private IntegrationRecordListOutput ConvertToIntegrationRecordListOutput(IntegrationRecordEntity entity)
{
return new IntegrationRecordListOutput
{
Id = entity.Id,
IntegrationBatchCode = entity.IntegrationBatchCode,
IntegrationTime = entity.IntegrationTime,
ProjectNumbers = entity.ProjectNumbers ?? string.Empty,
OriginalTaskCount = entity.OriginalTaskCount,
SuccessTaskCount = entity.SuccessTaskCount,
FailedTaskCount = entity.FailedTaskCount,
ElapsedMilliseconds = entity.ElapsedMilliseconds,
PersonnelFairnessScore = entity.PersonnelFairnessScore,
EquipmentUtilizationRate = entity.EquipmentUtilizationRate,
OperatorUserId = entity.OperatorUserId,
OperatorUserName = entity.OperatorUserName ?? string.Empty,
OperatorRealName = entity.OperatorRealName ?? string.Empty,
Remarks = entity.Remarks ?? string.Empty,
PublishStatus = entity.PublishStatus ?? string.Empty,
CreatedTime = entity.CreatedTime ?? DateTime.Now
};
}
#region
/// <summary>
/// 整合记录异常类
/// </summary>
public class IntegrationRecordException : Exception
{
public IntegrationRecordException(string message) : base(message) { }
public IntegrationRecordException(string message, Exception innerException) : base(message, innerException) { }
}
#endregion
}
}