流程图编辑

python 复制代码
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Text, ForeignKey, Float, JSON
from sqlalchemy.orm import relationship

Base = declarative_base()


# ... existing models ...

class ComponentType(Base):
    """组件类型定义"""
    __tablename__ = 'component_type'

    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False, comment='组件类型名称')
    category = Column(String(50), nullable=False, comment='组件分类')
    icon = Column(String(255), nullable=True, comment='组件图标')
    properties_template = Column(JSON, nullable=True, comment='属性模板')
    input_ports = Column(JSON, nullable=True, comment='输入端口定义')
    output_ports = Column(JSON, nullable=True, comment='输出端口定义')


class Flowchart(Base):
    """流程图"""
    __tablename__ = 'flowchart'

    id = Column(Integer, primary_key=True)
    name = Column(String(200), nullable=False, comment='流程图名称')
    description = Column(Text, nullable=True, comment='流程图描述')
    device_id = Column(String(50), ForeignKey('device_tree.device_id'), nullable=False, comment='关联设备ID')
    version = Column(String(20), nullable=False, default='1.0', comment='版本号')
    created_at = Column(String(20), nullable=False, comment='创建时间')
    updated_at = Column(String(20), nullable=False, comment='更新时间')

    # 关系
    device = relationship('DeviceTree', backref='flowcharts')
    components = relationship('Component', back_populates='flowchart', cascade='all, delete-orphan')
    connections = relationship('Connection', back_populates='flowchart', cascade='all, delete-orphan')


class Component(Base):
    """流程图组件(节点)"""
    __tablename__ = 'component'

    id = Column(Integer, primary_key=True)
    flowchart_id = Column(Integer, ForeignKey('flowchart.id'), nullable=False)
    component_type_id = Column(Integer, ForeignKey('component_type.id'), nullable=False)

    # 位置信息
    x = Column(Float, nullable=False, default=0.0, comment='X坐标')
    y = Column(Float, nullable=False, default=0.0, comment='Y坐标')

    # 组件属性
    label = Column(String(200), nullable=True, comment='组件标签')
    properties = Column(JSON, nullable=True, comment='组件属性配置')

    # 关系
    flowchart = relationship('Flowchart', back_populates='components')
    component_type = relationship('ComponentType', backref='components')
    source_connections = relationship('Connection', back_populates='source_component',
                                      foreign_keys='Connection.source_component_id')
    target_connections = relationship('Connection', back_populates='target_component',
                                      foreign_keys='Connection.target_component_id')


class Connection(Base):
    """组件连接(边)"""
    __tablename__ = 'connection'

    id = Column(Integer, primary_key=True)
    flowchart_id = Column(Integer, ForeignKey('flowchart.id'), nullable=False)

    # 连接的起点和终点
    source_component_id = Column(Integer, ForeignKey('component.id'), nullable=False)
    target_component_id = Column(Integer, ForeignKey('component.id'), nullable=False)
    source_port = Column(String(100), nullable=True, comment='源端口')
    target_port = Column(String(100), nullable=True, comment='目标端口')

    # 连接属性
    label = Column(String(200), nullable=True, comment='连接标签')
    properties = Column(JSON, nullable=True, comment='连接属性')

    # 路径信息(用于绘制贝塞尔曲线等)
    path_data = Column(JSON, nullable=True, comment='路径数据')

    # 关系
    flowchart = relationship('Flowchart', back_populates='connections')
    source_component = relationship('Component', back_populates='source_connections',
                                    foreign_keys=[source_component_id])
    target_component = relationship('Component', back_populates='target_connections',
                                    foreign_keys=[target_component_id])
python 复制代码
from flask import Blueprint, request, jsonify
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import Flowchart, Component, Connection, ComponentType, DeviceTree
from datetime import datetime

flowchart_bp = Blueprint('flowchart', __name__)

# 数据库配置
DATABASE_URL = "sqlite:///devices.db"
engine = create_engine(DATABASE_URL, echo=True)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

def get_db():
    db = SessionLocal()
    try:
        return db
    finally:
        db.close()

# ==================== 流程图 CRUD ====================

