123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- using Hotline.FlowEngine.Definitions;
- using Hotline.Orders;
- using Hotline.Share.Dtos.FlowEngine;
- using Hotline.Share.Enums.FlowEngine;
- using Hotline.Share.Enums.Order;
- using SqlSugar;
- using XF.Domain.Entities;
- using XF.Domain.Exceptions;
- using XF.Domain.Extensions;
- using XF.Domain.Repository;
- namespace Hotline.FlowEngine.Workflows;
- public class Workflow : CreationEntity
- {
- public string DefinitionId { get; set; }
- #region 业务模块
- [SugarColumn(IsNullable = true)]
- public string? ModuleId { get; set; }
- [SugarColumn(IsNullable = true)]
- public string? ModuleName { get; set; }
- [SugarColumn(IsNullable = true)]
- public string? ModuleCode { get; set; }
- #endregion
- [SugarColumn(Length = 2000)]
- public string Title { get; set; }
- /// <summary>
- /// 到期时间(期满时间)
- /// </summary>
- public DateTime ExpiredTime { get; set; }
- /// <summary>
- /// 办理时间限制(如:24小时、7个工作日)
- /// </summary>
- public string TimeLimit { get; set; }
- /// <summary>
- /// 流程流转到end节点的时间(配置模板的end节点前一个节点办理完成时间)
- /// </summary>
- public DateTime? CompleteTime { get; set; }
- /// <summary>
- /// 流程状态
- /// </summary>
- public EWorkflowStatus Status { get; set; }
- #region 实际办理节点,部门
- /// <summary>
- /// 实际办理节点名称(会签状态此字段保存最外层会签办理节点名称)
- /// </summary>
- [SugarColumn(IsNullable = true)]
- public string? ActualHandleStepName { get; set; }
- /// <summary>
- /// 到达实际办理节点时间(stepBox创建时间)
- /// </summary>
- public DateTime? ActualHandleStepTime { get; set; }
- /// <summary>
- /// 实际办理部门名称
- /// </summary>
- [SugarColumn(IsNullable = true)]
- public string? ActualHandleOrgName { get; set; }
- /// <summary>
- /// 实际办理部门编码
- /// </summary>
- [SugarColumn(IsNullable = true)]
- public string? ActualHandleOrgCode { get; set; }
- #endregion
- /// <summary>
- /// 会签类型
- /// </summary>
- public ECounterSignType? CounterSignType { get; set; }
- /// <summary>
- /// 会签办理节点code,嵌套会签为最外层会签办理节点code(不处于会签状态则无值)
- /// </summary>
- [SugarColumn(IsNullable = true)]
- public string? TopCountersignStepCode { get; set; }
- /// <summary>
- /// 处理方式(直办、交办)
- /// </summary>
- [SugarColumn(DefaultValue = "10")]
- public EProcessType ProcessType { get; set; } = EProcessType.Zhiban;
- /// <summary>
- /// 交办时间
- /// </summary>
- public DateTime AssignTime { get; set; }
- /// <summary>
- /// 办理意见(冗余,办理中...or 最终办理意见)
- /// </summary>
- [SugarColumn(Length = 2000)]
- public string Opinion { get; set; } = "办理中...";
- /// <summary>
- /// 办理人id
- /// </summary>
- [SugarColumn(ColumnDataType = "json", IsJson = true)]
- public List<HandlerGroupItem> HandlerUsers { get; set; } = new();
- /// <summary>
- /// 办理部门code
- /// </summary>
- [SugarColumn(ColumnDataType = "json", IsJson = true)]
- public List<HandlerGroupItem> HandlerOrgs { get; set; } = new();
- /// <summary>
- /// 指派部门code(所有流经部门留痕)
- /// </summary>
- [SugarColumn(ColumnDataType = "json", IsJson = true)]
- public List<string> AssignOrgCodes { get; set; } = new();
- /// <summary>
- /// 指派办理人Id(所有流经办理人留痕)
- /// </summary>
- [SugarColumn(ColumnDataType = "json", IsJson = true)]
- public List<string> AssignUserIds { get; set; } = new();
- /// <summary>
- /// 外部业务唯一标识
- /// </summary>
- public string ExternalId { get; set; }
- [Navigate(NavigateType.OneToOne, nameof(DefinitionId))]
- public Definition Definition { get; set; }
- /// <summary>
- /// 补充信息
- /// </summary>
- [Navigate(NavigateType.OneToMany, nameof(WorkflowSupplement.WorkflowId))]
- public List<WorkflowSupplement> Supplements { get; set; }
- ///// <summary>
- ///// 接办信息
- ///// </summary>
- //[Navigate(NavigateType.OneToMany, nameof(WorkflowAssign.WorkflowId))]
- //public List<WorkflowAssign> Assigns { get; set; }
- /// <summary>
- /// 会签
- /// </summary>
- [Navigate(NavigateType.OneToMany, nameof(WorkflowCountersign.WorkflowId))]
- public List<WorkflowCountersign> Countersigns { get; set; }
- /// <summary>
- /// 主节点,依据流转进度动态生成或删除
- /// </summary>
- [SugarColumn(IsIgnore = true)]
- public List<WorkflowStep> StepBoxes { get; set; }
- [SugarColumn(IsIgnore = true)]
- public List<WorkflowTrace> Traces { get; set; } = new();
- #region Method
- /// <summary>
- /// 流程结束
- /// </summary>
- public void Complete()
- {
- Status = EWorkflowStatus.Completed;
- CompleteTime = DateTime.Now;
- }
- public void Terminate(string opinion)
- {
- Status = EWorkflowStatus.Terminated;
- CompleteTime = DateTime.Now;
- Opinion = opinion;
- }
- ///// <summary>
- ///// 流程进行流转
- ///// </summary>
- //public void FLow(string currentStepName, DateTime currentStepTime, string? currentCountersignCode = null)
- //{
- // ActualHandleStepName = currentStepName;
- // ActualHandleStepTime = currentStepTime;
- // if (!string.IsNullOrEmpty(currentCountersignCode))
- // TopCountersignStepCode = currentCountersignCode;
- //}
- /// <summary>
- /// 更新实际办理节点、部门数据
- /// </summary>
- public void ActualHandle(
- string actualHandleStepName, DateTime actualHandleStepTime,
- string actualHandleOrgName, string actualHandleOrgCode)
- {
- ActualHandleStepName = actualHandleStepName;
- ActualHandleStepTime = actualHandleStepTime;
- ActualHandleOrgName = actualHandleOrgName;
- ActualHandleOrgCode = actualHandleOrgCode;
- }
- /// <summary>
- /// 更新workflow中实际办理节点数据(节点,时间,部门)
- /// </summary>
- public void SetWorkflowActualHandleInfo(WorkflowStep currentStepBox, WorkflowStep nextStepBox, string handlerOrgName, string handlerOrgCode)
- {
- //1.不在会签中,未发起会签(普通处理) 2.不在会签中,发起会签(保存会签节点),3.会签中,不更新
- if (IsInCountersign()) return;
- if (nextStepBox.StepType is EStepType.CountersignEnd or EStepType.End) return;
- ActualHandle(currentStepBox.Name, currentStepBox.CreationTime, handlerOrgName, handlerOrgCode);
- //if (isStartCountersign)
- // SetTopCountersignStepCode(stepBox.Code);
- }
- /// <summary>
- /// 检查会签是否结束
- /// </summary>
- public bool CheckIfCountersignOver()
- {
- //var countersignStepBox = StepBoxes.First(d => d.Code == TopCountersignStepCode);
- //var isCountersignOver = countersignStepBox.Steps.All(d =>
- // d.Status is EWorkflowStepStatus.Completed &&
- // (!d.HasStartCountersign || d.IsCountersignComplete.GetValueOrDefault()));
- //return isCountersignOver;
- return Countersigns.All(d => d.IsCompleted());
- }
- /// <summary>
- /// 流程是否处于会签中
- /// </summary>
- /// <returns></returns>
- public bool IsInCountersign() => !string.IsNullOrEmpty(TopCountersignStepCode);
- /// <summary>
- /// 开始会签
- /// </summary>
- public void StartCountersign(string currentCountersignCode, ECounterSignType counterSignType)
- {
- TopCountersignStepCode = currentCountersignCode;
- CounterSignType = counterSignType;
- }
- /// <summary>
- /// 结束流程会签状态
- /// </summary>
- public void EndCountersign() => TopCountersignStepCode = null;
- /// <summary>
- /// 重置最终办理意见
- /// </summary>
- public void ResetOption() => Opinion = "办理中...";
- /// <summary>
- /// 重新设置办理人(删除当前待办人/部门),撤回/跳转场景,因当前办理人不是流程指定办理人
- /// </summary>
- /// <param name="assignType"></param>
- /// <param name="handlerObjects"></param>
- public void ResetHandlers(EFlowAssignType assignType, List<HandlerGroupItem> handlerObjects)
- {
- HandlerOrgs = new List<HandlerGroupItem>();
- HandlerUsers = new List<HandlerGroupItem>();
- SetHandlers(assignType, handlerObjects);
- }
- /// <summary>
- /// 更新当前办理人(待办人或部门),正常流转场景
- /// </summary>
- public void UpdateHandlers(string handlerId, string handlerOrg, EFlowAssignType assignType, List<HandlerGroupItem> handlerObjects)
- {
- RemoveCurrentHandleGroup(handlerId, handlerOrg);
- SetHandlers(assignType, handlerObjects);
- }
- private void SetHandlers(EFlowAssignType assignType, List<HandlerGroupItem> handlerObjects)
- {
- switch (assignType)
- {
- case EFlowAssignType.Org:
- HandlerOrgs.AddRange(handlerObjects);
- HandlerOrgs = HandlerOrgs.Distinct().ToList();
- break;
- case EFlowAssignType.User:
- HandlerUsers.AddRange(handlerObjects);
- HandlerUsers = HandlerUsers.Distinct().ToList();
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(assignType), assignType, null);
- }
- }
- /// <summary>
- /// 更新当前办理人(逐级退回场景)
- /// </summary>
- /// <param name="handlerId"></param>
- /// <param name="handlerOrg"></param>
- /// <param name="prevStep"></param>
- public void UpdatePreviousHandlers(string handlerId, string handlerOrg, WorkflowStep prevStep)
- {
- RemoveCurrentHandleGroup(handlerId, handlerOrg);
- var groupId = Guid.NewGuid().ToString();
- var handlerObjects = prevStep.Handlers.Select(d => new HandlerGroupItem
- {
- GroupId = groupId,
- Id = d.Id,
- Name = d.Name
- });
- switch (prevStep.HandlerType)
- {
- case EHandlerType.OrgLevel:
- case EHandlerType.OrgType:
- case EHandlerType.AssignOrg:
- HandlerOrgs.AddRange(handlerObjects);
- HandlerOrgs = HandlerOrgs.Distinct().ToList();
- break;
- case EHandlerType.Role:
- case EHandlerType.AssignUser:
- HandlerUsers.AddRange(handlerObjects);
- HandlerUsers = HandlerUsers.Distinct().ToList();
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- /// <summary>
- /// 当前用户是否可以办理该流程
- /// </summary>
- /// <returns></returns>
- public bool CanHandle(string userId, string orgCode) =>
- Status is EWorkflowStatus.Runnable or EWorkflowStatus.Marked
- && (HandlerUsers.Any(d => d.Id == userId) || HandlerOrgs.Any(d => d.Id == orgCode));
- private void RemoveCurrentHandleGroup(string handlerId, string handlerOrg)
- {
- if (string.IsNullOrEmpty(handlerId) && string.IsNullOrEmpty(handlerOrg))
- throw new UserFriendlyException($"{nameof(RemoveCurrentHandleGroup)}, 办理对象参数为空");
- var groupOrg = HandlerOrgs.FirstOrDefault(d => d.Id == handlerOrg);
- if (groupOrg != null)
- {
- HandlerOrgs.RemoveAll(d => d.GroupId == groupOrg.GroupId);
- }
- var groupUser = HandlerUsers.FirstOrDefault(d => d.Id == handlerId);
- if (groupUser != null)
- {
- HandlerUsers.RemoveAll(d => d.GroupId == groupUser.GroupId);
- }
- }
- public void Assign(EFlowAssignType type, string handler)
- {
- handler = handler.ToLower();
- switch (type)
- {
- case EFlowAssignType.Org:
- var orgCodes = handler.GetHigherOrgCodes(true).ToList();
- AssignOrgCodes.AddRange(orgCodes);
- AssignOrgCodes = AssignOrgCodes.Distinct().ToList();
- break;
- case EFlowAssignType.User:
- if (!AssignUserIds.Exists(d => d == handler))
- AssignUserIds.Add(handler);
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(type), type, null);
- }
- }
- public void Assign(EFlowAssignType type, IEnumerable<string> handlers)
- {
- handlers = handlers.Select(d => d.ToLower());
- switch (type)
- {
- case EFlowAssignType.Org:
- var orgCodes = handlers.SelectMany(d => d.GetHigherOrgCodes(true)).ToList();
- AssignOrgCodes.AddRange(orgCodes);
- AssignOrgCodes = AssignOrgCodes.Distinct().ToList();
- break;
- case EFlowAssignType.User:
- AssignUserIds.AddRange(handlers);
- AssignUserIds = AssignUserIds.Distinct().ToList();
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(type), type, null);
- }
- }
- #endregion
- }
- /// <summary>
- /// 办理对象分组(以办理step分组,多人办理一个step为一组)
- /// </summary>
- public class HandlerGroupItem : IdName
- {
- public string GroupId { get; set; }
- }
|