This commit is contained in:
dengqichen 2024-12-19 16:09:57 +08:00
parent 226e9211d2
commit fd6b225e52
4 changed files with 117 additions and 119 deletions

View File

@ -31,6 +31,7 @@
"axios": "^1.6.2", "axios": "^1.6.2",
"dagre": "^0.8.5", "dagre": "^0.8.5",
"form-render": "^2.5.1", "form-render": "^2.5.1",
"less": "^4.2.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-diff-viewer-continued": "^3.4.0", "react-diff-viewer-continued": "^3.4.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@ -49,7 +50,6 @@
"eslint": "^8.55.0", "eslint": "^8.55.0",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5", "eslint-plugin-react-refresh": "^0.4.5",
"less": "^4.2.1",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.0.8" "vite": "^5.0.8"
} }
@ -3245,7 +3245,6 @@
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-2.0.6.tgz", "resolved": "https://registry.npmmirror.com/copy-anything/-/copy-anything-2.0.6.tgz",
"integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"is-what": "^3.14.1" "is-what": "^3.14.1"
@ -3614,7 +3613,6 @@
"version": "0.1.8", "version": "0.1.8",
"resolved": "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz", "resolved": "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz",
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
@ -4364,7 +4362,6 @@
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
@ -4387,7 +4384,6 @@
"version": "0.5.5", "version": "0.5.5",
"resolved": "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz", "resolved": "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz",
"integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"bin": { "bin": {
@ -4528,7 +4524,6 @@
"version": "3.14.1", "version": "3.14.1",
"resolved": "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz", "resolved": "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz",
"integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/isexe": { "node_modules/isexe": {
@ -4656,7 +4651,6 @@
"version": "4.2.1", "version": "4.2.1",
"resolved": "https://registry.npmmirror.com/less/-/less-4.2.1.tgz", "resolved": "https://registry.npmmirror.com/less/-/less-4.2.1.tgz",
"integrity": "sha512-CasaJidTIhWmjcqv0Uj5vccMI7pJgfD9lMkKtlnTHAdJdYK/7l8pM9tumLyJ0zhbD4KJLo/YvTj+xznQd5NBhg==", "integrity": "sha512-CasaJidTIhWmjcqv0Uj5vccMI7pJgfD9lMkKtlnTHAdJdYK/7l8pM9tumLyJ0zhbD4KJLo/YvTj+xznQd5NBhg==",
"dev": true,
"dependencies": { "dependencies": {
"copy-anything": "^2.0.1", "copy-anything": "^2.0.1",
"parse-node-version": "^1.0.1", "parse-node-version": "^1.0.1",
@ -4776,7 +4770,6 @@
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz", "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz",
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
@ -4791,7 +4784,6 @@
"version": "5.7.2", "version": "5.7.2",
"resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"license": "ISC", "license": "ISC",
"optional": true, "optional": true,
"bin": { "bin": {
@ -4841,7 +4833,6 @@
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", "resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"bin": { "bin": {
@ -4987,7 +4978,6 @@
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmmirror.com/needle/-/needle-3.3.1.tgz", "resolved": "https://registry.npmmirror.com/needle/-/needle-3.3.1.tgz",
"integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
@ -5115,7 +5105,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz", "resolved": "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz",
"integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.10" "node": ">= 0.10"
@ -5197,7 +5186,6 @@
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmmirror.com/pify/-/pify-4.0.1.tgz", "resolved": "https://registry.npmmirror.com/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"engines": { "engines": {
@ -5274,7 +5262,6 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz", "resolved": "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz",
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true "optional": true
}, },
@ -6355,7 +6342,6 @@
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"license": "MIT", "license": "MIT",
"optional": true "optional": true
}, },
@ -6363,7 +6349,6 @@
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmmirror.com/sax/-/sax-1.4.1.tgz", "resolved": "https://registry.npmmirror.com/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
"dev": true,
"license": "ISC", "license": "ISC",
"optional": true "optional": true
}, },

View File

@ -33,6 +33,7 @@
"axios": "^1.6.2", "axios": "^1.6.2",
"dagre": "^0.8.5", "dagre": "^0.8.5",
"form-render": "^2.5.1", "form-render": "^2.5.1",
"less": "^4.2.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-diff-viewer-continued": "^3.4.0", "react-diff-viewer-continued": "^3.4.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
@ -51,7 +52,6 @@
"eslint": "^8.55.0", "eslint": "^8.55.0",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5", "eslint-plugin-react-refresh": "^0.4.5",
"less": "^4.2.1",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.0.8" "vite": "^5.0.8"
} }

