import { IPublicTypeComponentMetadata, IPublicTypeSnippet } from '@alilc/lowcode-types'

const CustomFormMeta: IPublicTypeComponentMetadata = {
  group: '低代码组件',
  componentName: 'CustomForm',
  title: '自定义表单',
  docUrl: '',
  screenshot: '',
  devMode: 'proCode',
  category: '信息输入',
  npm: {
    package: '@dckj-npm/dc-material',
    version: '0.1.359',
    exportName: 'CustomForm',
    main: 'src/index.tsx',
    destructuring: true,
    subName: '',
  },
  configure: {
    component: {
      isContainer: true,
    },
    props: [
      // ─────────────────────────────────────────────────────────────────────
      // 分组一：全局布局
      // ─────────────────────────────────────────────────────────────────────
      {
        type: 'group',
        title: '全局布局',
        name: 'layoutGroup',
        display: 'accordion',
        items: [
          {
            title: {
              label: '列数',
              tip: '表单的整体列数，所有表单项按此列数排列。\n单列适合简单表单，多列适合信息密集的编辑页面。',
            },
            name: 'columns',
            setter: {
              componentName: 'RadioGroupSetter',
              props: {
                options: [
                  { title: '一列', value: 1 },
                  { title: '二列', value: 2 },
                  { title: '三列', value: 3 },
                  { title: '四列', value: 4 },
                ],
              },
              initialValue: 1,
            },
          },
          {
            title: {
              label: '标签位置',
              tip: '表单标签相对于输入框的位置：\n· 顶部（top）：标签在输入框上方，适合移动端或字段较多时\n· 左侧（left）：标签在输入框左侧，传统表单样式，配合「标签宽度」使用\n· 内嵌（inset）：标签显示在输入框内部，输入时标签浮动到上方',
            },
            name: 'labelAlign',
            setter: {
              componentName: 'RadioGroupSetter',
              props: {
                options: [
                  { title: '顶部', value: 'top' },
                  { title: '左侧', value: 'left' },
                  { title: '内嵌', value: 'inset' },
                ],
              },
              initialValue: 'top',
            },
            extraProps: {
              setValue: (target: any, value: string) => {
                if (value === 'left') {
                  target.getProps().setPropValue('labelCol', { fixedSpan: 4 })
                } else {
                  target.getProps().setPropValue('labelCol', null)
                }
                target.getProps().setPropValue('labelAlign', value)
              },
            },
          },
          {
            title: {
              label: '标签宽度',
              tip: '当标签位置为「左侧」时，设置标签列的固定宽度（格宫列数，1~24）。\nJSON 示例：{ "fixedSpan": 6 } 意为标签占 6 格。\n不填则自动宽度。常用值：4（短标签）、6（中等标签）、8（长标签）',
            },
            name: 'labelCol.fixedSpan',
            condition: (target: any) =>
              target.getProps().getPropValue('labelAlign') === 'left',
            setter: {
              componentName: 'NumberSetter',
              props: { min: 1, max: 12 },
              initialValue: 4,
            },
          },
          {
            title: {
              label: '行间距',
              tip: '每行表单项之间的上下间距（像素）。\n默认 0。建议设为 8~16px 让表单更舒适。',
            },
            name: '!rowGap',
            extraProps: {
              getValue: (target: any) => {
                const sp = target.getProps().getPropValue('spacing')
                return Array.isArray(sp) ? (sp[0] ?? 0) : 0
              },
              setValue: (target: any, value: number) => {
                const sp = target.getProps().getPropValue('spacing')
                const colGap = Array.isArray(sp) ? (sp[1] ?? 16) : 16
                target.getProps().setPropValue('spacing', [value, colGap])
              },
            },
            setter: {
              componentName: 'NumberSetter',
              props: { min: 0, max: 100 },
              initialValue: 0,
            },
          },
          {
            title: {
              label: '列间距',
              tip: '多列表单中各列之间的左右间距（像素）。\n默认 16px。单列表单中此设置无明显效果。',
            },
            name: '!colGap',
            extraProps: {
              getValue: (target: any) => {
                const sp = target.getProps().getPropValue('spacing')
                return Array.isArray(sp) ? (sp[1] ?? 16) : 16
              },
              setValue: (target: any, value: number) => {
                const sp = target.getProps().getPropValue('spacing')
                const rowGap = Array.isArray(sp) ? (sp[0] ?? 0) : 0
                target.getProps().setPropValue('spacing', [rowGap, value])
              },
            },
            setter: {
              componentName: 'NumberSetter',
              props: { min: 0, max: 100 },
              initialValue: 16,
            },
          },
          {
            title: {
              label: '组件宽度占满',
              tip: '全局控制所有表单项的输入组件是否撑满容器宽度（100%）。\n开启后相当为每个表单项设置 fullWidth=true。\n单个表单项的「宽度占满」设置优先级更高，可覆盖此全局值。',
            },
            name: 'fullWidth',
            setter: {
              componentName: 'BoolSetter',
              initialValue: true,
            },
          },
          {
            title: {
              label: '表单状态',
              tip: '编辑态：正常填写表单。\n只读态：所有输入框变为纯文本显示，空值显示"—"。\n常用于"查看详情"场景，绑定变量可动态切换编辑/只读。',
            },
            name: '!status',
            extraProps: {
              getValue: (target: any) => {
                return target.getProps().getPropValue('isPreview') ? 'readonly' : 'editable'
              },
              setValue: (target: any, value: string) => {
                target.getProps().setPropValue('isPreview', value === 'readonly')
              },
            },
            setter: {
              componentName: 'RadioGroupSetter',
              props: {
                options: [
                  { title: '编辑', value: 'editable' },
                  { title: '只读', value: 'readonly' },
                ],
              },
              initialValue: 'editable',
            },
          },
          {
            title: {
              label: '空态文案',
              tip: '当没有任何表单项时展示的提示文字。',
            },
            name: 'emptyContent',
            setter: {
              componentName: 'StringSetter',
              isRequired: false,
              initialValue: '添加表单项',
            },
          },
        ],
      },
      // ─────────────────────────────────────────────────────────────────────
      // 分组二：表单项配置
      // ─────────────────────────────────────────────────────────────────────
      {
        title: {
          label: '表单项',
          tip: '配置表单中每一行的字段。\n每个表单项需要填写「字段名」和「标题」，其余可选。\n字段名（field）是提交数据时的 key，需要与后端接口字段名保持一致。',
        },
        name: 'formItems',
        setter: {
          componentName: 'ArraySetter',
          props: {
            itemSetter: {
              componentName: 'ObjectSetter',
              props: {
                config: {
                  items: [
                    // ── 基础
                    {
                      title: {
                        label: '字段名',
                        tip: '必填。提交表单时该字段的 key 名称，需与后端接口字段名一致。\n例如：user_name、phone、banquet_date',
                      },
                      name: 'field',
                      setter: {
                        componentName: 'StringSetter',
                        isRequired: true,
                        initialValue: '',
                      },
                    },
                    {
                      title: {
                        label: '标题',
                        tip: '表单项左侧（或上方）显示的文字标签。\n例如：姓名、手机号、宴请日期',
                      },
                      name: 'label',
                      important: true,
                      display: 'inline',
                      setter: {
                        componentName: 'StringSetter',
                        isRequired: false,
                        initialValue: '',
                      },
                    },
                    {
                      title: {
                        label: '必填',
                        tip: '开启后标题旁显示红色星号，并在提交时自动校验该字段不能为空。',
                      },
                      name: 'required',
                      setter: {
                        componentName: 'BoolSetter',
                        isRequired: false,
                        initialValue: false,
                      },
                    },
                    // ── 组件类型
                    {
                      title: {
                        label: '组件类型',
                        tip: '选择该字段使用哪种输入控件：\n· 输入框（Input）：单行文本，最常用\n· 多行文本（TextArea）：适合备注、描述\n· 下拉选择（Select）：从预设选项中选一个\n· 单选组（RadioGroup）：横排单选按钮\n· 复选组（CheckboxGroup）：多选框\n· 数字输入（NumberPicker）：带加减按钮的数字\n· 日期选择（DatePicker）：日历弹出选日期\n· 上传（Upload）：文件/图片上传',
                      },
                      name: 'componentType',
                      important: true,
                      display: 'inline',
                      setter: {
                        componentName: 'SelectSetter',
                        props: {
                          options: [
                            { label: '输入框 (Input)', value: 'Input' },
                            { label: '多行文本 (TextArea)', value: 'TextArea' },
                            { label: '下拉选择 (Select)', value: 'Select' },
                            { label: '单选组 (RadioGroup)', value: 'RadioGroup' },
                            { label: '复选组 (CheckboxGroup)', value: 'CheckboxGroup' },
                            { label: '数字输入 (NumberPicker)', value: 'NumberPicker' },
                            { label: '日期选择 (DatePicker)', value: 'DatePicker' },
                            { label: '日期时间 (DateTimePicker)', value: 'DateTimePicker' },
                            { label: '上传 (Upload)', value: 'Upload' },
                          ],
                        },
                        initialValue: 'Input',
                      },
                    },
                    // ── 输入提示（仅对支持 placeholder 的组件显示）
                    {
                      title: {
                        label: '输入提示',
                        tip: '显示在输入框内的灰色提示文字（placeholder）。\n例如：请输入姓名、请选择日期',
                      },
                      name: 'placeholder',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return !['Upload', 'RadioGroup', 'CheckboxGroup'].includes(t)
                      },
                      setter: {
                        componentName: 'StringSetter',
                        isRequired: false,
                        initialValue: '',
                      },
                    },
                    // ── 默认值
                    {
                      title: {
                        label: '默认值',
                        tip: '该字段的初始默认值，表单打开时自动填入。\n· 文本类型填写字符串，例如：待处理\n· 数字类型填写数字，例如：0\n· 日期类型填写格式化字符串，例如：2026-01-01\n· 下拉/单选填写选项的 value 值，例如：male\n· 复选框填写数组，例如：["a","b"]\n\n优先级高于"全局初始值"（initialValues）中同名字段。',
                      },
                      name: 'initialValue',
                      setter: {
                        componentName: 'MixedSetter',
                        props: {
                          setters: [
                            { componentName: 'StringSetter', title: '字符串' },
                            { componentName: 'NumberSetter', title: '数字' },
                            { componentName: 'BoolSetter', title: '布尔' },
                            { componentName: 'JsonSetter', title: 'JSON（数组/对象）' },
                          ],
                        },
                        isRequired: false,
                      },
                    },
                    // ── 选项（下拉/单选/复选）
                    {
                      title: {
                        label: '选项列表',
                        tip: '仅在组件类型为「下拉选择」「单选组」「复选组」时生效。\n每个选项需配置：\n· 名称（label）：界面上显示的文字，例如：男\n· 值（value）：提交时实际传给后端的值，例如：male',
                      },
                      name: 'options',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || target.parent?.parent?.getPropValue?.('componentType')
                        return ['Select','RadioGroup','CheckboxGroup'].includes(t)
                      },
                      setter: {
                        componentName: 'ArraySetter',
                        props: {
                          itemSetter: {
                            componentName: 'ObjectSetter',
                            props: {
                              config: {
                                items: [
                                  {
                                    title: { label: '名称', tip: '选项显示的文字' },
                                    name: 'label',
                                    setter: {
                                      componentName: 'StringSetter',
                                      isRequired: true,
                                      initialValue: '',
                                    },
                                  },
                                  {
                                    title: { label: '值', tip: '提交时传给后端的实际值' },
                                    name: 'value',
                                    setter: {
                                      componentName: 'StringSetter',
                                      isRequired: true,
                                      initialValue: '',
                                    },
                                  },
                                ],
                              },
                            },
                          },
                        },
                        initialValue: [],
                      },
                    },
                    // ── 动态选项绑定（阶段二）
                    {
                      title: {
                        label: '动态选项绑定',
                        tip: '仅在组件类型为「下拉选择」「单选组」「复选组」时生效。\n绑定后优先级高于上方「选项列表」（静态配置）。\n支持绑定页面变量或数据源返回的数组，数组格式为 [{label, value}, ...]。\n常见用法：将套餐列表、城市列表等接口数据直接绑定到选项。\n若接口返回的数据字段名不是 label/value，请配合下方「选项显示字段名」和「选项值字段名」使用。',
                      },
                      name: 'optionsBind',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || target.parent?.parent?.getPropValue?.('componentType')
                        return ['Select','RadioGroup','CheckboxGroup'].includes(t)
                      },
                      setter: {
                        componentName: 'SetterFormVariable',
                        props: {
                          attributes: [
                            {
                              label: '选项数据',
                              value: 'optionsBind',
                              children: [
                                { label: '显示文字', isRequire: true, value: 'label' },
                                { label: '选项值', isRequire: true, value: 'value' },
                              ],
                            },
                          ],
                        },
                      },
                    },
                    // ── 动态选项字段映射（当数据源字段名不是 label/value 时使用）
                    {
                      title: {
                        label: '选项显示字段名',
                        tip: '当「动态选项绑定」的数据源字段名不是 label 时填写。\n例如后端返回 {package_name, id, ...}，想用 package_name 做显示文字，则填 "package_name"。\n不填则默认使用 label 字段。',
                      },
                      name: 'optionsLabelKey',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || target.parent?.parent?.getPropValue?.('componentType')
                        return ['Select','RadioGroup','CheckboxGroup'].includes(t)
                      },
                      setter: {
                        componentName: 'StringSetter',
                        isRequired: false,
                        initialValue: '',
                      },
                    },
                    {
                      title: {
                        label: '选项值字段名',
                        tip: '当「动态选项绑定」的数据源字段名不是 value 时填写。\n例如后端返回 {package_name, id, ...}：\n· 想用 id 做存储值 → 填 "id"\n· 想用 package_name 做存储值 → 填 "package_name"\n不填则默认使用 value 字段。\n配置后，字段联动规则的「匹配字段名 matchKey」会自动默认使用此字段名，无需重复配置。',
                      },
                      name: 'optionsValueKey',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || target.parent?.parent?.getPropValue?.('componentType')
                        return ['Select','RadioGroup','CheckboxGroup'].includes(t)
                      },
                      setter: {
                        componentName: 'StringSetter',
                        isRequired: false,
                        initialValue: '',
                      },
                    },
                    // ── 布局
                    {
                      title: {
                        label: '列跨度',
                        tip: '该表单项横向占几列（不超过表单总列数）。\n例如总列数为 4，设置为 2 则占一半宽度，设置为 4 则独占一行。',
                      },
                      name: 'columnSpan',
                      setter: {
                        componentName: 'RadioGroupSetter',
                        props: {
                          options: [
                            { title: '1格', value: 1 },
                            { title: '2格', value: 2 },
                            { title: '3格', value: 3 },
                            { title: '4格', value: 4 },
                          ],
                        },
                        initialValue: 1,
                      },
                    },
                    {
                      title: {
                        label: '尺寸',
                        tip: '单个表单项的组件尺寸，优先级高于表单全局 size。\n不设置时继承表单全局尺寸（默认 medium）。',
                      },
                      name: 'size',
                      setter: {
                        componentName: 'RadioGroupSetter',
                        props: {
                          options: [
                            { title: '小', value: 'small' },
                            { title: '中', value: 'medium' },
                            { title: '大', value: 'large' },
                          ],
                        },
                      },
                    },
                    {
                      title: {
                        label: '宽度占满',
                        tip: '开启后该表单项的输入组件宽度为 100%，撑满所在列的宽度。\n默认开启，通常不需要关闭。',
                      },
                      name: 'fullWidth',
                      setter: {
                        componentName: 'BoolSetter',
                        initialValue: true,
                      },
                    },
                    // ── 提示信息
                    {
                      title: {
                        label: '错误提示',
                        tip: '校验失败时显示的自定义错误文字，涵盖必填为空与正则/格式不匹配两种情况。\n不填则由组件自动生成，例如"xxx 不能为空"或"格式不正确"。\n示例：请输入正确的 11 位手机号',
                      },
                      name: '!helpMsg',
                      extraProps: {
                        getValue: (target: any) =>
                          target.parent?.getPropValue?.('help') ||
                          target.parent?.getPropValue?.('formItemProps')?.requiredMessage ||
                          '',
                        setValue: (target: any, value: string) => {
                          target.parent?.setPropValue?.('help', value || undefined)
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          if (!value) {
                            delete fp.requiredMessage
                          } else {
                            fp.requiredMessage = value
                          }
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: {
                        componentName: 'StringSetter',
                        isRequired: false,
                        initialValue: '',
                      },
                    },
                    {
                      title: {
                        label: '补充说明',
                        tip: '始终显示在输入框下方的灰色提示文字，与错误提示共存，用于告知用户填写要求或格式。\n例如：手机号用于接收预订通知短信',
                      },
                      name: 'extra',
                      setter: {
                        componentName: 'StringSetter',
                        isRequired: false,
                        initialValue: '',
                      },
                    },
                    // ── 组件属性（结构化，按组件类型分组）
                    // ── 通用：禁用
                    {
                      title: {
                        label: '禁用',
                        tip: '开启后该输入组件变为禁用状态，用户无法编辑。',
                      },
                      name: '!disabled',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return !['Upload'].includes(t)
                      },
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.disabled,
                        setValue: (target: any, value: boolean) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          cp.disabled = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'BoolSetter', initialValue: false },
                    },
                    // ── Input：最大字符数 / 只读
                    {
                      title: {
                        label: '最大字符数',
                        tip: '输入框最多允许输入的字符数。\n超出后无法继续输入。配合「显示计数」使用效果更好。',
                      },
                      name: '!maxLength',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return ['Input', 'TextArea'].includes(t)
                      },
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.maxLength,
                        setValue: (target: any, value: number) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          if (value === undefined || value === null || (value as any) === '') {
                            delete cp.maxLength
                          } else {
                            cp.maxLength = value
                          }
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'NumberSetter', props: { min: 1 } },
                    },
                    {
                      title: {
                        label: '显示计数',
                        tip: '开启后在输入框右下角显示"已输入/最大字符数"计数器。\n需配合「最大字符数」使用。',
                      },
                      name: '!hasLimitHint',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return ['Input', 'TextArea'].includes(t)
                      },
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.hasLimitHint,
                        setValue: (target: any, value: boolean) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          cp.hasLimitHint = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'BoolSetter', initialValue: false },
                    },
                    {
                      title: {
                        label: '只读',
                        tip: '开启后输入框内容不可编辑（与禁用不同，只读不改变样式）。\n常用于"自动计算填入"的字段，如套餐价格。',
                      },
                      name: '!readOnly',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return ['Input', 'TextArea'].includes(t)
                      },
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.readOnly,
                        setValue: (target: any, value: boolean) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          cp.readOnly = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'BoolSetter', initialValue: false },
                    },
                    // ── TextArea：行数
                    {
                      title: {
                        label: '显示行数',
                        tip: '多行文本框默认显示的行数（高度）。默认 4 行。',
                      },
                      name: '!rows',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'TextArea',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.rows,
                        setValue: (target: any, value: number) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          cp.rows = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'NumberSetter', props: { min: 1, max: 20 }, initialValue: 4 },
                    },
                    // ── NumberPicker：范围 / 步长 / 精度
                    {
                      title: {
                        label: '最小值',
                        tip: '数字输入框允许输入的最小值。',
                      },
                      name: '!min',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'NumberPicker',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.min,
                        setValue: (target: any, value: number) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          if (value === undefined || value === null || (value as any) === '') delete cp.min
                          else cp.min = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'NumberSetter' },
                    },
                    {
                      title: {
                        label: '最大值',
                        tip: '数字输入框允许输入的最大值。',
                      },
                      name: '!max',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'NumberPicker',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.max,
                        setValue: (target: any, value: number) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          if (value === undefined || value === null || (value as any) === '') delete cp.max
                          else cp.max = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'NumberSetter' },
                    },
                    {
                      title: {
                        label: '步长',
                        tip: '每次点击加减按钮时变化的数量。默认 1。',
                      },
                      name: '!step',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'NumberPicker',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.step,
                        setValue: (target: any, value: number) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          if (value === undefined || value === null || (value as any) === '') delete cp.step
                          else cp.step = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'NumberSetter', props: { min: 0 }, initialValue: 1 },
                    },
                    {
                      title: {
                        label: '小数位数',
                        tip: '数字保留几位小数。默认不限制（整数）。',
                      },
                      name: '!precision',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'NumberPicker',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.precision,
                        setValue: (target: any, value: number) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          if (value === undefined || value === null || (value as any) === '') delete cp.precision
                          else cp.precision = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'NumberSetter', props: { min: 0, max: 10 } },
                    },
                    // ── Select：可搜索 / 可清除 / 多选模式
                    {
                      title: {
                        label: '可搜索',
                        tip: '开启后下拉框支持输入关键字过滤选项。',
                      },
                      name: '!showSearch',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'Select',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.showSearch,
                        setValue: (target: any, value: boolean) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          cp.showSearch = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'BoolSetter', initialValue: false },
                    },
                    {
                      title: {
                        label: '可清除',
                        tip: '开启后选择框右侧显示清除图标，点击可清空已选值。',
                      },
                      name: '!hasClear',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return ['Select', 'DatePicker', 'DateTimePicker'].includes(t)
                      },
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.hasClear,
                        setValue: (target: any, value: boolean) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          cp.hasClear = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'BoolSetter', initialValue: false },
                    },
                    {
                      title: {
                        label: '多选模式',
                        tip: '设置下拉框的选择模式：\n· 单选（single）：只能选一个选项（默认）\n· 多选（multiple）：可以选多个，以标签形式展示\n· 标签输入（tag）：可以选多个，也支持直接输入新标签',
                      },
                      name: '!mode',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'Select',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.mode || 'single',
                        setValue: (target: any, value: string) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          cp.mode = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: {
                        componentName: 'RadioGroupSetter',
                        props: {
                          options: [
                            { title: '单选', value: 'single' },
                            { title: '多选', value: 'multiple' },
                            { title: '标签', value: 'tag' },
                          ],
                        },
                        initialValue: 'single',
                      },
                    },
                    // ── DatePicker / DateTimePicker：日期格式
                    {
                      title: {
                        label: '日期格式',
                        tip: '日期显示和提交的格式字符串。\n常用：\n· 仅日期：YYYY-MM-DD（默认）\n· 日期+时间：YYYY-MM-DD HH:mm\n· 年月：YYYY-MM',
                      },
                      name: '!dateFormat',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return ['DatePicker', 'DateTimePicker'].includes(t)
                      },
                      extraProps: {
                        getValue: (target: any) => {
                          const t = target.parent?.getPropValue?.('componentType')
                          return target.parent?.getPropValue?.('componentProps')?.format || (t === 'DateTimePicker' ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD')
                        },
                        setValue: (target: any, value: string) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          cp.format = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'StringSetter', initialValue: 'YYYY-MM-DD' },
                    },
                    // ── Upload：文件类型 / 数量限制
                    {
                      title: {
                        label: '允许的文件类型',
                        tip: '限制可上传的文件类型（传给 input[accept]）。\n例如：image/* 只允许图片，.pdf 只允许 PDF，不填则不限制。',
                      },
                      name: '!accept',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'Upload',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.accept,
                        setValue: (target: any, value: string) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          if (!value) delete cp.accept
                          else cp.accept = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'StringSetter' },
                    },
                    {
                      title: {
                        label: '最多上传数量',
                        tip: '允许上传的最多文件数量，超出后禁止继续上传。不填则不限制。',
                      },
                      name: '!limit',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'Upload',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('componentProps')?.limit,
                        setValue: (target: any, value: number) => {
                          const cp = { ...(target.parent?.getPropValue?.('componentProps') || {}) }
                          if (value === undefined || value === null || (value as any) === '') delete cp.limit
                          else cp.limit = value
                          target.parent?.setPropValue?.('componentProps', cp)
                        },
                      },
                      setter: { componentName: 'NumberSetter', props: { min: 1 } },
                    },
                    // ── 表单项控制
                    {
                      title: {
                        label: '自动校验',
                        tip: '开启后每次字段值变化时自动触发校验，不需等到提交才验证。\n适合需要即时反馈的场景（如手机号格式）。',
                      },
                      name: '!autoValidate',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('formItemProps')?.autoValidate,
                        setValue: (target: any, value: boolean) => {
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          fp.autoValidate = value
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: { componentName: 'BoolSetter', initialValue: false },
                    },
                    {
                      title: {
                        label: '隐藏冒号',
                        tip: '开启后在标题文字后面不显示冒号。',
                      },
                      name: '!colon',
                      extraProps: {
                        getValue: (target: any) => {
                          const v = target.parent?.getPropValue?.('formItemProps')?.colon
                          return v === false
                        },
                        setValue: (target: any, value: boolean) => {
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          fp.colon = !value
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: { componentName: 'BoolSetter', initialValue: false },
                    },
                    // ── 表单校验
                    // 最小长度（Input / TextArea / CheckboxGroup）
                    {
                      title: {
                        label: '最少字符数',
                        tip: 'Input/TextArea：输入字符不能少于此数量。\nCheckboxGroup：至少要选几项。',
                      },
                      name: '!minLength',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return ['Input', 'TextArea', 'CheckboxGroup'].includes(t)
                      },
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('formItemProps')?.minLength,
                        setValue: (target: any, value: number) => {
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          if (value === undefined || value === null || (value as any) === '') delete fp.minLength
                          else fp.minLength = value
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: { componentName: 'NumberSetter', props: { min: 0 } },
                    },
                    // 最大长度（Input / TextArea / CheckboxGroup / Select multiple）
                    {
                      title: {
                        label: '最多字符数（校验）',
                        tip: 'Input/TextArea：输入字符不能超过此数量（校验维度，与组件层的最大字符数独立）。\nCheckboxGroup：最多能选几项。',
                      },
                      name: '!maxLengthValidate',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return ['Input', 'TextArea', 'CheckboxGroup'].includes(t)
                      },
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('formItemProps')?.maxLength,
                        setValue: (target: any, value: number) => {
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          if (value === undefined || value === null || (value as any) === '') delete fp.maxLength
                          else fp.maxLength = value
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: { componentName: 'NumberSetter', props: { min: 0 } },
                    },
                    // 最小/最大值（NumberPicker）
                    {
                      title: {
                        label: '最小数值（校验）',
                        tip: '数字字段的最小合法值（校验维度）。',
                      },
                      name: '!minValue',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'NumberPicker',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('formItemProps')?.min,
                        setValue: (target: any, value: number) => {
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          if (value === undefined || value === null || (value as any) === '') delete fp.min
                          else fp.min = value
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: { componentName: 'NumberSetter' },
                    },
                    {
                      title: {
                        label: '最大数值（校验）',
                        tip: '数字字段的最大合法值（校验维度）。',
                      },
                      name: '!maxValue',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'NumberPicker',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('formItemProps')?.max,
                        setValue: (target: any, value: number) => {
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          if (value === undefined || value === null || (value as any) === '') delete fp.max
                          else fp.max = value
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: { componentName: 'NumberSetter' },
                    },
                    // 正则校验（Input / TextArea）—— 提供预置规则 + 自定义
                    {
                      title: {
                        label: '正则校验',
                        tip: '选择常用的格式校验规则，或选"自定义"后填写自己的正则表达式（无需前后加斜杠）。\n常用示例：\n· 手机号：^1[3-9]\\d{9}$\n· 邮箱：^[\\w.]+@[\\w.]+\\.[a-z]{2,}$\n· 正整数：^\\d+$\n· 身份证号：^\\d{17}[\\dXx]$',
                      },
                      name: '!patternPreset',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return ['Input', 'TextArea'].includes(t)
                      },
                      extraProps: {
                        getValue: (target: any) => {
                          const pattern = target.parent?.getPropValue?.('formItemProps')?.pattern
                          const presets: Record<string, string> = {
                            '^1[3-9]\\d{9}$': 'phone',
                            '^[\\w.+-]+@[\\w-]+\\.[a-z]{2,}$': 'email',
                            '^\\d+$': 'integer',
                            '^\\d+(\\.\\d+)?$': 'number',
                            '^\\d{17}[\\dXx]$': 'idcard',
                            '^[\\u4e00-\\u9fa5]+$': 'chinese',
                          }
                          return pattern ? (presets[pattern] || '__custom__') : ''
                        },
                        setValue: (target: any, value: string) => {
                          const patternMap: Record<string, string> = {
                            phone: '^1[3-9]\\d{9}$',
                            email: '^[\\w.+-]+@[\\w-]+\\.[a-z]{2,}$',
                            integer: '^\\d+$',
                            number: '^\\d+(\\.\\d+)?$',
                            idcard: '^\\d{17}[\\dXx]$',
                            chinese: '^[\\u4e00-\\u9fa5]+$',
                          }
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          if (!value || value === '__none__') {
                            delete fp.pattern
                          } else if (value === '__custom__') {
                            // 自定义时不修改 pattern，等用户在下方输入框填写
                          } else {
                            fp.pattern = patternMap[value]
                          }
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: {
                        componentName: 'SelectSetter',
                        props: {
                          options: [
                            { label: '不校验', value: '__none__' },
                            { label: '手机号（11位）', value: 'phone' },
                            { label: '邮箱地址', value: 'email' },
                            { label: '整数', value: 'integer' },
                            { label: '数字（含小数）', value: 'number' },
                            { label: '身份证号（15/18位）', value: 'idcard' },
                            { label: '纯中文', value: 'chinese' },
                            { label: '自定义正则…', value: '__custom__' },
                          ],
                        },
                        initialValue: '__none__',
                      },
                    },
                    {
                      title: {
                        label: '自定义正则',
                        tip: '填写自定义正则表达式（无需前后加斜杠），例如：^1[3-9]\\d{9}$',
                      },
                      name: '!pattern',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        if (!['Input', 'TextArea'].includes(t)) return false
                        const preset = target.parent?.getPropValue?.('formItemProps')?.__patternPreset
                        // 当预置选择了"自定义"时显示，或者 pattern 已有值但不匹配任何预置时也显示
                        const pattern = target.parent?.getPropValue?.('formItemProps')?.pattern
                        const builtinPatterns = ['^1[3-9]\\d{9}$', '^[\\w.+-]+@[\\w-]+\\.[a-z]{2,}$', '^\\d+$', '^\\d+(\\.\\d+)?$', '^\\d{17}[\\dXx]$', '^[\\u4e00-\\u9fa5]+$']
                        return preset === '__custom__' || (!!pattern && !builtinPatterns.includes(pattern))
                      },
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('formItemProps')?.pattern,
                        setValue: (target: any, value: string) => {
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          if (!value) delete fp.pattern
                          else fp.pattern = value
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: { componentName: 'StringSetter' },
                    },
                    {
                      title: {
                        label: '正则校验失败提示',
                        tip: '正则不匹配时显示的错误提示文字。',
                      },
                      name: '!patternMessage',
                      condition: (target: any) => {
                        const t = target.parent?.getPropValue?.('componentType') || 'Input'
                        return ['Input', 'TextArea'].includes(t) && !!target.parent?.getPropValue?.('formItemProps')?.pattern
                      },
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('formItemProps')?.patternMessage,
                        setValue: (target: any, value: string) => {
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          if (!value) delete fp.patternMessage
                          else fp.patternMessage = value
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: { componentName: 'StringSetter' },
                    },
                    // 格式校验（仅 Input）
                    {
                      title: {
                        label: '格式校验',
                        tip: '快速选择常用格式进行校验：\n· number：必须是数字\n· email：必须是邮箱格式\n· url：必须是网址格式\n· tel：必须是电话格式',
                      },
                      name: '!format',
                      condition: (target: any) => target.parent?.getPropValue?.('componentType') === 'Input',
                      extraProps: {
                        getValue: (target: any) => target.parent?.getPropValue?.('formItemProps')?.format,
                        setValue: (target: any, value: string) => {
                          const fp = { ...(target.parent?.getPropValue?.('formItemProps') || {}) }
                          if (!value) delete fp.format
                          else fp.format = value
                          target.parent?.setPropValue?.('formItemProps', fp)
                        },
                      },
                      setter: {
                        componentName: 'SelectSetter',
                        props: {
                          options: [
                            { label: '不限制', value: '' },
                            { label: '数字 (number)', value: 'number' },
                            { label: '邮箱 (email)', value: 'email' },
                            { label: '网址 (url)', value: 'url' },
                            { label: '电话 (tel)', value: 'tel' },
                          ],
                        },
                        initialValue: '',
                      },
                    },
                  ],
                },
              },
            },
          },
          initialValue: [],
        },
      },
      // ─────────────────────────────────────────────────────────────────────
      // 字段初始化
      // ─────────────────────────────────────────────────────────────────────
      {
        title: {
          label: '字段初始化',
          tip: '批量配置表单字段的初始值。\n\n· 字段名：与「表单项」中的「字段名」保持一致，例如 guest_count、user_name\n· 值类型：\n    固定值 — 直接填写静态默认值（字符串/数字/布尔/JSON）\n    变量绑定 — 绑定页面 state 或接口返回的动态变量\n\n💡 设置单个字段默认值时，也可在「表单项」列表中直接配置「默认值」，更快捷。',
        },
        name: 'initialValues',
        extraProps: {
          getValue: (target: any) => {
            const iv = target.getProps().getPropValue('initialValues')
            if (!iv) return []
            if (Array.isArray(iv)) {
              // 不过滤 field 为空的行，允许新添加的空行显示出来供用户填写
              // 仅过滤非对象的元素（防御性兼容旧脏数据）
              return iv
                .filter((row: any) => row && typeof row === 'object')
                .map((row: any) => ({
                  field: typeof row.field === 'string' ? row.field.trim() : '',
                  valueType: row.valueType === 'variable' ? 'variable' : 'fixed',
                  value: row.value,
                }))
            }
            // 对象格式：key 不可能为空字符串，保留原有过滤
            return Object.entries(iv as Record<string, any>).map(([field, value]) => ({
              field: String(field).trim(),
              valueType: 'fixed',
              value,
            })).filter((row) => row.field)
          },
          setValue: (target: any, rows: any[]) => {
            if (!Array.isArray(rows)) return
            // 不过滤 field 为空的行：用户点击"添加一项"时新行 field 为空字符串，
            // 若此处过滤掉，ArraySetter 重读 getValue 后新行消失，表现为"添加无效"。
            // 运行时 normalizeInitialValues 已忽略 field 为空的行，不影响实际行为。
            const cleanedRows = rows
              .filter((row: any) => row && typeof row === 'object')
              .map((row: any) => ({
                field: typeof row.field === 'string' ? row.field.trim() : '',
                valueType: row.valueType === 'variable' ? 'variable' : 'fixed',
                value: row.value,
              }))
            target.getProps().setPropValue('initialValues', cleanedRows)
          },
        },
        setter: {
          componentName: 'ArraySetter',
          props: {
            itemSetter: {
              componentName: 'ObjectSetter',
              props: {
                config: {
                  items: [
                    {
                      title: {
                        label: '字段名',
                        tip: '与「表单项」中的「字段名」保持一致，例如：guest_count、user_name',
                      },
                      name: 'field',
                      important: true,
                      display: 'inline',
                      setter: {
                        componentName: 'StringSetter',
                        isRequired: true,
                        initialValue: '',
                      },
                    },
                    {
                      title: {
                        label: '值类型',
                        tip: '· 固定值：静态初始值，例如"待处理"、10、true\n· 变量绑定：绑定页面 state 或动态数据，表单打开时从变量取值',
                      },
                      name: 'valueType',
                      setter: {
                        componentName: 'RadioGroupSetter',
                        props: {
                          options: [
                            { title: '固定值', value: 'fixed' },
                            { title: '变量绑定', value: 'variable' },
                          ],
                        },
                        initialValue: 'fixed',
                      },
                    },
                    {
                      title: {
                        label: '初始值',
                        tip: '该字段的默认值。\n· 文本类填字符串，例如：待处理\n· 数字类填数字，例如：10\n· 下拉/单选填选项的 value 值，例如：male\n· 复选框填 JSON 数组，例如：["a","b"]',
                      },
                      name: 'value',
                      condition: (target: any) =>
                        (target.parent?.getPropValue?.('valueType') || 'fixed') === 'fixed',
                      setter: {
                        componentName: 'MixedSetter',
                        props: {
                          setters: [
                            { componentName: 'StringSetter', title: '字符串' },
                            { componentName: 'NumberSetter', title: '数字' },
                            { componentName: 'BoolSetter', title: '布尔' },
                            { componentName: 'JsonSetter', title: 'JSON（数组/对象）' },
                          ],
                        },
                      },
                    },
                    {
                      title: {
                        label: '变量绑定',
                        tip: '绑定页面 state 或外部传入的变量，表单打开时从该变量读取初始值。\n例如：绑定 state.selectedPackage 可将上一步选择的套餐自动填入。',
                      },
                      name: 'value',
                      condition: (target: any) =>
                        target.parent?.getPropValue?.('valueType') === 'variable',
                      setter: {
                        componentName: 'VariableSetter',
                      },
                      extraProps: {
                        supportVariable: true,
                      },
                    },
                  ],
                },
              },
              initialValue: () => ({ field: '', valueType: 'fixed', value: '' }),
            },
          },
          initialValue: [],
        },
      },
      // ─────────────────────────────────────────────────────────────────────
      // 计算字段
      // ─────────────────────────────────────────────────────────────────────
      {
        title: {
          label: '计算字段',
          tip: '声明由多个表单字段自动拼接/计算出的衍生字段，每行一条规则。\n\n工作原理：每次任意字段值变化时自动重新计算，结果写入目标字段，提交时自动携带。\n\n表达式写法：用 {字段名} 引用表单中其他字段的当前值\n  例如：{package_name}，{package_price}元，预约日期：{banquet_date}\n\n配置步骤：\n  ① 目标字段名 = 要写入的字段名，例如：order_desc\n  ② 表达式 = 输入模板文字，用 {字段名} 插入字段值\n  ③ 保存后切换套餐/填值即可看到目标字段自动更新\n\n无需编写任何 JS 逻辑，配置即生效。',
        },
        name: 'computedFields',
        extraProps: {
          getValue: (target: any) => {
            const cf = target.getProps().getPropValue('computedFields')
            if (!cf) return []
            if (Array.isArray(cf)) return cf
            return Object.entries(cf as Record<string, string>).map(([targetField, template]) => ({ targetField, template }))
          },
          setValue: (target: any, value: any[]) => {
            if (!Array.isArray(value)) return
            target.getProps().setPropValue('computedFields', value.filter(Boolean))
          },
        },
        setter: {
          componentName: 'ArraySetter',
          props: {
            itemSetter: {
              componentName: 'ObjectSetter',
              props: {
                config: {
                  items: [
                    {
                      title: {
                        label: '目标字段名',
                        tip: '计算结果写入的字段名，提交时携带此字段。\n建议取语义化名称，例如：order_desc、booking_summary\n该字段不需要出现在上方「表单项」中，提交时会自动追加到表单值里。',
                      },
                      name: 'targetField',
                      important: true,
                      display: 'inline',
                      setter: { componentName: 'StringSetter', isRequired: true, initialValue: '' },
                    },
                    {
                      title: {
                        label: '表达式',
                        tip: '用 {字段名} 引用表单字段的当前值，支持任意文字拼接。\n\n示例：{package_name}，{guest_count}人，预订日期：{banquet_date}\n\n操作：先查看「表单项」中的字段名，在此处输入拼接模板，用 {字段名} 插入对应字段值，固定文字直接输入。',
                      },
                      name: 'template',
                      setter: { componentName: 'StringSetter', isRequired: true, initialValue: '' },
                    },
                  ],
                },
              },
              initialValue: () => ({ targetField: '', template: '' }),
            },
          },
          initialValue: [],
        },
      },
      // ─────────────────────────────────────────────────────────────────────
      // 字段联动
      // ─────────────────────────────────────────────────────────────────────
      {
        title: {
          label: '字段联动',
          tip: '配置"某字段变化 → 自动回填其他字段"的联动规则。\n\n【简单模式】适用于：选某个值 → 直接回填固定值或绑定变量\n  例如：选"豪华套餐" → 回填价格=9800\n  · 监听字段：值发生变化时触发检查，填字段名，例如 package_name\n  · 触发值：留空=任何变化都触发；填具体值=精确匹配才触发\n  · 回填字段：要被自动填入值的目标字段名\n  · 回填方式：固定值 或 变量（从 state 中选取）\n\n【数据源模式】适用于：根据所选值从一个列表中查找匹配项，自动回填该项的多个字段\n  典型场景：下拉框绑定了 state.packages（含 name/price/count），选择套餐名后自动回填价格和人数\n    监听字段 = package_name\n    数据源   = state.packages（与 package_name 下拉框的动态选项相同）\n    匹配字段 = value（Select 存储的是选项的 value 字段）\n    回填映射 = {"package_price":"price","guest_count":"count"}（JSON 格式）\n  注意：数据源中的每个对象需要有 matchKey 字段（用于匹配监听字段的值）以及各回填字段对应的属性。',
        },
        name: 'fieldLinkage',
        setter: {
          componentName: 'ArraySetter',
          props: {
            itemSetter: {
              componentName: 'ObjectSetter',
              props: {
                config: {
                  items: [
                        // ── 通用：监听字段 ──────────────────────────────────────
                        {
                          title: {
                            label: '监听字段',
                            tip: '当此字段值变化时触发联动检查，填表单项的字段名（field），例如：package_name\n可从上方「表单项」列表中查看各字段名。',
                          },
                          name: 'watchField',
                          important: true,
                          display: 'inline',
                          setter: { componentName: 'StringSetter', isRequired: true, initialValue: '' },
                        },
                        // ── 模式切换 ────────────────────────────────────────────
                        {
                          title: {
                            label: '联动模式',
                            tip: '· 简单：监听字段变化 → 直接设置某个字段的值（固定值或变量）\n· 数据源：监听字段变化 → 在指定数据源中查找匹配项 → 批量回填多个字段\n  （适合"选套餐 → 联动回填价格、人数"等场景）',
                          },
                          name: 'linkageMode',
                          setter: {
                            componentName: 'RadioGroupSetter',
                            props: {
                              options: [
                                { title: '简单', value: 'simple' },
                                { title: '数据源', value: 'dataSource' },
                              ],
                            },
                            initialValue: 'simple',
                          },
                        },
                        // ── 简单模式：触发值 ────────────────────────────────────
                        {
                          title: {
                            label: '触发值',
                            tip: '监听字段的值等于此值时才触发回填。\n· 留空 = 该字段任何变化都触发\n· 填具体值 = 精确匹配后触发，例如：豪华套餐、1、true\n\n多个触发值：添加多条相同监听字段的规则，每条配置不同触发值。',
                          },
                          name: 'matchValue',
                          condition: (target: any) =>
                            (target.parent?.getPropValue?.('linkageMode') || 'simple') === 'simple',
                          setter: { componentName: 'StringSetter', initialValue: '' },
                        },
                        // ── 简单模式：回填字段 ──────────────────────────────────
                        {
                          title: {
                            label: '回填字段',
                            tip: '触发条件满足后，自动填入值的目标字段名（field），例如：package_price\n可从上方「表单项」列表中查看各字段名。',
                          },
                          name: 'fillField',
                          condition: (target: any) =>
                            (target.parent?.getPropValue?.('linkageMode') || 'simple') === 'simple',
                          setter: { componentName: 'StringSetter', initialValue: '' },
                        },
                        // ── 简单模式：回填方式 ──────────────────────────────────
                        {
                          title: {
                            label: '回填方式',
                            tip: '· 固定值：直接填写静态回填值，例如 9800、"待处理"\n· 变量：回填值来自页面 state（适合动态数据场景）',
                          },
                          name: 'fillValueType',
                          condition: (target: any) =>
                            (target.parent?.getPropValue?.('linkageMode') || 'simple') === 'simple',
                          setter: {
                            componentName: 'RadioGroupSetter',
                            props: {
                              options: [
                                { title: '固定值', value: 'fixed' },
                                { title: '变量', value: 'variable' },
                              ],
                            },
                            initialValue: 'fixed',
                          },
                        },
                        // ── 简单模式：回填值（固定）────────────────────────────
                        {
                          title: {
                            label: '回填值',
                            tip: '触发条件满足后填入「回填字段」的具体值。\n· 字符串示例：豪华套餐、待处理\n· 数字示例：9800、10\n如需动态值，请将「回填方式」切换为「变量」。',
                          },
                          name: 'fillValue',
                          condition: (target: any) =>
                            (target.parent?.getPropValue?.('linkageMode') || 'simple') === 'simple' &&
                            (target.parent?.getPropValue?.('fillValueType') || 'fixed') === 'fixed',
                          setter: {
                            componentName: 'MixedSetter',
                            props: {
                              setters: [
                                { componentName: 'StringSetter', title: '字符串' },
                                { componentName: 'NumberSetter', title: '数字' },
                                { componentName: 'BoolSetter', title: '布尔' },
                              ],
                            },
                          },
                        },
                        // ── 简单模式：回填值（变量）────────────────────────────
                        {
                          title: {
                            label: '回填变量',
                            tip: '从页面 state 中选取变量作为回填值，表单联动时实时取该变量的当前值填入目标字段。\n\n如果 state 中没有现成变量，但回填值需要来自某个下拉框选项对象的字段（如选套餐后取价格），请改用「数据源」模式。',
                          },
                          name: 'fillValue',
                          condition: (target: any) =>
                            (target.parent?.getPropValue?.('linkageMode') || 'simple') === 'simple' &&
                            target.parent?.getPropValue?.('fillValueType') === 'variable',
                          setter: { componentName: 'VariableSetter' },
                          extraProps: { supportVariable: true },
                        },
                        // ── 数据源模式：数据源 ──────────────────────────────────
                        {
                          title: {
                            label: '数据源',
                            tip: '⚠️ 必须通过右侧「变量绑定」按钮选择变量，不能直接输入文本（如 "this.state.xxx"），否则运行时会报错。\n\n请选取一个数组变量作为查找来源。\n\n典型配置：\n1. 将 package_name 字段的「动态选项绑定」绑定到 state.packages\n2. 此处也选择同一个 state.packages\n\n数据格式要求（每个对象必须同时包含用于匹配的字段和用于回填的字段）：\n  state.packages = [\n    {value:"A", label:"豪华套餐", price:9800, count:10},\n    {value:"B", label:"标准套餐", price:5800, count:8}\n  ]\n其中 value/label 供下拉框显示用，price/count 供联动回填用。',
                          },
                          name: 'dataSource',
                          condition: (target: any) =>
                            target.parent?.getPropValue?.('linkageMode') === 'dataSource',
                          setter: { componentName: 'VariableSetter' },
                          extraProps: { supportVariable: true },
                        },
                        // ── 数据源模式：匹配字段 ────────────────────────────────
                        {
                          title: {
                            label: '匹配字段',
                            tip: '在数据源的每个对象中，用哪个字段的值与监听字段的当前值进行比对。\n\n下拉框（Select）默认存储选项的 value 字段，此处填 value 即可。\n如果下拉框存储的是 label（名称），则填 label。\n\n示例：state.packages = [{value:"A", label:"豪华套餐", price:9800, count:10}, ...]\n则此处填 value（与 package_name 字段存储的选项 value 对应）。\n\n注意：匹配字段的值类型需与下拉框存储的值类型一致（如都为字符串，或都为数字）。',
                          },
                          name: 'matchKey',
                          condition: (target: any) =>
                            target.parent?.getPropValue?.('linkageMode') === 'dataSource',
                          setter: { componentName: 'StringSetter', initialValue: 'value' },
                        },
                        // ── 数据源模式：回填映射 ────────────────────────────────
                        {
                          title: {
                            label: '回填映射',
                            tip: '找到匹配项后，将数据源对象中的哪些字段值填入表单的哪些字段。\n\nJSON 格式：{ "表单字段名": "数据源字段名", ... }\n\n示例（state.packages 中每项有 price 和 count 属性）：\n  {"package_price":"price","guest_count":"count"}\n\n效果：匹配到套餐后，自动将 price 回填到 package_price 字段，count 回填到 guest_count 字段。\n\n注意：数据源字段名（value 部分）必须是数据源对象中实际存在的属性名。',
                          },
                          name: 'fillFields',
                          condition: (target: any) =>
                            target.parent?.getPropValue?.('linkageMode') === 'dataSource',
                          setter: {
                            componentName: 'JsonSetter',
                            initialValue: {},
                          },
                        },
                      ],
                    },
                  },
                  initialValue: () => ({ watchField: '', linkageMode: 'simple', matchValue: '', fillField: '', fillValueType: 'fixed', fillValue: '' }),
                },
              },
              initialValue: [],
        },
      },
      // ─────────────────────────────────────────────────────────────────────
      // 提交参数配置
      // ─────────────────────────────────────────────────────────────────────
      {
        title: {
          label: '提交参数配置',
          tip: '控制表单提交时如何将字段值构建为请求参数，支持三种模式：\n\n① 直接透传（passthrough，默认）\n字段名与接口参数名完全一致时无需配置——表单字段值直接作为请求 body，零配置即可工作。\n\n② 字段重命名（rename）\n表单字段名与接口参数名不一致时使用，按规则将指定字段重命名，其余字段仍按原名透传。\n例如：表单字段 user_name → 接口参数 username\n\n③ 动态表单格式（itemList）\n后端接口接收 itemList:[{columnName,columnValue},...] 格式时使用，适合 /dynamicFormTableRecord/ 等接口。\n例如：{user_name:"张三"} → [{columnName:"user_name",columnValue:"张三"}]',
        },
        name: 'submitMapping',
        setter: {
          componentName: 'ObjectSetter',
          props: {
            config: {
              items: [
                // ── 模式选择 ──────────────────────────────────────────────
                {
                  title: {
                    label: '参数构建模式',
                    tip: '选择提交时参数的构建方式：\n· 直接透传：字段名与接口参数名一致，直接发送；最简单，首选。\n· 字段重命名：字段名与接口参数名不一致，在下方按需配置重命名规则即可。\n· 动态表单格式：接口接收 itemList:[{columnName,columnValue}] 格式，需完整配置字段映射列表。',
                  },
                  name: 'mode',
                  setter: {
                    componentName: 'SelectSetter',
                    props: {
                      options: [
                        { label: '① 直接透传（字段名与接口参数名一致）', value: 'passthrough' },
                        { label: '② 字段重命名（字段名与接口参数名不一致）', value: 'rename' },
                        { label: '③ 动态表单格式（itemList 格式）', value: 'itemList' },
                      ],
                    },
                    initialValue: 'passthrough',
                  },
                },
                // ── rename 模式：字段重命名映射 ───────────────────────────
                {
                  title: {
                    label: '字段重命名规则',
                    tip: '每行配置一条重命名规则，将表单字段名映射到接口参数名。\n· 来源字段（表单字段名）：填写表单项中 field 的值，例如 user_name\n· 目标参数名（接口参数名）：接口实际接收的参数名，例如 username\n\n未在此处列出的字段，将按原名透传到请求参数中。\n不需要填写表单中所有字段，只填需要重命名的字段即可。',
                  },
                  name: 'fieldRenameMap',
                  condition: (target: any) =>
                    target.parent?.getPropValue?.('mode') === 'rename',
                  setter: {
                    componentName: 'ArraySetter',
                    props: {
                      itemSetter: {
                        componentName: 'ObjectSetter',
                        props: {
                          config: {
                            items: [
                              {
                                title: {
                                  label: '来源字段（表单字段名）',
                                  tip: '表单项中 field 的值，即当前使用的字段名，例如：user_name',
                                },
                                name: 'fromField',
                                important: true,
                                display: 'inline',
                                setter: {
                                  componentName: 'StringSetter',
                                  isRequired: true,
                                  initialValue: '',
                                },
                              },
                              {
                                title: {
                                  label: '目标参数名（接口参数名）',
                                  tip: '接口实际接收的参数名，例如：username',
                                },
                                name: 'toField',
                                important: true,
                                display: 'inline',
                                setter: {
                                  componentName: 'StringSetter',
                                  isRequired: true,
                                  initialValue: '',
                                },
                              },
                            ],
                          },
                        },
                        initialValue: () => ({ fromField: '', toField: '' }),
                      },
                    },
                    initialValue: [],
                  },
                },
                // ── itemList 模式：目标字段名 ──────────────────────────────
                {
                  title: {
                    label: '目标字段名（itemList 写入位置）',
                    tip: '组装后的 [{columnName,columnValue},...] 数组写入 finalValues 的字段名，默认 itemList。\n需与数据源静态 options.params 中预设的字段名一致，提交时该值会被组装结果覆盖。\n通常保持默认值 itemList 即可。',
                  },
                  name: 'targetField',
                  condition: (target: any) =>
                    target.parent?.getPropValue?.('mode') === 'itemList',
                  setter: {
                    componentName: 'StringSetter',
                    initialValue: 'itemList',
                  },
                },
                // ── itemList 模式：字段映射列表 ────────────────────────────
                {
                  title: {
                    label: '字段映射列表',
                    tip: '每行定义一条映射规则，决定哪些字段进入 itemList，以及每项的 columnName。\n\n· 接口字段名（columnName）：dynamicFormTableRecord 表的字段标识，与后端 schema 一致。\n· 来源字段（field）：从哪个表单字段取值，填写表单项的 field 名，例如 user_name。\n· 模板（template）：用 {字段名} 引用并拼接多个表单字段，与 field 二选一。\n  例如：{banquet_date} {banquet_time} → "2026-03-12 18:00"（将日期和时间合并为一个值）\n\n来源字段与模板只需填一项，两者都填时 field 优先。\n未在此处列出的表单字段不会进入 itemList（也不会出现在请求参数里）。',
                  },
                  name: 'items',
                  condition: (target: any) =>
                    target.parent?.getPropValue?.('mode') === 'itemList',
                  setter: {
                    componentName: 'ArraySetter',
                    props: {
                      itemSetter: {
                        componentName: 'ObjectSetter',
                        props: {
                          config: {
                            items: [
                              {
                                title: {
                                  label: '接口字段名（columnName）',
                                  tip: 'dynamicFormTableRecord 中的字段标识，例如：user_name、banquet_time、guest_count',
                                },
                                name: 'columnName',
                                important: true,
                                display: 'inline',
                                setter: {
                                  componentName: 'StringSetter',
                                  isRequired: true,
                                  initialValue: '',
                                },
                              },
                              {
                                title: {
                                  label: '来源字段',
                                  tip: '从哪个表单字段取值，填写表单项的 field 名，例如：user_name\n与「模板」二选一，只需填一项。',
                                },
                                name: 'field',
                                setter: {
                                  componentName: 'StringSetter',
                                  initialValue: '',
                                },
                              },
                              {
                                title: {
                                  label: '模板',
                                  tip: '用 {字段名} 引用并拼接多个字段值，例如：{banquet_date} {banquet_time}\n与「来源字段」二选一，只需填一项。',
                                },
                                name: 'template',
                                setter: {
                                  componentName: 'StringSetter',
                                  initialValue: '',
                                },
                              },
                            ],
                          },
                        },
                        initialValue: () => ({ columnName: '', field: '' }),
                      },
                    },
                    initialValue: [],
                  },
                },
              ],
            },
          },
        },
      },
      // ─────────────────────────────────────────────────────────────────────
      // 分组六：操作按钮
      // ─────────────────────────────────────────────────────────────────────
      {
        type: 'group',
        title: '操作按钮',
        name: 'actionGroup',
        display: 'accordion',
        items: [
          // ── 对齐方式 ──────────────────────────────────────────────────────
          {
            title: {
              label: '对齐方式',
              tip: '表单底部操作按钮区域的水平对齐方式。\n· 居左：按钮靠左排列\n· 居中：按钮居中排列（默认）\n· 居右：按钮靠右排列',
            },
            name: 'operationAlign',
            setter: {
              componentName: 'RadioGroupSetter',
              props: {
                options: [
                  { title: '居左', value: 'left' },
                  { title: '居中', value: 'center' },
                  { title: '居右', value: 'right' },
                ],
              },
              initialValue: 'center',
            },
          },
          // ── 按钮列表 ──────────────────────────────────────────────────────
          {
            title: {
              label: '按钮列表',
              tip: '配置表单底部的操作按钮。\n\n默认包含「立即预订」（提交，primary 样式）和「重置」（重置，normal 样式）两个按钮，可按需增删改。\n\n字段说明：\n· 按钮文字：按钮显示的文字，例如：立即预订、保存草稿、取消\n· 操作类型：\n    提交表单 → 校验通过后收集字段值 → 调用「提交数据源（Fetch）」接口 → 触发 onSubmit 事件\n    重置表单 → 清空所有字段值，触发 onReset 事件\n    自定义   → 直接触发「点击事件」，不操作表单\n· 按钮样式：主要（primary 蓝色）/ 次要（secondary）/ 普通（normal 灰色）\n· 提交数据源（Fetch）：仅「提交表单」类型生效。点击后弹出 Fetch 数据源配置面板，选择接口地址和请求参数，请求参数支持绑定到表单字段值，提交时自动携带表单数据发起请求。\n· 提交时校验：关闭后跳过必填校验直接提交（适合草稿保存）\n· 点击事件：仅「自定义」类型生效\n\n不配置任何按钮时表单不显示按钮区域。',
            },
            name: 'operations',
            setter: {
              componentName: 'ArraySetter',
              props: {
                itemSetter: {
                  componentName: 'ObjectSetter',
                  props: {
                    config: {
                      items: [
                        // ── 按钮文字
                        {
                          title: {
                            label: '按钮文字',
                            tip: '按钮上显示的文字，例如：立即预订、保存草稿、取消',
                          },
                          name: 'text',
                          important: true,
                          display: 'inline',
                          setter: {
                            componentName: 'StringSetter',
                            isRequired: true,
                            initialValue: '立即预订',
                          },
                        },
                        // ── 操作类型
                        {
                          title: {
                            label: '操作类型',
                            tip: '· 提交表单：校验 → 收集字段值 → 调用「提交数据源（Fetch）」 → 触发 onSubmit 事件\n· 重置表单：清空所有字段，触发 onReset 事件\n· 自定义：直接调用「点击事件」函数，不涉及表单操作',
                          },
                          name: 'action',
                          important: true,
                          display: 'inline',
                          setter: {
                            componentName: 'SelectSetter',
                            props: {
                              options: [
                                { label: '提交表单', value: 'submit' },
                                { label: '重置表单', value: 'reset' },
                                { label: '自定义', value: 'custom' },
                              ],
                            },
                            initialValue: 'submit',
                          },
                          extraProps: {
                            setValue: (target: any, value: string) => {
                              // 根据操作类型自动填充默认文字（仅当文字为空时）
                              const textMap: Record<string, string> = {
                                submit: '立即预订',
                                reset: '重置',
                                custom: '按钮',
                              }
                              if (!target.parent?.getPropValue?.('text')) {
                                target.parent?.setPropValue?.('text', textMap[value] || '按钮')
                              }
                              // 根据操作类型自动设置默认样式
                              if (!target.parent?.getPropValue?.('type')) {
                                const typeMap: Record<string, string> = {
                                  submit: 'primary',
                                  reset: 'normal',
                                  custom: 'normal',
                                }
                                target.parent?.setPropValue?.('type', typeMap[value] || 'normal')
                              }
                              target.parent?.setPropValue?.('action', value)
                            },
                          },
                        },
                        // ── 按钮样式
                        {
                          title: {
                            label: '按钮样式',
                            tip: '· 主要（primary）：蓝色高亮，适合提交等主操作\n· 次要（secondary）：灰白色，适合次要操作\n· 普通（normal）：普通灰色样式，适合重置等辅助操作',
                          },
                          name: 'type',
                          setter: {
                            componentName: 'SelectSetter',
                            props: {
                              options: [
                                { label: '主要 (primary)', value: 'primary' },
                                { label: '次要 (secondary)', value: 'secondary' },
                                { label: '普通 (normal)', value: 'normal' },
                              ],
                            },
                            initialValue: 'normal',
                          },
                        },
                        // ── 提交时校验（仅 submit）
                        {
                          title: {
                            label: '提交时校验',
                            tip: '开启后点击此按钮时先执行必填校验，校验不通过则不触发提交。\n关闭后跳过校验，直接提交（适合"草稿保存"等场景）。\n仅对「提交表单」类型按钮生效。',
                          },
                          name: 'submitValidate',
                          condition: (target: any) =>
                            target.parent?.getPropValue?.('action') === 'submit',
                          setter: {
                            componentName: 'BoolSetter',
                            initialValue: true,
                          },
                        },
                        // ── 提交数据源（Fetch，仅 submit）
                        {
                          title: {
                            label: '提交数据源（Fetch）',
                            tip: '绑定页面级 Fetch 数据源，点击提交按钮校验通过后自动调用该数据源发起请求。\n\n【配置步骤】\n1. 在页面左侧「数据源」面板新建一个 fetch 类型数据源\n   · 填写接口地址（URI）、请求方式（POST/PUT）、鉴权 Headers\n   · isInit 设为 false（提交时才触发，不需要页面初始化时自动加载）\n2. 在此处点击「变量」按钮，选择 this.dataSourceMap.<数据源ID>\n\n【参数说明】\n表单提交时会将所有字段值（含 computedFields / submitMapping 处理后的 itemList）\n作为覆盖参数传入 .load(values)，与数据源静态 params 合并，无需手写 onSubmit。\n\n【多按钮场景】\n每个「提交表单」按钮可绑定独立的数据源，如"保存草稿"绑定草稿接口，"正式提交"绑定提交接口。\n\n仅对「提交表单」类型按钮生效。',
                          },
                          name: 'dataSource',
                          condition: (target: any) =>
                            target.parent?.getPropValue?.('action') === 'submit',
                          setter: {
                            componentName: 'MixedSetter',
                            props: {
                              setters: [
                                {
                                  componentName: 'VariableSetter',
                                  title: '绑定数据源变量',
                                },
                                {
                                  componentName: 'ExpressionSetter',
                                  title: '表达式',
                                },
                              ],
                            },
                          },
                        },
                        // ── 点击事件（仅 custom）
                        {
                          title: {
                            label: '点击事件',
                            tip: '自定义按钮被点击时调用的函数，例如：跳转页面、打开弹窗。\n仅对「自定义」类型按钮生效。',
                          },
                          name: 'onClick',
                          condition: (target: any) =>
                            target.parent?.getPropValue?.('action') === 'custom',
                          setter: {
                            componentName: 'FunctionSetter',
                          },
                          extraProps: {
                            supportVariable: true,
                          },
                        },
                      ],
                    },
                  },
                  initialValue: () => ({ text: '立即预订', action: 'submit', type: 'primary', submitValidate: true }),
                },
              },
              initialValue: [
                { text: '立即预订', action: 'submit', type: 'primary', submitValidate: true },
                { text: '重置', action: 'reset', type: 'normal' },
              ],
            },
          },
        ],
      },
    ],
    supports: {
      style: true,
      events: [
        {
          name: 'onReset',
          template:
            "onReset(\${extParams}){\n// \u70b9\u51fb\u91cd\u7f6e\u6309\u94ae\u540e\u89e6\u53d1\n// \u53ef\u5728\u6b64\u5904\u540c\u6b65\u9875\u9762 state \u6216\u6267\u884c\u5176\u4ed6\u6e05\u7a7a\u903b\u8f91\nconsole.log('[CustomForm] onReset');\n}",
        },
        {
          name: 'onChange',
          template:
            "onChange(field, value, allValues,\${extParams}){\n// 任意字段值变化时触发\n// field     = 变化的字段名（字符串）\n// value     = 该字段的最新值\n// allValues = 当前所有字段值（含 computedFields 计算字段）\n// 常见用法：将字段值同步到页面 state\n// this.setState({ [field]: value })\nconsole.log('[CustomForm] onChange', field, value, allValues);\n}",
        },
        {
          name: 'onSubmit',
          template:
            "onSubmit(values, errors, field,\${extParams}){\n// 提交成功（校验通过）时触发\n// values = 所有字段的当前值（含 computedFields 计算字段）\n// 无需再手动组装字段，直接使用 values 对象即可\nconsole.log('[CustomForm] onSubmit', values);\n}",
        },
        {
          name: 'onSubmitFailed',
          template:
            "onSubmitFailed(values, errors, field,\${extParams}){\n// 提交失败（校验未通过）时触发\n// errors = 校验错误信息对象，key 为字段名\nconsole.log('[CustomForm] onSubmitFailed', errors);\n}",
        },
      ],
    },
  },
}

