增加三方接口管理
This commit is contained in:
parent
f52f1bed8b
commit
1d222da2dc
@ -1,6 +1,6 @@
|
|||||||
.container {
|
.container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 600px;
|
min-height: 600px;
|
||||||
position: relative;
|
position: relative;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border: 1px solid #e8e8e8;
|
border: 1px solid #e8e8e8;
|
||||||
@ -10,7 +10,24 @@
|
|||||||
|
|
||||||
.canvas {
|
.canvas {
|
||||||
flex: 1;
|
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 {
|
.configPanel {
|
||||||
@ -18,10 +35,58 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
border-left: 1px solid #e8e8e8;
|
border-left: 1px solid #e8e8e8;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.lf-control) {
|
:global(.lf-control) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 330px;
|
right: 330px;
|
||||||
top: 10px;
|
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;
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { Card, Space } from 'antd';
|
import { Card } from 'antd';
|
||||||
import LogicFlow from '@logicflow/core';
|
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/core/es/index.css';
|
||||||
import '@logicflow/extension/es/style/index.css';
|
import '@logicflow/extension/es/style/index.css';
|
||||||
import styles from './index.module.css';
|
import styles from './index.module.css';
|
||||||
@ -21,20 +21,95 @@ const FlowDesigner: React.FC<FlowDesignerProps> = ({
|
|||||||
const [lf, setLf] = useState<LogicFlow>();
|
const [lf, setLf] = useState<LogicFlow>();
|
||||||
const [selectedNode, setSelectedNode] = useState<any>(null);
|
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({
|
const logicflow = new LogicFlow({
|
||||||
container: containerRef.current,
|
container: containerRef.current,
|
||||||
grid: true,
|
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);
|
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 }) => {
|
logicflow.on('node:click', ({ data }) => {
|
||||||
|
console.log('Node clicked:', data);
|
||||||
setSelectedNode(data);
|
setSelectedNode(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -42,22 +117,45 @@ const FlowDesigner: React.FC<FlowDesignerProps> = ({
|
|||||||
setSelectedNode(null);
|
setSelectedNode(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 如果有初始值,渲染流程图
|
logicflow.on('history:change', () => {
|
||||||
|
const graphData = logicflow.getGraphData();
|
||||||
|
onChange?.(JSON.stringify(graphData));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 渲染初始数据
|
||||||
if (value) {
|
if (value) {
|
||||||
try {
|
try {
|
||||||
const graphData = JSON.parse(value);
|
const graphData = JSON.parse(value);
|
||||||
logicflow.render(graphData);
|
logicflow.render(graphData);
|
||||||
|
console.log('Initial graph data rendered:', graphData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to parse graph data:', 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);
|
setLf(logicflow);
|
||||||
|
console.log('LogicFlow initialization completed');
|
||||||
|
|
||||||
|
return logicflow;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to initialize LogicFlow:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const logicflow = initLogicFlow();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
if (logicflow) {
|
||||||
|
console.log('Destroying LogicFlow instance');
|
||||||
logicflow.destroy();
|
logicflow.destroy();
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 处理节点配置更新
|
// 处理节点配置更新
|
||||||
@ -74,7 +172,11 @@ const FlowDesigner: React.FC<FlowDesignerProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.canvas} ref={containerRef} />
|
<div
|
||||||
|
className={styles.canvas}
|
||||||
|
ref={containerRef}
|
||||||
|
style={{ minHeight: '600px' }}
|
||||||
|
/>
|
||||||
{selectedNode && (
|
{selectedNode && (
|
||||||
<div className={styles.configPanel}>
|
<div className={styles.configPanel}>
|
||||||
<NodeConfig
|
<NodeConfig
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
import LogicFlow from '@logicflow/core';
|
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) {
|
export function registerNodes(lf: LogicFlow) {
|
||||||
// 开始节点
|
// 开始节点
|
||||||
class StartNode extends CircleNode {
|
class StartNodeModel extends CircleNodeModel {
|
||||||
static extendKey = 'StartNode';
|
initNodeData(data: any) {
|
||||||
|
super.initNodeData(data);
|
||||||
|
this.r = 30;
|
||||||
|
}
|
||||||
|
|
||||||
getNodeStyle() {
|
getNodeStyle() {
|
||||||
const style = super.getNodeStyle();
|
const style = super.getNodeStyle();
|
||||||
return {
|
return {
|
||||||
@ -13,11 +17,22 @@ export function registerNodes(lf: LogicFlow) {
|
|||||||
stroke: '#1890FF'
|
stroke: '#1890FF'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAttributes() {
|
||||||
|
this.text.editable = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartNodeView extends CircleNode { }
|
||||||
|
|
||||||
// 任务节点
|
// 任务节点
|
||||||
class TaskNode extends RectNode {
|
class TaskNodeModel extends RectNodeModel {
|
||||||
static extendKey = 'TaskNode';
|
initNodeData(data: any) {
|
||||||
|
super.initNodeData(data);
|
||||||
|
this.width = 120;
|
||||||
|
this.height = 60;
|
||||||
|
}
|
||||||
|
|
||||||
getNodeStyle() {
|
getNodeStyle() {
|
||||||
const style = super.getNodeStyle();
|
const style = super.getNodeStyle();
|
||||||
return {
|
return {
|
||||||
@ -28,9 +43,16 @@ export function registerNodes(lf: LogicFlow) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TaskNodeView extends RectNode { }
|
||||||
|
|
||||||
// 网关节点
|
// 网关节点
|
||||||
class GatewayNode extends DiamondNode {
|
class GatewayNodeModel extends DiamondNodeModel {
|
||||||
static extendKey = 'GatewayNode';
|
initNodeData(data: any) {
|
||||||
|
super.initNodeData(data);
|
||||||
|
this.rx = 40;
|
||||||
|
this.ry = 40;
|
||||||
|
}
|
||||||
|
|
||||||
getNodeStyle() {
|
getNodeStyle() {
|
||||||
const style = super.getNodeStyle();
|
const style = super.getNodeStyle();
|
||||||
return {
|
return {
|
||||||
@ -41,9 +63,15 @@ export function registerNodes(lf: LogicFlow) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GatewayNodeView extends DiamondNode { }
|
||||||
|
|
||||||
// 结束节点
|
// 结束节点
|
||||||
class EndNode extends CircleNode {
|
class EndNodeModel extends CircleNodeModel {
|
||||||
static extendKey = 'EndNode';
|
initNodeData(data: any) {
|
||||||
|
super.initNodeData(data);
|
||||||
|
this.r = 30;
|
||||||
|
}
|
||||||
|
|
||||||
getNodeStyle() {
|
getNodeStyle() {
|
||||||
const style = super.getNodeStyle();
|
const style = super.getNodeStyle();
|
||||||
return {
|
return {
|
||||||
@ -52,30 +80,39 @@ export function registerNodes(lf: LogicFlow) {
|
|||||||
stroke: '#FF4D4F'
|
stroke: '#FF4D4F'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAttributes() {
|
||||||
|
this.text.editable = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EndNodeView extends CircleNode { }
|
||||||
|
|
||||||
// 注册节点
|
// 注册节点
|
||||||
lf.register({
|
lf.register({
|
||||||
type: 'start',
|
type: 'start',
|
||||||
view: StartNode,
|
view: StartNodeView,
|
||||||
model: StartNode
|
model: StartNodeModel
|
||||||
});
|
});
|
||||||
|
|
||||||
lf.register({
|
lf.register({
|
||||||
type: 'task',
|
type: 'task',
|
||||||
view: TaskNode,
|
view: TaskNodeView,
|
||||||
model: TaskNode
|
model: TaskNodeModel
|
||||||
});
|
});
|
||||||
|
|
||||||
lf.register({
|
lf.register({
|
||||||
type: 'gateway',
|
type: 'gateway',
|
||||||
view: GatewayNode,
|
view: GatewayNodeView,
|
||||||
model: GatewayNode
|
model: GatewayNodeModel
|
||||||
});
|
});
|
||||||
|
|
||||||
lf.register({
|
lf.register({
|
||||||
type: 'end',
|
type: 'end',
|
||||||
view: EndNode,
|
view: EndNodeView,
|
||||||
model: EndNode
|
model: EndNodeModel
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 设置默认连线类型
|
||||||
|
lf.setDefaultEdgeType('polyline');
|
||||||
}
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Card, Tabs } from 'antd';
|
import { Card } from 'antd';
|
||||||
import type { TabsProps } from 'antd';
|
import FormRender, { useForm } from 'form-render';
|
||||||
import FormRender from 'form-render';
|
|
||||||
|
|
||||||
interface FormDesignerProps {
|
interface FormDesignerProps {
|
||||||
value?: string;
|
value?: string;
|
||||||
@ -32,6 +31,8 @@ const FormDesigner: React.FC<FormDesignerProps> = ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const form = useForm();
|
||||||
|
|
||||||
const handleSubmit = (formData: any) => {
|
const handleSubmit = (formData: any) => {
|
||||||
console.log('Form data:', formData);
|
console.log('Form data:', formData);
|
||||||
};
|
};
|
||||||
@ -44,6 +45,7 @@ const FormDesigner: React.FC<FormDesignerProps> = ({
|
|||||||
<div style={{ padding: 24 }}>
|
<div style={{ padding: 24 }}>
|
||||||
<Card title="表单预览">
|
<Card title="表单预览">
|
||||||
<FormRender
|
<FormRender
|
||||||
|
form={form}
|
||||||
schema={schema}
|
schema={schema}
|
||||||
onFinish={handleSubmit}
|
onFinish={handleSubmit}
|
||||||
onValidate={handleValidate}
|
onValidate={handleValidate}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user