using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MW.WorkFlow { /// /// 定义工作流的结构,包含所有活动及其跳转规则。 /// public class WorkflowDefinition { private readonly Dictionary _steps; public string InitialStepId { get; private set; } public WorkflowDefinition(string initialStepId) { InitialStepId = initialStepId ?? throw new ArgumentNullException(nameof(initialStepId)); _steps = new Dictionary(); } /// /// 添加一个工作流步骤到定义中。 /// /// 要添加的步骤。 public void AddStep(WorkflowStep step) { if (step == null) throw new ArgumentNullException(nameof(step)); if (_steps.ContainsKey(step.Id)) { throw new ArgumentException($"工作流步骤ID '{step.Id}' 已存在。"); } _steps.Add(step.Id, step); } /// /// 根据ID获取工作流步骤。 /// /// 步骤的唯一ID。 /// 对应的 WorkflowStep。 public WorkflowStep GetStep(string stepId) { if (_steps.TryGetValue(stepId, out var step)) { return step; } throw new ArgumentException($"未找到ID为 '{stepId}' 的工作流步骤。"); } public bool ContainsStep(string stepId) { return !string.IsNullOrWhiteSpace(stepId) && _steps.ContainsKey(stepId); } /// /// 获取所有步骤的ID列表。 /// public IEnumerable GetAllStepIds() => _steps.Keys; } /// /// 表示工作流中的一个步骤,包含一个活动和可能的条件跳转。 /// public class WorkflowStep { public string Id { get; } // 步骤的唯一标识符 public IActivity Activity { get; } // 该步骤要执行的活动 public string FlowName { get; private set; } // 所属流程名称,用于界面显示和断点定位 public string NextStepId { get; private set; } // 默认的下一个步骤ID public List JumpConditions { get; } // 条件跳转列表 public WorkflowStep(string id, IActivity activity) { Id = id ?? throw new ArgumentNullException(nameof(id)); Activity = activity ?? throw new ArgumentNullException(nameof(activity)); JumpConditions = new List(); } /// /// 设置默认的下一个步骤ID。 /// public WorkflowStep WithNextStep(string nextStepId) { NextStepId = nextStepId; return this; } public WorkflowStep WithFlowName(string flowName) { FlowName = flowName; return this; } /// /// 添加一个条件跳转。 /// /// 跳转条件。 /// 满足条件时要跳转到的目标步骤ID。 public WorkflowStep AddJumpCondition(Func condition, string targetStepId) { JumpConditions.Add(new JumpCondition(condition, targetStepId)); return this; } public WorkflowStep AddDynamicJumpCondition(Func condition, Func targetStepResolver) { JumpConditions.Add(new JumpCondition(condition, targetStepResolver)); return this; } public WorkflowStep AddJumpOnContextValue(string contextKey, T expectedValue, string targetStepId) { if (string.IsNullOrWhiteSpace(contextKey)) throw new ArgumentNullException(nameof(contextKey)); return AddJumpCondition( (ctx, result) => ctx != null && ctx.TryGetData(contextKey, out var actualValue) && EqualityComparer.Default.Equals(actualValue, expectedValue), targetStepId); } public WorkflowStep AddJumpOnContextValueOnSuccess(string contextKey, T expectedValue, string targetStepId) { if (string.IsNullOrWhiteSpace(contextKey)) throw new ArgumentNullException(nameof(contextKey)); return AddJumpCondition( (ctx, result) => result == ActivityResult.Success && ctx != null && ctx.TryGetData(contextKey, out var actualValue) && EqualityComparer.Default.Equals(actualValue, expectedValue), targetStepId); } public WorkflowStep AddJumpOnRouteValue(string routeKey, T expectedValue, string targetStepId) { if (string.IsNullOrWhiteSpace(routeKey)) throw new ArgumentNullException(nameof(routeKey)); return AddJumpCondition( (ctx, result) => ctx != null && ctx.TryGetRoute(routeKey, out var actualValue) && EqualityComparer.Default.Equals(actualValue, expectedValue), targetStepId); } public WorkflowStep AddJumpOnRouteValueOnSuccess(string routeKey, T expectedValue, string targetStepId) { if (string.IsNullOrWhiteSpace(routeKey)) throw new ArgumentNullException(nameof(routeKey)); return AddJumpCondition( (ctx, result) => result == ActivityResult.Success && ctx != null && ctx.TryGetRoute(routeKey, out var actualValue) && EqualityComparer.Default.Equals(actualValue, expectedValue), targetStepId); } public WorkflowStep AddRouteBranchOnSuccess(string routeKey, IDictionary routeTargets) { if (string.IsNullOrWhiteSpace(routeKey)) throw new ArgumentNullException(nameof(routeKey)); if (routeTargets == null) throw new ArgumentNullException(nameof(routeTargets)); return AddDynamicJumpCondition( (ctx, result) => result == ActivityResult.Success && TryResolveRouteBranchTarget(ctx, routeKey, routeTargets, out var _), (ctx, result) => ResolveRouteBranchTarget(ctx, routeKey, routeTargets)); } public WorkflowStep AddRouteBranch(ActivityResult expectedResult, string routeKey, IDictionary routeTargets) { if (string.IsNullOrWhiteSpace(routeKey)) throw new ArgumentNullException(nameof(routeKey)); if (routeTargets == null) throw new ArgumentNullException(nameof(routeTargets)); return AddDynamicJumpCondition( (ctx, result) => result == expectedResult && TryResolveRouteBranchTarget(ctx, routeKey, routeTargets, out var _), (ctx, result) => ResolveRouteBranchTarget(ctx, routeKey, routeTargets)); } public WorkflowStep AddRouteJump(string routeContextKey = "WorkflowRoutes") { return AddDynamicJumpCondition( (ctx, result) => TryResolveRouteTarget(ctx, routeContextKey, out var _), (ctx, result) => ResolveRouteTarget(ctx, routeContextKey)); } public WorkflowStep AddRouteJumpOnSuccess(string routeContextKey = "WorkflowRoutes") { return AddDynamicJumpCondition( (ctx, result) => result == ActivityResult.Success && TryResolveRouteTarget(ctx, routeContextKey, out var _), (ctx, result) => ResolveRouteTarget(ctx, routeContextKey)); } // 可以添加更多方便的条件方法,例如: public WorkflowStep AddJumpOnSuccess(string targetStepId) { return AddJumpCondition((ctx, result) => result == ActivityResult.Success, targetStepId); } public WorkflowStep AddJumpOnFailure(string targetStepId) { return AddJumpCondition((ctx, result) => result == ActivityResult.Failure, targetStepId); } public WorkflowStep AddJumpOnCanceled(string targetStepId) { return AddJumpCondition((ctx, result) => result == ActivityResult.Canceled, targetStepId); } private bool TryResolveRouteTarget(WorkflowContext context, string routeContextKey, out string targetStepId) { if (context != null && context.TryGetData>(routeContextKey, out var routes) && routes != null && routes.TryGetValue(Id, out targetStepId) && !string.IsNullOrWhiteSpace(targetStepId)) { return true; } targetStepId = null; return false; } private string ResolveRouteTarget(WorkflowContext context, string routeContextKey) { if (TryResolveRouteTarget(context, routeContextKey, out var targetStepId)) { return targetStepId; } throw new InvalidOperationException($"步骤 '{Id}' 未找到有效的路由目标。上下文键: '{routeContextKey}'。"); } private bool TryResolveRouteBranchTarget(WorkflowContext context, string routeKey, IDictionary routeTargets, out string targetStepId) { if (context != null && context.TryGetRoute(routeKey, out var routeValue) && routeTargets != null && routeTargets.TryGetValue(routeValue, out targetStepId) && !string.IsNullOrWhiteSpace(targetStepId)) { return true; } targetStepId = null; return false; } private string ResolveRouteBranchTarget(WorkflowContext context, string routeKey, IDictionary routeTargets) { if (TryResolveRouteBranchTarget(context, routeKey, routeTargets, out var targetStepId)) { return targetStepId; } throw new InvalidOperationException($"步骤 '{Id}' 未找到匹配的路由分支。路由键: '{routeKey}'。"); } } /// /// 定义一个条件跳转规则。 /// public class JumpCondition { public Func Condition { get; } // 判断是否跳转的条件 public string TargetStepId { get; } // 满足条件时跳转到的目标步骤ID private readonly Func _targetStepResolver; public JumpCondition(Func condition, string targetStepId) : this(condition, (ctx, result) => targetStepId) { TargetStepId = targetStepId ?? throw new ArgumentNullException(nameof(targetStepId)); } public JumpCondition(Func condition, Func targetStepResolver) { Condition = condition ?? throw new ArgumentNullException(nameof(condition)); _targetStepResolver = targetStepResolver ?? throw new ArgumentNullException(nameof(targetStepResolver)); } public string ResolveTargetStepId(WorkflowContext context, ActivityResult result) { var targetStepId = _targetStepResolver(context, result); if (string.IsNullOrWhiteSpace(targetStepId)) { throw new InvalidOperationException("跳转目标步骤ID不能为空。"); } return targetStepId; } } }