| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- using System.Text.Json;
- namespace Admin.NET.Plugin.ApprovalFlow.Service;
- /// <summary>
- /// 流程推进引擎 — 核心状态机
- /// 不暴露为 API,由其他 Service 内部调用
- /// </summary>
- public class FlowEngineService : ITransient
- {
- private readonly SqlSugarRepository<ApprovalFlow> _flowRep;
- private readonly SqlSugarRepository<ApprovalFlowInstance> _instanceRep;
- private readonly SqlSugarRepository<ApprovalFlowTask> _taskRep;
- private readonly SqlSugarRepository<ApprovalFlowLog> _logRep;
- private readonly SqlSugarRepository<SysUserRole> _userRoleRep;
- private readonly SqlSugarRepository<SysUser> _userRep;
- private readonly UserManager _userManager;
- private readonly FlowNotifyService _notifyService;
- public FlowEngineService(
- SqlSugarRepository<ApprovalFlow> flowRep,
- SqlSugarRepository<ApprovalFlowInstance> instanceRep,
- SqlSugarRepository<ApprovalFlowTask> taskRep,
- SqlSugarRepository<ApprovalFlowLog> logRep,
- SqlSugarRepository<SysUserRole> userRoleRep,
- SqlSugarRepository<SysUser> userRep,
- UserManager userManager,
- FlowNotifyService notifyService)
- {
- _flowRep = flowRep;
- _instanceRep = instanceRep;
- _taskRep = taskRep;
- _logRep = logRep;
- _userRoleRep = userRoleRep;
- _userRep = userRep;
- _userManager = userManager;
- _notifyService = notifyService;
- }
- // ═══════════════════════════════════════════
- // 核心生命周期
- // ═══════════════════════════════════════════
- /// <summary>
- /// 发起流程
- /// </summary>
- public async Task<long> StartFlow(StartFlowInput input)
- {
- var flow = await _flowRep.AsQueryable()
- .Where(u => u.BizType == input.BizType && u.IsPublished && !u.IsDelete)
- .OrderByDescending(u => u.Version)
- .FirstAsync() ?? throw Oops.Oh($"未找到业务类型 [{input.BizType}] 的已发布流程定义");
- if (string.IsNullOrWhiteSpace(flow.FlowJson))
- throw Oops.Oh("流程定义的 FlowJson 为空,请先设计流程图");
- var flowData = JsonSerializer.Deserialize<ApprovalFlowItem>(flow.FlowJson)
- ?? throw Oops.Oh("FlowJson 反序列化失败");
- var instance = new ApprovalFlowInstance
- {
- FlowId = flow.Id,
- FlowVersion = flow.Version,
- BizType = input.BizType,
- BizId = input.BizId,
- BizNo = input.BizNo,
- Title = input.Title ?? $"{flow.Name}-{input.BizNo}",
- InitiatorId = _userManager.UserId,
- InitiatorName = _userManager.RealName,
- Status = FlowInstanceStatusEnum.Running,
- FlowJsonSnapshot = flow.FlowJson,
- StartTime = DateTime.Now,
- };
- var startNode = flowData.Nodes.FirstOrDefault(n =>
- n.Type is "bpmn:startEvent" or "start-node")
- ?? throw Oops.Oh("流程图中未找到开始节点");
- var firstTaskNodeId = FindNextNodeId(flowData, startNode.Id);
- instance.CurrentNodeId = firstTaskNodeId;
- await _instanceRep.InsertAsync(instance);
- await WriteLog(instance.Id, null, startNode.Id, FlowLogActionEnum.Submit, input.Comment);
- await CreateTasksForNode(instance, flowData, firstTaskNodeId);
- await InvokeHandler(input.BizType, h => h.OnFlowStarted(input.BizId, instance.Id));
- return instance.Id;
- }
- /// <summary>
- /// 同意
- /// </summary>
- public async Task Approve(long taskId, string? comment)
- {
- var task = await GetPendingTask(taskId);
- task.Status = FlowTaskStatusEnum.Approved;
- task.Comment = comment;
- task.ActionTime = DateTime.Now;
- await _taskRep.AsUpdateable(task).ExecuteCommandAsync();
- await WriteLog(task.InstanceId, taskId, task.NodeId, FlowLogActionEnum.Approve, comment);
- var instance = await _instanceRep.GetByIdAsync(task.InstanceId)
- ?? throw Oops.Oh("流程实例不存在");
- if (await IsNodeCompleted(instance, task.NodeId))
- {
- await InvokeHandler(instance.BizType,
- h => h.OnNodeCompleted(instance.BizId, task.NodeId, task.NodeName ?? ""));
- var flowData = DeserializeFlowJson(instance.FlowJsonSnapshot);
- await AdvanceToNext(instance, flowData, task.NodeId);
- }
- }
- /// <summary>
- /// 拒绝
- /// </summary>
- public async Task Reject(long taskId, string? comment)
- {
- var task = await GetPendingTask(taskId);
- task.Status = FlowTaskStatusEnum.Rejected;
- task.Comment = comment;
- task.ActionTime = DateTime.Now;
- await _taskRep.AsUpdateable(task).ExecuteCommandAsync();
- await CancelPendingTasks(task.InstanceId, task.NodeId, task.Id);
- var instance = await _instanceRep.GetByIdAsync(task.InstanceId)
- ?? throw Oops.Oh("流程实例不存在");
- instance.Status = FlowInstanceStatusEnum.Rejected;
- instance.EndTime = DateTime.Now;
- await _instanceRep.AsUpdateable(instance).ExecuteCommandAsync();
- await WriteLog(instance.Id, taskId, task.NodeId, FlowLogActionEnum.Reject, comment);
- await InvokeHandler(instance.BizType,
- h => h.OnFlowCompleted(instance.BizId, FlowInstanceStatusEnum.Rejected));
- await _notifyService.NotifyFlowCompleted(instance.InitiatorId, instance.Id, instance.Title, FlowInstanceStatusEnum.Rejected);
- }
- // ═══════════════════════════════════════════
- // 扩展操作
- // ═══════════════════════════════════════════
- /// <summary>
- /// 转办
- /// </summary>
- public async Task Transfer(long taskId, long targetUserId, string? comment)
- {
- var task = await GetPendingTask(taskId);
- task.Status = FlowTaskStatusEnum.Transferred;
- task.Comment = comment;
- task.ActionTime = DateTime.Now;
- task.TransferToId = targetUserId;
- await _taskRep.AsUpdateable(task).ExecuteCommandAsync();
- var targetUser = await _userRep.GetByIdAsync(targetUserId);
- var newTask = new ApprovalFlowTask
- {
- InstanceId = task.InstanceId,
- NodeId = task.NodeId,
- NodeName = task.NodeName,
- AssigneeId = targetUserId,
- AssigneeName = targetUser?.RealName,
- Status = FlowTaskStatusEnum.Pending,
- };
- await _taskRep.InsertAsync(newTask);
- await WriteLog(task.InstanceId, taskId, task.NodeId, FlowLogActionEnum.Transfer,
- $"{comment} → 转办给 {targetUser?.RealName}");
- var instance = await _instanceRep.GetByIdAsync(task.InstanceId);
- await _notifyService.NotifyTransferred(targetUserId, task.InstanceId, instance?.Title ?? "", _userManager.RealName);
- }
- /// <summary>
- /// 撤回(发起人撤回)
- /// </summary>
- public async Task Withdraw(long instanceId)
- {
- var instance = await _instanceRep.GetByIdAsync(instanceId)
- ?? throw Oops.Oh("流程实例不存在");
- if (instance.InitiatorId != _userManager.UserId)
- throw Oops.Oh("只有发起人可以撤回");
- if (instance.Status != FlowInstanceStatusEnum.Running)
- throw Oops.Oh("当前流程状态不允许撤回");
- var pendingTasks = await _taskRep.AsQueryable()
- .Where(t => t.InstanceId == instanceId && t.Status == FlowTaskStatusEnum.Pending)
- .ToListAsync();
- var doneTasks = await _taskRep.AsQueryable()
- .Where(t => t.InstanceId == instanceId &&
- t.Status != FlowTaskStatusEnum.Pending &&
- t.Status != FlowTaskStatusEnum.Cancelled)
- .CountAsync();
- if (doneTasks > 0)
- throw Oops.Oh("已有人审批过,不可撤回");
- var cancelledUserIds = pendingTasks.Select(t => t.AssigneeId).Distinct().ToList();
- foreach (var t in pendingTasks)
- {
- t.Status = FlowTaskStatusEnum.Cancelled;
- t.ActionTime = DateTime.Now;
- }
- await _taskRep.AsUpdateable(pendingTasks).ExecuteCommandAsync();
- instance.Status = FlowInstanceStatusEnum.Cancelled;
- instance.EndTime = DateTime.Now;
- await _instanceRep.AsUpdateable(instance).ExecuteCommandAsync();
- await WriteLog(instanceId, null, instance.CurrentNodeId, FlowLogActionEnum.Withdraw, null);
- await InvokeHandler(instance.BizType,
- h => h.OnFlowCompleted(instance.BizId, FlowInstanceStatusEnum.Cancelled));
- await _notifyService.NotifyWithdrawn(cancelledUserIds, instanceId, instance.Title, instance.InitiatorName);
- }
- /// <summary>
- /// 退回上一步
- /// </summary>
- public async Task ReturnToPrev(long taskId, string? comment)
- {
- var task = await GetPendingTask(taskId);
- var instance = await _instanceRep.GetByIdAsync(task.InstanceId)
- ?? throw Oops.Oh("流程实例不存在");
- var flowData = DeserializeFlowJson(instance.FlowJsonSnapshot);
- var prevNodeId = FindPrevUserTaskNodeId(flowData, task.NodeId);
- if (prevNodeId == null)
- throw Oops.Oh("已是第一个审批节点,无法退回");
- await CancelPendingTasks(task.InstanceId, task.NodeId);
- task.Status = FlowTaskStatusEnum.Returned;
- task.Comment = comment;
- task.ActionTime = DateTime.Now;
- await _taskRep.AsUpdateable(task).ExecuteCommandAsync();
- instance.CurrentNodeId = prevNodeId;
- await _instanceRep.AsUpdateable(instance).ExecuteCommandAsync();
- await CreateTasksForNode(instance, flowData, prevNodeId);
- await WriteLog(instance.Id, taskId, task.NodeId, FlowLogActionEnum.Return, comment);
- var returnedTasks = await _taskRep.AsQueryable()
- .Where(t => t.InstanceId == instance.Id && t.NodeId == prevNodeId && t.Status == FlowTaskStatusEnum.Pending)
- .ToListAsync();
- var returnedUserIds = returnedTasks.Select(t => t.AssigneeId).Distinct().ToList();
- await _notifyService.NotifyReturned(returnedUserIds, instance.Id, instance.Title, _userManager.RealName);
- }
- /// <summary>
- /// 加签
- /// </summary>
- public async Task AddSign(long taskId, long targetUserId, string? comment)
- {
- var task = await GetPendingTask(taskId);
- var targetUser = await _userRep.GetByIdAsync(targetUserId);
- var newTask = new ApprovalFlowTask
- {
- InstanceId = task.InstanceId,
- NodeId = task.NodeId,
- NodeName = task.NodeName,
- AssigneeId = targetUserId,
- AssigneeName = targetUser?.RealName,
- Status = FlowTaskStatusEnum.Pending,
- IsAddSign = true,
- AddSignById = _userManager.UserId,
- };
- await _taskRep.InsertAsync(newTask);
- await WriteLog(task.InstanceId, taskId, task.NodeId, FlowLogActionEnum.AddSign,
- $"{comment} → 加签给 {targetUser?.RealName}");
- var instance = await _instanceRep.GetByIdAsync(task.InstanceId);
- await _notifyService.NotifyAddSign(targetUserId, task.InstanceId, instance?.Title ?? "", _userManager.RealName);
- }
- /// <summary>
- /// 催办
- /// </summary>
- public async Task Urge(long instanceId)
- {
- var instance = await _instanceRep.GetByIdAsync(instanceId)
- ?? throw Oops.Oh("流程实例不存在");
- if (instance.Status != FlowInstanceStatusEnum.Running)
- throw Oops.Oh("当前流程不在审批中");
- await WriteLog(instanceId, null, instance.CurrentNodeId, FlowLogActionEnum.Urge, "催办");
- var pendingTasks = await _taskRep.AsQueryable()
- .Where(t => t.InstanceId == instanceId && t.Status == FlowTaskStatusEnum.Pending)
- .ToListAsync();
- var userIds = pendingTasks.Select(t => t.AssigneeId).Distinct().ToList();
- await _notifyService.NotifyUrge(userIds, instanceId, instance.Title);
- }
- // ═══════════════════════════════════════════
- // 内部引擎方法
- // ═══════════════════════════════════════════
- private async Task AdvanceToNext(ApprovalFlowInstance instance, ApprovalFlowItem flowData, string currentNodeId)
- {
- var nextNodeId = FindNextNodeId(flowData, currentNodeId);
- if (nextNodeId == null)
- {
- await CompleteInstance(instance, FlowInstanceStatusEnum.Approved);
- return;
- }
- var nextNode = flowData.Nodes.FirstOrDefault(n => n.Id == nextNodeId);
- if (nextNode == null)
- {
- await CompleteInstance(instance, FlowInstanceStatusEnum.Approved);
- return;
- }
- if (nextNode.Type is "bpmn:endEvent" or "end-node")
- {
- await CompleteInstance(instance, FlowInstanceStatusEnum.Approved);
- return;
- }
- if (nextNode.Type is "bpmn:exclusiveGateway")
- {
- var bizData = await GetBizData(instance.BizType, instance.BizId);
- var targetNodeId = EvaluateGateway(nextNode.Properties?.Conditions, flowData, nextNode.Id, bizData);
- instance.CurrentNodeId = targetNodeId;
- await _instanceRep.AsUpdateable(instance).UpdateColumns(i => new { i.CurrentNodeId }).ExecuteCommandAsync();
- await AdvanceToNext(instance, flowData, nextNode.Id);
- return;
- }
- instance.CurrentNodeId = nextNodeId;
- await _instanceRep.AsUpdateable(instance).UpdateColumns(i => new { i.CurrentNodeId }).ExecuteCommandAsync();
- await CreateTasksForNode(instance, flowData, nextNodeId);
- }
- private async Task CompleteInstance(ApprovalFlowInstance instance, FlowInstanceStatusEnum status)
- {
- instance.Status = status;
- instance.EndTime = DateTime.Now;
- await _instanceRep.AsUpdateable(instance)
- .UpdateColumns(i => new { i.Status, i.EndTime })
- .ExecuteCommandAsync();
- await InvokeHandler(instance.BizType,
- h => h.OnFlowCompleted(instance.BizId, status));
- await _notifyService.NotifyFlowCompleted(instance.InitiatorId, instance.Id, instance.Title, status);
- }
- private async Task CreateTasksForNode(ApprovalFlowInstance instance, ApprovalFlowItem flowData, string nodeId)
- {
- var node = flowData.Nodes.FirstOrDefault(n => n.Id == nodeId)
- ?? throw Oops.Oh($"FlowJson 中未找到节点 [{nodeId}]");
- var approvers = await ResolveApprovers(node.Properties, instance.InitiatorId);
- if (approvers.Count == 0)
- throw Oops.Oh($"节点 [{node.Properties?.NodeName ?? nodeId}] 未配置审批人或审批人列表为空");
- var tasks = approvers.Select(a => new ApprovalFlowTask
- {
- InstanceId = instance.Id,
- NodeId = nodeId,
- NodeName = node.Properties?.NodeName ?? node.Text?.Value,
- AssigneeId = a.userId,
- AssigneeName = a.userName,
- Status = FlowTaskStatusEnum.Pending,
- }).ToList();
- await _taskRep.AsInsertable(tasks).ExecuteCommandAsync();
- var assigneeIds = tasks.Select(t => t.AssigneeId).Distinct().ToList();
- await _notifyService.NotifyNewTask(assigneeIds, instance.Id, instance.Title, node.Properties?.NodeName ?? node.Text?.Value);
- }
- private async Task<List<(long userId, string userName)>> ResolveApprovers(FlowProperties? props, long initiatorId)
- {
- if (props == null || string.IsNullOrWhiteSpace(props.ApproverType))
- return new List<(long, string)>();
- var approverType = props.ApproverType;
- if (approverType == nameof(ApproverTypeEnum.Initiator))
- {
- var initiator = await _userRep.GetByIdAsync(initiatorId);
- return initiator != null
- ? new List<(long, string)> { (initiator.Id, initiator.RealName ?? "") }
- : new List<(long, string)>();
- }
- if (string.IsNullOrWhiteSpace(props.ApproverIds))
- return new List<(long, string)>();
- var ids = props.ApproverIds.Split(',', StringSplitOptions.RemoveEmptyEntries)
- .Select(s => long.TryParse(s.Trim(), out var v) ? v : 0).Where(id => id > 0).ToList();
- if (approverType == nameof(ApproverTypeEnum.SpecificUser))
- {
- var users = await _userRep.AsQueryable()
- .Where(u => ids.Contains(u.Id)).ToListAsync();
- return users.Select(u => (u.Id, u.RealName ?? "")).ToList();
- }
- if (approverType == nameof(ApproverTypeEnum.Role))
- {
- var userIds = await _userRoleRep.AsQueryable()
- .Where(ur => ids.Contains(ur.RoleId))
- .Select(ur => ur.UserId)
- .ToListAsync();
- var users = await _userRep.AsQueryable()
- .Where(u => userIds.Contains(u.Id)).ToListAsync();
- return users.Select(u => (u.Id, u.RealName ?? "")).ToList();
- }
- if (approverType == nameof(ApproverTypeEnum.Department))
- {
- var users = await _userRep.AsQueryable()
- .Where(u => ids.Contains(u.OrgId)).ToListAsync();
- return users.Select(u => (u.Id, u.RealName ?? "")).ToList();
- }
- return new List<(long, string)>();
- }
- /// <summary>
- /// 评估排他网关 — 依次尝试各非默认分支的条件表达式,首个匹配的获胜;
- /// 全不匹配则走默认分支;无默认则走第一条出边
- /// 支持简单比较表达式:variable op value(op: ==,!=,>,>=,<,<=)
- /// </summary>
- private string EvaluateGateway(List<GatewayCondition>? conditions, ApprovalFlowItem flowData, string gatewayNodeId, Dictionary<string, object>? bizData)
- {
- if (conditions != null && conditions.Count > 0 && bizData != null && bizData.Count > 0)
- {
- foreach (var cond in conditions.Where(c => !c.IsDefault))
- {
- if (!string.IsNullOrWhiteSpace(cond.Expression) && EvalSimpleExpression(cond.Expression, bizData))
- return cond.TargetNodeId;
- }
- var defaultBranch = conditions.FirstOrDefault(c => c.IsDefault);
- if (defaultBranch != null)
- return defaultBranch.TargetNodeId;
- }
- else if (conditions != null && conditions.Count > 0)
- {
- var defaultBranch = conditions.FirstOrDefault(c => c.IsDefault);
- if (defaultBranch != null) return defaultBranch.TargetNodeId;
- return conditions.First().TargetNodeId;
- }
- var edge = flowData.Edges.FirstOrDefault(e => e.SourceNodeId == gatewayNodeId);
- return edge?.TargetNodeId ?? throw Oops.Oh("排他网关没有出边");
- }
- /// <summary>
- /// 简单表达式求值:支持 "field op value" 格式(如 "urgent == 1", "customLevel >= 3", "amount > 10000")
- /// 多条件用 && 连接
- /// </summary>
- private static bool EvalSimpleExpression(string expression, Dictionary<string, object> bizData)
- {
- var parts = expression.Split("&&", StringSplitOptions.TrimEntries);
- foreach (var part in parts)
- {
- if (!EvalSingleComparison(part.Trim(), bizData))
- return false;
- }
- return true;
- }
- private static bool EvalSingleComparison(string expr, Dictionary<string, object> bizData)
- {
- string[] ops = { ">=", "<=", "!=", "==", ">", "<" };
- foreach (var op in ops)
- {
- var idx = expr.IndexOf(op, StringComparison.Ordinal);
- if (idx < 0) continue;
- var fieldName = expr[..idx].Trim();
- var valueStr = expr[(idx + op.Length)..].Trim().Trim('"', '\'');
- if (!bizData.TryGetValue(fieldName, out var fieldValue))
- return false;
- if (decimal.TryParse(fieldValue?.ToString(), out var numLeft) && decimal.TryParse(valueStr, out var numRight))
- {
- return op switch
- {
- "==" => numLeft == numRight,
- "!=" => numLeft != numRight,
- ">" => numLeft > numRight,
- ">=" => numLeft >= numRight,
- "<" => numLeft < numRight,
- "<=" => numLeft <= numRight,
- _ => false,
- };
- }
- var strLeft = fieldValue?.ToString() ?? "";
- return op switch
- {
- "==" => strLeft.Equals(valueStr, StringComparison.OrdinalIgnoreCase),
- "!=" => !strLeft.Equals(valueStr, StringComparison.OrdinalIgnoreCase),
- _ => false,
- };
- }
- return false;
- }
- private async Task<Dictionary<string, object>?> GetBizData(string bizType, long bizId)
- {
- var handlers = App.GetServices<IFlowBizHandler>();
- var handler = handlers?.FirstOrDefault(h => h.BizType == bizType);
- if (handler == null) return null;
- return await handler.GetBizData(bizId);
- }
- private string? FindNextNodeId(ApprovalFlowItem flowData, string currentNodeId)
- {
- var edge = flowData.Edges.FirstOrDefault(e => e.SourceNodeId == currentNodeId);
- return edge?.TargetNodeId;
- }
- private string? FindPrevUserTaskNodeId(ApprovalFlowItem flowData, string currentNodeId)
- {
- var inEdge = flowData.Edges.FirstOrDefault(e => e.TargetNodeId == currentNodeId);
- if (inEdge == null) return null;
- var prevNode = flowData.Nodes.FirstOrDefault(n => n.Id == inEdge.SourceNodeId);
- if (prevNode == null) return null;
- if (prevNode.Type is "bpmn:userTask" or "user-node" or "task-node")
- return prevNode.Id;
- // 递归跳过网关等非用户任务节点
- return FindPrevUserTaskNodeId(flowData, prevNode.Id);
- }
- private async Task<bool> IsNodeCompleted(ApprovalFlowInstance instance, string nodeId)
- {
- var flowData = DeserializeFlowJson(instance.FlowJsonSnapshot);
- var node = flowData.Nodes.FirstOrDefault(n => n.Id == nodeId);
- var mode = node?.Properties?.MultiApproveMode;
- if (mode == nameof(MultiApproveModeEnum.All))
- {
- var pendingCount = await _taskRep.AsQueryable()
- .Where(t => t.InstanceId == instance.Id && t.NodeId == nodeId && t.Status == FlowTaskStatusEnum.Pending)
- .CountAsync();
- return pendingCount == 0;
- }
- // 默认或签(Any):一人通过即完成,取消其他 Pending
- await CancelPendingTasks(instance.Id, nodeId);
- return true;
- }
- private async Task CancelPendingTasks(long instanceId, string nodeId, long? excludeTaskId = null)
- {
- var tasks = await _taskRep.AsQueryable()
- .Where(t => t.InstanceId == instanceId && t.NodeId == nodeId && t.Status == FlowTaskStatusEnum.Pending)
- .WhereIF(excludeTaskId.HasValue, t => t.Id != excludeTaskId!.Value)
- .ToListAsync();
- foreach (var t in tasks)
- {
- t.Status = FlowTaskStatusEnum.Cancelled;
- t.ActionTime = DateTime.Now;
- }
- if (tasks.Count > 0)
- await _taskRep.AsUpdateable(tasks).ExecuteCommandAsync();
- }
- private async Task<ApprovalFlowTask> GetPendingTask(long taskId)
- {
- var task = await _taskRep.GetByIdAsync(taskId)
- ?? throw Oops.Oh("审批任务不存在");
- if (task.Status != FlowTaskStatusEnum.Pending)
- throw Oops.Oh("该任务已处理");
- if (task.AssigneeId != _userManager.UserId)
- throw Oops.Oh("当前用户不是该任务的审批人");
- return task;
- }
- private async Task WriteLog(long instanceId, long? taskId, string? nodeId, FlowLogActionEnum action, string? comment)
- {
- await _logRep.InsertAsync(new ApprovalFlowLog
- {
- InstanceId = instanceId,
- TaskId = taskId,
- NodeId = nodeId,
- Action = action,
- OperatorId = _userManager.UserId,
- OperatorName = _userManager.RealName,
- Comment = comment,
- });
- }
- private static ApprovalFlowItem DeserializeFlowJson(string? json)
- {
- if (string.IsNullOrWhiteSpace(json))
- throw Oops.Oh("FlowJson 快照为空");
- return JsonSerializer.Deserialize<ApprovalFlowItem>(json)
- ?? throw Oops.Oh("FlowJson 反序列化失败");
- }
- private async Task InvokeHandler(string bizType, Func<IFlowBizHandler, Task> action)
- {
- var handlers = App.GetServices<IFlowBizHandler>();
- var handler = handlers?.FirstOrDefault(h => h.BizType == bizType);
- if (handler != null)
- await action(handler);
- }
- }
|