@flowchart_bp.route('/flowcharts', methods=['GET'])
def get_flowcharts():
    """获取所有流程图"""
    db = get_db()
    try:
        flowcharts = db.query(Flowchart).all()
        return jsonify([{
            'id': f.id,
            'name': f.name,
            'description': f.description,
            'device_id': f.device_id,
            'version': f.version,
            'created_at': f.created_at,
            'updated_at': f.updated_at
        } for f in flowcharts])
    finally:
        db.close()

@flowchart_bp.route('/flowcharts/<int:flowchart_id>', methods=['GET'])
def get_flowchart(flowchart_id):
    """获取单个流程图(完整数据)"""
    db = get_db()
    try:
        flowchart = db.query(Flowchart).filter(Flowchart.id == flowchart_id).first()
        if not flowchart:
            return jsonify({'error': 'Flowchart not found'}), 404
        
        # 获取组件
        components = []
        for comp in flowchart.components:
            components.append({
                'id': comp.id,
                'component_type_id': comp.component_type_id,
                'x': comp.x,
                'y': comp.y,
                'label': comp.label,
                'properties': comp.properties,
                'component_type': {
                    'name': comp.component_type.name,
                    'category': comp.component_type.category,
                    'icon': comp.component_type.icon,
                    'input_ports': comp.component_type.input_ports,
                    'output_ports': comp.component_type.output_ports
                }
            })
        
        # 获取连接
        connections = []
        for conn in flowchart.connections:
            connections.append({
                'id': conn.id,
                'source_component_id': conn.source_component_id,
                'target_component_id': conn.target_component_id,
                'source_port': conn.source_port,
                'target_port': conn.target_port,
                'label': conn.label,
                'properties': conn.properties,
                'path_data': conn.path_data
            })
        
        return jsonify({
            'flowchart': {
                'id': flowchart.id,
                'name': flowchart.name,
                'description': flowchart.description,
                'device_id': flowchart.device_id,
                'version': flowchart.version,
                'created_at': flowchart.created_at,
                'updated_at': flowchart.updated_at
            },
            'components': components,
            'connections': connections
        })
    finally:
        db.close()

@flowchart_bp.route('/flowcharts', methods=['POST'])
def create_flowchart():
    """创建流程图"""
    data = request.json
    db = get_db()
    try:
        # 验证设备是否存在
        device = db.query(DeviceTree).filter(DeviceTree.device_id == data['device_id']).first()
        if not device:
            return jsonify({'error': 'Device not found'}), 404
        
        now = datetime.now().isoformat()
        flowchart = Flowchart(
            name=data['name'],
            description=data.get('description'),
            device_id=data['device_id'],
            version=data.get('version', '1.0'),
            created_at=now,
            updated_at=now
        )
        db.add(flowchart)
        db.commit()
        return jsonify({
            'id': flowchart.id,
            'name': flowchart.name,
            'description': flowchart.description,
            'device_id': flowchart.device_id,
            'version': flowchart.version,
            'created_at': flowchart.created_at,
            'updated_at': flowchart.updated_at
        }), 201
    except Exception as e:
        db.rollback()
        return jsonify({'error': str(e)}), 400
    finally:
        db.close()

@flowchart_bp.route('/flowcharts/<int:flowchart_id>', methods=['PUT'])
def update_flowchart(flowchart_id):
    """更新流程图"""
    data = request.json
    db = get_db()
    try:
        flowchart = db.query(Flowchart).filter(Flowchart.id == flowchart_id).first()
        if not flowchart:
            return jsonify({'error': 'Flowchart not found'}), 404
        
        flowchart.name = data.get('name', flowchart.name)
        flowchart.description = data.get('description', flowchart.description)
        flowchart.version = data.get('version', flowchart.version)
        flowchart.updated_at = datetime.now().isoformat()
        
        db.commit()
        return jsonify({
            'id': flowchart.id,
            'name': flowchart.name,
            'description': flowchart.description,
            'device_id': flowchart.device_id,
            'version': flowchart.version,
            'created_at': flowchart.created_at,
            'updated_at': flowchart.updated_at
        })
    except Exception as e:
        db.rollback()
        return jsonify({'error': str(e)}), 400
    finally:
        db.close()