View File

@ -1,70 +1,54 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { PageContainer } from '@ant-design/pro-components'; import { PageContainer } from '@ant-design/pro-components';
import { Card, Tabs, Form, message, Row, Col, Menu } from 'antd'; import { Row, Col, Menu, Tabs } from 'antd';
import { useParams, useNavigate } from 'react-router-dom';
import FormRender, { useForm } from 'form-render';
import type { NodeDefinitionData } from './types'; import type { NodeDefinitionData } from './types';
import * as service from './service'; import * as service from './service';
const { TabPane } = Tabs; // Tab 配置
const TAB_CONFIG = [
{ key: 'panel', label: '属性(预览)', schemaKey: 'panelVariablesSchema' },
{ key: 'local', label: '环境变量(预览)', schemaKey: 'localVariablesSchema' },
{ key: 'form', label: '表单(预览)', schemaKey: 'formVariablesSchema' },
{ key: 'ui', label: 'UI配置', schemaKey: 'uiVariables' }
];
const NodeDesignForm: React.FC = () => { const NodeDesignForm: React.FC = () => {
const navigate = useNavigate(); // 缓存节点定义数据
const { nodeCode } = useParams<{ nodeCode: string }>();
const [loading, setLoading] = useState(false);
const [nodeDefinitions, setNodeDefinitions] = useState<NodeDefinitionData[]>([]); const [nodeDefinitions, setNodeDefinitions] = useState<NodeDefinitionData[]>([]);
const [selectedNode, setSelectedNode] = useState<NodeDefinitionData>(); const [loading, setLoading] = useState(false);
// 当前选中的节点
const form = useForm(); const [selectedNode, setSelectedNode] = useState<NodeDefinitionData | null>(null);
// 当前选中的 tab
const [activeTab, setActiveTab] = useState<string>('panel');
// 加载节点定义数据 // 加载节点定义数据
useEffect(() => { useEffect(() => {
const loadNodeDefinitions = async () => { const loadNodeDefinitions = async () => {
try { try {
setLoading(true); setLoading(true);
const data = await service.getNodeDefinitions(); const data = await service.getNodeDefinitionsDefined();
setNodeDefinitions(data); setNodeDefinitions(data);
// 默认选中第一个节点
// 如果是编辑模式,找到对应的节点定义 if (data.length > 0) {
if (nodeCode) {
const node = data.find(n => n.nodeCode === nodeCode);
if (node) {
setSelectedNode(node);
} else {
message.error('未找到对应的节点定义');
navigate('/workflow/node-design');
}
} else if (data.length > 0) {
// 如果是新增模式,默认选中第一个节点
setSelectedNode(data[0]); setSelectedNode(data[0]);
} }
} catch (error) { } catch (error) {
message.error('加载节点定义失败'); console.error('加载节点定义失败:', error);
} finally { } finally {
setLoading(false); setLoading(false);
} }
}; };
loadNodeDefinitions(); loadNodeDefinitions();
}, [nodeCode, navigate]); }, []);
// 处理表单提交 // 获取当前节点可用的 Tab 列表
const handleSubmit = async (values: any) => { const getAvailableTabs = (node: NodeDefinitionData | null) => {
try { if (!node) return [];
setLoading(true); return TAB_CONFIG.filter(tab => {
if (nodeCode) { const value = node[tab.schemaKey as keyof NodeDefinitionData];
await service.updateNodeUIConfig(nodeCode, values); return value !== null && value !== undefined;
message.success('更新成功'); });
} else {
// TODO: 实现创建节点的接口
message.success('创建成功');
}
navigate('/workflow/node-design');
} catch (error) {
message.error('操作失败');
} finally {
setLoading(false);
}
}; };
// 处理节点选择 // 处理节点选择
@ -72,82 +56,111 @@ const NodeDesignForm: React.FC = () => {
const node = nodeDefinitions.find(n => n.nodeCode === nodeCode); const node = nodeDefinitions.find(n => n.nodeCode === nodeCode);
if (node) { if (node) {
setSelectedNode(node); setSelectedNode(node);
form.setValues({}); // 清空表单 // 获取可用的 tab 列表
const availableTabs = getAvailableTabs(node);
// 如果当前选中的 tab 不在可用列表中,则选择第一个可用的 tab
if (availableTabs.length > 0 && !availableTabs.find(tab => tab.key === activeTab)) {
setActiveTab(availableTabs[0].key);
}
} }
}; };
// 渲染 Tab 内容
const renderTabContent = (tabKey: string) => {
if (!selectedNode) return null;
const content = selectedNode[tabKey as keyof NodeDefinitionData];
return (
<div style={{
padding: '16px',
background: '#fafafa',
border: '1px solid #f0f0f0',
borderRadius: '4px',
minHeight: '200px'
}}>
<pre style={{
margin: 0,
padding: '8px',
background: '#fff',
border: '1px solid #f0f0f0',
borderRadius: '2px',
maxHeight: '600px',
overflow: 'auto'
}}>
{content ? JSON.stringify(content, null, 2) : '暂无数据'}
</pre>
</div>
);
};
return ( return (
<PageContainer <PageContainer
loading={loading} loading={loading}
header={{ header={{
title: `${nodeCode ? '编辑' : '新增'}节点设计`, title: '节点设计',
breadcrumb: { breadcrumb: {
items: [ items: [
{ title: '工作流' }, { title: '工作流' },
{ title: '节点设计', path: '/workflow/node-design' }, { title: '节点设计', path: '/workflow/node-design' }
{ title: nodeCode ? '编辑' : '新增' },
], ],
}, },
}} }}
> >
<Card> <div style={{ background: '#fff', minHeight: 'calc(100vh - 200px)' }}>
<Row gutter={24}> <Row>
<Col span={6}> <Col span={5} style={{ borderRight: '1px solid #f0f0f0', padding: '16px 0' }}>
<Card title="节点类型" bordered={false}> <div style={{
<Menu padding: '0 24px 16px',
mode="vertical" fontSize: '16px',
selectedKeys={[selectedNode?.nodeCode || '']} fontWeight: 500,
onClick={({ key }) => handleNodeSelect(key)} color: '#000000d9',
items={nodeDefinitions.map(node => ({ borderBottom: '1px solid #f0f0f0',
key: node.nodeCode, marginBottom: '8px'
label: node.nodeName, }}>
}))}
style={{ border: 'none' }} </div>
/> <Menu
</Card> mode="vertical"
selectedKeys={[selectedNode?.nodeCode || '']}
items={nodeDefinitions.map(node => ({
key: node.nodeCode,
label: node.nodeName,
}))}
onClick={({ key }) => handleNodeSelect(key)}
style={{
border: 'none',
padding: '0 16px'
}}
/>
</Col> </Col>
<Col span={18}> <Col span={19}>
{selectedNode && ( <div style={{ padding: '16px 24px' }}>
<Tabs defaultActiveKey="panel"> {selectedNode && getAvailableTabs(selectedNode).length > 0 ? (
<TabPane tab="面板变量" key="panel"> <Tabs
{selectedNode.panelVariablesSchema && ( activeKey={activeTab}
<FormRender onChange={setActiveTab}
form={form} type="card"
schema={selectedNode.panelVariablesSchema} items={getAvailableTabs(selectedNode).map(tab => ({
disabled key: tab.key,
/> label: tab.label,
)} children: renderTabContent(tab.schemaKey)
</TabPane> }))}
<TabPane tab="本地变量" key="local"> />
{selectedNode.localVariablesSchema && ( ) : (
<FormRender <div style={{
form={form} textAlign: 'center',
schema={selectedNode.localVariablesSchema} padding: '32px',
disabled color: '#00000073',
/> fontSize: '14px'
)} }}>
</TabPane>
<TabPane tab="表单变量" key="form"> </div>
{selectedNode.formVariablesSchema && ( )}
<FormRender </div>
form={form}
schema={selectedNode.formVariablesSchema}
disabled
/>
)}
</TabPane>
<TabPane tab="UI配置" key="ui">
<FormRender
form={form}
schema={selectedNode.uiVariables}
onFinish={handleSubmit}
/>
</TabPane>
</Tabs>
)}
</Col> </Col>
</Row> </Row>
</Card> </div>
</PageContainer> </PageContainer>
); );
}; };

View File

@ -18,5 +18,5 @@ export const updateNodeUIConfig = (nodeCode: string, uiVariables: any) =>
request.put(`${BASE_URL}/node-design/${nodeCode}/ui`, uiVariables); request.put(`${BASE_URL}/node-design/${nodeCode}/ui`, uiVariables);
// 获取已定义的节点类型配置 // 获取已定义的节点类型配置
export const getNodeDefinitions = () => export const getNodeDefinitionsDefined = () =>
request.get<NodeDefinitionData[]>(`${BASE_URL}/node-definition/defined`); request.get<NodeDefinitionData[]>(`${BASE_URL}/node-definition/defined`);