using System.Text.Json;
using Workflow.Domain.Engine;
using Workflow.Domain.Entities;
namespace Workflow.Application.Engine;
///
/// WorkflowGraph(X6 JSON 强类型)与 WorkflowNode/WorkflowEdge(领域实体)的双向适配层。
/// 使 ProcessEngine 从「读关系表」切换到「读 X6 JSON 快照」时,下游所有 Process*Async 方法零改动——
/// 引擎启动时把图映射成内存实体集合,FindNodeAsync/GetOutgoingEdges 等改查内存集合即可。
///
/// ID 兼容约定(见技术方案文档 5.7):X6 节点/边 id 用纯 Guid 字符串(前端 crypto.randomUUID() 生成),
/// 不带 "node_" 前缀,保证 Guid ↔ string 无损往返(WorkflowToken.NodeId 是 Guid)。
///
public static class WorkflowGraphAdapter
{
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
/// 把 WorkflowGraph 映射成内存 WorkflowNode 集合(供 ProcessEngine 查询)。
public static List ToNodes(WorkflowGraph graph, Guid definitionId)
{
var nodes = new List(graph.Nodes.Count);
foreach (var gn in graph.Nodes)
{
var nodeType = WorkflowShapeMap.ToNodeType(gn.Shape);
if (nodeType is null) continue; // 未知 shape 跳过(发布校验已拦截)
nodes.Add(new WorkflowNode
{
Id = ParseGuid(gn.Id),
DefinitionId = definitionId,
NodeType = nodeType.Value,
Name = gn.GetTitle() ?? nodeType.Value.ToString(),
// Config:把 data 对象序列化回字符串,复用现有 NodeConfigParser 解析链
Config = gn.Data is { ValueKind: JsonValueKind.Object or JsonValueKind.Array } data
? data.GetRawText()
: null,
// 审批节点绑定的表单定义 id(钉钉式树编译进 data.formDefinitionId)。
// ApproveTaskCommandHandler.SaveNodeFormDataAsync 据此加载表单做字段权限校验。
FormDefinitionId = TryGetFormDefinitionId(gn.Data),
PositionX = (int)Math.Round(gn.X),
PositionY = (int)Math.Round(gn.Y),
// 审计字段填充非空默认值(实体是 IFullAudit,避免下游 null 引用)
CreatedBy = "system",
UpdatedBy = "system",
});
}
return nodes;
}
/// 把 WorkflowGraph 映射成内存 WorkflowEdge 集合(供 ProcessEngine 查询)。
public static List ToEdges(WorkflowGraph graph, Guid definitionId)
{
var edges = new List(graph.Edges.Count);
foreach (var ge in graph.Edges)
{
var sourceId = ParseGuid(ge.Source.Cell);
var targetId = ParseGuid(ge.Target.Cell);
if (sourceId == Guid.Empty || targetId == Guid.Empty) continue;
edges.Add(new WorkflowEdge
{
Id = ParseGuid(ge.Id),
DefinitionId = definitionId,
SourceNodeId = sourceId,
TargetNodeId = targetId,
EdgeType = ge.GetEdgeType(),
Label = null, // 引擎不读 Label
Condition = ge.GetCondition(),
Order = ge.GetOrder(),
CreatedBy = "system",
UpdatedBy = "system",
});
}
return edges;
}
/// 纯 Guid 字符串解析为 Guid;非法返回 Guid.Empty(适配层会跳过)。
private static Guid ParseGuid(string? id)
{
if (string.IsNullOrWhiteSpace(id)) return Guid.Empty;
return Guid.TryParse(id, out var g) ? g : Guid.Empty;
}
/// 从节点 data.formDefinitionId(钉钉式树编译产物)提取表单定义 id。
private static Guid? TryGetFormDefinitionId(System.Text.Json.JsonElement? data)
{
if (data is not { ValueKind: System.Text.Json.JsonValueKind.Object } obj) return null;
if (!obj.TryGetProperty("formDefinitionId", out var prop)) return null;
var raw = prop.ValueKind == System.Text.Json.JsonValueKind.String ? prop.GetString() : null;
return Guid.TryParse(raw, out var g) ? g : null;
}
}