using Hotline.File;
using Hotline.Share.Dtos;
using Hotline.Share.Dtos.FlowEngine.Definition;
using Hotline.Share.Dtos.FlowEngine.Workflow;
using Hotline.Share.Enums.FlowEngine;
using SqlSugar;
using XF.Domain.Exceptions;
namespace Hotline.FlowEngine.Workflows;
public class WorkflowStep : StepBasicEntity
{
///
/// 配置下一步节点 & 谁被选中
///
[SugarColumn(ColumnDataType = "json", IsJson = true)]
public List NextSteps { get; set; } = new();
///
/// 前一级节点Id,会签汇总节点无此字段(因可能有多个上级来源)
///
public string? PrevStepId { get; set; }
public string? PrevStepCode { get; set; }
///
/// 主办
///
public bool IsMain { get; set; }
///
/// 原生节点(区别动态生成)
///
public bool IsOrigin { get; set; }
#region 会签
///
/// 会签id(或外层会签的id)
///
public string? CountersignId { get; set; }
///
/// 节点处于会签流程中的位置(区别直接办理会签和会签内非会签节点)
/// outer属于特殊会签
/// 最顶层的发起会签节点为none
///
public ECountersignPosition CountersignPosition { get; set; }
///
/// 会签直属办理节点
///
[SugarColumn(ColumnDataType = "json", IsJson = true)]
public List? CountersignSteps { get; set; } = new();
///
/// 发起的会签是否汇总
///
public bool IsStartedCountersignEnd { get; set; }
#region 发起会签节点特有
///
/// 发起会签生成会签Id(不发起会签节点无此字段)
///
public string? StartCountersignId { get; set; }
#endregion
#region 会签汇总节点特有
///
/// 是否为会签汇总节点
///
public bool IsCountersignEndStep { get; set; }
///
/// 开启会签节点id(会签汇总节点对应会签发起节点id)
///
public string? CountersignStartStepId { get; set; }
#endregion
#endregion
[Navigate(NavigateType.ManyToOne, nameof(WorkflowId))]
public Workflow Workflow { get; set; }
[Navigate(NavigateType.OneToOne, nameof(Id),
nameof(Workflows.WorkflowTrace.StepId))]
public WorkflowTrace WorkflowTrace { get; set; }
[Navigate(NavigateType.OneToMany, nameof(WorkflowStepHandler.WorkflowStepId))]
public List StepHandlers { get; set; }
#region Method
///
/// 是否处于会签流程中(不包含顶层发起会签节点)
///
public bool IsInCountersign() => CountersignPosition != ECountersignPosition.None;
/////
///// 是否发起过会签
/////
//public bool HasStartedCountersign() => !string.IsNullOrEmpty(StartCountersignId);
///
/// 接办
///
public void Accept(string userId, string? userName, string orgId, string? orgName, string? orgAreaCode,
string? orgAreaName)
{
AcceptorId = userId;
AcceptorName = userName;
AcceptorOrgId = orgId;
AcceptorOrgName = orgName;
AcceptorOrgAreaCode = orgAreaCode;
AcceptorOrgAreaName = orgAreaName;
AcceptTime = DateTime.Now;
Status = EWorkflowStepStatus.WaitForHandle;
}
///
/// 节点办理完成
///
public void Handle(
string userId, string? userName,
string orgId, string? orgName,
string? orgAreaCode, string? orgAreaName,
bool orgIsCenter, string opinion, string nextStepCode)
{
base.Handle(userId, userName, orgId, orgName, orgAreaCode, orgAreaName, orgIsCenter, opinion);
Status = EWorkflowStepStatus.Handled;
if (!IsInCountersign()
&& InstanceMode is EInstanceMode.Config
&& StepType is not EStepType.End)
{
var step = NextSteps.FirstOrDefault(d => d.Code == nextStepCode);
if (step != null)
step.Selected = true;
}
}
///
/// 会签结束
///
public void CountersignEnd() => IsStartedCountersignEnd = true;
///
/// 开启会签
///
public void StartCountersign(string startCountersignId)
{
IsStartCountersign = true;
StartCountersignId = startCountersignId;
IsStartedCountersignEnd = false;
}
//public void CreateCountersignSteps(List nextSteps) =>
// CountersignSteps = nextSteps
// .Select(d => new CountersignStep { StepId = d.Id })
// .ToList();
///
/// step设置为可接办状态
///
public void SetAssigned() => Status = EWorkflowStepStatus.WaitForAccept;
///
/// 依据当前节点获取下一节点会签状态
///
///
public ECountersignPosition GetNextStepCountersignPosition() =>
IsStartCountersign
? ECountersignPosition.Inner
: IsInCountersign()
? ECountersignPosition.Outer
: ECountersignPosition.None;
public bool IsCenter() => BusinessType is EBusinessType.Center or EBusinessType.Send;
public bool IsOrg() => BusinessType is EBusinessType.Department;
///
/// 重置节点,只清除办理痕迹(退回场景/依据会签开始节点复制会签汇总节点,将上一级节点重置等待重新办理)
///
public void Reset()
{
HandlerId = null;
HandlerName = null;
HandlerOrgId = null;
HandlerOrgName = null;
HandlerOrgAreaCode = null;
HandlerOrgAreaName = null;
HandleTime = null;
AcceptorId = null;
AcceptorName = null;
AcceptorOrgId = null;
AcceptorOrgName = null;
AcceptorOrgAreaCode = null;
AcceptorOrgAreaName = null;
AcceptTime = null;
IsStartCountersign = false;
NextSteps.ForEach(d => d.Selected = false);
}
///
/// 重置办理参数
///
public void ResetParameters()
{
NextHandlers = new();
NextMainHandler = null;
NextStepCode = null;
BackToCountersignEnd = false;
IsSms = false;
Opinion = null;
FileJson = new();
StepExpiredTime = null;
}
/////
///// 发起会签节点发起的会签是否全都办理完成
/////
/////
//public bool StartedCountersignHasAllHandled()
//{
// //if (!HasStartedCountersign())
// // throw new UserFriendlyException("该节点未发起会签");
// //outer属于特殊会签
// return CountersignSteps.All(d => d.Completed);
//}
///
/// 动态实例化节点是否应该终止
///
///
public bool DynamicShouldTerminal() => !string.IsNullOrEmpty(NextStepCode) && TerminalDynamicMark == NextStepCode;
///
/// 是否是顶级会签汇总节点
///
public bool IsTopCountersignEndStep(string? topCountersignStepId)
{
if (string.IsNullOrEmpty(topCountersignStepId))
throw new UserFriendlyException($"无效顶级会签节点编号,wfId: {WorkflowId}");
return IsCountersignEndStep && CountersignStartStepId == topCountersignStepId;
}
public WorkflowStepHandler?
FindActualHandler(ICollection roles, string? userId = null, string? orgId = null) =>
StepHandlers.FirstOrDefault(d => d.IsHandler(roles, userId, orgId));
public WorkflowStepHandler? GetActualHandler() =>
StepHandlers.FirstOrDefault(d => d.IsActualHandler);
#endregion
}
/*
获取开始节点下一步待选节点:
是否属于多次实例化配置(dynamic动态实例化配置:结合办理人动态生成待办节点)
t:无需检查是否到结束标识,所以按配置的重复实例化策略结合当前操作人生成待办节点,如:生成x级部门办理,下一接口再选具体部门
f:开始节点配置的下一节点集合
获取开始节点所选下一步节点的具体参数:
是否属于多次实例化配置
t:所选x级部门返回对应办理对象集合(具体部门)
f:按模板配置返回办理对象集合
获取待办节点下一步待选节点:
是否属于多次实例化配置(无需检查definetion,直接找到当前待办节点获取参数(需要的参数冗余至待办节点上))
t:检查是否到结束标识(检查当前办理节点的办理对象与结束标识(orglevel:int)是否一致)
t:返回配置的下一节点(看作单次实例化,当前节点已办完)//definitionId,stepCodes,按配置走
f:按配置的重复实例化策略结合当前操作人,生成如:{x:X级部门办理},{0:中心办理},最高级最多只能到中心,按动态策略走,动态策略枚举
是否处于会签中
t:按会签策略的下一级 + 上一级(isCSEnd会签汇总节点标记),并对上一级选项打上标记,如:{x:X级部门办理},{0:中心办理},按动态策略走,动态策略枚举
f:按照definition(按配置走)
返回当前节点的配置下一步
获取下一步的具体参数:
检查模式
按动态策略:依据当前操作人、动态类型枚举 查询对应待选部门
按配置策略:原有实现方案
start:
check配置是否允许当前用户发起
next: (nextStepCode/x, userId[]/orgId[],dto.other)
check该不该当前用户办(handlers,all不需要check)
办理当前节点
创建后面节点
是否动态实例化
t:检查是否到结束标识(参数orgId==mark?)
t:(参数时stepcode)按配置创建
f:(参数是x级部门)按动态实例化策略创建
是否处于会签中
t: 是否返回上一级汇总 (isCSEnd)
t: 1.update上一级的会签完成情况[]
2.如果会签全完成,创建新的待办汇总节点(IsCountersignSummaryStep = true)?更新发起节点状态?thk
f: 创建新的下一步节点
*/