@flowchart_bp.route('/flowcharts/<int:flowchart_id>', methods=['DELETE'])
def delete_flowchart(flowchart_id):
    """删除流程图"""
    db = get_db()
    try:
        flowchart = db.query(Flowchart).filter(Flowchart.id == flowchart_id).first()
        if not flowchart:
            return jsonify({'error': 'Flowchart not found'}), 404
        
        db.delete(flowchart)
        db.commit()
        return jsonify({'message': 'Flowchart deleted'})
    except Exception as e:
        db.rollback()
        return jsonify({'error': str(e)}), 400
    finally:
        db.close()

# ==================== 组件类型管理 ====================

@flowchart_bp.route('/component-types', methods=['GET'])
def get_component_types():
    """获取所有组件类型"""
    db = get_db()
    try:
        types = db.query(ComponentType).all()
        return jsonify([{
            'id': t.id,
            'name': t.name,
            'category': t.category,
            'icon': t.icon,
            'properties_template': t.properties_template,
            'input_ports': t.input_ports,
            'output_ports': t.output_ports
        } for t in types])
    finally:
        db.close()

@flowchart_bp.route('/component-types', methods=['POST'])
def create_component_type():
    """创建组件类型"""
    data = request.json
    db = get_db()
    try:
        component_type = ComponentType(
            name=data['name'],
            category=data['category'],
            icon=data.get('icon'),
            properties_template=data.get('properties_template'),
            input_ports=data.get('input_ports'),
            output_ports=data.get('output_ports')
        )
        db.add(component_type)
        db.commit()
        return jsonify({
            'id': component_type.id,
            'name': component_type.name,
            'category': component_type.category,
            'icon': component_type.icon,
            'properties_template': component_type.properties_template,
            'input_ports': component_type.input_ports,
            'output_ports': component_type.output_ports
        }), 201
    except Exception as e:
        db.rollback()
        return jsonify({'error': str(e)}), 400
    finally:
        db.close()

# ==================== 组件和连接操作 ====================

@flowchart_bp.route('/flowcharts/<int:flowchart_id>/components', methods=['POST'])
def add_component(flowchart_id):
    """添加组件到流程图"""
    data = request.json
    db = get_db()
    try:
        # 验证流程图是否存在
        flowchart = db.query(Flowchart).filter(Flowchart.id == flowchart_id).first()
        if not flowchart:
            return jsonify({'error': 'Flowchart not found'}), 404
        
        # 验证组件类型是否存在
        component_type = db.query(ComponentType).filter(ComponentType.id == data['component_type_id']).first()
        if not component_type:
            return jsonify({'error': 'Component type not found'}), 404
        
        component = Component(
            flowchart_id=flowchart_id,
            component_type_id=data['component_type_id'],
            x=data.get('x', 0.0),
            y=data.get('y', 0.0),
            label=data.get('label'),
            properties=data.get('properties')
        )
        db.add(component)
        db.commit()
        
        return jsonify({
            'id': component.id,
            'flowchart_id': component.flowchart_id,
            'component_type_id': component.component_type_id,
            'x': component.x,
            'y': component.y,
            'label': component.label,
            'properties': component.properties
        }), 201
    except Exception as e:
        db.rollback()
        return jsonify({'error': str(e)}), 400
    finally:
        db.close()

