310 lines
12 KiB
TypeScript
310 lines
12 KiB
TypeScript
import type {ProFormColumnsType} from '@ant-design/pro-components';
|
|
import request from '@/utils/request';
|
|
|
|
interface EditorConfig {
|
|
language?: string;
|
|
theme?: string;
|
|
minimap?: boolean;
|
|
lineNumbers?: boolean;
|
|
wordWrap?: boolean;
|
|
fontSize?: number;
|
|
tabSize?: number;
|
|
autoComplete?: boolean;
|
|
folding?: boolean;
|
|
}
|
|
|
|
interface DataSourceConfig {
|
|
type: 'api';
|
|
url: string;
|
|
valueField: string;
|
|
labelField: string;
|
|
dependsOn?: string[];
|
|
params?: Record<string, string>;
|
|
}
|
|
|
|
interface JsonSchemaProperty {
|
|
type: string;
|
|
title?: string;
|
|
description?: string;
|
|
default?: any;
|
|
enum?: any[];
|
|
enumNames?: string[];
|
|
format?: string;
|
|
editorConfig?: EditorConfig;
|
|
dataSource?: DataSourceConfig;
|
|
items?: {
|
|
type: string;
|
|
enum?: any[];
|
|
enumNames?: string[];
|
|
};
|
|
minimum?: number;
|
|
maximum?: number;
|
|
minLength?: number;
|
|
maxLength?: number;
|
|
pattern?: string;
|
|
readOnly?: boolean;
|
|
}
|
|
|
|
interface JsonSchema {
|
|
type: string;
|
|
properties: Record<string, JsonSchemaProperty>;
|
|
required?: string[];
|
|
}
|
|
|
|
// 处理参数替换,将 ${fieldName} 替换为实际值
|
|
const replaceParams = (params: Record<string, string>, formValues: Record<string, any>): Record<string, any> => {
|
|
const result: Record<string, any> = {};
|
|
for (const [key, value] of Object.entries(params)) {
|
|
if (typeof value === 'string' && value.startsWith('${') && value.endsWith('}')) {
|
|
const fieldName = value.slice(2, -1);
|
|
result[key] = formValues[fieldName] || formValues[key];
|
|
} else {
|
|
result[key] = value;
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
// 获取远程数据源的选项
|
|
const fetchDataSourceOptions = async (
|
|
dataSource: DataSourceConfig,
|
|
formValues: Record<string, any> = {}
|
|
) => {
|
|
try {
|
|
// 处理依赖参数
|
|
const params = {
|
|
...formValues, // 包含所有表单值
|
|
...(dataSource.params ? replaceParams(dataSource.params, formValues) : {}) // 覆盖特定参数
|
|
};
|
|
|
|
console.log('Fetching data from:', dataSource.url);
|
|
console.log('With params:', params);
|
|
|
|
// 发起请求
|
|
const response = await request.get(dataSource.url, { params });
|
|
console.log('API Response:', response);
|
|
|
|
// 转换响应数据为选项格式
|
|
if (!Array.isArray(response)) {
|
|
console.warn('Response is not an array:', response);
|
|
return [];
|
|
}
|
|
|
|
const options = response.map(item => {
|
|
const option = {
|
|
label: item[dataSource.labelField],
|
|
value: item[dataSource.valueField],
|
|
};
|
|
console.log('Mapped option:', option);
|
|
return option;
|
|
});
|
|
|
|
console.log('Final options:', options);
|
|
return options;
|
|
} catch (error) {
|
|
console.error('Failed to fetch data source options:', error);
|
|
return [];
|
|
}
|
|
};
|
|
|
|
export const convertJsonSchemaToColumns = (schema: JsonSchema): ProFormColumnsType[] => {
|
|
if (!schema?.properties) return [];
|
|
|
|
return Object.entries(schema.properties).map(([key, value]: [string, JsonSchemaProperty]) => {
|
|
const baseConfig = {
|
|
title: value.description ? `${value.title || key} (${value.description})` : (value.title || key),
|
|
dataIndex: key,
|
|
formItemProps: {
|
|
required: schema.required?.includes(key),
|
|
},
|
|
initialValue: value.default,
|
|
readonly: value.readOnly,
|
|
};
|
|
|
|
// 根据类型处理不同的表单项
|
|
switch (value.type) {
|
|
case 'string':
|
|
// 如果有数据源配置,使用远程数据源的选择器
|
|
if (value.dataSource && value.dataSource.type === 'api') {
|
|
const dataSource = value.dataSource;
|
|
return {
|
|
...baseConfig,
|
|
valueType: 'select',
|
|
fieldProps: {
|
|
showSearch: true,
|
|
placeholder: `请选择${value.title || key}`,
|
|
disabled: value.readOnly,
|
|
allowClear: true,
|
|
showArrow: true,
|
|
filterOption: (input: string, option: any) =>
|
|
option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0,
|
|
onChange: (value: any, option: any) => {
|
|
console.log('Select value changed:', value, option);
|
|
},
|
|
},
|
|
dependencies: dataSource.dependsOn,
|
|
request: async (params: any) => {
|
|
console.log('Select field request triggered:', key);
|
|
console.log('Request params:', params);
|
|
|
|
// 获取表单当前值,包括当前字段的值
|
|
const formValues = {
|
|
...params?.form?.getFieldsValue(),
|
|
[key]: params?.value, // 包含当前字段的值
|
|
...params // 包含其他参数
|
|
};
|
|
console.log('Current form values:', formValues);
|
|
|
|
// 检查依赖字段是否都有值
|
|
const hasDependencies = !dataSource.dependsOn?.some(
|
|
field => {
|
|
const value = formValues[field];
|
|
return value === undefined || value === null || value === '';
|
|
}
|
|
);
|
|
|
|
console.log('Dependencies check:', {
|
|
required: dataSource.dependsOn,
|
|
formValues,
|
|
hasDependencies
|
|
});
|
|
|
|
// 如果有依赖且依赖值都存在,或者没有依赖,则发起请求
|
|
if (!dataSource.dependsOn || hasDependencies) {
|
|
return await fetchDataSourceOptions(dataSource, formValues);
|
|
}
|
|
|
|
console.log('Skipping request due to missing dependencies');
|
|
return [];
|
|
},
|
|
};
|
|
}
|
|
// 如果有枚举值,使用选择器
|
|
if (value.enum) {
|
|
return {
|
|
...baseConfig,
|
|
valueType: 'select',
|
|
fieldProps: {
|
|
options: value.enum.map((item, index) => ({
|
|
label: value.enumNames?.[index] || item,
|
|
value: item,
|
|
})),
|
|
placeholder: `请选择${value.title || key}`,
|
|
disabled: value.readOnly,
|
|
},
|
|
};
|
|
}
|
|
// 处理 monaco-editor 格式
|
|
if (value.format === 'monaco-editor') {
|
|
const editorConfig = value.editorConfig || {};
|
|
return {
|
|
...baseConfig,
|
|
valueType: 'code',
|
|
fieldProps: {
|
|
language: editorConfig.language || 'shell',
|
|
height: 300,
|
|
options: {
|
|
minimap: { enabled: editorConfig.minimap ?? false },
|
|
fontSize: editorConfig.fontSize || 14,
|
|
lineNumbers: editorConfig.lineNumbers ? 'on' : 'off',
|
|
wordWrap: editorConfig.wordWrap ? 'on' : 'off',
|
|
tabSize: editorConfig.tabSize || 2,
|
|
scrollBeyondLastLine: false,
|
|
automaticLayout: true,
|
|
folding: editorConfig.folding ?? true,
|
|
autoClosingBrackets: 'always',
|
|
autoClosingQuotes: 'always',
|
|
formatOnPaste: true,
|
|
formatOnType: true,
|
|
suggestOnTriggerCharacters: editorConfig.autoComplete ?? true,
|
|
renderWhitespace: 'boundary',
|
|
readOnly: value.readOnly,
|
|
}
|
|
}
|
|
};
|
|
}
|
|
// 否则使用文本输入框
|
|
return {
|
|
...baseConfig,
|
|
valueType: 'text',
|
|
fieldProps: {
|
|
placeholder: `请输入${value.title || key}`,
|
|
disabled: value.readOnly,
|
|
},
|
|
};
|
|
|
|
case 'number':
|
|
case 'integer':
|
|
return {
|
|
...baseConfig,
|
|
valueType: 'digit',
|
|
fieldProps: {
|
|
min: value.minimum,
|
|
max: value.maximum,
|
|
placeholder: `请输入${value.title || key}`,
|
|
style: { width: '100%' },
|
|
disabled: value.readOnly,
|
|
},
|
|
};
|
|
|
|
case 'boolean':
|
|
return {
|
|
...baseConfig,
|
|
valueType: 'switch',
|
|
fieldProps: {
|
|
disabled: value.readOnly,
|
|
},
|
|
};
|
|
|
|
case 'array':
|
|
// 处理数组类型的枚举值
|
|
if (value.items?.enum || value.enum) {
|
|
const enumValues = value.items?.enum || value.enum || [];
|
|
const enumNames = value.items?.enumNames || value.enumNames;
|
|
return {
|
|
...baseConfig,
|
|
valueType: 'select',
|
|
fieldProps: {
|
|
mode: 'multiple',
|
|
options: enumValues.map((item, index) => ({
|
|
label: enumNames?.[index] || item,
|
|
value: item,
|
|
})),
|
|
placeholder: `请选择${value.title || key}`,
|
|
disabled: value.readOnly,
|
|
},
|
|
};
|
|
}
|
|
// 否则使用标签输入
|
|
return {
|
|
...baseConfig,
|
|
valueType: 'select',
|
|
fieldProps: {
|
|
mode: 'tags',
|
|
placeholder: `请输入${value.title || key}`,
|
|
disabled: value.readOnly,
|
|
},
|
|
};
|
|
|
|
case 'object':
|
|
return {
|
|
...baseConfig,
|
|
valueType: 'jsonCode',
|
|
fieldProps: {
|
|
placeholder: `请输入${value.title || key}`,
|
|
disabled: value.readOnly,
|
|
},
|
|
};
|
|
|
|
default:
|
|
return {
|
|
...baseConfig,
|
|
valueType: 'text',
|
|
fieldProps: {
|
|
placeholder: `请输入${value.title || key}`,
|
|
disabled: value.readOnly,
|
|
},
|
|
};
|
|
}
|
|
});
|
|
};
|