增加三方接口管理

This commit is contained in:
戚辰先生 2024-12-05 09:34:44 +08:00
parent f52f1bed8b
commit 1d222da2dc
4 changed files with 239 additions and 33 deletions

View File

@ -1,6 +1,6 @@
.container {
width: 100%;
height: 600px;
min-height: 600px;
position: relative;
background: #fff;
border: 1px solid #e8e8e8;
@ -10,7 +10,24 @@
.canvas {
flex: 1;
height: 100%;
min-height: 600px;
position: relative;
overflow: hidden;
background: #fafafa;
}
.canvas::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
linear-gradient(#e8e8e8 1px, transparent 1px),
linear-gradient(90deg, #e8e8e8 1px, transparent 1px);
background-size: 20px 20px;
opacity: 0.5;
}
.configPanel {
@ -18,10 +35,58 @@
height: 100%;
border-left: 1px solid #e8e8e8;
overflow-y: auto;
background: #fff;
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.06);
}
:global(.lf-control) {
position: absolute;
right: 330px;
top: 10px;
display: flex;
gap: 8px;
background: #fff;
padding: 4px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
z-index: 2;
}
:global(.lf-dnd-panel) {
position: absolute;
left: 10px;
top: 10px;
width: 160px;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
padding: 12px;
border-radius: 4px;
display: flex;
flex-direction: column;
gap: 8px;
z-index: 2;
}
:global(.lf-dnd-panel .lf-dnd-item) {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 35px;
border: 1px solid #e8e8e8;
border-radius: 4px;
cursor: grab;
user-select: none;
transition: all 0.3s;
}
:global(.lf-dnd-panel .lf-dnd-item:hover) {
border-color: #1890ff;
color: #1890ff;
}
:global(.lf-dnd-panel .lf-dnd-item img) {
width: 20px;
height: 20px;
margin-right: 8px;
}

View File

@ -1,7 +1,7 @@
import React, { useEffect, useRef, useState } from 'react';
import { Card, Space } from 'antd';
import { Card } from 'antd';
import LogicFlow from '@logicflow/core';
import { DndPanel, SelectionSelect, Control } from '@logicflow/extension';
import { DndPanel, SelectionSelect, Control, Menu } from '@logicflow/extension';
import '@logicflow/core/es/index.css';
import '@logicflow/extension/es/style/index.css';
import styles from './index.module.css';
@ -21,20 +21,95 @@ const FlowDesigner: React.FC<FlowDesignerProps> = ({
const [lf, setLf] = useState<LogicFlow>();
const [selectedNode, setSelectedNode] = useState<any>(null);
useEffect(() => {
if (containerRef.current) {
// 初始化 LogicFlow
// 初始化 LogicFlow
const initLogicFlow = () => {
if (!containerRef.current) {
console.error('Container ref is not ready');
return;
}
try {
// 注册插件
LogicFlow.use(DndPanel);
LogicFlow.use(SelectionSelect);
LogicFlow.use(Control);
LogicFlow.use(Menu);
const logicflow = new LogicFlow({
container: containerRef.current,
grid: true,
plugins: [DndPanel, SelectionSelect, Control]
nodeTextEdit: true,
edgeTextEdit: true,
width: containerRef.current.offsetWidth || 800,
height: containerRef.current.offsetHeight || 600,
style: {
circle: {
r: 30,
stroke: '#000000',
strokeWidth: 1,
},
rect: {
width: 100,
height: 50,
stroke: '#000000',
strokeWidth: 1,
},
diamond: {
rx: 20,
ry: 20,
stroke: '#000000',
strokeWidth: 1,
},
nodeText: {
fontSize: 12,
color: '#000000',
},
edgeText: {
fontSize: 12,
color: '#000000',
background: {
fill: '#FFFFFF',
},
},
},
});
console.log('LogicFlow instance created');
// 注册自定义节点
registerNodes(logicflow);
// 配置拖拽面板
logicflow.setPatternItems([
{
type: 'start',
text: '开始节点',
label: '开始节点',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVDhP7ZQxDsIwDEV7AcZeggOwMXAFJg7BxMgBuAcrZ2DiGuwcgImNA3AFBgaWDhUlqhKnKWFh4EtWaif2s/OdAn8VY8wE13jEHR6wjUu0eIoL7ODBa0zQzlrswQWvcOcLSpzhFu2sxRN0wTZKLnGOT7jgHXZQcoYuOMKvkFZQcoMuKOdTkH4RpBWUdNEFU0idOsE7bnBYEL0gScvnkE5LgS44wA4+UHY5R3vMMtqZxB4+UQZkl+1M4hTf0K7Szjp4wQztrIMXlEFZQUkXL5jBf4KygpIuXjCDsoLyXwQzKCsoSWGwD3Q5p3qCzuvYAAAAAElFTkSuQmCC'
},
{
type: 'task',
text: '任务节点',
label: '任务节点',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAB5SURBVDhP7ZTBCYAwDEU7QkfxZi/eHMGbo3Rwhe7hCB3Bo+kHIZgmTUXQgw8k5Cd5tE34VUSkhw3ucYUTrNBiggUecYsNWkzwCyvc4QMtJviFJZ7wCS0mGIQVnvEFLSb4hRVe8A0tJhiEFd7wAy0m+IUVZmHxPyLZAYNFt+rXusajAAAAAElFTkSuQmCC'
},
{
type: 'gateway',
text: '网关节点',
label: '网关节点',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACxSURBVDhP7ZQxDoMwDEU5AiM34AqMHXqFTj0EE2MP0L1bz8DENeicgYmNA3AFBgaWVrIiRyZRU1VIPPIT2Mb+NlYS8FeJMQ5wjkvc4QYnWKHFU5zjFtdeY4Z21mIHF7zAjS8ocYprtLMWj9AF2yi5wBk+4II32EHJKbrgAL9CWkHJFbqgnE9B+kWQVlDSRRdMIXXqCG+4wn5B9IIkLZ9DOi0FumAfW3hH2eUU7THLaGcSO/gBUb+nujmI/XsAAAAASUVORK5CYII='
},
{
type: 'end',
text: '结束节点',
label: '结束节点',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVDhP7ZQxDsIwDEV7AcZeggOwMXAFJg7BxMgBuAcrZ2DiGuwcgImNA3AFBgaWDhUlqhKnKWFh4EtWaif2s/OdAn8VY8wE13jEHR6wjUu0eIoL7ODBa0zQzlrswQWvcOcLSpzhFu2sxRN0wTZKLnGOT7jgHXZQcoYuOMKvkFZQcoMuKOdTkH4RpBWUdNEFU0idOsE7bnBYEL0gScvnkE5LgS44wA4+UHY5R3vMMtqZxB4+UQZkl+1M4hTf0K7Szjp4wQztrIMXlEFZQUkXL5jBf4KygpIuXjCDsoLyXwQzKCsoSWGwD3Q5p3qCzuvYAAAAAElFTkSuQmCC'
}
]);
// 注册事件
logicflow.on('node:click', ({ data }) => {
console.log('Node clicked:', data);
setSelectedNode(data);
});
@ -42,22 +117,45 @@ const FlowDesigner: React.FC<FlowDesignerProps> = ({
setSelectedNode(null);
});
// 如果有初始值,渲染流程图
logicflow.on('history:change', () => {
const graphData = logicflow.getGraphData();
onChange?.(JSON.stringify(graphData));
});
// 渲染初始数据
if (value) {
try {
const graphData = JSON.parse(value);
logicflow.render(graphData);
console.log('Initial graph data rendered:', graphData);
} catch (error) {
console.error('Failed to parse graph data:', error);
logicflow.render({ nodes: [], edges: [] });
}
} else {
logicflow.render({ nodes: [], edges: [] });
console.log('Empty graph rendered');
}
setLf(logicflow);
console.log('LogicFlow initialization completed');
return () => {
logicflow.destroy();
};
return logicflow;
} catch (error) {
console.error('Failed to initialize LogicFlow:', error);
return null;
}
};
useEffect(() => {
const logicflow = initLogicFlow();
return () => {
if (logicflow) {
console.log('Destroying LogicFlow instance');
logicflow.destroy();
}
};
}, []);
// 处理节点配置更新
@ -74,7 +172,11 @@ const FlowDesigner: React.FC<FlowDesignerProps> = ({
return (
<div className={styles.container}>
<div className={styles.canvas} ref={containerRef} />
<div
className={styles.canvas}
ref={containerRef}
style={{ minHeight: '600px' }}
/>
{selectedNode && (
<div className={styles.configPanel}>
<NodeConfig

View File

@ -1,10 +1,14 @@
import LogicFlow from '@logicflow/core';
import { CircleNode, RectNode, DiamondNode } from '@logicflow/core';
import { CircleNode, CircleNodeModel, RectNode, RectNodeModel, DiamondNode, DiamondNodeModel } from '@logicflow/core';
export function registerNodes(lf: LogicFlow) {
// 开始节点
class StartNode extends CircleNode {
static extendKey = 'StartNode';
class StartNodeModel extends CircleNodeModel {
initNodeData(data: any) {
super.initNodeData(data);
this.r = 30;
}
getNodeStyle() {
const style = super.getNodeStyle();
return {
@ -13,11 +17,22 @@ export function registerNodes(lf: LogicFlow) {
stroke: '#1890FF'
};
}
setAttributes() {
this.text.editable = false;
}
}
class StartNodeView extends CircleNode { }
// 任务节点
class TaskNode extends RectNode {
static extendKey = 'TaskNode';
class TaskNodeModel extends RectNodeModel {
initNodeData(data: any) {
super.initNodeData(data);
this.width = 120;
this.height = 60;
}
getNodeStyle() {
const style = super.getNodeStyle();
return {
@ -28,9 +43,16 @@ export function registerNodes(lf: LogicFlow) {
}
}
class TaskNodeView extends RectNode { }
// 网关节点
class GatewayNode extends DiamondNode {
static extendKey = 'GatewayNode';
class GatewayNodeModel extends DiamondNodeModel {
initNodeData(data: any) {
super.initNodeData(data);
this.rx = 40;
this.ry = 40;
}
getNodeStyle() {
const style = super.getNodeStyle();
return {
@ -41,9 +63,15 @@ export function registerNodes(lf: LogicFlow) {
}
}
class GatewayNodeView extends DiamondNode { }
// 结束节点
class EndNode extends CircleNode {
static extendKey = 'EndNode';
class EndNodeModel extends CircleNodeModel {
initNodeData(data: any) {
super.initNodeData(data);
this.r = 30;
}
getNodeStyle() {
const style = super.getNodeStyle();
return {
@ -52,30 +80,39 @@ export function registerNodes(lf: LogicFlow) {
stroke: '#FF4D4F'
};
}
setAttributes() {
this.text.editable = false;
}
}
class EndNodeView extends CircleNode { }
// 注册节点
lf.register({
type: 'start',
view: StartNode,
model: StartNode
view: StartNodeView,
model: StartNodeModel
});
lf.register({
type: 'task',
view: TaskNode,
model: TaskNode
view: TaskNodeView,
model: TaskNodeModel
});
lf.register({
type: 'gateway',
view: GatewayNode,
model: GatewayNode
view: GatewayNodeView,
model: GatewayNodeModel
});
lf.register({
type: 'end',
view: EndNode,
model: EndNode
view: EndNodeView,
model: EndNodeModel
});
// 设置默认连线类型
lf.setDefaultEdgeType('polyline');
}

View File

@ -1,7 +1,6 @@
import React, { useState } from 'react';
import { Card, Tabs } from 'antd';
import type { TabsProps } from 'antd';
import FormRender from 'form-render';
import { Card } from 'antd';
import FormRender, { useForm } from 'form-render';
interface FormDesignerProps {
value?: string;
@ -32,6 +31,8 @@ const FormDesigner: React.FC<FormDesignerProps> = ({
}
});
const form = useForm();
const handleSubmit = (formData: any) => {
console.log('Form data:', formData);
};
@ -44,6 +45,7 @@ const FormDesigner: React.FC<FormDesignerProps> = ({
<div style={{ padding: 24 }}>
<Card title="表单预览">
<FormRender
form={form}
schema={schema}
onFinish={handleSubmit}
onValidate={handleValidate}