123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- using Hotline.Share.Dtos;
- using Hotline.Share.Dtos.File;
- using Hotline.Share.Dtos.FlowEngine;
- using Hotline.Share.Dtos.FlowEngine.Definition;
- using Hotline.Share.Dtos.FlowEngine.Workflow;
- using Hotline.Share.Enums.FlowEngine;
- using Hotline.Share.Enums.Order;
- using SqlSugar;
- using XF.Domain.Entities;
- using XF.Domain.Repository;
- namespace Hotline.FlowEngine.Workflows;
- public abstract class StepBasicEntity : CreationEntity
- {
- public string WorkflowId { get; set; }
- /// <summary>
- /// 业务唯一标识
- /// </summary>
- public string? ExternalId { get; set; }
- #region 业务模块(冗余)
- public string? ModuleId { get; set; }
- public string? ModuleName { get; set; }
- public string? ModuleCode { get; set; }
- #endregion
- /// <summary>
- /// 是否转办
- /// </summary>
- public bool? IsForwarded { get; set; }
- /// <summary>
- /// 流程指派类型
- /// </summary>
- public EFlowAssignType? FlowAssignType { get; set; }
- /// <summary>
- /// 该节点指派办理对象(依据不同指派方式可能为:orgId或userId),该字段subStep才会存在,stepBox不存在
- /// 采用list类型,兼容或签
- /// </summary>
- [SugarColumn(ColumnDataType = "json", IsJson = true)]
- public List<Kv> Handlers { get; set; } = new();
- /// <summary>
- /// 上一节点办理时,nextStepCode下拉框中选中的值
- /// config模式:当前节点的difinition.code, dynamic模式:x级部门办理的x:int
- /// </summary>
- public string? PrevChosenStepCode { get; set; }
- /// <summary>
- /// 是否实际办理过该工单
- /// </summary>
- public bool IsActualHandled { get; set; }
- /// <summary>
- /// 节点超期状态
- /// </summary>
- public EExpiredStatus? ExpiredStatus { get; set; }
- /// <summary>
- /// 配置下一步节点 & 谁被选中
- /// </summary>
- [SugarColumn(ColumnDataType = "json", IsJson = true)]
- public List<StepSimple>? NextSteps { get; set; } = new();
- /// <summary>
- /// 前一级节点Id,会签汇总节点无此字段(因可能有多个上级来源)
- /// </summary>
- public string? PrevStepId { get; set; }
- public string? PrevStepCode { get; set; }
- /// <summary>
- /// 主办
- /// </summary>
- [SugarColumn(DefaultValue = "f")]
- public bool IsMain { get; set; }
- /// <summary>
- /// 原生节点(区别动态生成)
- /// </summary>
- [SugarColumn(DefaultValue = "f")]
- public bool IsOrigin { get; set; }
- /// <summary>
- /// 节点办理状态
- /// </summary>
- public EWorkflowStepStatus Status { get; set; }
- /// <summary>
- /// 备注
- /// </summary>
- [SugarColumn(ColumnDescription = "备注", ColumnDataType = "varchar(5000)")]
- public string? Remark { get; set; }
- #region 会签
- /// <summary>
- /// 会签id(或外层会签的id)
- /// </summary>
- public string? CountersignId { get; set; }
- /// <summary>
- /// 节点处于会签流程中的位置(区别直接办理会签和会签内非会签节点)
- /// outer属于特殊会签
- /// 最顶层的发起会签节点为none
- /// </summary>
- [SugarColumn(DefaultValue = "0")]
- public ECountersignPosition CountersignPosition { get; set; }
- /// <summary>
- /// 会签直属办理节点(弃用)
- /// </summary>
- [SugarColumn(ColumnDataType = "json", IsJson = true)]
- public List<CountersignStep>? CountersignSteps { get; set; } = new();
- #region 发起会签节点特有
- /// <summary>
- /// 发起会签生成会签Id(不发起会签节点无此字段)
- /// </summary>
- public string? StartCountersignId { get; set; }
- /// <summary>
- /// 发起的会签是否汇总
- /// </summary>
- [SugarColumn(DefaultValue = "f")]
- public bool IsStartedCountersignEnd { get; set; }
- #endregion
- #region 会签汇总节点特有
- /// <summary>
- /// 是否为会签汇总节点
- /// </summary>
- [SugarColumn(DefaultValue = "f")]
- public bool IsCountersignEndStep { get; set; }
- /// <summary>
- /// 开启会签节点id(会签汇总节点对应会签发起节点id)
- /// </summary>
- public string? CountersignStartStepId { get; set; }
- #endregion
- #endregion
- #region 接办
- /// <summary>
- /// 接办人
- /// </summary>
- public string? AcceptorId { get; set; }
- public string? AcceptorName { get; set; }
- /// <summary>
- /// 接办人部门code
- /// </summary>
- public string? AcceptorOrgId { get; set; }
- public string? AcceptorOrgName { get; set; }
- /// <summary>
- /// 接办人部门行政区划代码
- /// </summary>
- public string? AcceptorOrgAreaCode { get; set; }
- /// <summary>
- /// 接办人部门行政区划名称
- /// </summary>
- public string? AcceptorOrgAreaName { get; set; }
- /// <summary>
- /// 接办时间
- /// </summary>
- public DateTime? AcceptTime { get; set; }
- #endregion
- #region 办理
- /// <summary>
- /// 办理人
- /// </summary>
- public string? HandlerId { get; set; }
- public string? HandlerName { get; set; }
- /// <summary>
- /// 办理人部门code
- /// </summary>
- public string? HandlerOrgId { get; set; }
- public bool? HandlerOrgIsCenter { get; set; }
- /// <summary>
- /// 办理人部门名称
- /// </summary>
- public string? HandlerOrgName { get; set; }
- /// <summary>
- /// 办理人部门行政区划代码
- /// </summary>
- public string? HandlerOrgAreaCode { get; set; }
- /// <summary>
- /// 办理人部门行政区划名称
- /// </summary>
- public string? HandlerOrgAreaName { get; set; }
- /// <summary>
- /// 办理完成时间
- /// </summary>
- public DateTime? HandleTime { get; set; }
- /// <summary>
- /// 角色id(如果指派给角色)
- /// </summary>
- public string? RoleId { get; set; }
- public string? RoleName { get; set; }
- #endregion
- #region Definition
- public string Name { get; set; }
- /// <summary>
- /// 模板内唯一
- /// </summary>
- public string Code { get; set; }
- public EStepType StepType { get; init; }
- /// <summary>
- /// 节点业务类型
- /// </summary>
- public EBusinessType BusinessType { get; set; }
- /// <summary>
- /// 办理人类型
- /// </summary>
- public EHandlerType HandlerType { get; set; }
- /// <summary>
- /// 是否有否决按钮
- /// </summary>
- public bool CanReject { get; set; }
- /// <summary>
- /// 执行模式(自动与否)
- /// 只有普通节点支持自动,会签、动态节点均不支持自动
- /// </summary>
- public EExecuteMode ExecuteMode { get; set; }
- #region 会签相关配置
- /// <summary>
- /// 是否支持发起会签(即使支持发起,当下一节点为汇总或结束节点时亦不可发起)
- /// </summary>
- public bool CanStartCountersign { get; set; }
- /// <summary>
- /// 会签策略
- /// </summary>
- public ECountersignPolicy? CountersignPolicy { get; set; }
- #endregion
- #region 依据配置生成节点的方式
- /// <summary>
- /// 实例化模式
- /// </summary>
- public EInstanceMode InstanceMode { get; set; }
- /// <summary>
- /// 动态实例化策略(多次模式才有)
- /// </summary>
- public EDynamicPolicy? InstancePolicy { get; set; }
- /// <summary>
- /// 到此标记终止动态实例化(多次模式才有)
- /// <remarks>
- /// 按直属部门重复既保存orgLevel:int
- /// </remarks>
- /// </summary>
- public string? TerminalDynamicMark { get; set; }
- #endregion
- /// <summary>
- /// 标签
- /// </summary>
- public string? Tag { get; set; }
- #endregion
- #region 办理参数
- #region 办理时赋值
- /// <summary>
- /// (下一节点办理人)根据审批者类型不同,此字段为不同内容
- /// <example>
- /// 部门等级/分类为:orgCodes, 角色为:userIds
- /// </example>
- /// </summary>
- [SugarColumn(ColumnDataType = "json", IsJson = true)]
- public List<FlowStepHandler> NextHandlers { get; set; } = new();
- /// <summary>
- /// 下一节点主办,(NextHandlers其中一个, 如果不是会签则只有一个)
- /// </summary>
- public string? NextMainHandler { get; set; }
- /// <summary>
- /// 下一节点code(stepBox无值)
- /// </summary>
- public string? NextStepCode { get; set; }
- /// <summary>
- /// 是否短信通知
- /// </summary>
- public bool IsSms { get; set; }
- /// <summary>
- /// 办理意见
- /// </summary>
- [SugarColumn(Length = 8000)]
- public string? Opinion { get; set; }
- /// <summary>
- /// 附件
- /// </summary>
- [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
- public List<FileJson>? FileJson { get; set; }
-
- /// <summary>
- /// 发起会签
- /// </summary>
- public bool IsStartCountersign { get; set; }
- #endregion
- #region 创建时赋值
- /// <summary>
- /// 节点期满时间
- /// </summary>
- public DateTime? StepExpiredTime { get; set; }
- /// nextStep 信息
- /// <summary>
- /// 是否回到会签发起节点汇总
- /// </summary>
- public bool BackToCountersignEnd { get; set; }
- public EFlowDirection? FlowDirection { get; set; }
- #endregion
- #endregion
- [Navigate(NavigateType.ManyToOne, nameof(WorkflowId))]
- public Workflow Workflow { get; set; }
-
- #region method
- /// <summary>
- /// 开启会签
- /// </summary>
- public void StartCountersign(string startCountersignId)
- {
- IsStartCountersign = true;
- StartCountersignId = startCountersignId;
- IsStartedCountersignEnd = false;
- }
-
- public bool HasAccepted() => !string.IsNullOrEmpty(AcceptorId);
- public void Accept(
- string userId, string? userName,
- string orgId, string? orgName,
- string? orgAreaCode, string? orgAreaName)
- {
- if (string.IsNullOrEmpty(AcceptorId))
- {
- AcceptorId = userId;
- AcceptorName = userName;
- }
- if (string.IsNullOrEmpty(AcceptorOrgId))
- AcceptorOrgId = orgId;
- if (string.IsNullOrEmpty(AcceptorOrgName))
- AcceptorOrgName = orgName;
- if (string.IsNullOrEmpty(AcceptorOrgAreaCode))
- AcceptorOrgAreaCode = orgAreaCode;
- if (string.IsNullOrEmpty(AcceptorOrgAreaName))
- 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 = null)
- {
- if (!HasAccepted())
- Accept(userId, userName, orgId, orgName, orgAreaCode, orgAreaName);
- Status = EWorkflowStepStatus.Handled;
- if (string.IsNullOrEmpty(HandlerId))
- {
- HandlerId = userId;
- HandlerName = userName;
- }
- if (string.IsNullOrEmpty(HandlerOrgId))
- HandlerOrgId = orgId;
- if (string.IsNullOrEmpty(HandlerOrgName))
- HandlerOrgName = orgName;
- if (string.IsNullOrEmpty(HandlerOrgAreaCode))
- HandlerOrgAreaCode = orgAreaCode;
- if (string.IsNullOrEmpty(HandlerOrgAreaName))
- HandlerOrgAreaName = orgAreaName;
- HandlerOrgIsCenter ??= orgIsCenter;
- HandleTime = DateTime.Now;
- if (!string.IsNullOrEmpty(opinion))
- Opinion = opinion;
- ExpiredStatus = HandleTime > StepExpiredTime
- ? EExpiredStatus.Expired
- : EExpiredStatus.Normal;
- 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;
- }
- }
- /// <summary>
- /// 指派
- /// </summary>
- public void Assign(
- string? handlerId, string? handlerName,
- string? handlerOrgId, string? handlerOrgName,
- string? roleId = null, string? roleName = null)
- {
- HandlerId = handlerId;
- HandlerName = handlerName;
- HandlerOrgId = handlerOrgId;
- HandlerOrgName = handlerOrgName;
- RoleId = roleId;
- RoleName = roleName;
- }
- /// <summary>
- /// 是否处于会签流程中(不包含顶层发起会签节点)
- /// </summary>
- public bool IsInCountersign() => CountersignPosition != ECountersignPosition.None;
- public Kv GetHandler()
- {
- return FlowAssignType switch
- {
- EFlowAssignType.Org => new Kv(HandlerOrgId, HandlerOrgName),
- EFlowAssignType.User => new Kv(HandlerId, HandlerName),
- EFlowAssignType.Role => new Kv(RoleId, RoleName),
- EFlowAssignType.OrgAndRole => new Kv(RoleId, $"{HandlerOrgName} - {RoleName}"),
- _ => throw new ArgumentOutOfRangeException()
- };
- }
- public FlowStepHandler GetWorkflowStepHandler()
- {
- switch (FlowAssignType)
- {
- case EFlowAssignType.Org:
- return new FlowStepHandler
- {
- Key = HandlerOrgId,
- Value = HandlerOrgName,
- UserId = HandlerId,
- Username = HandlerName,
- OrgId = HandlerOrgId,
- OrgName = HandlerOrgName,
- RoleId = RoleId,
- RoleName = RoleName
- };
- case EFlowAssignType.User:
- return new FlowStepHandler
- {
- Key = HandlerId,
- Value = HandlerName,
- UserId = HandlerId,
- Username = HandlerName,
- OrgId = HandlerOrgId,
- OrgName = HandlerOrgName,
- RoleId = RoleId,
- RoleName = RoleName
- };
- case EFlowAssignType.Role:
- return new FlowStepHandler
- {
- Key = RoleId,
- Value = RoleName,
- UserId = HandlerId,
- Username = HandlerName,
- OrgId = HandlerOrgId,
- OrgName = HandlerOrgName,
- RoleId = RoleId,
- RoleName = RoleName
- };
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- #endregion
- }
- /*
- feature:
- 1. step增加字段记录roleId, roleName
- 2. 指派时为对应办理对象赋值,办理时为所有办理对象字段赋值
- 3. 配置办理对象为角色时,如果未指定办理人则指派给角色办理
- 4. thk从默认派单池中分配给对应办理人时指定办理对象
- refactor:
- 1. step增加字段记录发起会签或是或签
- 2. status增加或签无需办理状态
- 3. 办理节点时判断是否立即结束会签或者等全部节点办完再结束
- */
|