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 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
{
///
/// 整合记录服务
///
[DynamicApi(Area = "app")]
public partial class IntegrationRecordService : BaseService, IIntegrationRecordService, IDynamicApi
{
private readonly IIntegrationRecordRepository _integrationRecordRepository;
private readonly WorkOrderRepository _workOrderRepository;
private readonly ILogger _logger;
public IntegrationRecordService(
IIntegrationRecordRepository integrationRecordRepository,
WorkOrderRepository workOrderRepository,
ILogger logger)
{
_integrationRecordRepository = integrationRecordRepository;
_workOrderRepository = workOrderRepository;
_logger = logger;
}
///
/// 生成整合记录核心方法
/// 深度业务思考:按照文档5.1-5.5步骤实现完整的记录生成流程
///
[HttpPost]
public async Task 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 整合记录数据准备
///
/// 生成唯一批次编码
/// 格式:INT + yyyyMMddHHmmss + XXX,总长度23字符,符合数据库30字符限制
/// 业务思考:确保编码唯一性和数据库兼容性,与编排服务保持一致
///
private async Task 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;
}
///
/// 获取任务实体数据
/// 包含关联数据的批量获取
///
private async Task> GetTaskEntitiesForRecordAsync(List taskIds)
{
return await _workOrderRepository.Select
.Where(w => taskIds.Contains(w.Id))
.IncludeMany(w => w.WorkOrderFLPersonnels)
.Include(w => w.ShiftEntity)
.Include(w => w.ProcessEntity)
.ToListAsync();
}
///
/// 提取项目编号
/// 去重并格式化处理
///
private List ExtractProjectNumbers(List tasks)
{
return tasks.Select(t => t.ProjectNumber)
.Where(pn => !string.IsNullOrEmpty(pn))
.Distinct()
.OrderBy(pn => pn)
.ToList();
}
#endregion
#region 5.2 分配结果序列化
///
/// 策略配置序列化
/// 深度业务思考:保存完整的策略配置以便后续分析和重现
///
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
});
}
///
/// 人员分配结果序列化
/// 包含详细的匹配信息和分析数据
///
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