using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Integration
{
///
/// 任务变更事件实体
/// 记录任务变更事件,用于变更感知和自动触发机制
///
/// 业务思考:
/// 1. 事件驱动架构:基于事件的变更检测和处理机制
/// 2. 变更溯源:完整记录变更的前因后果和处理过程
/// 3. 批量处理:支持批量变更事件的聚合处理
/// 4. 性能优化:通过事件队列机制避免实时处理对系统性能的影响
///
[Table(Name = "sse_task_change_event")]
[Index("idx_task_id", "TaskId")] // 任务ID索引
[Index("idx_integration_record", "IntegrationRecordId")] // 整合记录索引
[Index("idx_event_time", "EventTime")] // 事件时间索引
[Index("idx_processing_status", "ProcessingStatus")] // 处理状态索引
[Index("idx_tenant_time", "TenantId,EventTime")] // 租户+时间组合索引
public class TaskChangeEventEntity : EntityTenant
{
///
/// 任务ID
/// 发生变更的任务ID
///
[Required]
public long TaskId { get; set; }
///
/// 任务代码
/// 冗余存储,提高查询性能
///
[Column(StringLength = 50)]
[Required]
public string TaskCode { get; set; } = string.Empty;
///
/// 关联的整合记录ID
/// 指向受影响的整合记录
///
public long? IntegrationRecordId { get; set; }
///
/// 根版本整合记录ID
/// 指向版本链的根节点,用于快速定位整个版本链
///
public long? RootIntegrationRecordId { get; set; }
///
/// 事件类型
/// TaskModified, TaskDeleted, TaskStatusChanged, TaskPriorityChanged,
/// TaskTimeChanged, TaskPersonnelChanged, TaskEquipmentChanged, TaskCompleted
///
[Column(StringLength = 50)]
[Required]
public string EventType { get; set; } = string.Empty;
///
/// 变更字段名称
/// 具体发生变更的字段名,多个字段用逗号分隔
///
[Column(StringLength = 200)]
public string ChangedFields { get; set; } = string.Empty;
///
/// 变更前的值(JSON格式)
/// 存储变更前的字段值快照
///
[Column(DbType = "json")]
public string BeforeValueJson { get; set; } = "{}";
///
/// 变更后的值(JSON格式)
/// 存储变更后的字段值快照
///
[Column(DbType = "json")]
public string AfterValueJson { get; set; } = "{}";
///
/// 事件发生时间
/// 任务实际发生变更的时间
///
[Required]
public DateTime EventTime { get; set; } = DateTime.Now;
///
/// 变更触发用户ID
/// 执行变更操作的用户ID
///
public long? TriggeredByUserId { get; set; }
///
/// 变更触发用户名
///
[Column(StringLength = 50)]
public string TriggeredByUserName { get; set; } = string.Empty;
///
/// 变更触发用户真实姓名
///
[Column(StringLength = 50)]
public string TriggeredByRealName { get; set; } = string.Empty;
///
/// 事件来源
/// Manual-手动操作, System-系统自动, Import-数据导入, API-API调用, Sync-同步操作
///
[Column(StringLength = 20)]
[Required]
public string EventSource { get; set; } = "Manual";
///
/// 事件优先级
/// 1-9,9为最高优先级,影响处理顺序
///
[Required]
public int EventPriority { get; set; } = 5;
///
/// 影响评估评分
/// 0-100分,评估该变更对整合记录的潜在影响
///
public int ImpactAssessmentScore { get; set; } = 0;
///
/// 处理状态
/// Pending-待处理, Processing-处理中, Completed-已完成, Failed-处理失败, Ignored-已忽略
///
[Column(StringLength = 20)]
[Required]
public string ProcessingStatus { get; set; } = "Pending";
///
/// 处理开始时间
///
public DateTime? ProcessingStartTime { get; set; }
///
/// 处理完成时间
///
public DateTime? ProcessingCompletedTime { get; set; }
///
/// 处理人员用户ID
/// 实际处理该事件的用户ID
///
public long? ProcessedByUserId { get; set; }
///
/// 处理人员用户名
///
[Column(StringLength = 50)]
public string ProcessedByUserName { get; set; } = string.Empty;
///
/// 处理结果摘要
/// 简述处理结果和采取的行动
///
[Column(StringLength = 500)]
public string ProcessingResultSummary { get; set; } = string.Empty;
///
/// 处理详情JSON
/// 存储详细的处理过程和结果信息
///
[Column(DbType = "json")]
public string ProcessingDetailsJson { get; set; } = "{}";
///
/// 是否触发了重新分配
///
[Required]
public bool TriggeredReallocation { get; set; } = false;
///
/// 创建的新版本ID
/// 如果该事件导致创建了新版本
///
public long? CreatedNewVersionId { get; set; }
///
/// 事件分组ID
/// 用于将相关的多个事件分组处理,如批量修改
///
public long? EventGroupId { get; set; }
///
/// 事件分组序号
/// 在同一分组内的事件序号
///
public int EventGroupSequence { get; set; } = 1;
///
/// 是否需要通知
/// 标记该事件是否需要发送通知给相关人员
///
[Required]
public bool RequiresNotification { get; set; } = true;
///
/// 通知状态
/// NotSent-未发送, Sent-已发送, Failed-发送失败, NotRequired-无需发送
///
[Column(StringLength = 20)]
[Required]
public string NotificationStatus { get; set; } = "NotSent";
///
/// 通知发送时间
///
public DateTime? NotificationSentTime { get; set; }
///
/// 重试次数
/// 处理失败后的重试次数
///
[Required]
public int RetryCount { get; set; } = 0;
///
/// 最大重试次数
///
[Required]
public int MaxRetryCount { get; set; } = 3;
///
/// 下次重试时间
///
public DateTime? NextRetryTime { get; set; }
///
/// 错误信息
/// 记录处理过程中的错误信息
///
[Column(StringLength = 1000)]
public string ErrorMessage { get; set; } = string.Empty;
///
/// 事件标签
/// 用于事件分类和筛选,多个标签用逗号分隔
///
[Column(StringLength = 200)]
public string EventTags { get; set; } = string.Empty;
///
/// 业务备注
///
[Column(StringLength = 500)]
public string Remarks { get; set; } = string.Empty;
///
/// 是否为测试事件
///
[Required]
public bool IsTestEvent { get; set; } = false;
///
/// 数据版本
///
[Required]
public int DataVersion { get; set; } = 1;
#region 计算属性
///
/// 处理耗时(毫秒)
///
[Navigate(nameof(ProcessingStartTime))]
public long ProcessingElapsedMilliseconds
{
get
{
if (ProcessingStartTime.HasValue && ProcessingCompletedTime.HasValue)
{
return (long)(ProcessingCompletedTime.Value - ProcessingStartTime.Value).TotalMilliseconds;
}
return 0;
}
set { } // FreeSql需要set访问器,但这是计算属性,所以提供空实现
}
///
/// 事件年龄(自事件发生到现在的分钟数)
///
[Navigate(nameof(EventTime))]
public int EventAgeMinutes
{
get
{
return (int)(DateTime.Now - EventTime).TotalMinutes;
}
set { } // FreeSql需要set访问器,但这是计算属性,所以提供空实现
}
///
/// 是否超时
/// 判断事件是否长时间未处理
///
[Navigate(nameof(EventTime))]
public bool IsOverdue
{
get
{
if (ProcessingStatus == "Completed" || ProcessingStatus == "Ignored")
return false;
var timeoutMinutes = EventPriority >= 8 ? 30 : EventPriority >= 5 ? 120 : 480; // 高优先级30分钟,中等2小时,低优先级8小时
return EventAgeMinutes > timeoutMinutes;
}
set { } // FreeSql需要set访问器,但这是计算属性,所以提供空实现
}
#endregion
#region 业务方法
///
/// 获取变更前的值
/// 将JSON反序列化为字典
///
public Dictionary GetBeforeValues()
{
try
{
if (string.IsNullOrWhiteSpace(BeforeValueJson) || BeforeValueJson == "{}")
return new Dictionary();
return System.Text.Json.JsonSerializer.Deserialize>(BeforeValueJson)
?? new Dictionary();
}
catch
{
return new Dictionary();
}
}
///
/// 获取变更后的值
/// 将JSON反序列化为字典
///
public Dictionary GetAfterValues()
{
try
{
if (string.IsNullOrWhiteSpace(AfterValueJson) || AfterValueJson == "{}")
return new Dictionary();
return System.Text.Json.JsonSerializer.Deserialize>(AfterValueJson)
?? new Dictionary();
}
catch
{
return new Dictionary();
}
}
///
/// 设置变更前的值
///
public void SetBeforeValues(Dictionary values)
{
BeforeValueJson = System.Text.Json.JsonSerializer.Serialize(values ?? new Dictionary());
}
///
/// 设置变更后的值
///
public void SetAfterValues(Dictionary values)
{
AfterValueJson = System.Text.Json.JsonSerializer.Serialize(values ?? new Dictionary());
}
///
/// 获取处理详情
///
public Dictionary GetProcessingDetails()
{
try
{
if (string.IsNullOrWhiteSpace(ProcessingDetailsJson) || ProcessingDetailsJson == "{}")
return new Dictionary();
return System.Text.Json.JsonSerializer.Deserialize>(ProcessingDetailsJson)
?? new Dictionary();
}
catch
{
return new Dictionary();
}
}
///
/// 设置处理详情
///
public void SetProcessingDetails(Dictionary details)
{
ProcessingDetailsJson = System.Text.Json.JsonSerializer.Serialize(details ?? new Dictionary());
}
///
/// 开始处理事件
/// 设置处理开始时间和状态
///
public void StartProcessing(long processedByUserId, string processedByUserName)
{
ProcessingStatus = "Processing";
ProcessingStartTime = DateTime.Now;
ProcessedByUserId = processedByUserId;
ProcessedByUserName = processedByUserName;
}
///
/// 完成处理事件
/// 设置处理完成时间和状态
///
public void CompleteProcessing(string resultSummary, bool triggeredReallocation = false, long? createdVersionId = null)
{
ProcessingStatus = "Completed";
ProcessingCompletedTime = DateTime.Now;
ProcessingResultSummary = resultSummary;
TriggeredReallocation = triggeredReallocation;
CreatedNewVersionId = createdVersionId;
}
///
/// 处理失败
/// 设置失败状态和错误信息
///
public void FailProcessing(string errorMessage)
{
ProcessingStatus = "Failed";
ProcessingCompletedTime = DateTime.Now;
ErrorMessage = errorMessage;
RetryCount++;
// 计算下次重试时间(指数退避)
if (RetryCount <= MaxRetryCount)
{
var delayMinutes = Math.Pow(2, RetryCount) * 5; // 5, 10, 20 分钟
NextRetryTime = DateTime.Now.AddMinutes(delayMinutes);
ProcessingStatus = "Pending"; // 重置为待处理状态以便重试
}
}
///
/// 忽略事件
/// 设置忽略状态,不再处理
///
public void IgnoreEvent(string reason)
{
ProcessingStatus = "Ignored";
ProcessingCompletedTime = DateTime.Now;
ProcessingResultSummary = $"事件已忽略: {reason}";
}
///
/// 判断是否可以重试
///
public bool CanRetry()
{
return ProcessingStatus == "Pending" &&
RetryCount < MaxRetryCount &&
(!NextRetryTime.HasValue || NextRetryTime.Value <= DateTime.Now);
}
///
/// 计算影响评估评分
/// 基于变更类型、字段和业务规则计算影响评分
///
public int CalculateImpactScore()
{
int score = 0;
// 基于事件类型的基础分数
score += EventType switch
{
"TaskDeleted" => 90,
"TaskStatusChanged" => 80,
"TaskTimeChanged" => 70,
"TaskPriorityChanged" => 60,
"TaskPersonnelChanged" => 75,
"TaskEquipmentChanged" => 75,
"TaskModified" => 50,
"TaskCompleted" => 30,
_ => 20
};
// 基于变更字段的影响调整
if (ChangedFields.Contains("WorkOrderDate")) score += 20;
if (ChangedFields.Contains("ShiftId")) score += 15;
if (ChangedFields.Contains("Priority")) score += 10;
if (ChangedFields.Contains("AssignedPersonnelId")) score += 15;
if (ChangedFields.Contains("AssignedEquipmentId")) score += 15;
if (ChangedFields.Contains("Status")) score += 25;
// 基于事件优先级调整
score += EventPriority * 2;
return Math.Min(100, Math.Max(0, score));
}
#endregion
}
///
/// 事件处理状态枚举
///
public static class TaskChangeEventProcessingStatus
{
///
/// 待处理
///
public const string Pending = "Pending";
///
/// 处理中
///
public const string Processing = "Processing";
///
/// 已完成
///
public const string Completed = "Completed";
///
/// 处理失败
///
public const string Failed = "Failed";
///
/// 已忽略
///
public const string Ignored = "Ignored";
}
///
/// 事件类型枚举
///
public static class TaskChangeEventType
{
///
/// 任务修改
///
public const string TaskModified = "TaskModified";
///
/// 任务删除
///
public const string TaskDeleted = "TaskDeleted";
///
/// 任务状态变更
///
public const string TaskStatusChanged = "TaskStatusChanged";
///
/// 任务优先级变更
///
public const string TaskPriorityChanged = "TaskPriorityChanged";
///
/// 任务时间变更
///
public const string TaskTimeChanged = "TaskTimeChanged";
///
/// 任务人员变更
///
public const string TaskPersonnelChanged = "TaskPersonnelChanged";
///
/// 任务设备变更
///
public const string TaskEquipmentChanged = "TaskEquipmentChanged";
///
/// 任务完成
///
public const string TaskCompleted = "TaskCompleted";
}
}