@flowchart_bp.route('/flowcharts/<int:flowchart_id>/connections', methods=['POST'])
def add_connection(flowchart_id):
    """添加连接到流程图"""
    data = request.json
    db = get_db()
    try:
        # 验证流程图是否存在
        flowchart = db.query(Flowchart).filter(Flowchart.id == flowchart_id).first()
        if not flowchart:
            return jsonify({'error': 'Flowchart not found'}), 404
        
        # 验证组件是否存在且属于该流程图
        source_comp = db.query(Component).filter(
            Component.id == data['source_component_id'],
            Component.flowchart_id == flowchart_id
        ).first()
        target_comp = db.query(Component).filter(
            Component.id == data['target_component_id'],
            Component.flowchart_id == flowchart_id
        ).first()
        
        if not source_comp or not target_comp:
            return jsonify({'error': 'Component not found in flowchart'}), 404
        
        connection = Connection(
            flowchart_id=flowchart_id,
            source_component_id=data['source_component_id'],
            target_component_id=data['target_component_id'],
            source_port=data.get('source_port'),
            target_port=data.get('target_port'),
            label=data.get('label'),
            properties=data.get('properties'),
            path_data=data.get('path_data')
        )
        db.add(connection)
        db.commit()
        
        return jsonify({
            'id': connection.id,
            'flowchart_id': connection.flowchart_id,
            'source_component_id': connection.source_component_id,
            'target_component_id': connection.target_component_id,
            'source_port': connection.source_port,
            'target_port': connection.target_port,
            'label': connection.label,
            'properties': connection.properties,
            'path_data': connection.path_data
        }), 201
    except Exception as e:
        db.rollback()
        return jsonify({'error': str(e)}), 400
    finally:
        db.close()

@flowchart_bp.route('/flowcharts/<int:flowchart_id>/save', methods=['POST'])
def save_flowchart(flowchart_id):
    """保存完整流程图状态"""
    data = request.json
    db = get_db()
    try:
        flowchart = db.query(Flowchart).filter(Flowchart.id == flowchart_id).first()
        if not flowchart:
            return jsonify({'error': 'Flowchart not found'}), 404
        
        # 更新流程图基本信息
        if 'flowchart' in data:
            flowchart_info = data['flowchart']
            flowchart.name = flowchart_info.get('name', flowchart.name)
            flowchart.description = flowchart_info.get('description', flowchart.description)
            flowchart.version = flowchart_info.get('version', flowchart.version)
            flowchart.updated_at = datetime.now().isoformat()
        
        # 删除现有的组件和连接
        db.query(Component).filter(Component.flowchart_id == flowchart_id).delete()
        db.query(Connection).filter(Connection.flowchart_id == flowchart_id).delete()
        
        # 添加新的组件
        if 'components' in data:
            for comp_data in data['components']:
                component = Component(
                    flowchart_id=flowchart_id,
                    component_type_id=comp_data['component_type_id'],
                    x=comp_data.get('x', 0.0),
                    y=comp_data.get('y', 0.0),
                    label=comp_data.get('label'),
                    properties=comp_data.get('properties')
                )
                db.add(component)
        
        # 添加新的连接
        if 'connections' in data:
            for conn_data in data['connections']:
                connection = Connection(
                    flowchart_id=flowchart_id,
                    source_component_id=conn_data['source_component_id'],
                    target_component_id=conn_data['target_component_id'],
                    source_port=conn_data.get('source_port'),
                    target_port=conn_data.get('target_port'),
                    label=conn_data.get('label'),
                    properties=conn_data.get('properties'),
                    path_data=conn_data.get('path_data')
                )
                db.add(connection)
        
        db.commit()
        return jsonify({'message': 'Flowchart saved successfully'})
    except Exception as e:
        db.rollback()
        return jsonify({'error': str(e)}), 400
    finally:
        db.close()

后端架构设计说明:

核心模型:

  1. ComponentType - 组件类型定义
  • 定义不同类型的组件(如传感器、执行器、控制器等)
  • 包含端口定义、属性模板等
  1. Flowchart - 流程图
  • 流程图的基本信息
  • 关联到具体设备
  1. Component - 组件实例
  • 流程图中的具体组件
  • 包含位置、属性等信息
  1. Connection - 连接关系
  • 定义组件间的连接
  • 支持端口连接和路径数据

主要API接口:

  1. 流程图管理:
  • 创建、更新、删除流程图
  • 获取流程图列表和详情
  1. 组件类型管理:
  • 定义和管理组件类型
  • 提供给前端组件库使用
  1. 流程图编辑:
  • 添加/删除组件
  • 添加/删除连接
  • 保存完整流程图状态

