import snippets from './snippets'; import { createFormItemSchema } from '../data-source-form/utils'; /** * @title 将 xRecordSchema JSON 字段定义转换为低代码子组件 Schema * @description * 解析 xRecordSchema(支持单对象、数组、字符串),对每个字段补全 uiSchema, * 调用 createFormItemSchema 生成低代码引擎可识别的组件 Schema。 */ export const parseXRecordSchemaToChildSchemas = (value: any): any[] => { let fields = value; // 解析字符串 if (typeof fields === 'string') { try { fields = JSON.parse(fields); } catch { return []; } } if (!fields) { return []; } // 处理 properties 格式 if (fields.properties && typeof fields.properties === 'object') { fields = Object.keys(fields.properties).map((name) => ({ ...fields.properties[name], name, })); } // 处理 fields 格式 if (fields.fields && Array.isArray(fields.fields)) { fields = fields.fields; } // 处理 children 格式 if (fields.children && Array.isArray(fields.children)) { fields = fields.children; } // 单对象转数组 if (!Array.isArray(fields)) { fields = [fields]; } // 补全每个字段的 uiSchema 并生成子组件 Schema return fields .filter(Boolean) .map((field: any) => { const uiSchema = { ...(field.uiSchema || {}) }; // 从 interface 映射 x-component(如 Select、Input 等) if (!uiSchema['x-component'] && field.interface) { uiSchema['x-component'] = field.interface; } // 兼容简单格式(只有 componentName/component,没有 interface 和 uiSchema) if (!uiSchema['x-component']) { uiSchema['x-component'] = field.componentName || field.component || 'Input'; } // 从 field.type 映射 uiSchema.type if (!uiSchema.type && field.type) { uiSchema.type = field.type; } // 确保 title 存在(用于生成 label) if (!uiSchema.title && field.label) { uiSchema.title = field.label; } return createFormItemSchema({ ...field, uiSchema }, 'edit'); }) .filter((schema: any) => !!schema?.componentName); }; export default { snippets, componentName: 'DataSourceSubForm', title: '子表单', category: '无代码表单', group: '无代码组件', docUrl: '', screenshot: '', devMode: 'proCode', npm: { package: '@pisell/materials', version: '1.0.3', exportName: 'DataSourceSubForm', main: 'src/index.tsx', destructuring: true, subName: '', }, generalProps: [ { type: 'group', title: { type: 'i18n', 'en-US': 'Data', 'zh-CN': '数据', }, display: 'accordion', items: [ { name: 'value', title: { label: { type: 'i18n', 'en-US': 'Value', 'zh-CN': '表单值', }, tip: { type: 'i18n', 'en-US': 'Form value object', 'zh-CN': '表单值对象', }, }, setter: ['JsonSetter', 'VariableSetter'], }, { name: 'xRecordSchema', title: { label: { type: 'i18n', 'en-US': 'Record Schema', 'zh-CN': '字段配置', }, tip: { type: 'i18n', 'en-US': 'Define form fields structure, supports JSON string, array, or object format', 'zh-CN': '定义表单字段结构,支持 JSON 字符串、数组或对象格式', }, }, setter: ['JsonSetter', 'StringSetter', 'VariableSetter'], extraProps: { setValue(target: any, value: any) { // 先写入 prop 值,确保持久化 const result = target.getProps().setPropValue('xRecordSchema', value); const parsedSchemas = parseXRecordSchemaToChildSchemas(value); // 先清空现有子节点,避免第二次及之后调用时 importSchema 做 diff/merge 导致节点数量异常 target.node.children.importSchema([]); // 节点刚添加时可能尚未挂载完成,用 setTimeout 错开时序 setTimeout(() => { target.node.children.importSchema(parsedSchemas); // replaceSchema 后有概率不触发重渲染,手动 rerender setTimeout(() => { target.document?.project?.simulatorHost?.rerender(); }); }); return result; }, }, }, ], }, { type: 'group', title: { type: 'i18n', 'en-US': 'Appearance', 'zh-CN': '外观', }, display: 'accordion', items: [ { name: 'renderMode', title: { label: { type: 'i18n', 'en-US': 'Render Mode', 'zh-CN': '渲染模式', }, }, defaultValue: 'edit', setter: [ { componentName: 'RadioGroupSetter', props: { options: [ { title: '编辑', value: 'edit' }, { title: '禁用', value: 'disabled' }, { title: '预览', value: 'preview' }, ], }, }, 'VariableSetter', ], }, { name: 'layout', title: { label: { type: 'i18n', 'en-US': 'Layout', 'zh-CN': '布局方式', }, }, defaultValue: 'vertical', setter: [ { componentName: 'RadioGroupSetter', props: { options: [ { title: '垂直', value: 'vertical' }, { title: '水平', value: 'horizontal' }, { title: '行内', value: 'inline' }, ], }, }, 'VariableSetter', ], }, ], }, ], configure: { props: [ { name: 'onChange', title: { label: { type: 'i18n', 'en-US': 'On Change', 'zh-CN': '值变化回调', }, }, setter: { componentName: 'FunctionSetter', props: { template: 'onChange(value,${extParams}){\n// 表单值变化时触发\nconsole.log("onChange", value);\n}', }, }, }, ], component: { isContainer: true, }, supports: { style: true, className: true, events: [ { name: 'onChange', template: 'onChange(value,${extParams}){\n// 表单值变化时触发\nconsole.log("onChange", value);\n}', }, ], }, }, };