using Hotline.FlowEngine.Definitions;
using Hotline.Orders;
using Hotline.Settings;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.FlowEngine;
using Hotline.Share.Enums.FlowEngine;
using Hotline.Share.Enums.Order;
using Hotline.Share.Enums.Settings;
using SqlSugar;
using XF.Domain.Entities;
using XF.Domain.Exceptions;
using XF.Domain.Extensions;
using XF.Domain.Repository;
namespace Hotline.FlowEngine.Workflows;
public partial class Workflow : CreationEntity
{
public string DefinitionId { get; set; }
///
/// 流程类型
///
public EFlowType FlowType { get; set; }
///
/// 审核结果
///
public EReviewResult ReviewResult { get; set; }
#region 业务模块(冗余)
public string? ModuleId { get; set; }
public string? ModuleName { get; set; }
public string? ModuleCode { get; set; }
#endregion
///
/// 流程标题
///
[SugarColumn(ColumnDataType = "varchar(2000)")]
public string Title { get; set; }
///
/// end节点办理完成时间
///
public DateTime? EndTime { get; set; }
///
/// 流程状态
///
public EWorkflowStatus Status { get; set; }
#region 实际办理信息(节点,部门,意见)
///
/// 实际办理节点code(会签状态此字段保存最外层会签发起节点code)
///
public string? ActualHandleStepCode { get; set; }
///
/// 实际办理节点名称(会签状态此字段保存最外层会签发起节点名称)
///
public string? ActualHandleStepName { get; set; }
///
/// 实际办理节点id
///
public string? ActualHandleStepId { get; set; }
///
/// 到达实际办理节点时间(stepBox创建时间)
///
public DateTime? ActualHandleStepCreateTime { get; set; }
///
/// 实际办理节点签收时间
///
public DateTime? ActualHandleStepAcceptTime { get; set; }
///
/// 实际办理时间
///
public DateTime? ActualHandleTime { get; set; }
///
/// 实际办理人id
///
public string? ActualHandlerId { get; set; }
///
/// 实际办理人名称
///
public string? ActualHandlerName { get; set; }
///
/// 实际办理部门名称
///
public string? ActualHandleOrgName { get; set; }
///
/// 实际办理部门编码
///
public string? ActualHandleOrgCode { get; set; }
///
/// 实际办理部门等级
///
public int? ActualHandleOrgLevel { get; set; }
///
/// 实际办理部门行政区划编码
///
public string? ActualHandleOrgAreaCode { get; set; }
///
/// 实际办理部门行政区划名称
///
public string? ActualHandleOrgAreaName { get; set; }
///
/// 实际办理意见(办理中...or 最终办理意见)
///
[SugarColumn(Length = 8000)]
public string ActualOpinion { get; set; } = "办理中...";
///
/// 真实办理人姓名(手动填写)
///
public string? RealHandlerName { get; set; }
///
/// 真实办理人电话(手动填写)
///
public string? RealHandlerPhone { get; set; }
///
/// 沟通方式(手动填写)
///
public ERealCommunicationMode? RealCommunicationMode { get; set; }
///
/// 沟通时间(手动填写)
///
public DateTime? RealCommunicationTime { get; set; }
///
/// 沟通地点(手动填写)
///
public string? RealCommunicationAddress { get; set; }
///
/// 已与市民沟通
///
public bool? RealIsContacted { get; set; }
///
/// 已与市民现场沟通
///
public bool? RealContactLocale { get; set; }
#endregion
#region 当前办理节点信息(指派时赋值)
public string? CurrentStepId { get; set; }
///
/// 当前办理节点code(非会签:当前被指派节点,会签:会签发起节点)
///
public string? CurrentStepCode { get; set; }
///
/// 当前节点名称
///
public string? CurrentStepName { get; set; }
///
/// 到达当前节点时间
///
public DateTime? CurrentStepCreateTime { get; set; }
///
/// 当前办理节点签收时间
///
public DateTime? CurrentStepAcceptTime { get; set; }
///
/// 当前办理时间
///
public DateTime? CurrentHandleTime { get; set; }
///
/// 当前办理人id
///
public string? CurrentHandlerId { get; set; }
///
/// 当前办理人名称
///
public string? CurrentHandlerName { get; set; }
///
/// 当前办理部门名称
///
public string? CurrentHandleOrgName { get; set; }
///
/// 当前办理部门编码
///
public string? CurrentHandleOrgId { get; set; }
///
/// 当前办理部门等级
///
public int? CurrentHandleOrgLevel { get; set; }
///
/// 当前办理部门行政区划编码
///
public string? CurrentHandleOrgAreaCode { get; set; }
///
/// 当前办理部门行政区划名称
///
public string? CurrentHandleOrgAreaName { get; set; }
#endregion
#region 会签
///
/// 会签类型
///
public ECounterSignType? CounterSignType { get; set; }
///
/// 当前会签办理节点Id,嵌套会签为最外层会签办理节点Id
///
public string? TopCountersignStepId { get; set; }
///
/// 流程是否处于会签中(实时)
///
public bool IsInCountersign { get; set; }
#endregion
// ///
// /// 办结时长(分钟)
// /// 办结时间-交办时间
// ///
// public double HandleDuration { get; set; }
//
// ///
// /// 办结工作日时长
// ///
// public double HandleDurationWorkday { get; set; }
///
/// 全流程时长(秒)
/// 归档时间-创建时间
///
public double AllDuration { get; set; }
///
/// 外部业务唯一标识
///
public string ExternalId { get; set; }
#region 当前办理对象
///
/// 办理人id
///
[SugarColumn(ColumnDataType = "json", IsJson = true)]
public List HandlerUsers { get; set; } = new();
///
/// 办理部门id
///
[SugarColumn(ColumnDataType = "json", IsJson = true)]
public List HandlerOrgs { get; set; } = new();
#endregion
#region 流经对象
///
/// 流经部门
///
[SugarColumn(ColumnDataType = "json", IsJson = true)]
public List FlowedOrgIds { get; set; } = new();
///
/// 流经办理人
///
[SugarColumn(ColumnDataType = "json", IsJson = true)]
public List FlowedUserIds { get; set; } = new();
#endregion
#region 会签实际办理对象
[SugarColumn(ColumnDataType = "json", IsJson = true)]
public List? CsActualHandleOrgIds { get; set; }
[SugarColumn(ColumnDataType = "json", IsJson = true)]
public List? CsActualHandleUserIds { get; set; }
#endregion
#region 一级部门
///
/// 一级部门code
///
public string? OrgLevelOneCode { get; set; }
///
/// 一级部门名称
///
public string? OrgLevelOneName { get; set; }
#endregion
#region 受理人(开启流程的话务员)
///
/// 受理人id
///
public string? AcceptorId { get; set; }
///
/// 受理人名称
///
public string? AcceptorName { get; set; }
///
/// 受理人工号
///
public string? AcceptorStaffNo { get; set; }
///
/// 受理人部门编码
///
public string? AcceptorOrgId { get; set; }
///
/// 受理人部门名称
///
public string? AcceptorOrgName { get; set; }
///
/// 受理人部门行政区划编码
///
public string? AcceptorOrgAreaCode { get; set; }
///
/// 受理人部门行政区划名称
///
public string? AcceptorOrgAreaName { get; set; }
#endregion
}
public partial class Workflow
{
[Navigate(NavigateType.OneToOne, nameof(DefinitionId))]
public WorkflowDefinition WorkflowDefinition { get; set; }
///
/// 补充信息
///
[Navigate(NavigateType.OneToMany, nameof(WorkflowSupplement.WorkflowId))]
public List Supplements { get; set; }
///
/// 会签
///
[Navigate(NavigateType.OneToMany, nameof(WorkflowCountersign.WorkflowId))]
public List Countersigns { get; set; }
///
/// 主节点,依据流转进度动态生成或删除
///
//[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToMany, nameof(WorkflowStep.WorkflowId))]
public List Steps { get; set; }
///
/// 流转记录
///
//[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToMany, nameof(WorkflowTrace.WorkflowId))]
public List Traces { get; set; } = new();
#region Method
///
/// 流程结束
///
public void Complete(WorkflowStep endStep, EReviewResult reviewResult = EReviewResult.Unknown)
{
//if (FlowType is EFlowType.Review && !reviewResult.HasValue)
// throw new UserFriendlyException("无审核结果");
Status = EWorkflowStatus.Completed;
EndTime = DateTime.Now;
if (FlowType is EFlowType.Review && ReviewResult is EReviewResult.Unknown)
ReviewResult = reviewResult;
ClearHandlers();
SetAllDuration();
UpdateActualOption();
}
public void Terminate(string opinion)
{
Status = EWorkflowStatus.Terminated;
EndTime = DateTime.Now;
ActualOpinion = opinion;
ClearHandlers();
}
///
/// 归档时为最终办理意见赋值
///
public void UpdateActualOption()
{
//if (FlowType is EFlowType.Review) return;
WorkflowStep? step;
if (Steps.Count == 2
&& Steps.Exists(d => d.StepType == EStepType.Start)
&& Steps.Exists(d => d.StepType == EStepType.End))
{
step = Steps.FirstOrDefault(d => d.StepType == EStepType.Start);
}
else
{
step = Steps.FirstOrDefault(d => d.Id == ActualHandleStepId);
}
if (step is null)
throw new UserFriendlyException($"未查询到对应实际办理子节点,workflowId: {Id}");
ActualOpinion = step.Opinion;
ActualHandleStepAcceptTime = step.AcceptTime;
}
/////
///// 更新workflow中实际办理节点数据(节点,时间,部门)
/////
//public void UpdateWorkflowActualHandleInfo(WorkflowStep currentStep,
// string actualHandlerId, string? actualHandlerName,
// string actualHandleOrgCode, string? actualHandleOrgName,
// string? actualHandleOrgAreaCode, string? actualHandleOrgAreaName,
// int currentHandlerOrgLevel)
//{
// /*
// a.会签中:记录顶级会签发起节点, 会签结束前不更新。会签结束后再发起会签才会记录下一次会签的顶级发起节点
// b.非会签中,记录当前节点
// */
// if (currentStep.IsInCountersign()) return;
// if (currentStep.StepType is EStepType.Summary or EStepType.End) return;
// ActualHandle(currentStep,
// actualHandlerId, actualHandlerName,
// actualHandleOrgCode, actualHandleOrgName,
// actualHandleOrgAreaCode, actualHandleOrgAreaName);
// //SetHandleDuration();
// //实际办理部门为一级部门时记录
// if (currentHandlerOrgLevel == 1)
// UpdateLevelOneOrg(actualHandleOrgCode, actualHandleOrgName);
//}
///
/// 指派、未办理时调用
///
public void UpdateActualStepWhenAssign(WorkflowStep nextStep, FlowStepHandler nextStepHandler)
{
ResetActualStep();
ActualHandleStepId = nextStep.Id;
ActualHandleStepCode = nextStep.Code;
ActualHandleStepName = nextStep.Name;
ActualHandleStepCreateTime = nextStep.CreationTime;
ActualHandlerId = nextStepHandler.UserId;
ActualHandlerName = nextStepHandler.Username;
ActualHandleOrgCode = nextStepHandler.OrgId;
ActualHandleOrgName = nextStepHandler.OrgName;
if (!string.IsNullOrEmpty(ActualHandleOrgCode))
ActualHandleOrgLevel = ActualHandleOrgCode.CalcOrgLevel();
//实际办理部门为一级部门时记录
if (ActualHandleOrgLevel.HasValue && ActualHandleOrgLevel == 1)
UpdateLevelOneOrg(ActualHandleOrgCode, ActualHandleOrgName);
}
///
/// 办理时调用
///
public void UpdateActualStepWhenHandle(
WorkflowStep step,
string? handleOrgAreaCode,
string? handleOrgAreaName,
int handlerOrgLevel)
{
ActualHandleStepAcceptTime = step.AcceptTime;
ActualHandleTime = step.HandleTime;
ActualHandleOrgAreaCode = handleOrgAreaCode;
ActualHandleOrgAreaName = handleOrgAreaName;
ActualHandleOrgLevel = handlerOrgLevel;
//坐席->派单存在不选办理对象的场景,所以要补赋值
ActualHandleStepId = step.Id;
ActualHandleStepCode = step.Code;
ActualHandleStepName = step.Name;
ActualHandleStepCreateTime = step.CreationTime;
ActualHandlerId = step.HandlerId;
ActualHandlerName = step.HandlerName;
ActualHandleOrgCode = step.HandlerOrgId;
ActualHandleOrgName = step.HandlerOrgName;
}
///
/// 指派、未办理时调用
///
public void UpdateCurrentStepWhenAssign(WorkflowStep nextStep, FlowStepHandler nextStepHandler)
{
ResetCurrentStep();
CurrentStepId = nextStep.Id;
CurrentStepCode = nextStep.Code;
CurrentStepName = nextStep.Name;
CurrentStepCreateTime = nextStep.CreationTime;
CurrentHandlerId = nextStepHandler.UserId;
CurrentHandlerName = nextStepHandler.Username;
CurrentHandleOrgId = nextStepHandler.OrgId;
CurrentHandleOrgName = nextStepHandler.OrgName;
if (!string.IsNullOrEmpty(CurrentHandleOrgId))
CurrentHandleOrgLevel = CurrentHandleOrgId.CalcOrgLevel();
// //实际办理部门为一级部门时记录
// if (CurrentHandleOrgLevel.HasValue && CurrentHandleOrgLevel == 1)
// UpdateLevelOneOrg(CurrentHandleOrgId, CurrentHandleOrgName);
}
public void UpdateCurrentStepAcceptTime(DateTime acceptTime) => CurrentStepAcceptTime = acceptTime;
public void UpdateActualStepAcceptTime(DateTime acceptTime) => ActualHandleStepAcceptTime = acceptTime;
///
/// 办理时调用
///
public void UpdateCurrentStepWhenHandle(
WorkflowStep step,
string? handleOrgAreaCode,
string? handleOrgAreaName,
int handlerOrgLevel)
{
//CurrentStepAcceptTime = step.AcceptTime;
CurrentHandleTime = step.HandleTime;
CurrentHandleOrgAreaCode = handleOrgAreaCode;
CurrentHandleOrgAreaName = handleOrgAreaName;
CurrentHandleOrgLevel ??= handlerOrgLevel;
//坐席->派单存在不选办理对象的场景,所以要补赋值
CurrentStepId = step.Id;
CurrentStepCode = step.Code;
CurrentStepName = step.Name;
CurrentStepCreateTime = step.CreationTime;
CurrentHandlerId = step.HandlerId;
CurrentHandlerName = step.HandlerName;
CurrentHandleOrgId = step.HandlerOrgId;
CurrentHandleOrgName = step.HandlerOrgName;
}
private void ResetActualStep()
{
ActualHandleStepCode = null;
ActualHandleStepName = null;
ActualHandleStepId = null;
ActualHandleStepCreateTime = null;
ActualHandleStepAcceptTime = null;
ActualHandleTime = null;
ActualHandlerId = null;
ActualHandlerName = null;
ActualHandleOrgCode = null;
ActualHandleOrgName = null;
ActualHandleOrgAreaCode = null;
ActualHandleOrgAreaName = null;
}
private void ResetCurrentStep()
{
CurrentStepId = null;
CurrentStepCode = null;
CurrentStepName = null;
CurrentStepCreateTime = null;
CurrentStepAcceptTime = null;
CurrentHandleTime = null;
CurrentHandlerId = null;
CurrentHandlerName = null;
CurrentHandleOrgId = null;
CurrentHandleOrgName = null;
CurrentHandleOrgLevel = null;
CurrentHandleOrgAreaCode = null;
CurrentHandleOrgAreaName = null;
}
///
/// 检查会签是否结束
///
public bool CheckIfCountersignOver()
{
return Countersigns.All(d => d.IsCompleted());
}
///
/// 开始会签
///
public void StartCountersign(string startCsStepId, ECounterSignType? counterSignType)
{
IsInCountersign = true;
TopCountersignStepId = startCsStepId;
CounterSignType = counterSignType;
}
///
/// 结束流程会签状态(保留topStepId创建节点时判断用,直到下次会签开启时更新)
///
public void EndCountersign() => IsInCountersign = false;
///
/// 重置最终办理意见
///
public void ResetOption() => ActualOpinion = "办理中...";
///
/// 状态设置为可流转
///
public void SetStatusRunnable() => Status = EWorkflowStatus.Runnable;
///
/// 重新设置办理人(删除当前待办人/部门),撤回/跳转场景,因当前办理人不是流程指定办理人
///
///
///
public void ResetHandlers(EFlowAssignType assignType, List handlerObjects)
{
ClearHandlers();
SetHandlers(assignType, handlerObjects);
}
///
/// 清除办理对象
///
public void ClearHandlers()
{
HandlerOrgs = new List();
HandlerUsers = new List();
}
///
/// 更新当前办理人(待办人或部门),正常流转场景
///
public void UpdateHandlers(string handlerId, string handlerOrg, EFlowAssignType assignType,
List handlerObjects, bool isCreateNewStep)
{
RemoveCurrentHandleGroup(handlerId, handlerOrg);
if (isCreateNewStep)
SetHandlers(assignType, handlerObjects);
}
public void UpdateHandlers(List handlers, EFlowAssignType assignType, List handlerObjects)
{
foreach (var handler in handlers)
{
var orgItem = HandlerOrgs.FirstOrDefault(d => d.Key == handler);
if (orgItem != null)
{
HandlerOrgs.RemoveAll(d => d.GroupId == orgItem.GroupId);
}
var userItem = HandlerUsers.FirstOrDefault(d => d.Key == handler);
if (userItem != null)
{
HandlerUsers.RemoveAll(d => d.GroupId == userItem.GroupId);
}
}
SetHandlers(assignType, handlerObjects);
}
private void SetHandlers(EFlowAssignType assignType, List handlerObjects)
{
switch (assignType)
{
case EFlowAssignType.Org:
HandlerOrgs.AddRange(handlerObjects);
HandlerOrgs = HandlerOrgs.Distinct().ToList();
break;
case EFlowAssignType.User:
case EFlowAssignType.Role:
HandlerUsers.AddRange(handlerObjects);
HandlerUsers = HandlerUsers.Distinct().ToList();
break;
default:
throw new ArgumentOutOfRangeException(nameof(assignType), assignType, null);
}
}
///
/// 更新当前办理人(逐级退回场景)
///
///
///
///
public void UpdatePreviousHandlers(string handlerId, string handlerOrg, WorkflowStep prevStep)
{
RemoveCurrentHandleGroup(handlerId, handlerOrg);
var groupId = Guid.NewGuid().ToString();
var handlerObjects = new HandlerGroupItem
{
GroupId = groupId,
Key = prevStep.HandlerId,
Value = prevStep.HandlerName
};
HandlerUsers.Add(handlerObjects);
HandlerUsers = HandlerUsers.Distinct().ToList();
//switch (prevStep.HandlerType)
//{
// case EHandlerType.OrgLevel:
// case EHandlerType.OrgType:
// case EHandlerType.AssignedOrg:
// HandlerOrgs.AddRange(handlerObjects);
// HandlerOrgs = HandlerOrgs.Distinct().ToList();
// break;
// case EHandlerType.Role:
// case EHandlerType.AssignedUser:
// HandlerUsers.AddRange(handlerObjects);
// HandlerUsers = HandlerUsers.Distinct().ToList();
// break;
// default:
// throw new ArgumentOutOfRangeException();
//}
}
///
/// 当前用户是否可以办理该流程
///
///
public bool IsCanHandle(string userId, string orgId, string[] roleIds)
{
if (Steps is null || !Steps.Any())
throw new UserFriendlyException("未查询节点信息");
return Status is EWorkflowStatus.Runnable &&
//(HandlerUsers.Any(d => d.Key == userId) || HandlerOrgs.Any(d => d.Key == orgCode));
Steps.Any(d => d.IsCanHandle(userId, orgId, roleIds));
}
private void RemoveCurrentHandleGroup(string handlerId, string handlerOrg)
{
if (string.IsNullOrEmpty(handlerId) && string.IsNullOrEmpty(handlerOrg))
throw new UserFriendlyException($"{nameof(RemoveCurrentHandleGroup)}, 办理对象参数为空");
var orgItem = HandlerOrgs.FirstOrDefault(d => d.Key == handlerOrg);
if (orgItem != null)
{
HandlerOrgs.RemoveAll(d => d.GroupId == orgItem.GroupId);
}
var userItem = HandlerUsers.FirstOrDefault(d => d.Key == handlerId);
if (userItem != null)
{
HandlerUsers.RemoveAll(d => d.GroupId == userItem.GroupId);
}
}
public void Assign(EFlowAssignType type, string handler)
{
handler = handler.ToLower();
switch (type)
{
case EFlowAssignType.Org:
var orgCodes = handler.GetHigherOrgCodes(true).ToList();
FlowedOrgIds.AddRange(orgCodes);
FlowedOrgIds = FlowedOrgIds.Distinct().ToList();
break;
case EFlowAssignType.User:
case EFlowAssignType.Role:
if (!FlowedUserIds.Exists(d => d == handler))
FlowedUserIds.Add(handler);
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
}
public void Assign(EFlowAssignType type, IEnumerable handlers)
{
if (!handlers.Any()) return;
FlowedUserIds ??= new();
FlowedOrgIds ??= new();
handlers = handlers.Select(d => d.ToLower());
switch (type)
{
case EFlowAssignType.Org:
var orgCodes = handlers.SelectMany(d => d.GetHigherOrgCodes(true)).ToList();
FlowedOrgIds.AddRange(orgCodes);
FlowedOrgIds = FlowedOrgIds.Distinct().ToList();
break;
case EFlowAssignType.User:
case EFlowAssignType.Role:
FlowedUserIds.AddRange(handlers);
FlowedUserIds = FlowedUserIds.Distinct().ToList();
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
}
///
/// 更新受理人信息
///
public void UpdateAcceptor(string userId, string? userName, string? staffNo, string orgId, string? orgName)
{
AcceptorId = userId;
AcceptorName = userName;
AcceptorStaffNo = staffNo;
AcceptorOrgId = orgId;
AcceptorOrgName = orgName;
}
///
/// 更新一级部门信息(实际办理部门为一级部门时记录)
///
public void UpdateLevelOneOrg(string orgId, string? orgName)
{
OrgLevelOneCode = orgId;
OrgLevelOneName = orgName;
}
// public void CenterToOrg(DateTime expiredTime)
// {
// ProcessType = EProcessType.Jiaoban;
// ExpiredTime = expiredTime;
// CenterToOrgTime = DateTime.Now;
// }
//
// public void OrgToCenter(DateTime expiredTime)
// {
// ProcessType = EProcessType.Zhiban;
// ExpiredTime = expiredTime;
// CenterToOrgTime = null;
// }
public void Redo()
{
ResetOption();
Status = EWorkflowStatus.Runnable;
}
public void SetAllDuration()
{
if (!EndTime.HasValue)
throw new ArgumentNullException($"{EndTime} is null");
AllDuration = Math.Round((EndTime - CreationTime).Value.TotalSeconds);
}
public bool IsReviewPass() => FlowType == EFlowType.Review && ReviewResult == EReviewResult.Approval;
public bool IsReviewType() => FlowType == EFlowType.Review;
///
/// 查询实际办理节点
///
///
public WorkflowStep? GetActualStep() => Steps.FirstOrDefault(d => d.Id == ActualHandleStepId);
public void AddCsActualHandler(string userId, string orgId)
{
CsActualHandleUserIds ??= new();
if (CsActualHandleUserIds.All(d => d != userId))
CsActualHandleUserIds.Add(userId);
CsActualHandleOrgIds ??= new();
if (CsActualHandleOrgIds.All(d => d != orgId))
CsActualHandleOrgIds.Add(orgId);
}
public bool IsTopCountersignEndStep(WorkflowStep step)
{
if (string.IsNullOrEmpty(TopCountersignStepId))
throw new UserFriendlyException("该流程当前未开启会签");
return step.IsCountersignEndStep && step.CountersignStartStepId == TopCountersignStepId;
}
#endregion
}