前端交互流程:

  1. 加载流程图:

    复制代码
       GET /flowcharts/{id} → 获取完整流程图数据
    1. **编辑流程图**:

      复制代码
      ```
      
      POST /flowcharts/{id}/components → 添加组件
      
      POST /flowcharts/{id}/connections → 添加连接
      
      POST /flowcharts/{id}/save → 保存完整状态
      
      ```
    2. **组件库**:

      复制代码
      GET /component-types → 获取可用组件类型

    这个设计支持复杂的流程图编辑需求,可以与前端流程图库(如React Flow、Draw.io等)很好地集成。

  1. 编辑流程图:

    复制代码
       POST /flowcharts/{id}/components → 添加组件
    
       POST /flowcharts/{id}/connections → 添加连接
    
       POST /flowcharts/{id}/save → 保存完整状态
  1. 组件库: GET /component-types → 获取可用组件

这个设计支持复杂的流程图编辑需求,可以与前端流程图库(如React Flow、Draw.io等)很好地集成。

与前端流程图库集成的含义

"可以与前端流程图库很好地集成"意味着后端API设计能够无缝配合前端流程图编辑器的操作需求。让我详细解释这个概念:

1. 前端流程图库的基本功能

前端流程图库(如React Flow、Draw.io)通常提供:

  • 拖拽创建节点:从组件库拖拽组件到画布
  • 连线功能:在节点间创建连接
  • 节点属性编辑:配置节点的属性
  • 画布操作:缩放、平移、选择等
  • 实时同步:编辑时实时保存状态

2. 后端数据格式适配

后端需要提供的数据结构要与前端库兼容:

React Flow 数据格式示例:
复制代码
// React Flow 期望的数据格式

const flowData = {

  nodes: [

    {

      id: '1',

      type: 'customNode',

      position: { x: 100, y: 100 },

      data: { label: '传感器', properties: {...} }

    }

  ],

  edges: [

    {

      id: 'e1-2',

      source: '1',

      target: '2',

      sourceHandle: 'output1',

      targetHandle: 'input1'

    }

  ]

}
后端对应的数据转换:

// 后端数据 → 前端格式

复制代码
function convertToReactFlow(backendData) {

  return {

    nodes: backendData.components.map(comp => ({

      id: comp.id.toString(),

      type: comp.component_type.category, // 映射到前端节点类型

      position: { x: comp.x, y: comp.y },

      data: {

        label: comp.label,

        properties: comp.properties,

        componentType: comp.component_type

      }

    })),

    edges: backendData.connections.map(conn => ({

      id: `e${conn.source_component_id}-${conn.target_component_id}`,

      source: conn.source_component_id.toString(),

      target: conn.target_component_id.toString(),

      sourceHandle: conn.source_port,

      targetHandle: conn.target_port,

      data: {

        label: conn.label,

        path_data: conn.path_data

      }

    }))

  }

}

3. API接口配合前端操作

实时保存策略:
复制代码
// 前端编辑时实时调用API

const onNodesChange = (changes) => {

  // 批量更新节点位置

  fetch(`/api/flowcharts/${flowchartId}/components/batch-update`, {

    method: 'PUT',

    body: JSON.stringify(changes)

  })

}

const onConnect = (connection) => {

  // 创建新连接

  fetch(`/api/flowcharts/${flowchartId}/connections`, {

    method: 'POST',

    body: JSON.stringify(connection)

  })

}
增量更新 vs 全量保存:
  • 增量更新:每次操作单独保存(适合实时协作)
  • 全量保存:编辑完成后一次性保存整个流程图

4. 实际集成示例

前端代码示例(React Flow):
复制代码
import ReactFlow, { MiniMap, Controls, Background } from 'react-flow-renderer';

