添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,291 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MW.WorkFlow
|
||||
{
|
||||
/// <summary>
|
||||
/// 定义工作流的结构,包含所有活动及其跳转规则。
|
||||
/// </summary>
|
||||
public class WorkflowDefinition
|
||||
{
|
||||
private readonly Dictionary<string, WorkflowStep> _steps;
|
||||
public string InitialStepId { get; private set; }
|
||||
|
||||
public WorkflowDefinition(string initialStepId)
|
||||
{
|
||||
InitialStepId = initialStepId ?? throw new ArgumentNullException(nameof(initialStepId));
|
||||
_steps = new Dictionary<string, WorkflowStep>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个工作流步骤到定义中。
|
||||
/// </summary>
|
||||
/// <param name="step">要添加的步骤。</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据ID获取工作流步骤。
|
||||
/// </summary>
|
||||
/// <param name="stepId">步骤的唯一ID。</param>
|
||||
/// <returns>对应的 WorkflowStep。</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有步骤的ID列表。
|
||||
/// </summary>
|
||||
public IEnumerable<string> GetAllStepIds() => _steps.Keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示工作流中的一个步骤,包含一个活动和可能的条件跳转。
|
||||
/// </summary>
|
||||
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<JumpCondition> 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<JumpCondition>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置默认的下一个步骤ID。
|
||||
/// </summary>
|
||||
public WorkflowStep WithNextStep(string nextStepId)
|
||||
{
|
||||
NextStepId = nextStepId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WorkflowStep WithFlowName(string flowName)
|
||||
{
|
||||
FlowName = flowName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个条件跳转。
|
||||
/// </summary>
|
||||
/// <param name="condition">跳转条件。</param>
|
||||
/// <param name="targetStepId">满足条件时要跳转到的目标步骤ID。</param>
|
||||
public WorkflowStep AddJumpCondition(Func<WorkflowContext, ActivityResult, bool> condition, string targetStepId)
|
||||
{
|
||||
JumpConditions.Add(new JumpCondition(condition, targetStepId));
|
||||
return this;
|
||||
}
|
||||
|
||||
public WorkflowStep AddDynamicJumpCondition(Func<WorkflowContext, ActivityResult, bool> condition, Func<WorkflowContext, ActivityResult, string> targetStepResolver)
|
||||
{
|
||||
JumpConditions.Add(new JumpCondition(condition, targetStepResolver));
|
||||
return this;
|
||||
}
|
||||
|
||||
public WorkflowStep AddJumpOnContextValue<T>(string contextKey, T expectedValue, string targetStepId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(contextKey)) throw new ArgumentNullException(nameof(contextKey));
|
||||
|
||||
return AddJumpCondition(
|
||||
(ctx, result) => ctx != null &&
|
||||
ctx.TryGetData<T>(contextKey, out var actualValue) &&
|
||||
EqualityComparer<T>.Default.Equals(actualValue, expectedValue),
|
||||
targetStepId);
|
||||
}
|
||||
|
||||
public WorkflowStep AddJumpOnContextValueOnSuccess<T>(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<T>(contextKey, out var actualValue) &&
|
||||
EqualityComparer<T>.Default.Equals(actualValue, expectedValue),
|
||||
targetStepId);
|
||||
}
|
||||
|
||||
public WorkflowStep AddJumpOnRouteValue<T>(string routeKey, T expectedValue, string targetStepId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(routeKey)) throw new ArgumentNullException(nameof(routeKey));
|
||||
|
||||
return AddJumpCondition(
|
||||
(ctx, result) => ctx != null &&
|
||||
ctx.TryGetRoute<T>(routeKey, out var actualValue) &&
|
||||
EqualityComparer<T>.Default.Equals(actualValue, expectedValue),
|
||||
targetStepId);
|
||||
}
|
||||
|
||||
public WorkflowStep AddJumpOnRouteValueOnSuccess<T>(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<T>(routeKey, out var actualValue) &&
|
||||
EqualityComparer<T>.Default.Equals(actualValue, expectedValue),
|
||||
targetStepId);
|
||||
}
|
||||
|
||||
public WorkflowStep AddRouteBranchOnSuccess<T>(string routeKey, IDictionary<T, string> 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<T>(ActivityResult expectedResult, string routeKey, IDictionary<T, string> 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<IDictionary<string, string>>(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<T>(WorkflowContext context, string routeKey, IDictionary<T, string> routeTargets, out string targetStepId)
|
||||
{
|
||||
if (context != null &&
|
||||
context.TryGetRoute<T>(routeKey, out var routeValue) &&
|
||||
routeTargets != null &&
|
||||
routeTargets.TryGetValue(routeValue, out targetStepId) &&
|
||||
!string.IsNullOrWhiteSpace(targetStepId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
targetStepId = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private string ResolveRouteBranchTarget<T>(WorkflowContext context, string routeKey, IDictionary<T, string> routeTargets)
|
||||
{
|
||||
if (TryResolveRouteBranchTarget(context, routeKey, routeTargets, out var targetStepId))
|
||||
{
|
||||
return targetStepId;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"步骤 '{Id}' 未找到匹配的路由分支。路由键: '{routeKey}'。");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定义一个条件跳转规则。
|
||||
/// </summary>
|
||||
public class JumpCondition
|
||||
{
|
||||
public Func<WorkflowContext, ActivityResult, bool> Condition { get; } // 判断是否跳转的条件
|
||||
public string TargetStepId { get; } // 满足条件时跳转到的目标步骤ID
|
||||
private readonly Func<WorkflowContext, ActivityResult, string> _targetStepResolver;
|
||||
|
||||
public JumpCondition(Func<WorkflowContext, ActivityResult, bool> condition, string targetStepId)
|
||||
: this(condition, (ctx, result) => targetStepId)
|
||||
{
|
||||
TargetStepId = targetStepId ?? throw new ArgumentNullException(nameof(targetStepId));
|
||||
}
|
||||
|
||||
public JumpCondition(Func<WorkflowContext, ActivityResult, bool> condition, Func<WorkflowContext, ActivityResult, string> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user