流程图编辑

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. 性能优化:支持索引和高效查询

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

相关推荐
heartbeat..4 小时前
Java List 完全指南:从接口特性到四大实现类深度解析
java·list
韩立学长4 小时前
【开题答辩实录分享】以《智慧酒店管理——手机预订和住宿管理》为例进行选题答辩实录分享
android·java·后端
何中应4 小时前
【面试题-8】Spring/Spring MVC/Spring Boot/Spring Cloud
java·spring boot·后端·spring·mvc·面试题
坐不住的爱码4 小时前
mybatis-动态sql语句-<foreach>
java·sql·mybatis
while(1){yan}4 小时前
HTTP的数据报格式
java·开发语言·网络·网络协议·http·青少年编程·面试
ID_180079054734 小时前
淘宝关键词搜索 API 系列 数据返回参考(附解析与实战)
java·服务器·前端
Neolnfra4 小时前
SMB、FTP、MySQL... 配置不当,即是漏洞
linux·数据库·mysql·安全·网络安全·系统安全·安全架构
雷神乐乐4 小时前
Mysql数据泵导入导出数据
数据库·oracle
摇滚侠4 小时前
Redis 零基础到进阶,Redis 持久化,RDB,AOF,RDB AOF 混合,笔记 28-46
数据库·redis·笔记