function FlowchartEditor({ flowchartId }) {

  const [nodes, setNodes] = useState([]);

  const [edges, setEdges] = useState([]);

  // 加载流程图数据

  useEffect(() => {

    fetch(`/api/flowcharts/${flowchartId}`)

      .then(res => res.json())

      .then(data => {

        const flowData = convertToReactFlow(data);

        setNodes(flowData.nodes);

        setEdges(flowData.edges);

      });

  }, [flowchartId]);

  // 保存流程图

  const saveFlowchart = () => {

    const backendData = convertToBackend({ nodes, edges });

    fetch(`/api/flowcharts/${flowchartId}/save`, {

      method: 'POST',

      body: JSON.stringify(backendData)

    });

  };

  return (

    <div style={{ height: 600 }}>

      <ReactFlow

        nodes={nodes}

        edges={edges}

        onNodesChange={setNodes}

        onEdgesChange={setEdges}

        onConnect={onConnect}

        onNodeDragStop={onNodeDragStop}

      >

        <MiniMap />

        <Controls />

        <Background />

      </ReactFlow>

      <button onClick={saveFlowchart}>保存</button>

    </div>

  );

}

5. 集成的好处

  1. 开发效率:前端库提供丰富的UI组件和交互,后端专注数据管理
  1. 用户体验:流畅的拖拽、连线体验
  1. 扩展性:支持自定义节点类型、复杂连线等高级功能
  1. 标准化:遵循前端库的数据格式规范

6. 数据映射关系

前端概念 后端模型 说明
Node Component 流程图中的组件实例
Edge Connection 组件间的连接线
Node Type ComponentType 组件的类型定义
Position x, y 坐标 组件在画布上的位置
Handles Ports 连接的锚点

通过这样的设计,后端API能够完美配合前端流程图库的各种操作,提供流畅的编辑体验。

1. 获取流程图列表

GET /flowcharts

响应示例:

复制代码
[

  {

    "id": 1,

    "name": "生产线流程图",

    "description": "设备A的生产流程",

    "device_id": "device_001",

    "version": "1.0",

    "created_at": "2024-01-01T10:00:00",

    "updated_at": "2024-01-01T10:00:00"

  }

]

2. 获取单个流程图的完整数据

GET /flowcharts/{flowchart_id}

响应示例:

复制代码
{

  "flowchart": {

    "id": 1,

    "name": "生产线流程图",

    "description": "设备A的生产流程",

    "device_id": "device_001",

    "version": "1.0",

    "created_at": "2024-01-01T10:00:00",

    "updated_at": "2024-01-01T10:00:00"

  },

  "components": [

    {

      "id": 1,

      "component_type_id": 1,

      "x": 100.0,

      "y": 50.0,

      "label": "传感器1",

      "properties": {"threshold": 50},

      "component_type": {

        "name": "传感器",

        "category": "input",

        "icon": "sensor.png",

        "input_ports": [],

        "output_ports": ["output1"]

      }

    }

  ],

  "connections": [

    {

      "id": 1,

      "source_component_id": 1,

      "target_component_id": 2,

      "source_port": "output1",

      "target_port": "input1",

      "label": "数据流",

      "properties": {},

      "path_data": null

    }

  ]

}

3. 获取特定设备的流程图

GET /devices/{device_id}/flowcharts

响应示例:

复制代码
[

  {

    "id": 1,

    "name": "控制流程图",

    "description": "设备控制逻辑",

    "version": "1.0"

  },

  {

    "id": 2,

    "name": "监控流程图",

    "description": "设备监控界面",

    "version": "1.0"

  }

]

4. 前端集成示例

使用Fetch API:

// 获取流程图列表

复制代码
async function getFlowcharts() {

  try {

    const response = await fetch('/flowcharts');

    const flowcharts = await response.json();

    return flowcharts;

  } catch (error) {

    console.error('获取流程图列表失败:', error);

  }

}

// 获取单个流程图

async function getFlowchart(flowchartId) {

  try {

    const response = await fetch(`/flowcharts/${flowchartId}`);

    const flowchartData = await response.json();

    return flowchartData;

  } catch (error) {

    console.error('获取流程图失败:', error);

  }

}

React Hooks示例:

复制代码
import { useState, useEffect } from 'react';

function useFlowchart(flowchartId) {

  const [flowchart, setFlowchart] = useState(null);

  const [loading, setLoading] = useState(true);

  const [error, setError] = useState(null);

  useEffect(() => {

    async function fetchFlowchart() {

      try {

        setLoading(true);

        const response = await fetch(`/flowcharts/${flowchartId}`);

        if (!response.ok) {

          throw new Error('获取流程图失败');

        }

        const data = await response.json();

        setFlowchart(data);

      } catch (err) {

        setError(err.message);

      } finally {

        setLoading(false);

      }

    }

    if (flowchartId) {

      fetchFlowchart();

    }

  }, [flowchartId]);

  return { flowchart, loading, error };

}

