using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Integration
{
///
/// 智能整合记录实体
/// 用于记录每次智能任务整合的完整过程和结果
///
/// 业务思考:
/// 1. 作为重要的业务审计数据,需要完整记录整合的全过程
/// 2. 支持多租户模式,确保数据安全隔离
/// 3. 提供丰富的查询维度,支持历史分析和决策支持
/// 4. 考虑JSON存储复杂结果数据,平衡存储效率和查询性能
///
[Table(Name = "sse_integration_record")]
[Index("idx_integration_batch_code", "IntegrationBatchCode", true)] // 批次编码唯一索引
[Index("idx_integration_time", "IntegrationTime")] // 时间索引,支持时间范围查询
[Index("idx_operator", "OperatorUserId")] // 操作员索引
[Index("idx_tenant_time", "TenantId,IntegrationTime")] // 租户+时间组合索引
public class IntegrationRecordEntity : EntityTenant
{
///
/// 整合批次编码
/// 格式:INT + yyyyMMddHHmmss + XXX,如:INT20240314143025123
/// 业务意义:唯一标识一次整合操作,便于追踪和关联
///
[Column(StringLength = 30)]
[Required(ErrorMessage = "整合批次编码不能为空")]
public string IntegrationBatchCode { get; set; } = string.Empty;
///
/// 整合执行时间
/// 记录实际执行整合操作的时间点
///
[Required]
public DateTime IntegrationTime { get; set; } = DateTime.Now;
///
/// 操作人员用户ID
/// 关联到系统用户表,记录执行整合的操作员
///
[Required(ErrorMessage = "操作人员ID不能为空")]
public long OperatorUserId { get; set; }
///
/// 操作人员用户名
/// 冗余存储,提高查询性能,避免频繁关联用户表
///
[Column(StringLength = 50)]
[Required(ErrorMessage = "操作人员用户名不能为空")]
public string OperatorUserName { get; set; } = string.Empty;
///
/// 操作人员真实姓名
/// 用于业务场景下的可读性显示
///
[Column(StringLength = 50)]
[Required(ErrorMessage = "操作人员姓名不能为空")]
public string OperatorRealName { get; set; } = string.Empty;
///
/// 整合的任务ID列表(JSON格式存储)
/// 存储格式:[1,2,3,4,5]
/// 业务意义:记录本次整合涉及的所有任务,支持反向查询
///
[Column(DbType = "longtext")]
[Required(ErrorMessage = "任务ID列表不能为空")]
public string TaskIdsJson { get; set; } = "[]";
///
/// 整合策略配置(JSON格式存储)
/// 包含:人员分配策略、设备分配策略、各种配置参数
/// 业务价值:记录决策依据,支持策略效果分析和优化
///
[Column(DbType = "json")]
[Required]
public string StrategyConfigJson { get; set; } = "{}";
///
/// 人员分配结果详情(JSON格式存储)
/// 包含:成功匹配列表、失败原因、工作负载分析等
/// 存储完整的PersonnelAllocationResult对象
///
[Column(DbType = "json")]
public string PersonnelAllocationResultJson { get; set; } = "{}";
///
/// 设备分配结果详情(JSON格式存储)
/// 包含:成功匹配列表、失败原因、利用率分析等
/// 存储完整的EquipmentAllocationResult对象
///
[Column(DbType = "json")]
public string EquipmentAllocationResultJson { get; set; } = "{}";
///
/// 成功分配的任务数量
/// 统计字段,提高查询性能
///
[Required]
public int SuccessTaskCount { get; set; } = 0;
///
/// 分配失败的任务数量
/// 统计字段,用于成功率计算和分析
///
[Required]
public int FailedTaskCount { get; set; } = 0;
///
/// 整合执行总耗时(毫秒)
/// 性能监控指标,用于系统优化分析
///
[Required]
public long ElapsedMilliseconds { get; set; } = 0;
///
/// 人员分配公平性评分(0-100)
/// 业务指标,评估人员工作负载分配的公平程度
///
public int PersonnelFairnessScore { get; set; } = 0;
///
/// 设备整体利用率(百分比,保留1位小数)
/// 业务指标,评估设备资源利用效率
///
[Column(DbType = "decimal(5,1)")]
public decimal EquipmentUtilizationRate { get; set; } = 0.0m;
///
/// 整合结果摘要描述
/// 简洁的文本描述,便于快速了解整合结果
/// 示例:总任务数: 25, 成功: 23, 失败: 2, 成功率: 92%
///
[Column(StringLength = 500)]
public string ResultSummary { get; set; } = string.Empty;
///
/// 失败原因分类统计(JSON格式存储)
/// 格式:{"PersonnelAllocationFailed": 2, "EquipmentAllocationFailed": 1}
/// 业务价值:支持失败原因分析和系统改进
///
[Column(DbType = "json")]
public string FailureReasonStats { get; set; } = "{}";
///
/// 涉及的项目编号列表(逗号分隔)
/// 便于按项目查询整合历史,支持项目级别的数据分析
/// 示例:PRJ001,PRJ002,PRJ003
///
[Column(StringLength = 500)]
public string ProjectNumbers { get; set; } = string.Empty;
///
/// 整合类型
/// 标识整合的触发方式:Manual-手动触发, Scheduled-定时触发, Auto-自动触发
///
[Column(StringLength = 20)]
[Required]
public string IntegrationType { get; set; } = "Manual";
///
/// 业务备注信息
/// 操作员填写的备注,记录特殊情况或业务背景
///
[Column(StringLength = 1000)]
public string Remarks { get; set; } = string.Empty;
///
/// 是否为测试数据
/// 区分生产数据和测试数据,便于数据清理和分析
///
[Required]
public bool IsTestData { get; set; } = false;
///
/// 数据版本号
/// 支持数据结构演进和向后兼容
///
[Required]
public int DataVersion { get; set; } = 1;
///
/// 整合记录发布状态
/// 控制整合记录的生命周期管理
/// Draft-草稿, Published-已发布, Completed-已完成, Cancelled-已撤销
///
[Column(StringLength = 20)]
[Required]
public string PublishStatus { get; set; } = IntegrationRecordPublishStatus.Draft;
///
/// 发布时间
/// 记录正式发布生效的时间点
///
public DateTime? PublishedTime { get; set; }
///
/// 发布操作员用户ID
/// 记录执行发布操作的用户,可能与创建者不同
///
public long? PublishedByUserId { get; set; }
///
/// 发布操作员用户名
///
[Column(StringLength = 50)]
public string PublishedByUserName { get; set; } = string.Empty;
///
/// 发布操作员真实姓名
///
[Column(StringLength = 50)]
public string PublishedByRealName { get; set; } = string.Empty;
///
/// 发布说明
/// 记录发布时的业务说明或特殊情况备注
///
[Column(StringLength = 500)]
public string PublishRemarks { get; set; } = string.Empty;
///
/// 完成时间
/// 所有任务执行完毕的时间点
///
public DateTime? CompletedTime { get; set; }
///
/// 撤销时间
/// 记录被撤销的时间点
///
public DateTime? CancelledTime { get; set; }
///
/// 撤销操作员用户ID
///
public long? CancelledByUserId { get; set; }
///
/// 撤销操作员用户名
///
[Column(StringLength = 50)]
public string CancelledByUserName { get; set; } = string.Empty;
///
/// 撤销原因
/// 记录撤销的具体原因和说明
///
[Column(StringLength = 500)]
public string CancelReason { get; set; } = string.Empty;
#region 版本管理和变更追踪扩展字段
///
/// 当前版本号
/// 每次修改后自增,用于版本管理和冲突检测
///
[Required]
public int CurrentVersion { get; set; } = 1;
///
/// 父版本ID
/// 指向上一个版本的整合记录,构建版本链
/// null表示这是初始版本
///
public long? ParentVersionId { get; set; }
///
/// 根版本ID
/// 指向版本链的根节点,用于快速定位同一整合记录的所有版本
///
[Required]
public long RootVersionId { get; set; }
///
/// 版本创建原因
/// 记录为什么创建这个新版本:TaskModified-任务修改, ManualAdjustment-手动调整, SystemReallocation-系统重新分配
///
[Column(StringLength = 50)]
public string VersionReason { get; set; } = string.Empty;
///
/// 变更摘要
/// 简述本版本相对于上一版本的主要变更内容
///
[Column(StringLength = 1000)]
public string ChangeSummary { get; set; } = string.Empty;
///
/// 变更详情JSON
/// 存储详细的变更信息,包括变更类型、影响的任务、前后对比等
/// 格式:{"changedTasks": [...], "modifications": [...], "affectedPersonnel": [...]}
///
[Column(DbType = "json")]
public string ChangeDetailsJson { get; set; } = "{}";
///
/// 是否为活跃版本
/// true表示这是当前生效的版本,每个根版本只能有一个活跃版本
///
[Required]
public bool IsActiveVersion { get; set; } = true;
///
/// 变更触发源
/// 记录变更的触发来源:TaskChange-任务变更, UserModification-用户修改, SystemOptimization-系统优化
///
[Column(StringLength = 30)]
public string ChangeTriggerSource { get; set; } = "Initial";
///
/// 原始任务数量
/// 记录初始分配时的任务数量,用于对比分析
///
public int OriginalTaskCount { get; set; } = 0;
///
/// 变更影响评分
/// 0-100分,评估本次变更对整体分配方案的影响程度
///
public int ChangeImpactScore { get; set; } = 0;
///
/// 自动重新分配标志
/// 标记是否可以自动进行重新分配,还是需要人工干预
///
[Required]
public bool AllowAutoReallocation { get; set; } = true;
///
/// 上次检查变更时间
/// 用于变更检测和增量更新机制
///
public DateTime? LastChangeCheckTime { get; set; }
///
/// 快照数据JSON
/// 存储关键业务数据的快照,用于版本对比和回滚
/// 包含:任务分配快照、人员工作负载快照、设备利用率快照等
///
[Column(DbType = "json")]
public string SnapshotDataJson { get; set; } = "{}";
#endregion
#region 计算属性
///
/// 整合成功率(计算属性)
/// 返回成功率百分比,保留1位小数
///
[Navigate(nameof(SuccessTaskCount))]
public decimal SuccessRate
{
get
{
var totalTasks = SuccessTaskCount + FailedTaskCount;
return totalTasks > 0 ? Math.Round((decimal)SuccessTaskCount / totalTasks * 100, 1) : 0;
}
set { } // FreeSql需要set访问器,但这是计算属性,所以提供空实现
}
///
/// 任务总数(计算属性)
///
[Navigate(nameof(SuccessTaskCount))]
public int TotalTaskCount
{
get => SuccessTaskCount + FailedTaskCount;
set { } // FreeSql需要set访问器,但这是计算属性,所以提供空实现
}
///
/// 整体匹配成功率(计算属性)
///
public decimal OverallMatchSuccessRate => SuccessRate / 100;
///
/// 平均任务复杂度(计算属性)
///
public decimal AverageTaskComplexity => 2.5m; // 暂时使用固定值
///
/// 平均每任务耗时(计算属性)
/// 返回毫秒数,用于性能分析
///
[Navigate(nameof(ElapsedMilliseconds))]
public long AverageTimePerTask
{
get
{
var totalTasks = TotalTaskCount;
return totalTasks > 0 ? ElapsedMilliseconds / totalTasks : 0;
}
set { } // FreeSql需要set访问器,但这是计算属性,所以提供空实现
}
#endregion
#region 业务方法
///
/// 反序列化任务ID列表
/// 将JSON格式的TaskIdsJson转换为List<long>
///
public List GetTaskIds()
{
try
{
if (string.IsNullOrWhiteSpace(TaskIdsJson))
return new List();
// 优先尝试JSON反序列化
try
{
return System.Text.Json.JsonSerializer.Deserialize>(TaskIdsJson) ?? new List();
}
catch
{
// 兼容旧格式(逗号分隔)
return TaskIdsJson.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(p => p.Trim())
.Where(p => !string.IsNullOrEmpty(p))
.Select(long.Parse)
.ToList();
}
}
catch
{
return new List();
}
}
///
/// 设置任务ID列表
/// 将List<long>序列化为JSON存储
///
public void SetTaskIds(List taskIds)
{
TaskIdsJson = System.Text.Json.JsonSerializer.Serialize(taskIds ?? new List());
}
///
/// 获取项目编号列表
/// 将逗号分隔的项目编号字符串转换为列表
///
public List GetProjectNumbers()
{
if (string.IsNullOrWhiteSpace(ProjectNumbers))
return new List();
return ProjectNumbers.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(p => p.Trim())
.Where(p => !string.IsNullOrEmpty(p))
.ToList();
}
///
/// 设置项目编号列表
/// 将列表转换为逗号分隔的字符串存储
///
public void SetProjectNumbers(List projectNumbers)
{
if (projectNumbers == null || !projectNumbers.Any())
{
ProjectNumbers = string.Empty;
return;
}
ProjectNumbers = string.Join(",", projectNumbers.Where(p => !string.IsNullOrWhiteSpace(p)));
}
///
/// 更新统计信息
/// 根据分配结果更新各项统计字段
///
public void UpdateStatistics(int successCount, int failedCount, long elapsedMs, int fairnessScore, decimal utilizationRate)
{
SuccessTaskCount = successCount;
FailedTaskCount = failedCount;
ElapsedMilliseconds = elapsedMs;
PersonnelFairnessScore = fairnessScore;
EquipmentUtilizationRate = utilizationRate;
ResultSummary = $"总任务数: {TotalTaskCount}, 成功: {SuccessTaskCount}, 失败: {FailedTaskCount}, 成功率: {SuccessRate}%";
}
#region 版本管理业务方法
///
/// 创建新版本
/// 基于当前版本创建一个新的版本记录,用于变更追踪
///
/// 版本创建原因
/// 变更摘要
/// 操作员用户ID
/// 操作员姓名
/// 新版本的整合记录实体
public IntegrationRecordEntity CreateNewVersion(string reason, string changeSummary, long operatorUserId, string operatorName)
{
var newVersion = new IntegrationRecordEntity
{
// 继承基本信息
IntegrationBatchCode = this.IntegrationBatchCode,
TenantId = this.TenantId,
RootVersionId = this.RootVersionId == 0 ? this.Id : this.RootVersionId,
ParentVersionId = this.Id,
CurrentVersion = this.CurrentVersion + 1,
// 版本变更信息
VersionReason = reason,
ChangeSummary = changeSummary,
ChangeTriggerSource = reason,
IsActiveVersion = true, // 新版本为活跃版本
// 操作员信息
OperatorUserId = operatorUserId,
OperatorUserName = operatorName,
OperatorRealName = operatorName,
IntegrationTime = DateTime.Now,
// 继承配置信息
StrategyConfigJson = this.StrategyConfigJson,
IntegrationType = this.IntegrationType,
// 继承发布状态相关信息
PublishStatus = this.PublishStatus,
PublishedTime = this.PublishedTime,
PublishedByUserId = this.PublishedByUserId,
PublishedByUserName = this.PublishedByUserName,
PublishedByRealName = this.PublishedByRealName,
PublishRemarks = this.PublishRemarks,
// 初始化新版本的其他字段
TaskIdsJson = "[]",
PersonnelAllocationResultJson = "{}",
EquipmentAllocationResultJson = "{}",
FailureReasonStats = "{}",
ChangeDetailsJson = "{}",
SnapshotDataJson = "{}",
DataVersion = this.DataVersion,
AllowAutoReallocation = true,
LastChangeCheckTime = DateTime.Now
};
// 当前版本标记为非活跃
this.IsActiveVersion = false;
return newVersion;
}
///
/// 获取变更详情
/// 解析ChangeDetailsJson并返回结构化的变更详情
///
public IntegrationChangeDetails GetChangeDetails()
{
try
{
if (string.IsNullOrWhiteSpace(ChangeDetailsJson) || ChangeDetailsJson == "{}")
return new IntegrationChangeDetails();
return System.Text.Json.JsonSerializer.Deserialize(ChangeDetailsJson)
?? new IntegrationChangeDetails();
}
catch
{
return new IntegrationChangeDetails();
}
}
///
/// 设置变更详情
/// 将变更详情对象序列化为JSON存储
///
public void SetChangeDetails(IntegrationChangeDetails changeDetails)
{
ChangeDetailsJson = System.Text.Json.JsonSerializer.Serialize(changeDetails ?? new IntegrationChangeDetails());
}
///
/// 获取快照数据
/// 解析SnapshotDataJson并返回快照数据对象
///
public IntegrationSnapshot GetSnapshotData()
{
try
{
if (string.IsNullOrWhiteSpace(SnapshotDataJson) || SnapshotDataJson == "{}")
return new IntegrationSnapshot();
return System.Text.Json.JsonSerializer.Deserialize(SnapshotDataJson)
?? new IntegrationSnapshot();
}
catch
{
return new IntegrationSnapshot();
}
}
///
/// 设置快照数据
/// 将快照数据对象序列化为JSON存储
///
public void SetSnapshotData(IntegrationSnapshot snapshotData)
{
SnapshotDataJson = System.Text.Json.JsonSerializer.Serialize(snapshotData ?? new IntegrationSnapshot());
}
///
/// 计算变更影响评分
/// 基于变更的任务数量、人员影响、设备影响等计算影响评分
///
public int CalculateChangeImpactScore(IntegrationChangeDetails changeDetails)
{
if (changeDetails == null) return 0;
int score = 0;
int totalTasks = TotalTaskCount > 0 ? TotalTaskCount : 1;
// 基于变更任务比例计算基础分数 (40%)
var changedTaskRatio = (double)changeDetails.ChangedTaskIds.Count / totalTasks;
score += (int)(changedTaskRatio * 40);
// 基于人员变更数量计算分数 (30%)
var personnelChangeRatio = Math.Min(1.0, (double)changeDetails.AffectedPersonnelIds.Count / 10);
score += (int)(personnelChangeRatio * 30);
// 基于设备变更数量计算分数 (20%)
var equipmentChangeRatio = Math.Min(1.0, (double)changeDetails.AffectedEquipmentIds.Count / 10);
score += (int)(equipmentChangeRatio * 20);
// 基于变更类型的严重程度 (10%)
var severityScore = changeDetails.ChangeTypes.Contains("TaskTimeConflict") ? 10 :
changeDetails.ChangeTypes.Contains("PersonnelUnavailable") ? 8 :
changeDetails.ChangeTypes.Contains("EquipmentUnavailable") ? 6 : 2;
score += severityScore;
return Math.Min(100, Math.Max(0, score));
}
///
/// 检查是否需要重新分配
/// 基于变更影响评分和业务规则判断是否需要重新分配
///
public bool ShouldTriggerReallocation()
{
// 如果不允许自动重新分配,返回false
if (!AllowAutoReallocation) return false;
// 如果变更影响评分超过阈值,需要重新分配
if (ChangeImpactScore >= 30) return true;
// 如果有任务时间冲突,必须重新分配
var changeDetails = GetChangeDetails();
if (changeDetails.ChangeTypes.Contains("TaskTimeConflict")) return true;
// 如果有关键人员不可用,需要重新分配
if (changeDetails.ChangeTypes.Contains("PersonnelUnavailable")) return true;
return false;
}
#endregion
#endregion
}
///
/// 整合类型枚举
///
public static class IntegrationType
{
///
/// 手动触发
///
public const string Manual = "Manual";
///
/// 定时触发
///
public const string Scheduled = "Scheduled";
///
/// 自动触发
///
public const string Auto = "Auto";
}
///
/// 整合记录发布状态枚举
/// 定义整合记录的生命周期状态
///
public static class IntegrationRecordPublishStatus
{
///
/// 草稿状态 - 刚生成的整合记录,未正式生效
///
public const string Draft = "Draft";
///
/// 已发布状态 - 已发布生效,任务开始执行
///
public const string Published = "Published";
///
/// 已完成状态 - 所有任务执行完毕
///
public const string Completed = "Completed";
///
/// 已撤销状态 - 发布后被撤销
///
public const string Cancelled = "Cancelled";
}
}