deploy-ease-platform/backend/docs/deploy-flow-graph-frontend-guide.md
2025-11-04 22:37:01 +08:00

12 KiB
Raw Permalink Blame History

部署记录流程图前端绘制指南

概述

本文档说明前端如何调用API获取部署记录的工作流流程图数据以及如何使用这些数据绘制流程图并标记节点状态。

API接口

获取部署流程图数据

接口地址: GET /api/v1/deploy/records/{deployRecordId}/flow-graph

路径参数:

  • deployRecordId (Long): 部署记录ID

响应示例:

{
  "success": true,
  "message": "操作成功",
  "data": {
    "deployRecordId": 16,
    "workflowInstanceId": 16,
    "processInstanceId": "b24d97ec-b97f-11f0-be70-de5a4815c9ef",
    "deployStatus": "REJECTED",
    "graph": {
      "nodes": [
        {
          "id": "startNode",
          "nodeCode": "start",
          "nodeType": "START",
          "nodeName": "开始",
          "position": {
            "x": 100,
            "y": 200
          },
          "configs": {},
          "inputMapping": {},
          "outputs": []
        },
        {
          "id": "sid_4ee9fab9_d626_4691_816c_9435902fc3d0",
          "nodeCode": "approval",
          "nodeType": "APPROVAL",
          "nodeName": "审批节点",
          "position": {
            "x": 300,
            "y": 200
          },
          "configs": {
            "userIds": ["admin"]
          },
          "inputMapping": {},
          "outputs": []
        },
        {
          "id": "endNode",
          "nodeCode": "end",
          "nodeType": "END",
          "nodeName": "结束",
          "position": {
            "x": 500,
            "y": 200
          },
          "configs": {},
          "inputMapping": {},
          "outputs": []
        }
      ],
      "edges": [
        {
          "source": "startNode",
          "target": "sid_4ee9fab9_d626_4691_816c_816c_9435902fc3d0"
        },
        {
          "source": "sid_4ee9fab9_d626_4691_816c_9435902fc3d0",
          "target": "endNode"
        }
      ]
    },
    "nodeInstances": [
      {
        "id": 1,
        "processInstanceId": "b24d97ec-b97f-11f0-be70-de5a4815c9ef",
        "nodeId": "startNode",
        "nodeName": "开始",
        "nodeType": "START",
        "status": "COMPLETED",
        "startTime": "2025-11-04T21:10:00",
        "endTime": "2025-11-04T21:10:01"
      },
      {
        "id": 2,
        "processInstanceId": "b24d97ec-b97f-11f0-be70-de5a4815c9ef",
        "nodeId": "sid_4ee9fab9_d626_4691_816c_9435902fc3d0",
        "nodeName": "审批节点",
        "nodeType": "APPROVAL",
        "status": "REJECTED",
        "startTime": "2025-11-04T21:10:01",
        "endTime": "2025-11-04T21:14:34"
      },
      {
        "id": null,
        "processInstanceId": "b24d97ec-b97f-11f0-be70-de5a4815c9ef",
        "nodeId": "endNode",
        "nodeName": "结束",
        "nodeType": "END",
        "status": "NOT_STARTED",
        "startTime": null,
        "endTime": null
      }
    ]
  }
}

数据结构说明

DeployRecordFlowGraphDTO

字段 类型 说明
deployRecordId Long 部署记录ID
workflowInstanceId Long 工作流实例ID
processInstanceId String Flowable流程实例ID
deployStatus String 部署状态CREATED/PENDING_APPROVAL/RUNNING/SUCCESS/FAILED/REJECTED/CANCELLED/TERMINATED/PARTIAL_SUCCESS
graph WorkflowDefinitionGraph 流程图结构数据(包含节点和边的位置信息)
nodeInstances List 节点执行状态列表

WorkflowDefinitionGraph

字段 类型 说明
nodes List 节点列表(包含位置信息)
edges List 边列表(连接关系)

WorkflowDefinitionGraphNode

字段 类型 说明
id String 节点ID用于匹配nodeInstances
nodeCode String 节点代码
nodeType String 节点类型START/END/APPROVAL/SHELL等
nodeName String 节点名称
position Map<String, Object> 节点位置信息x, y坐标
configs Map<String, Object> 节点配置信息
inputMapping Map<String, Object> 输入映射
outputs List 输出字段列表