// 使用示例

function FlowchartViewer({ flowchartId }) {

  const { flowchart, loading, error } = useFlowchart(flowchartId);

  if (loading) return <div>加载中...</div>;

  if (error) return <div>错误: {error}</div>;

  if (!flowchart) return <div>未找到流程图</div>;

  return (

    <div>

      <h2>{flowchart.flowchart.name}</h2>

      <p>组件数量: {flowchart.components.length}</p>

      <p>连接数量: {flowchart.connections.length}</p>

    </div>

  );

}

5. 数据转换到前端格式

获取到后端数据后,通常需要转换为前端流程图库需要的格式:

// 转换为React Flow格式

复制代码
function convertToReactFlow(backendData) {

  const nodes = backendData.components.map(comp => ({

    id: comp.id.toString(),

    type: comp.component_type.category, // 或自定义类型

    position: { x: comp.x, y: comp.y },

    data: {

      label: comp.label,

      properties: comp.properties,

      componentType: comp.component_type

    }

  }));

  const edges = backendData.connections.map(conn => ({

    id: `e${conn.source_component_id}-${conn.target_component_id}`,

    source: conn.source_component_id.toString(),

    target: conn.target_component_id.toString(),

    sourceHandle: conn.source_port,

    targetHandle: conn.target_port,

    label: conn.label,

    data: conn.properties

  }));

  return { nodes, edges };

}

6. 查询参数支持

可以添加查询参数来筛选流程图:

GET /flowcharts?device_id=device_001&version=1.0

GET /flowcharts?limit=10&offset=0

GET /flowcharts?search=生产线

这样就可以灵活地获取需要的流程图数据了。

数据库中流程图内容的记录方式

流程图的内容在数据库中通过关系型数据结构进行存储,主要涉及以下几个表:

1. Flowchart 表 - 流程图基本信息

复制代码
CREATE TABLE flowchart (

    id INTEGER PRIMARY KEY,

    name VARCHAR(200) NOT NULL,           -- 流程图名称

    description TEXT,                     -- 描述

    device_id VARCHAR(50) NOT NULL,       -- 关联的设备ID

    version VARCHAR(20) NOT NULL,         -- 版本号

    created_at VARCHAR(20) NOT NULL,      -- 创建时间

    updated_at VARCHAR(20) NOT NULL       -- 更新时间

);

2. Component 表 - 流程图中的组件(节点)

复制代码
CREATE TABLE component (

    id INTEGER PRIMARY KEY,

    flowchart_id INTEGER NOT NULL,        -- 所属流程图ID

    component_type_id INTEGER NOT NULL,   -- 组件类型ID

    x FLOAT NOT NULL DEFAULT 0.0,         -- X坐标

    y FLOAT NOT NULL DEFAULT 0.0,         -- Y坐标

    label VARCHAR(200),                   -- 组件标签

    properties JSON,                      -- 组件属性(JSON格式)

    FOREIGN KEY (flowchart_id) REFERENCES flowchart(id),

    FOREIGN KEY (component_type_id) REFERENCES component_type(id)

);

3. Connection 表 - 组件间的连接(边)

复制代码
CREATE TABLE connection (

    id INTEGER PRIMARY KEY,

    flowchart_id INTEGER NOT NULL,        -- 所属流程图ID

    source_component_id INTEGER NOT NULL, -- 源组件ID

    target_component_id INTEGER NOT NULL, -- 目标组件ID

    source_port VARCHAR(100),             -- 源端口

    target_port VARCHAR(100),             -- 目标端口

    label VARCHAR(200),                   -- 连接标签

    properties JSON,                      -- 连接属性

    path_data JSON,                       -- 路径数据(用于绘制曲线)

    FOREIGN KEY (flowchart_id) REFERENCES flowchart(id),

    FOREIGN KEY (source_component_id) REFERENCES component(id),

    FOREIGN KEY (target_component_id) REFERENCES component(id)

);

