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()
后端架构设计说明:
核心模型:
- ComponentType - 组件类型定义
- 定义不同类型的组件(如传感器、执行器、控制器等)
- 包含端口定义、属性模板等
- Flowchart - 流程图
- 流程图的基本信息
- 关联到具体设备
- Component - 组件实例
- 流程图中的具体组件
- 包含位置、属性等信息
- Connection - 连接关系
- 定义组件间的连接
- 支持端口连接和路径数据
主要API接口:
- 流程图管理:
- 创建、更新、删除流程图
- 获取流程图列表和详情
- 组件类型管理:
- 定义和管理组件类型
- 提供给前端组件库使用
- 流程图编辑:
- 添加/删除组件
- 添加/删除连接
- 保存完整流程图状态
前端交互流程:
-
加载流程图:
GET /flowcharts/{id} → 获取完整流程图数据-
**编辑流程图**:
``` POST /flowcharts/{id}/components → 添加组件 POST /flowcharts/{id}/connections → 添加连接 POST /flowcharts/{id}/save → 保存完整状态 ``` -
**组件库**:
GET /component-types → 获取可用组件类型
这个设计支持复杂的流程图编辑需求,可以与前端流程图库(如React Flow、Draw.io等)很好地集成。
-
-
编辑流程图:
POST /flowcharts/{id}/components → 添加组件 POST /flowcharts/{id}/connections → 添加连接 POST /flowcharts/{id}/save → 保存完整状态
- 组件库: 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. 集成的好处
- 开发效率:前端库提供丰富的UI组件和交互,后端专注数据管理
- 用户体验:流畅的拖拽、连线体验
- 扩展性:支持自定义节点类型、复杂连线等高级功能
- 标准化:遵循前端库的数据格式规范
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}
}
存储优势
- 关系完整性:通过外键保证数据一致性
- 灵活扩展:JSON字段支持复杂属性配置
- 版本控制:通过version字段支持流程图版本管理
- 组件复用:ComponentType表支持组件类型复用
- 性能优化:支持索引和高效查询
这样设计既保证了数据的结构化存储,又提供了足够的灵活性来支持复杂的流程图编辑需求。