表单设计器

This commit is contained in:
dengqichen 2025-10-23 22:51:54 +08:00
parent 90d0792f0d
commit c033c10fb9
3 changed files with 100 additions and 11 deletions

View File

@ -19,6 +19,7 @@ import {
} from 'antd';
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
import type { FieldConfig, FormConfig } from '../types';
import { DataSourceType } from '@/pages/Workflow/Design/utils/dataSourceLoader';
const { Text } = Typography;
const { TabPane } = Tabs;
@ -40,7 +41,7 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
React.useEffect(() => {
if (selectedField) {
// 确保 apiDataSource 被正确设置到表单
// 确保嵌套对象被正确设置到表单
const formValues = {
...selectedField,
apiDataSource: selectedField.apiDataSource || {
@ -50,6 +51,9 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
labelField: '',
valueField: '',
},
predefinedDataSource: selectedField.predefinedDataSource || {
sourceType: '',
},
};
form.setFieldsValue(formValues);
}
@ -75,6 +79,14 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
};
console.log('🔄 切换到 API 数据源,已初始化配置对象');
}
// 切换到预定义数据源时,初始化 predefinedDataSource 对象
if (changedValues.dataSourceType === 'predefined' && !updatedField.predefinedDataSource) {
updatedField.predefinedDataSource = {
sourceType: '',
};
console.log('🔄 切换到预定义数据源,已初始化配置对象');
}
}
// 如果改变的是 apiDataSource 的子字段
@ -86,9 +98,18 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
console.log('💾 API 数据源配置已更新:', updatedField.apiDataSource);
}
// 如果改变的是 predefinedDataSource 的子字段
if ('predefinedDataSource' in changedValues) {
updatedField.predefinedDataSource = {
...updatedField.predefinedDataSource,
...changedValues.predefinedDataSource,
};
console.log('💾 预定义数据源配置已更新:', updatedField.predefinedDataSource);
}
// 合并其他字段
Object.keys(changedValues).forEach(key => {
if (key !== 'dataSourceType' && key !== 'apiDataSource') {
if (key !== 'dataSourceType' && key !== 'apiDataSource' && key !== 'predefinedDataSource') {
(updatedField as any)[key] = changedValues[key];
}
});
@ -314,9 +335,10 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
{/* 数据源类型选择 */}
<Form.Item label="数据源类型" name="dataSourceType">
<Radio.Group buttonStyle="solid">
<Radio.Button value="static"></Radio.Button>
<Radio.Button value="api"></Radio.Button>
<Radio.Group buttonStyle="solid" style={{ display: 'flex', flexWrap: 'nowrap' }}>
<Radio.Button value="static" style={{ flex: 1, textAlign: 'center' }}></Radio.Button>
<Radio.Button value="predefined" style={{ flex: 1, textAlign: 'center' }}></Radio.Button>
<Radio.Button value="api" style={{ flex: 1, textAlign: 'center' }}></Radio.Button>
</Radio.Group>
</Form.Item>
@ -358,6 +380,42 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
</div>
)}
{/* 预定义方法配置 */}
{selectedField.dataSourceType === 'predefined' && (
<div>
<Text strong></Text>
<div style={{ marginTop: 12 }}>
<Form.Item
label="数据源"
name={['predefinedDataSource', 'sourceType']}
rules={[{ required: true, message: '请选择数据源' }]}
>
<Select placeholder="选择预定义数据源">
{Object.keys(DataSourceType).map((key) => {
const sourceType = DataSourceType[key as keyof typeof DataSourceType];
return (
<Select.Option key={sourceType} value={sourceType}>
{key.replace(/_/g, ' ')}
</Select.Option>
);
})}
</Select>
</Form.Item>
<div style={{
padding: 12,
background: '#f5f5f5',
borderRadius: 4,
fontSize: 12,
color: '#666'
}}>
<div><strong>💡 </strong></div>
<div style={{ marginTop: 4 }}>使URL和字段映射</div>
</div>
</div>
</div>
)}
{/* API 数据源配置 */}
{selectedField.dataSourceType === 'api' && (
<div>

View File

@ -1,11 +1,12 @@
/**
* Hook
* API数据
* API数据和预定义数据源
*/
import { useState, useEffect } from 'react';
import type { FieldConfig, FieldOption } from '../types';
import request from '../../../utils/request';
import { loadDataSource, DataSourceType as WorkflowDataSourceType } from '@/pages/Workflow/Design/utils/dataSourceLoader';
/**
*
@ -40,6 +41,30 @@ export const useFieldOptions = (field: FieldConfig): FieldOption[] => {
return;
}
// 预定义数据源(使用 Workflow 中定义的数据源加载器)
if (field.dataSourceType === 'predefined' && field.predefinedDataSource) {
const { sourceType } = field.predefinedDataSource;
if (!sourceType) {
console.warn('⚠️ 预定义数据源配置不完整,缺少 sourceType');
setOptions([]);
return;
}
try {
// 调用 Workflow 的数据源加载器
const dataSourceOptions = await loadDataSource(sourceType as WorkflowDataSourceType);
// dataSourceLoader 已经转换为 { label, value } 格式
setOptions(dataSourceOptions);
console.log('✅ 预定义数据源加载成功', { sourceType, count: dataSourceOptions.length });
} catch (error) {
console.error('❌ 加载预定义数据源失败', { sourceType, error });
setOptions([]);
}
return;
}
// API 数据源
if (field.dataSourceType === 'api' && field.apiDataSource) {
const { url, method = 'GET', dataPath, labelField, valueField } = field.apiDataSource;
@ -98,7 +123,7 @@ export const useFieldOptions = (field: FieldConfig): FieldOption[] => {
};
loadOptions();
}, [field.dataSourceType, field.options, field.apiDataSource]);
}, [field.dataSourceType, field.options, field.apiDataSource, field.predefinedDataSource]);
return options;
};

View File

@ -29,7 +29,7 @@ export interface FieldOption {
}
// 数据源类型
export type DataSourceType = 'static' | 'api';
export type DataSourceType = 'static' | 'api' | 'predefined';
// API 数据源配置
export interface ApiDataSource {
@ -41,6 +41,11 @@ export interface ApiDataSource {
valueField: string; // 值字段名(如 'id', 'code', 'value'
}
// 预定义数据源配置(使用 dataSourceLoader 中定义的数据源)
export interface PredefinedDataSource {
sourceType: string; // 数据源类型,对应 DataSourceType 枚举(如 'JENKINS_SERVERS'
}
// 字段配置
export interface FieldConfig {
id: string;
@ -51,9 +56,10 @@ export interface FieldConfig {
required?: boolean;
disabled?: boolean;
defaultValue?: any;
options?: FieldOption[]; // 静态选项数据
dataSourceType?: DataSourceType; // 数据源类型static静态或 api接口
apiDataSource?: ApiDataSource; // API 数据源配置(当 dataSourceType 为 'api' 时使用)
options?: FieldOption[]; // 静态选项数据
dataSourceType?: DataSourceType; // 数据源类型static静态、api接口或 predefined预定义
apiDataSource?: ApiDataSource; // API 数据源配置(当 dataSourceType 为 'api' 时使用)
predefinedDataSource?: PredefinedDataSource; // 预定义数据源配置(当 dataSourceType 为 'predefined' 时使用)
min?: number;
max?: number;
rows?: number;