4. ComponentType 表 - 组件类型定义

复制代码
CREATE TABLE component_type (

    id INTEGER PRIMARY KEY,

    name VARCHAR(100) NOT NULL,           -- 类型名称

    category VARCHAR(50) NOT NULL,        -- 分类

    icon VARCHAR(255),                    -- 图标

    properties_template JSON,             -- 属性模板

    input_ports JSON,                     -- 输入端口定义

    output_ports JSON                      -- 输出端口定义

);

数据关系图

Flowchart (1) ──── (N) Component

│ │

│ │

└─── (N) Connection ───┘

存储示例

假设有一个简单的流程图,包含一个传感器和一个控制器:

流程图记录:

INSERT INTO flowchart VALUES (1, '控制流程图', '传感器到控制器', 'device_001', '1.0', '2024-01-01T10:00:00', '2024-01-01T10:00:00');

组件记录:

-- 传感器组件

INSERT INTO component VALUES (1, 1, 1, 100.0, 50.0, '温度传感器', '{"threshold": 50, "unit": "°C"}');

-- 控制器组件

INSERT INTO component VALUES (2, 1, 2, 300.0, 50.0, 'PID控制器', '{"kp": 1.0, "ki": 0.1, "kd": 0.05}');

连接记录:

-- 传感器连接到控制器

INSERT INTO connection VALUES (1, 1, 1, 2, 'output1', 'input1', '温度信号', '{}', '{"type": "bezier"}');

数据查询方式

获取完整流程图:

复制代码
SELECT * FROM flowchart WHERE id = 1;

SELECT c.*, ct.name, ct.category, ct.icon, ct.input_ports, ct.output_ports

FROM component c

JOIN component_type ct ON c.component_type_id = ct.id

WHERE c.flowchart_id = 1;

SELECT * FROM connection WHERE flowchart_id = 1;

JSON字段存储的内容:

复制代码
Component.properties 示例:

{

  "threshold": 50,

  "unit": "°C",

  "alarm_enabled": true,

  "calibration_offset": 2.5

}



Connection.path_data 示例:

{

  "type": "bezier",

  "controlPoints": [

    {"x": 150, "y": 50},

    {"x": 250, "y": 50}

  ]

}

ComponentType.properties_template 示例:

复制代码
{

  "threshold": {"type": "number", "default": 0, "min": -100, "max": 100},

  "unit": {"type": "select", "options": ["°C", "°F", "K"]},

  "alarm_enabled": {"type": "boolean", "default": false}

}

存储优势

  1. 关系完整性:通过外键保证数据一致性
  1. 灵活扩展:JSON字段支持复杂属性配置
  1. 版本控制:通过version字段支持流程图版本管理
  1. 组件复用:ComponentType表支持组件类型复用
  1. 性能优化:支持索引和高效查询

这样设计既保证了数据的结构化存储,又提供了足够的灵活性来支持复杂的流程图编辑需求。

相关推荐
大数据新鸟1 天前
操作系统之虚拟内存
java·服务器·网络
Tong Z1 天前
常见的限流算法和实现原理
java·开发语言
凭君语未可1 天前
Java 中的实现类是什么
java·开发语言
He少年1 天前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python
迷枫7121 天前
达梦数据库的体系架构
数据库·oracle·架构
克里斯蒂亚诺更新1 天前
myeclipse的pojie
java·ide·myeclipse
迷藏4941 天前
**eBPF实战进阶:从零构建网络流量监控与过滤系统**在现代云原生架构中,**网络可观测性**和**安全隔离**已成为
java·网络·python·云原生·架构
迷藏4941 天前
**发散创新:基于Solid协议的Web3.0去中心化身份认证系统实战解析**在Web3.
java·python·web3·去中心化·区块链
qq_433502181 天前
Codex cli 飞书文档创建进阶实用命令 + Skill 创建&使用 小白完整教程
java·前端·飞书
夜晚打字声1 天前
9(九)Jmeter如何连接数据库
数据库·jmeter·oracle