表单设计器

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'; } from 'antd';
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons'; import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
import type { FieldConfig, FormConfig } from '../types'; import type { FieldConfig, FormConfig } from '../types';
import { DataSourceType } from '@/pages/Workflow/Design/utils/dataSourceLoader';
const { Text } = Typography; const { Text } = Typography;
const { TabPane } = Tabs; const { TabPane } = Tabs;
@ -40,7 +41,7 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
React.useEffect(() => { React.useEffect(() => {
if (selectedField) { if (selectedField) {
// 确保 apiDataSource 被正确设置到表单 // 确保嵌套对象被正确设置到表单
const formValues = { const formValues = {
...selectedField, ...selectedField,
apiDataSource: selectedField.apiDataSource || { apiDataSource: selectedField.apiDataSource || {
@ -50,6 +51,9 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
labelField: '', labelField: '',
valueField: '', valueField: '',
}, },
predefinedDataSource: selectedField.predefinedDataSource || {
sourceType: '',
},
}; };
form.setFieldsValue(formValues); form.setFieldsValue(formValues);
} }
@ -75,6 +79,14 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
}; };
console.log('🔄 切换到 API 数据源,已初始化配置对象'); console.log('🔄 切换到 API 数据源,已初始化配置对象');
} }
// 切换到预定义数据源时,初始化 predefinedDataSource 对象
if (changedValues.dataSourceType === 'predefined' && !updatedField.predefinedDataSource) {
updatedField.predefinedDataSource = {
sourceType: '',
};
console.log('🔄 切换到预定义数据源,已初始化配置对象');
}
} }
// 如果改变的是 apiDataSource 的子字段 // 如果改变的是 apiDataSource 的子字段
@ -86,9 +98,18 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
console.log('💾 API 数据源配置已更新:', updatedField.apiDataSource); 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 => { Object.keys(changedValues).forEach(key => {
if (key !== 'dataSourceType' && key !== 'apiDataSource') { if (key !== 'dataSourceType' && key !== 'apiDataSource' && key !== 'predefinedDataSource') {
(updatedField as any)[key] = changedValues[key]; (updatedField as any)[key] = changedValues[key];
} }
}); });
@ -314,9 +335,10 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
{/* 数据源类型选择 */} {/* 数据源类型选择 */}
<Form.Item label="数据源类型" name="dataSourceType"> <Form.Item label="数据源类型" name="dataSourceType">
<Radio.Group buttonStyle="solid"> <Radio.Group buttonStyle="solid" style={{ display: 'flex', flexWrap: 'nowrap' }}>
<Radio.Button value="static"></Radio.Button> <Radio.Button value="static" style={{ flex: 1, textAlign: 'center' }}></Radio.Button>
<Radio.Button value="api"></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> </Radio.Group>
</Form.Item> </Form.Item>
@ -358,6 +380,42 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
</div> </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 数据源配置 */} {/* API 数据源配置 */}
{selectedField.dataSourceType === 'api' && ( {selectedField.dataSourceType === 'api' && (
<div> <div>

View File

@ -1,11 +1,12 @@
/** /**
* Hook * Hook
* API数据 * API数据和预定义数据源
*/ */
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import type { FieldConfig, FieldOption } from '../types'; import type { FieldConfig, FieldOption } from '../types';
import request from '../../../utils/request'; 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; 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 数据源 // API 数据源
if (field.dataSourceType === 'api' && field.apiDataSource) { if (field.dataSourceType === 'api' && field.apiDataSource) {
const { url, method = 'GET', dataPath, labelField, valueField } = field.apiDataSource; const { url, method = 'GET', dataPath, labelField, valueField } = field.apiDataSource;
@ -98,7 +123,7 @@ export const useFieldOptions = (field: FieldConfig): FieldOption[] => {
}; };
loadOptions(); loadOptions();
}, [field.dataSourceType, field.options, field.apiDataSource]); }, [field.dataSourceType, field.options, field.apiDataSource, field.predefinedDataSource]);
return options; return options;
}; };

View File

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