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 }