WorkflowNodeInstanceDTO

字段 类型 说明
id Long 节点实例ID可能为null表示未开始
nodeId String 节点ID与graph.nodes中的id匹配
nodeName String 节点名称
nodeType String 节点类型
status String 节点执行状态NOT_STARTED/RUNNING/COMPLETED/FAILED/REJECTED等
startTime LocalDateTime 开始时间
endTime LocalDateTime 结束时间

前端绘制流程

1. 调用API获取数据

// 使用React示例
const fetchDeployFlowGraph = async (deployRecordId: number) => {
  const response = await fetch(`/api/v1/deploy/records/${deployRecordId}/flow-graph`, {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  });
  const result = await response.json();
  return result.data;
};

2. 绘制流程图

使用流程图库(如 react-flowantv x6mxGraph 等)绘制流程图:

步骤1创建节点映射

// 将nodeInstances转换为Map方便查找
const nodeStatusMap = new Map(
  data.nodeInstances.map(node => [node.nodeId, node])
);

步骤2根据graph.nodes创建节点

const flowNodes = data.graph.nodes.map(node => {
  const nodeInstance = nodeStatusMap.get(node.id);
  const status = nodeInstance?.status || 'NOT_STARTED';
  
  return {
    id: node.id,
    type: mapNodeType(node.nodeType), // 根据节点类型选择不同的节点组件
    position: { x: node.position.x, y: node.position.y },
    data: {
      label: node.nodeName,
      nodeType: node.nodeType,
      status: status, // 节点状态,用于样式标记
      nodeInstance: nodeInstance, // 完整的节点实例信息
      configs: node.configs
    },
    style: getNodeStyle(status) // 根据状态设置样式
  };
});

步骤3根据graph.edges创建边

const flowEdges = data.graph.edges.map(edge => ({
  id: `${edge.source}-${edge.target}`,
  source: edge.source,
  target: edge.target,
  style: getEdgeStyle(edge, nodeStatusMap) // 根据节点状态设置边的样式
}));

3. 节点状态样式映射

// 节点状态颜色映射
const statusColorMap = {
  'NOT_STARTED': '#d9d9d9',      // 灰色 - 未开始
  'RUNNING': '#1890ff',          // 蓝色 - 运行中
  'COMPLETED': '#52c41a',        // 绿色 - 已完成
  'FAILED': '#ff4d4f',           // 红色 - 失败
  'REJECTED': '#ff4d4f',         // 红色 - 审批被拒绝
  'CANCELLED': '#d9d9d9',        // 灰色 - 已取消
  'TERMINATED': '#ff4d4f'        // 红色 - 已终止
};

const getNodeStyle = (status: string) => {
  return {
    background: statusColorMap[status] || '#d9d9d9',
    border: `2px solid ${statusColorMap[status] || '#d9d9d9'}`,
    borderRadius: '8px',
    padding: '10px',
    color: '#fff',
    fontWeight: 'bold'
  };
};

4. 边的状态样式

const getEdgeStyle = (edge: any, nodeStatusMap: Map<string, any>) => {
  const sourceStatus = nodeStatusMap.get(edge.source)?.status || 'NOT_STARTED';
  const targetStatus = nodeStatusMap.get(edge.target)?.status || 'NOT_STARTED';
  
  // 如果源节点已完成,边显示为已完成
  if (sourceStatus === 'COMPLETED') {
    return {
      stroke: '#52c41a',
      strokeWidth: 2
    };
  }
  
  // 如果源节点失败或被拒绝,边显示为失败
  if (sourceStatus === 'FAILED' || sourceStatus === 'REJECTED') {
    return {
      stroke: '#ff4d4f',
      strokeWidth: 2,
      strokeDasharray: '5,5' // 虚线表示流程中断
    };
  }
  
  // 默认样式
  return {
    stroke: '#d9d9d9',
    strokeWidth: 1
  };
};

5. 整体部署状态标记