const snippets: IPublicTypeSnippet[] = [
  {
    title: '自定义表单（完整示例）',
    screenshot: '',
    schema: {
      componentName: 'CustomForm',
      props: {
        columns: 2,
        initialValues: [
          { field: 'guest_count', valueType: 'fixed', value: 10 },
        ],
        computedFields: [
          { targetField: 'order_desc', template: '{package_name},{package_price}元，预订日期：{banquet_date}，人数：{guest_count}人' },
        ],
        formItems: [
          {
            field: 'banquet_date',
            label: '宴请日期',
            required: true,
            placeholder: '请选择日期时间',
            componentType: 'DateTimePicker',
            componentProps: { format: 'YYYY-MM-DD HH:mm' },
          },
          {
            field: 'guest_count',
            label: '宴请人数',
            required: true,
            placeholder: '请输入人数',
            componentType: 'NumberPicker',
          },
          {
            field: 'package_name',
            label: '套餐名称',
            required: true,
            componentType: 'Select',
            placeholder: '请选择套餐',
            options: [],
          },
          {
            field: 'package_price',
            label: '套餐价格',
            componentType: 'Input',
            componentProps: { readOnly: true },
            extra: '选择套餐后自动填入',
          },
          {
            field: 'user_name',
            label: '预订人姓名',
            required: true,
            placeholder: '请输入姓名',
            componentType: 'Input',
          },
          {
            field: 'user_mobile',
            label: '联系方式',
            required: true,
            placeholder: '请输入手机号',
            componentType: 'Input',
          },
          {
            field: 'memo',
            label: '备注',
            placeholder: '请输入备注（选填）',
            componentType: 'TextArea',
            columnSpan: 2,
          },
        ],
        fieldLinkage: [
          { watchField: 'package_name', linkageMode: 'simple', matchValue: '豪华套餐', fillField: 'package_price', fillValueType: 'fixed', fillValue: 9800 },
        ],
        operations: [
          { text: '立即预订', action: 'submit', type: 'primary', submitValidate: true },
          { text: '重置', action: 'reset', type: 'normal' },
        ],
      },
    },
  },
]

export default {
  ...CustomFormMeta,
  snippets,
}
