This commit is contained in:
dengqichen 2024-12-20 09:59:08 +08:00
parent 9c9ff6a21a
commit 0f5acb22dc

View File

@ -1,15 +1,15 @@
import React, { useState, useEffect } from 'react'; import React, {useState, useEffect} from 'react';
import { PageContainer } from '@ant-design/pro-layout'; import {PageContainer} from '@ant-design/pro-layout';
import { Button, Card, Form, Input, InputNumber, Select, Switch, Space, Menu, Tabs, Row, Col, message } from 'antd'; import {Button, Card, Form, Input, InputNumber, Select, Switch, Space, Menu, Tabs, Row, Col, message} from 'antd';
import type { NodeDesignData } from './types'; import type {NodeDesignData} from './types';
import * as service from './service'; import * as service from './service';
// Tab 配置 // Tab 配置
const TAB_CONFIG = [ const TAB_CONFIG = [
{ key: 'panel', label: '属性(预览)', schemaKey: 'panelVariablesSchema', readonly: true }, {key: 'panel', label: '属性(预览)', schemaKey: 'panelVariablesSchema', readonly: true},
{ key: 'local', label: '环境变量(预览)', schemaKey: 'localVariablesSchema', readonly: true }, {key: 'local', label: '环境变量(预览)', schemaKey: 'localVariablesSchema', readonly: true},
{ key: 'form', label: '表单(预览)', schemaKey: 'formVariablesSchema', readonly: true }, {key: 'form', label: '表单(预览)', schemaKey: 'formVariablesSchema', readonly: true},
{ key: 'ui', label: 'UI配置', schemaKey: 'uiVariables', readonly: false } {key: 'ui', label: 'UI配置', schemaKey: 'uiVariables', readonly: false}
]; ];
// 渲染具体的表单控件 // 渲染具体的表单控件
@ -35,9 +35,9 @@ const renderField = (schema: any) => {
return <Input {...commonProps} />; return <Input {...commonProps} />;
case 'integer': case 'integer':
case 'number': case 'number':
return <InputNumber {...commonProps} style={{ width: '100%' }} />; return <InputNumber {...commonProps} style={{width: '100%'}}/>;
case 'boolean': case 'boolean':
return <Switch />; return <Switch/>;
default: default:
return <Input {...commonProps} />; return <Input {...commonProps} />;
} }
@ -48,29 +48,29 @@ const FormRenderer: React.FC<{
schema: any; schema: any;
path?: string; path?: string;
readOnly?: boolean; readOnly?: boolean;
}> = ({ schema, path = '', readOnly = false }) => { }> = ({schema, path = '', readOnly = false}) => {
if (!schema || !schema.properties) return null; if (!schema || !schema.properties) return null;
const renderPortConfig = (portSchema: any, portPath: string) => { const renderPortConfig = (portSchema: any, portPath: string) => {
if (!portSchema || !portSchema.properties) return null; if (!portSchema || !portSchema.properties) return null;
const { position, attrs } = portSchema.properties; const {position, attrs} = portSchema.properties;
return ( return (
<> <>
{/* 先渲染端口位置 */} {/* 先渲染端口位置 */}
<Form.Item <Form.Item
name={`${portPath}.position`} name={`${portPath}.position`}
label={ label={
<span style={{ fontSize: '14px' }}> <span style={{fontSize: '14px'}}>
{position.title} {position.title}
</span> </span>
} }
tooltip={position.description} tooltip={position.description}
required={portSchema.required?.includes('position')} required={portSchema.required?.includes('position')}
initialValue={'default' in position ? position.default : undefined} initialValue={'default' in position ? position.default : undefined}
style={{ marginBottom: 16 }} style={{marginBottom: 16}}
> >
{readOnly ? ( {readOnly ? (
<span style={{ color: '#666' }}>{position.default || '-'}</span> <span style={{color: '#666'}}>{position.default || '-'}</span>
) : ( ) : (
renderField(position) renderField(position)
)} )}
@ -88,7 +88,7 @@ const FormRenderer: React.FC<{
border: '1px solid #f0f0f0' border: '1px solid #f0f0f0'
}} }}
styles={{ styles={{
body: { padding: '16px' } body: {padding: '16px'}
}} }}
> >
<FormRenderer <FormRenderer
@ -103,7 +103,7 @@ const FormRenderer: React.FC<{
}; };
return ( return (
<div style={{ padding: '8px 0' }}> <div style={{padding: '8px 0'}}>
{Object.entries(schema.properties).map(([key, value]: [string, any]) => { {Object.entries(schema.properties).map(([key, value]: [string, any]) => {
const fieldPath = path ? `${path}.${key}` : key; const fieldPath = path ? `${path}.${key}` : key;
if (value.type === 'object') { if (value.type === 'object') {
@ -125,7 +125,7 @@ const FormRenderer: React.FC<{
border: '1px solid #f0f0f0' border: '1px solid #f0f0f0'
}} }}
styles={{ styles={{
body: { padding: '16px' } body: {padding: '16px'}
}} }}
> >
{renderPortConfig(inPort, `${fieldPath}.in`)} {renderPortConfig(inPort, `${fieldPath}.in`)}
@ -142,7 +142,7 @@ const FormRenderer: React.FC<{
border: '1px solid #f0f0f0' border: '1px solid #f0f0f0'
}} }}
styles={{ styles={{
body: { padding: '16px' } body: {padding: '16px'}
}} }}
> >
{renderPortConfig(outPort, `${fieldPath}.out`)} {renderPortConfig(outPort, `${fieldPath}.out`)}
@ -156,7 +156,7 @@ const FormRenderer: React.FC<{
<Card <Card
key={fieldPath} key={fieldPath}
title={ title={
<span style={{ fontSize: '14px', fontWeight: 500 }}> <span style={{fontSize: '14px', fontWeight: 500}}>
{value.title} {value.title}
</span> </span>
} }
@ -168,7 +168,7 @@ const FormRenderer: React.FC<{
border: '1px solid #f0f0f0' border: '1px solid #f0f0f0'
}} }}
styles={{ styles={{
body: { padding: '16px' } body: {padding: '16px'}
}} }}
> >
<FormRenderer <FormRenderer
@ -185,17 +185,17 @@ const FormRenderer: React.FC<{
key={fieldPath} key={fieldPath}
name={fieldPath} name={fieldPath}
label={ label={
<span style={{ fontSize: '14px' }}> <span style={{fontSize: '14px'}}>
{value.title} {value.title}
</span> </span>
} }
tooltip={value.description} tooltip={value.description}
required={schema.required?.includes(key)} required={schema.required?.includes(key)}
initialValue={'default' in value ? value.default : undefined} initialValue={'default' in value ? value.default : undefined}
style={{ marginBottom: 16 }} style={{marginBottom: 16}}
> >
{readOnly ? ( {readOnly ? (
<span style={{ color: '#666' }}>{value.default || '-'}</span> <span style={{color: '#666'}}>{value.default || '-'}</span>
) : ( ) : (
renderField(value) renderField(value)
)} )}
@ -246,7 +246,14 @@ const NodeDesignForm: React.FC = () => {
// 处理节点选择 // 处理节点选择
const handleNodeSelect = (node: NodeDesignData) => { const handleNodeSelect = (node: NodeDesignData) => {
setSelectedNode(node); setSelectedNode(node);
form.resetFields(); // 更新表单数据
form.setFieldsValue({
'base.nodeType': node.nodeCode, // 使用 nodeCode 作为节点类型
'base.nodeCode': node.nodeCode,
'base.nodeName': node.nodeName,
'base.category': node.category,
'base.description': node.description
});
}; };
// 处理 Tab 切换 // 处理 Tab 切换
@ -259,11 +266,23 @@ const NodeDesignForm: React.FC = () => {
const handleSave = async () => { const handleSave = async () => {
try { try {
const values = await form.validateFields(); const values = await form.validateFields();
console.log('Form values:', values); const { base, ...otherValues } = values;
const saveData = {
...selectedNode,
nodeType: base.nodeType,
nodeCode: base.nodeCode,
nodeName: base.nodeName,
category: base.category,
description: base.description,
uiVariables: otherValues // 其他表单数据
};
await service.saveNodeDefinition(saveData);
message.success('保存成功'); message.success('保存成功');
} catch (error) { } catch (error) {
console.error('表单验证失败:', error); console.error('保存失败:', error);
message.error('表单验证失败'); message.error('保存失败');
} }
}; };
@ -290,7 +309,7 @@ const NodeDesignForm: React.FC = () => {
], ],
}} }}
> >
<div style={{ display: 'flex', gap: '24px', padding: '24px' }}> <div style={{display: 'flex', gap: '24px', padding: '24px'}}>
<Tabs <Tabs
tabPosition="left" tabPosition="left"
type="card" type="card"
@ -304,8 +323,8 @@ const NodeDesignForm: React.FC = () => {
items={nodeDefinitionsDefined.map(node => ({ items={nodeDefinitionsDefined.map(node => ({
key: node.nodeCode, key: node.nodeCode,
label: ( label: (
<div style={{ padding: '4px 0' }}> <div style={{padding: '4px 0'}}>
<div style={{ fontSize: '14px', fontWeight: 500 }}> <div style={{fontSize: '14px', fontWeight: 500}}>
{node.nodeName} {node.nodeName}
</div> </div>
<div style={{ <div style={{
@ -329,13 +348,58 @@ const NodeDesignForm: React.FC = () => {
layout="vertical" layout="vertical"
key={`${selectedNode?.nodeCode}-${activeTab}`} key={`${selectedNode?.nodeCode}-${activeTab}`}
> >
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="base.nodeType"
label="节点类型"
rules={[{required: true}]}
>
<Input disabled/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="base.nodeCode"
label="节点编码"
rules={[{required: true}]}
>
<Input disabled/>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="base.nodeName"
label="节点名称"
rules={[{required: true}]}
>
<Input/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="base.category"
label="节点类别"
>
<Input disabled/>
</Form.Item>
</Col>
</Row>
<Form.Item
name="base.description"
label="节点描述"
>
<Input.TextArea rows={4}/>
</Form.Item>
<Tabs <Tabs
activeKey={activeTab} activeKey={activeTab}
onChange={handleTabChange} onChange={handleTabChange}
items={getAvailableTabs(selectedNode).map(tab => ({ items={getAvailableTabs(selectedNode).map(tab => ({
key: tab.key, key: tab.key,
label: ( label: (
<span style={{ fontSize: '14px' }}> <span style={{fontSize: '14px'}}>
{tab.label} {tab.label}
</span> </span>
), ),