// 根据deployStatus显示整体状态
const deployStatusMap = {
  'CREATED': { color: '#1890ff', text: '已创建' },
  'PENDING_APPROVAL': { color: '#faad14', text: '待审批' },
  'RUNNING': { color: '#1890ff', text: '运行中' },
  'SUCCESS': { color: '#52c41a', text: '部署成功' },
  'FAILED': { color: '#ff4d4f', text: '部署失败' },
  'REJECTED': { color: '#ff4d4f', text: '审批被拒绝' },
  'CANCELLED': { color: '#d9d9d9', text: '已取消' },
  'TERMINATED': { color: '#ff4d4f', text: '已终止' },
  'PARTIAL_SUCCESS': { color: '#faad14', text: '部分成功' }
};

// 在流程图上方显示整体状态
const statusInfo = deployStatusMap[data.deployStatus];

完整示例React + react-flow

import React, { useEffect, useState } from 'react';
import ReactFlow, { Node, Edge } from 'react-flow-renderer';

interface DeployFlowGraphProps {
  deployRecordId: number;
}

const DeployFlowGraph: React.FC<DeployFlowGraphProps> = ({ deployRecordId }) => {
  const [nodes, setNodes] = useState<Node[]>([]);
  const [edges, setEdges] = useState<Edge[]>([]);
  const [deployStatus, setDeployStatus] = useState<string>('');

  useEffect(() => {
    fetchDeployFlowGraph(deployRecordId).then(data => {
      // 创建节点状态映射
      const nodeStatusMap = new Map(
        data.nodeInstances.map(node => [node.nodeId, node])
      );

      // 创建节点
      const flowNodes = data.graph.nodes.map(node => {
        const nodeInstance = nodeStatusMap.get(node.id);
        const status = nodeInstance?.status || 'NOT_STARTED';
        
        return {
          id: node.id,
          type: 'default',
          position: { x: node.position.x, y: node.position.y },
          data: {
            label: (
              <div>
                <div>{node.nodeName}</div>
                <div style={{ fontSize: '12px', color: getStatusColor(status) }}>
                  {getStatusText(status)}
                </div>
              </div>
            ),
            status: status
          },
          style: {
            background: getStatusColor(status),
            color: '#fff',
            border: `2px solid ${getStatusColor(status)}`,
            borderRadius: '8px',
            padding: '10px',
            width: 150
          }
        };
      });

      // 创建边
      const flowEdges = data.graph.edges.map(edge => ({
        id: `${edge.source}-${edge.target}`,
        source: edge.source,
        target: edge.target,
        style: {
          stroke: getEdgeColor(edge, nodeStatusMap),
          strokeWidth: 2
        }
      }));

      setNodes(flowNodes);
      setEdges(flowEdges);
      setDeployStatus(data.deployStatus);
    });
  }, [deployRecordId]);

  return (
    <div>
      <div style={{ marginBottom: '20px' }}>
        <h3>部署状态:{getDeployStatusText(deployStatus)}</h3>
      </div>
      <ReactFlow nodes={nodes} edges={edges} fitView />
    </div>
  );
};

注意事项

  1. 节点ID匹配graph.nodes 中的 idnodeInstances 中的 nodeId 需要匹配,用于确定每个节点的执行状态。

  2. 未开始的节点:如果某个节点还没有开始执行,nodeInstances 中可能没有对应的记录,或者 statusNOT_STARTEDid 可能为 null

  3. 状态优先级

    • 如果部署状态为 REJECTED,说明审批被拒绝,相关审批节点的状态应该也是 REJECTED
    • 如果部署状态为 PARTIAL_SUCCESS,说明部分节点失败,需要检查哪些节点的状态是 FAILED
  4. 节点位置graph.nodes 中的 position 字段包含了节点在画布上的位置信息x, y坐标直接使用即可。

  5. 边的绘制顺序graph.edges 中的边定义了节点之间的连接关系,按照 sourcetarget 绘制即可。

状态流转示意

CREATED → PENDING_APPROVAL → RUNNING → SUCCESS
                              ↓
                          FAILED/REJECTED
  • CREATED:部署记录已创建,工作流已启动
  • PENDING_APPROVAL:等待审批中
  • RUNNING:审批通过,正在执行部署
  • SUCCESS:部署成功
  • FAILED:部署失败
  • REJECTED:审批被拒绝(终态)
  • CANCELLED:已取消
  • TERMINATED:已终止
  • PARTIAL_SUCCESS:部分成功(工作流完成但存在失败的节点)