表单页设计

云控专属可视化开发工具

  • 全网独家定制
  • 数据私有化部署
  • 支持多级菜单管理
  • 多用户分级管理
  • 二次开发成本直降80%

全局方法

提供两个用于获取表单数据的全局方法:

方法名说明
get[formName]ControlByName(name)根据字段 name 获取表单项(完整数据对象)
get[formName]ValueByName(name)根据字段 name 获取表单项的值

说明

  • formName表单名称(动态拼接)
  • Control:返回完整字段对象(包含 label、type、value 等)
  • name表单字段唯一标识
  • Value:仅返回字段值,多用于跨字段取值、表单联动及复杂校验场景(如确认密码校验

表单 opt 配置

opt = {
  list: [...],     // 字段配置
  form: {...},     // 表单配置
  events: {...},    // 事件
  config: {...}    // 表单接口行为配置
}

字段列表 list

每个字段对象包含以下属性:

属性名说明类型是否必填默认值
type组件类型string
name字段名(唯一标识)string
control组件属性配置object{}
formItem表单项配置(标签、校验规则)object{}
customRules自定义校验规则array[]
config扩展配置(远程数据、联动等)object{}
{
  type: "input",                          // 组件类型,固定为 input
  name: "username",                       // 字段名,绑定数据用的 key
  control: {
    modelValue: "",                       // 绑定的输入值,双向绑定
    type: "text",                        // 输入框类型,如 text、password 等
    placeholder: "请输入用户名",            // 输入框占位提示文字
    maxlength: 20,                       // 最大输入长度
    minlength: 3,                        // 最小输入长度
    showWordLimit: true,                 // 是否显示字数统计
    clearable: true,                     // 是否显示清除按钮
    disabled: false,                     // 是否禁用输入框
    readonly: false,                     // 是否只读
    autocomplete: "off",                 // 浏览器自动完成功能,off 禁用
    autofocus: false,                    // 是否自动聚焦
    tabindex: "1",                      // tab 键顺序
    validateEvent: true,                 // 是否触发表单验证事件
    inputStyle: {                        // 输入框自定义样式
      color: "#333",                    // 字体颜色
      fontSize: "14px"                  // 字体大小
    },
    size: "default",                    // 输入框尺寸,可选 small、default、large
    options: [                         // 选项数组,常用于 select、radio、checkbox 等
      { label: "选项1", value: "1" }, // 选项 label 和 value
      { label: "选项2", value: "2" }
    ],
    multiple: false,                   // 是否多选,select 组件常用
    filterable: true,                  // 是否支持搜索筛选,select 组件常用
    rows: 4,                          // 多行文本框行数,textarea 专用
    resize: "vertical",               // textarea 是否允许调整大小及方向
    autosize: {                       // textarea 自动高度配置
      minRows: 2,                    // 最小行数
      maxRows: 6                     // 最大行数
    },
    buttonStyle: "outline",           // radio 按钮样式
    min: 0,                          // 输入数字类组件最小值,如 inputNumber、slider
    max: 100,                        // 最大值
    step: 1,                         // 步长
    format: "yyyy-MM-dd",             // 日期格式,datePicker 专用
    placeholderTime: "选择时间",       // 时间选择器占位提示
    disabledDate: (date) => date < new Date(),  // 禁用日期函数,禁止选择今天之前日期
    showAlpha: false,                 // 颜色选择器是否显示透明度
    activeColor: "#409EFF",           // 颜色选择器主题色
    checked: false,                   // 开关状态,switch 组件专用
    icon: "Check",                   // 按钮图标名
    loading: false,                  // 按钮加载状态
    text: "提交",                    // 按钮文本
    columns: [                       // 表格列配置
      { label: "姓名", prop: "name" },
      { label: "年龄", prop: "age" }
    ],
    data: [],                        // 表格数据
    style: {                        // 容器样式
      padding: "10px",              // 内边距
      backgroundColor: "#f5f5f5"   // 背景颜色
    },
    height: 300,                    // 富文本编辑器高度
    action: "/upload",              // 上传接口地址
    multipleUpload: false,          // 是否支持多文件上传
    showFileList: true              // 是否显示文件列表
  },
  formItem: {
    label: "确认密码",                // 表单标签
    rules: [
      {
        validator: (rule, value, callback) => {  // 自定义验证函数
          if (value === "") {
            callback(new Error("请输入确认密码"));  // 不符合规则时传入错误信息
          } else {
            const password = getform1ValueByName("password");  // 获取其他字段值进行校验
            if (password === value) {
              callback();                            // 校验通过
            } else {
              callback(new Error("两次密码输入不一致"));  // 校验失败错误提示
            }
          }
        },
        trigger: "blur"                      // 触发校验的时机
      }
    ]
  },
  customRules: [
    {
      type: "required",                   // 必填规则类型
      message: "必填项",                   // 提示信息
      trigger: "blur"                     // 触发校验时机
    }
  ],
  config: {
    optionsType: 1,                      // 自定义配置项类型
    optionsFun: "demo/options",          // 远程接口或本地方法名
    method: "get",                      // 请求方法
    linkage: "name1",                   // 关联的其他组件字段名
    before: (params, { type, route, model }) => {  // 请求前钩子,修改参数
      console.log(type);
      return params;
    },
    after: (res, success, type) => {    // 请求后钩子,处理结果
      console.log(type, res);
      return res;
    }
  }
}

name 字段名

说明:绑定数据的字段名,在同一表单中必须唯一

项目内容
类型string
必填
默认值
示例"username"

control 组件属性配置

属性名说明类型是否必填默认值示例值
modelValue绑定的输入值,通常双向绑定string | number""""
type输入框类型,如 text、passwordstring"text""text"
placeholder输入框占位提示文字string"""请输入用户名"
maxlength最大输入长度number20
minlength最小输入长度number3
showWordLimit是否显示字数统计booleanfalsetrue
clearable是否显示清除按钮booleanfalsetrue
disabled是否禁用输入框booleanfalsefalse
readonly是否只读booleanfalsefalse
autocomplete浏览器自动完成功能string"off""off"
autofocus是否自动聚焦booleanfalsefalse
tabindextab 键顺序string | number"1"
validateEvent是否触发表单验证事件booleantruetrue
inputStyle输入框自定义样式对象object{}{ color: "#333", fontSize: "14px" }
size输入框尺寸,支持 small/default/largestring"default""default"
options选项数组(常用于 select、radio 等)Array<{ label: string; value: any }>[][ { label: "选项1", value: "1" }, { label: "选项2", value: "2" } ]
multiple是否多选booleanfalsefalse
filterable是否支持搜索筛选booleanfalsetrue
rows多行文本框行数,textarea 专用number24
resizetextarea 是否允许调整大小及方向string"none""vertical"
autosizetextarea 自动高度配置objectnull{ minRows: 2, maxRows: 6 }
buttonStyleradio 按钮样式string"outline""outline"
min数字类组件最小值number00
max数字类组件最大值number100100
step数字类组件步长number11
format日期格式,datePicker 专用string"""yyyy-MM-dd"
placeholderTime时间选择器占位提示string"""选择时间"
disabledDate禁用日期函数functionnull(date) => date < new Date()
showAlpha颜色选择器是否显示透明度booleanfalsefalse
activeColor颜色选择器主题色string"#409EFF""#409EFF"
checked开关状态,switch 组件专用booleanfalsefalse
icon按钮图标名string"""Check"
loading按钮加载状态booleanfalsefalse
text按钮文本string"""提交"
columns表格列配置Array<{ label: string; prop: string }>[][ { label: "姓名", prop: "name" }, { label: "年龄", prop: "age" } ]
data表格数据Array[][]
style容器样式object{}{ padding: "10px", backgroundColor: "#f5f5f5" }
height富文本编辑器高度number300300
action上传接口地址string"""/upload"
multipleUpload是否支持多文件上传booleanfalsefalse
showFileList是否显示文件列表booleantruetrue

formItem 表单项配置

属性名说明类型是否必填默认值示例值
label表单标签文字string"""确认密码"
rules校验规则数组Array见自定义验证函数示例

校验示例

opt = {
  list: [
  {
    type: "password",
    name: "userPassword",
    control:
    {
      modelValue: ""
    },
    config:
    {},
    formItem:
    {
      label: "密码",
      rules: [
      {
        required: true,
        message: "请输入密码",
        trigger: "blur"
      },
      {
        min: 6,
        message: "密码长度不能少于6位",
        trigger: "blur"
      }]
    }
  },
  {
    type: "password",
    name: "confirmPassword",
    control:
    {
      modelValue: ""
    },
    config:
    {},
    formItem:
    {
      label: "确认密码",
      rules: [
      {
        required: true,
        message: "请再次输入密码",
        trigger: "blur"
      },
      {
        validator: (rule, value, callback) =>
        {

          // 👉 注意这里也要改
          const password = getTestDemoValueByName("userPassword");

          if (!value)
          {
            callback(new Error("请再次输入密码"));
          }
          else if (value !== password)
          {
            callback(new Error("两次密码输入不一致"));
          }
          else
          {
            callback();
          }
        },
        trigger: "blur"
      }]
    }
  }],
  form:
  {
    size: "default",
    labelWidth: "100px",
    name: "TestDemo"
  },
  config:
  {
    submitCancel: true
  }
}

customRules 自定义校验规则

属性名说明类型是否必填默认值示例值
type规则类型string"required"
message规则提示信息string"必填项"
trigger触发校验时机string"blur"
opt = {
  list: [

  {
    type: "input",
    control:
    {
      modelValue: "2@qq.com"
    },
    config:
    {},
    name: "inputEmail",
    formItem:
    {
      label: "邮箱地址"
    },
    customRules: [
    {
      type: "required",
      message: "必填项",
      trigger: "blur"
    },
    {
      type: "email",
      message: "请输入邮箱地址",
      trigger: "blur"
    }]
  },

 ],
  form:
  {
    size: "default"
  },
  config:
  {
    submitCancel: true
  },
  events:
  {
  }
}

config 扩展配置

属性名说明类型是否必填默认值示例值
optionsType选项数据来源类型number1
optionsFun远程接口 URL 地址string"https://api.example.com/v1/getOptions"
method请求方法string"post"
linkage关联其他组件字段名string"name1"

optionsType 取值说明:

说明示例
0固定选项:使用 options 数组中的静态数据,optionsFun 无需配置options: [{ label: "选项A", value: "a" }]
1远程接口:通过 optionsFun 配置的接口 URL 动态加载选项数据optionsFun: "https://api.example.com/v1/getOptions"
2数据字典:从系统字典中加载选项数据。字典可在**页面设计 → 表单配置 → 设置数据字典 中配置,也可在字典管理**中配置全局字典optionsFun: "dict_demo_status"(字典标识)

各类型完整示例:

// optionsType: 0 —— 固定选项
{
  type: "select",
  name: "device_id",
  control: {
    modelValue: "",
    appendToBody: true
  },
  options: [
    { label: "选项1", value: "1" },
    { label: "选项2", value: "2" }
  ],
  config: {
    optionsType: 0
  },
  formItem: {
    label: "设备"
  }
}

// optionsType: 1 —— 远程接口
{
  type: "select",
  name: "user_id",
  control: {
    modelValue: "",
    appendToBody: true
  },
  options: [],
  config: {
    optionsType: 1,
    optionsFun: "https://api.example.com/v1/getUserList",
    method: "post",
    value: "id"
  },
  formItem: {
    label: "用户"
  }
}

// optionsType: 2 —— 数据字典
{
  type: "select",
  name: "status",
  control: {
    modelValue: "",
    appendToBody: true
  },
  options: [],
  config: {
    optionsType: 2,
    optionsFun: "dict_order_status"  // 字典标识
  },
  formItem: {
    label: "订单状态"
  }
}

events 组件事件

某些组件支持在 events 中配置事件回调,用于处理组件特定的交互行为。

事件名适用组件说明参数
clickbutton按钮点击事件instance:组件上下文
submitbutton(嵌套表单场景)子表单提交确认回调instance:包含 selected(子表单数据)、modelcontext
cancelbutton(嵌套表单场景)子表单取消关闭回调instance:组件上下文
beforeselect / selectPlus远程选项数据请求发送前拦截,用于修改请求参数、注入 token 等instance:包含 headersdatatypeenvcontext
afterselect / selectPlus远程选项数据加载完成后处理,用于数据格式映射instance:包含 responsetypesuccess

click(按钮点击)

用于处理按钮点击事件,常见于以下业务场景:

  • 请求数据:点击按钮触发接口请求,获取数据
  • 数据处理:对接口返回数据进行提取、格式化、拼接等操作
  • 更新组件:将处理后的数据回填给表单中的指定组件(如 textarea、table、input 等)

支持同步 / 异步操作,通常配合 env.runtime.request 使用,实现"点击按钮 → 请求数据 → 处理数据 → 回填组件"的完整闭环。

核心能力:

  • 可控制按钮的 loading 状态
  • 可获取当前表单所有字段数据(context.model
  • 可更新任意表单组件的值(直接修改 context.model.xxx
示例
events: {
  click: async (instance) => {
    const { schema, env, context } = instance;

    try {
      // 1️⃣ 开启按钮 loading
      schema.control.loading = true;

      // 2️⃣ 发起请求
      const response = await env.runtime.request({
        url: "https://api.example.com/v1/generate",
        method: "post",
        data: {
          topic: context.model.topic,
          audience: context.model.target_audience
        }
      });

      // 3️⃣ 处理返回数据
      const list = response?.data?.data || [];

      // 4️⃣ 更新给指定组件(回填数据)
      // 场景A:更新给 textarea 组件(拼接为文本)
      context.model.article_content = list
        .map(item => item.content)
        .join("\n\n");

      // 场景B:更新给 table 组件(渲染为表格数据)
      context.model.articleTable = list.map((item, index) => ({
        id: index,
        content: item.content
      }));

      env.runtime.ElMessage.success("生成成功");
    } catch (err) {
      console.error(err);
      env.runtime.ElMessage.error("请求失败");
    } finally {
      // 5️⃣ 关闭按钮 loading
      schema.control.loading = false;
    }
  }
}

submit(子表单提交回调)

button 组件配置了 config.source(子表单 ID)时,点击按钮会打开指定的子表单。子表单提交确认后触发 submit 事件,用于接收子表单返回的数据并回填到主表单。

核心参数说明:

参数类型说明
selectedObject子表单中表格字段的数据,键为表格字段的 name,值为已选中的行数据(数组)
modelObject子表单所有字段的完整数据对象,表格字段的值为 JSON 字符串
context.modelObject主表单数据模型(推荐使用,通过它回填数据到主表单字段)
envObject运行环境(包含 runtime.ElMessage 等)

modelselected 的关系:

// model:子表单所有字段的完整数据
model = {
  article_topic: "如何提高学习效率",
  target_audience: "大学生",
  writing_style: "通俗易懂",
  paragraph_count: 3,
  articleTable: '[{"id":0,"content":"段落1"},{"id":1,"content":"段落2"},{"id":2,"content":"段落3"}]'  // ⚠️ JSON 字符串
}

// selected:仅包含表格字段,值为已选中行的数组
selected = {
  articleTable: [                        // ✅ 数组,仅已选中的行
    { id: 0, content: "段落1" },
    { id: 2, content: "段落3" }
  ]
}

两种回填方式:

方式数据来源表格字段格式适用场景
通过 selected 回填selected.表格字段名数组获取表格中用户勾选的数据,遍历处理后回填
通过 model 回填model.表格字段名model.普通字段名JSON 字符串直接存储完整数据(如保存到数据库)或获取普通字段值
示例
events: {
  submit: (instance) => {
    const { selected, model, env, context } = instance;

    console.warn("📌 子表单完整数据(model):", model);
    console.warn("📌 表格已选数据(selected):", selected);

    // =========================================================
    // 方式一:通过 selected 回填(仅表格已选中的行)
    // =========================================================
    // selected.articleTable 是数组,直接遍历提取 content
    const aiList = selected.articleTable || [];
    const aiText = aiList
      .filter(item => item && item.content)
      .map(item => String(item.content))
      .join("\n\n");

    const oldText = context.model.article_content || "";
    if (oldText && oldText.trim() !== "") {
      context.model.article_content = oldText + "\n\n" + aiText;
    } else {
      context.model.article_content = aiText;
    }

    // =========================================================
    // 方式二:通过 model 回填(子表单所有字段)
    // =========================================================
    // model.articleTable 是 JSON 字符串,可直接赋值给主表字段
    context.model.articleTableJson = model.articleTable;

    // 获取子表单普通字段的值
    context.model.topic = model.article_topic;
    context.model.audience = model.target_audience;
    context.model.style = model.writing_style;
    context.model.count = model.paragraph_count;

    env.runtime.ElMessage.success("回填成功");
  },
  cancel: (instance) => {
    console.log("子表单已取消");
  }
}

cancel(子表单取消回调)

子表单点击取消或关闭时触发。

before(选项请求前拦截)

用于 select / selectPlus 组件远程加载选项数据前,对请求进行修改。更多参数详情请参考 before(instance)

示例
events: {
  before: (instance) => {
    const { headers, data, type, env } = instance;

    // 注入 token
    const newHeaders = {
      ...headers,
      Authorization: "Bearer " + (env?.user?.token || "")
    };

    // 修改请求参数
    const newData = {
      ...data,
      status: 1  // 只加载启用状态的选项
    };

    return {
      url: instance.url,
      method: instance.method || "post",
      headers: newHeaders,
      data: newData
    };
  }
}

after(选项数据后处理)

用于 select / selectPlus 组件远程加载选项数据后,对返回结果进行数据映射或结构转换。更多参数详情请参考 after(instance)

示例
events: {
  after: (instance) => {
    const { type, success, response } = instance;

    // 将后端返回的数据映射为组件所需的格式
    return {
      code: 200,
      data: response?.data?.data?.list,  // 提取选项数组
      msg: response?.data?.msg
    };
  }
}

type 组件类型

  • {string} 组件类型标识(必填)

组件类型用于标识当前表单项的类型,固定字符串,不可为空。

支持类型:

  • input:单行文本
  • textarea:多行文本
  • radio:单选框
  • checkbox:多选框
  • select:下拉选择
  • datePicker:日期选择器
  • timePicker:时间选择器
  • colorPicker:颜色选择器
  • switch:开关
  • inputNumber:数字输入框
  • cascader:级联选择器
  • rate:评分
  • slider:滑块
  • treeSelect:树选择
  • txt:文本展示
  • title:标题
  • tabs:标签页
  • flex:布局容器
  • card:卡片
  • divider:分割线
  • button:按钮
  • table:表格
  • component:自定义组件
  • upload:上传
  • tinymce:富文本编辑器
  • grid:栅格布局
  • div:普通容器

input(单行文本)

用于输入标题、名称、链接、UID 等简单字符串信息。

🔸type 固定值:"input"(单行文本输入组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的输入值string | number""
type输入框类型(text 等)string"text"
placeholder输入框占位提示文字string""
maxlength最大输入长度number
minlength最小输入长度number
showWordLimit是否显示字数统计booleanfalse
clearable是否显示清除按钮booleanfalse
disabled是否禁用输入框booleanfalse
readonly是否只读booleanfalse
autocomplete浏览器自动完成功能string"off"
autofocus是否自动聚焦booleanfalse
tabindextab 键顺序string | number
validateEvent是否触发表单验证事件booleantrue
inputStyle输入框自定义样式object{}
size输入框尺寸(small等)string"default"
示例
{
  "type": "input",
  "name": "username",
  "control": {
    "modelValue": "",
    "type": "text",
    "placeholder": "请输入用户名",
    "maxlength": 20,
    "minlength": 3,
    "showWordLimit": true,
    "clearable": true,
    "disabled": false,
    "readonly": false,
    "autocomplete": "off",
    "autofocus": false,
    "tabindex": "1",
    "validateEvent": true,
    "inputStyle": {},
    "size": "default"
  },
  "formItem": {
    "label": "用户名",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!/^[a-zA-Z]/.test(value)) {
            callback(new Error("必须以字母开头"));
          } else {
            callback();
          }
        },
        "trigger": "blur"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请输入用户名",
      "trigger": "blur"
    },
    {
      "min": 3,
      "max": 20,
      "message": "长度在 3 到 20 个字符",
      "trigger": "blur"
    }
  ],
  "config": {}
}

textarea(多行文本)

用于输入多行文本信息,如备注、评论、详细描述等。

🔸type 固定值:"textarea"(多行文本输入组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的输入值string""
placeholder输入框占位提示文字string""
maxlength最大输入长度number
minlength最小输入长度number
rows显示行数number2
showWordLimit是否显示字数统计booleanfalse
clearable是否显示清除按钮booleanfalse
disabled是否禁用输入框booleanfalse
readonly是否只读booleanfalse
resize是否允许调整大小string"none"
autofocus是否自动聚焦booleanfalse
validateEvent是否触发表单验证事件booleantrue
inputStyle输入框自定义样式object{}
size输入框尺寸string"default"
示例
{
  "type": "textarea",
  "name": "description",
  "control": {
    "modelValue": "",
    "placeholder": "请输入内容",
    "maxlength": 500,
    "minlength": 5,
    "rows": 4,
    "showWordLimit": true,
    "clearable": true,
    "disabled": false,
    "readonly": false,
    "resize": "vertical",
    "autofocus": false,
    "validateEvent": true,
    "inputStyle": {},
    "size": "default"
  },
  "formItem": {
    "label": "描述",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value || value.trim() === "") {
            callback(new Error("请输入描述"));
          } else {
            callback();
          }
        },
        "trigger": "blur"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请输入描述",
      "trigger": "blur"
    }
  ],
  "config": {}
}

radio(单选框)

用于在多个选项中选择一个。

🔸type 固定值:"radio"(单选框组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的选中值string | number
options选项数组Array<{label, value}>[]
disabled是否禁用booleanfalse
size单选框组尺寸string"default"
border是否显示边框booleanfalse
示例
{
  "type": "radio",
  "name": "gender",
  "control": {
    "modelValue": "male",
    "options": [
      { "label": "", "value": "male" },
      { "label": "", "value": "female" }
    ],
    "disabled": false,
    "size": "default",
    "border": false
  },
  "formItem": {
    "label": "性别",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value) {
            callback(new Error("请选择性别"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请选择性别",
      "trigger": "change"
    }
  ],
  "config": {}
}

checkbox(多选框)

用于多选操作,用户可选择多个选项。

🔸type 固定值:"checkbox"(多选框组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的选中值数组array[]
options选项数组Array<{label, value}>[]
disabled是否禁用booleanfalse
size多选框组尺寸string"default"
min最小选中数量number
max最大选中数量number
示例
{
  "type": "checkbox",
  "name": "hobbies",
  "control": {
    "modelValue": ["reading", "traveling"],
    "options": [
      { "label": "阅读", "value": "reading" },
      { "label": "旅行", "value": "traveling" },
      { "label": "运动", "value": "sports" }
    ],
    "disabled": false,
    "size": "default",
    "min": 1,
    "max": 3
  },
  "formItem": {
    "label": "兴趣爱好",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value || value.length === 0) {
            callback(new Error("请选择至少一个爱好"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请选择至少一个爱好",
      "trigger": "change"
    },
    {
      "type": "array",
      "min": 1,
      "message": "请选择至少一个爱好",
      "trigger": "change"
    }
  ],
  "config": {}
}

select(下拉选择)

用于从下拉列表中选择一个或多个值。

🔸type 固定值:"select"(下拉选择组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的值(多选时为数组)string | array""
options选项数组Array<{label, value}>[]
multiple是否多选booleanfalse
disabled是否禁用booleanfalse
clearable是否显示清除按钮booleanfalse
placeholder占位提示文字string""
filterable是否支持搜索过滤booleanfalse
size组件尺寸string"default"
示例
{
  "type": "select",
  "name": "country",
  "control": {
    "modelValue": "",
    "options": [
      { "label": "中国", "value": "cn" },
      { "label": "美国", "value": "us" },
      { "label": "英国", "value": "uk" }
    ],
    "multiple": false,
    "disabled": false,
    "clearable": true,
    "placeholder": "请选择国家",
    "filterable": true,
    "size": "default"
  },
  "formItem": {
    "label": "国家",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value) {
            callback(new Error("请选择国家"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请选择国家",
      "trigger": "change"
    }
  ],
  "config": {}
}

datePicker(日期选择器)

用于选择日期或日期范围。

🔸type 固定值:"datePicker"(日期选择器组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的值(范围模式为数组)string | array | nullnull
type选择器类型string"date"
format展示格式string
valueFormat绑定值格式string
placeholder占位提示文字string""
disabled是否禁用booleanfalse
clearable是否显示清除按钮booleanfalse
editable输入框是否可编辑booleantrue
range是否为范围选择booleanfalse
size组件尺寸string"default"
示例
{
  "type": "datePicker",
  "name": "birthday",
  "control": {
    "modelValue": null,
    "type": "date",
    "format": "yyyy-MM-dd",
    "valueFormat": "yyyy-MM-dd",
    "placeholder": "选择日期",
    "disabled": false,
    "clearable": true,
    "editable": true,
    "range": false,
    "size": "default"
  },
  "formItem": {
    "label": "生日",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value) {
            callback(new Error("请选择日期"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请选择日期",
      "trigger": "change"
    }
  ],
  "config": {}
}

timePicker(时间选择器)

用于选择时间或时间范围。

🔸type 固定值:"timePicker"(时间选择器组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的值(范围模式为数组)string | array | nullnull
isRange是否为时间范围选择booleanfalse
format显示格式string"HH:mm:ss"
valueFormat绑定值格式string"HH:mm:ss"
placeholder占位提示文字string""
disabled是否禁用booleanfalse
clearable是否显示清除按钮booleanfalse
size组件尺寸string"default"
示例
{
  "type": "timePicker",
  "name": "meetingTime",
  "control": {
    "modelValue": null,
    "isRange": false,
    "format": "HH:mm:ss",
    "valueFormat": "HH:mm:ss",
    "placeholder": "选择时间",
    "disabled": false,
    "clearable": true,
    "size": "default"
  },
  "formItem": {
    "label": "会议时间",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value) {
            callback(new Error("请选择时间"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请选择时间",
      "trigger": "change"
    }
  ],
  "config": {}
}

colorPicker(颜色选择器)

用于选择颜色值。

🔸type 固定值:"colorPicker"(颜色选择器组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的颜色值string""
disabled是否禁用booleanfalse
showAlpha是否显示透明度选择booleanfalse
size组件尺寸string"default"
示例
{
  "type": "colorPicker",
  "name": "themeColor",
  "control": {
    "modelValue": "#409EFF",
    "disabled": false,
    "showAlpha": false,
    "size": "default"
  },
  "formItem": {
    "label": "主题颜色",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value) {
            callback(new Error("请选择颜色"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请选择颜色",
      "trigger": "change"
    }
  ],
  "config": {}
}

switch(开关)

用于切换开/关状态。

🔸type 固定值:"switch"(开关组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的开关状态booleanfalse
disabled是否禁用booleanfalse
activeText开启时显示文字string""
inactiveText关闭时显示文字string""
activeColor开启时颜色string"#409EFF"
inactiveColor关闭时颜色string"#C0CCDA"
示例
{
  "type": "switch",
  "name": "isActive",
  "control": {
    "modelValue": true,
    "disabled": false,
    "activeText": "",
    "inactiveText": "",
    "activeColor": "#409EFF",
    "inactiveColor": "#C0CCDA"
  },
  "formItem": {
    "label": "是否激活",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          callback();
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [],
  "config": {}
}

inputNumber(数字输入框)

用于输入数字,可以设置范围、步进等。

🔸type 固定值:"inputNumber"(数字输入框组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的数值number0
min最小值number
max最大值number
step步进值number1
disabled是否禁用booleanfalse
size组件尺寸string"default"
示例
{
  "type": "inputNumber",
  "name": "age",
  "control": {
    "modelValue": 18,
    "min": 0,
    "max": 120,
    "step": 1,
    "disabled": false,
    "size": "default"
  },
  "formItem": {
    "label": "年龄",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (value === null || value === undefined) {
            callback(new Error("请输入年龄"));
          } else if (value < 0 || value > 120) {
            callback(new Error("年龄范围为 0-120"));
          } else {
            callback();
          }
        },
        "trigger": "blur"
      }
    ]
  },
  "customRules": [
    {
      "type": "number",
      "min": 0,
      "max": 120,
      "message": "年龄范围为 0-120",
      "trigger": "blur"
    }
  ],
  "config": {}
}

cascader(级联选择器)

用于选择多级分类数据。

🔸type 固定值:"cascader"(级联选择器组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的选中值数组array[]
options级联选项数据Array<{label, value, children}>[]
disabled是否禁用booleanfalse
clearable是否显示清除按钮booleanfalse
placeholder占位提示文字string""
size组件尺寸string"default"
示例
{
  "type": "cascader",
  "name": "address",
  "control": {
    "modelValue": [],
    "options": [
      {
        "label": "浙江",
        "value": "zj",
        "children": [
          { "label": "杭州", "value": "hz" },
          { "label": "宁波", "value": "nb" }
        ]
      },
      {
        "label": "江苏",
        "value": "js",
        "children": [
          { "label": "南京", "value": "nj" },
          { "label": "苏州", "value": "sz" }
        ]
      }
    ],
    "disabled": false,
    "clearable": true,
    "placeholder": "请选择地址",
    "size": "default"
  },
  "formItem": {
    "label": "地址",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value || value.length === 0) {
            callback(new Error("请选择地址"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请选择地址",
      "trigger": "change"
    }
  ],
  "config": {}
}

rate(评分)

用于评分选择,通常显示星星。

🔸type 固定值:"rate"(评分组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue当前评分number0
max最大分数number5
disabled是否禁用booleanfalse
allowHalf是否允许半星评分booleanfalse
showText是否显示文本说明booleanfalse
showScore是否显示数字评分booleanfalse
size组件尺寸string"default"
示例
{
  "type": "rate",
  "name": "score",
  "control": {
    "modelValue": 3,
    "max": 5,
    "disabled": false,
    "allowHalf": true,
    "showText": false,
    "showScore": false,
    "size": "default"
  },
  "formItem": {
    "label": "评分",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (value === null || value === undefined || value === 0) {
            callback(new Error("请评分"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请评分",
      "trigger": "change"
    }
  ],
  "config": {}
}

slider(滑动条)

用于选择数值范围或单个数值。

🔸type 固定值:"slider"(滑动条组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue当前数值(范围模式为数组)number | array0
min最小值number0
max最大值number100
step步长number1
disabled是否禁用booleanfalse
range是否范围选择booleanfalse
showTooltip是否显示提示booleantrue
size组件尺寸string"default"
示例
{
  "type": "slider",
  "name": "volume",
  "control": {
    "modelValue": 50,
    "min": 0,
    "max": 100,
    "step": 1,
    "disabled": false,
    "range": false,
    "showTooltip": true,
    "size": "default"
  },
  "formItem": {
    "label": "音量",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (value === null || value === undefined) {
            callback(new Error("请选择音量"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [],
  "config": {}
}

treeSelect(树形选择器)

用于选择树形结构中的某个或多个节点。

🔸type 固定值:"treeSelect"(树形选择器组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue绑定的值(多选时为数组)array | string[]
treeData树形数据Array<{label, id, children}>[]
multiple是否多选booleanfalse
disabled是否禁用booleanfalse
clearable是否显示清除按钮booleanfalse
placeholder占位提示文字string""
size组件尺寸string"default"
示例
{
  "type": "treeSelect",
  "name": "category",
  "control": {
    "modelValue": [],
    "treeData": [
      {
        "label": "电子产品",
        "id": 1,
        "children": [
          { "label": "手机", "id": 2 },
          { "label": "电脑", "id": 3 }
        ]
      }
    ],
    "multiple": true,
    "disabled": false,
    "clearable": true,
    "placeholder": "请选择类别",
    "size": "default"
  },
  "formItem": {
    "label": "类别",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value || (Array.isArray(value) && value.length === 0)) {
            callback(new Error("请选择类别"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请选择类别",
      "trigger": "change"
    }
  ],
  "config": {}
}

txt(文本显示)

用于显示只读文本。

🔸type 固定值:"txt"(文本显示组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue显示的文本内容string""
示例
{
  "type": "txt",
  "name": "descriptionText",
  "control": {
    "modelValue": "这是只读文本"
  },
  "formItem": {
    "label": "说明",
    "rules": []
  },
  "customRules": [],
  "config": {}
}

title(标题)

用于显示标题文本。

🔸type 固定值:"title"(标题组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue标题文本内容string""
示例
{
  "type": "title",
  "name": "pageTitle",
  "control": {
    "modelValue": "用户管理"
  },
  "formItem": {},
  "customRules": [],
  "config": {}
}

tabs(标签页)

用于创建标签页切换。

🔸type 固定值:"tabs"(标签页组件)

🔸control 对象属性说明

属性名说明类型默认值
modelValue当前激活的标签名string""
tabs标签数组Array<{label, name}>[]
示例
{
  "type": "tabs",
  "name": "mainTabs",
  "control": {
    "modelValue": "tab1",
    "tabs": [
      { "label": "标签1", "name": "tab1" },
      { "label": "标签2", "name": "tab2" }
    ]
  },
  "formItem": {},
  "customRules": [],
  "config": {}
}

flex(弹性布局)

用于布局弹性容器。

🔸type 固定值:"flex"(弹性布局组件)

🔸control 对象属性说明

属性名说明类型默认值
justify主轴对齐方式string"start"
align侧轴对齐方式string"stretch"
direction主轴方向string"row"
wrap是否换行string"nowrap"
示例
{
  "type": "flex",
  "name": "flexContainer",
  "control": {
    "justify": "start",
    "align": "center",
    "direction": "row",
    "wrap": "nowrap"
  },
  "formItem": {},
  "customRules": [],
  "config": {}
}

card(卡片)

用于显示卡片容器。

🔸type 固定值:"card"(卡片组件)

🔸control 对象属性说明

属性名说明类型默认值
header卡片头部标题string""
bordered是否有边框booleanfalse
shadow是否有阴影booleanfalse
示例
{
  "type": "card",
  "name": "userCard",
  "control": {
    "header": "用户信息",
    "bordered": true,
    "shadow": true
  },
  "formItem": {},
  "customRules": [],
  "config": {}
}

divider(分割线)

用于分隔内容。

🔸type 固定值:"divider"(分割线组件)

🔸control 对象属性说明

属性名说明类型默认值
direction分割线方向string"horizontal"
contentPosition内容位置string"center"
示例
{
  "type": "divider",
  "name": "lineDivider",
  "control": {
    "direction": "horizontal",
    "contentPosition": "center"
  },
  "formItem": {},
  "customRules": [],
  "config": {}
}

button(按钮)

用于触发操作。

🔸type 固定值:"button"(按钮组件)

🔸control 对象属性说明

属性名说明类型默认值
text按钮显示文本string""
type按钮类型string"default"
size按钮尺寸string"default"
disabled是否禁用booleanfalse
loading是否加载中booleanfalse
icon按钮图标名称string""
示例
{
  "type": "button",
  "name": "submitBtn",
  "control": {
    "text": "提交",
    "type": "primary",
    "size": "default",
    "disabled": false,
    "loading": false,
    "icon": "Check"
  },
  "formItem": {},
  "customRules": [],
  "config": {}
}

table(表格)

用于显示表格数据。

🔸type 固定值:"table"(表格组件)

🔸control 对象属性说明

属性名说明类型默认值
columns表格列配置Array<{label, prop}>[]
data表格数据Array<object>[]
示例
{
  "type": "table",
  "name": "userTable",
  "control": {
    "columns": [
      { "label": "姓名", "prop": "name" },
      { "label": "年龄", "prop": "age" }
    ],
    "data": []
  },
  "formItem": {},
  "customRules": [],
  "config": {}
}

component(自定义组件)

用于嵌入自定义组件。

🔸type 固定值:"component"(自定义组件)

🔸control 对象属性说明

属性名说明类型默认值
componentName自定义组件名称string""
props传递给自定义组件的属性object{}
示例
{
  "type": "component",
  "name": "customComp",
  "control": {
    "componentName": "MyComponent",
    "props": {}
  },
  "formItem": {},
  "customRules": [],
  "config": {}
}

upload(上传)

用于文件上传。

🔸type 固定值:"upload"(上传组件)

🔸control 对象属性说明

属性名说明类型默认值
action上传接口地址string""
multiple是否支持多文件上传booleanfalse
accept接受的文件类型string""
fileList已上传文件列表array[]
disabled是否禁用booleanfalse
showFileList是否显示文件列表booleantrue
drag是否启用拖拽上传booleanfalse
directory是否支持选择整个文件夹上传(浏览器需支持 webkitdirectorybooleanfalse
data上传时携带的额外参数,支持引用其他表单组件的值(见下方说明)object{}
limit最大上传数量number无限制

🔸data 参数说明

上传时携带的额外字段,会随文件一起提交到 action 接口。

  • 支持静态值{ token: "abc123" }
  • 支持引用其他表单组件的值:用 $.字段名 语法

例如:

"data": {
  "category_id": "$.category_id"
}

表示上传时,把当前表单中 name = category_id 的组件的值一起提交。

🔸示例 1:普通单文件上传

{
  "type": "upload",
  "name": "avatar",
  "control": {
    "action": "/upload",
    "multiple": false,
    "accept": "image/*",
    "fileList": [],
    "disabled": false,
    "showFileList": true
  },
  "formItem": {
    "label": "头像上传",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value || (Array.isArray(value) && value.length === 0)) {
            callback(new Error("请上传文件"));
          } else {
            callback();
          }
        },
        "trigger": "change"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请上传文件",
      "trigger": "change"
    }
  ],
  "config": {}
}

🔸示例 2:文件夹上传 + 携带其他表单字段

[
  {
    "type": "select",
    "control": {
      "modelValue": "",
      "appendToBody": true,
      "filterable": true
    },
    "options": [],
    "config": {
      "optionsType": 1,
      "optionsFun": "http://api.example.com/api/ProductCategoryFullOptions",
      "method": "post",
      "value": "id"
    },
    "name": "category_id",
    "formItem": {
      "label": "平台-设备-群体-款式"
    }
  },
  {
    "type": "upload",
    "control": {
      "modelValue": "",
      "action": "http://api.example.com/api/uploadMedia",
      "limit": 10000,
      "drag": true,
      "directory": true,
      "data": {
        "category_id": "$.category_id"
      }
    },
    "config": {},
    "name": "media_url",
    "formItem": {
      "label": "媒体文件"
    }
  }
]

说明:

  • directory: true → 用户点击上传区域时,可以选择整个文件夹,文件夹内所有文件会一起上传
  • data: { category_id: "$.category_id" } → 上传每个文件时,都会把当前表单中 category_id 的值作为额外参数一起提交
  • limit: 10000 → 文件夹里可能有大量文件,需要把限制调大

---

#### tinymce(富文本编辑器)
用于编辑富文本内容。

**🔸type**
固定值:`"tinymce"`(富文本编辑器组件)

**🔸control 对象属性说明**

| 属性名     | 说明                     | 类型                 | 默认值    |
|------------|--------------------------|----------------------|-----------|
| modelValue | 富文本内容               | `string`             | `""`      |
| disabled   | 是否禁用编辑             | `boolean`            | `false`   |
| height     | 编辑器高度(像素)       | `number`             | `300`     |

```js [示例]
{
  "type": "tinymce",
  "name": "content",
  "control": {
    "modelValue": "",
    "disabled": false,
    "height": 300
  },
  "formItem": {
    "label": "内容",
    "rules": [
      {
        "validator": (rule, value, callback) => {
          if (!value) {
            callback(new Error("请输入内容"));
          } else {
            callback();
          }
        },
        "trigger": "blur"
      }
    ]
  },
  "customRules": [
    {
      "required": true,
      "message": "请输入内容",
      "trigger": "blur"
    }
  ],
  "config": {}
}

grid(网格布局)

用于布局网格容器。

🔸type 固定值:"grid"(网格布局组件)

🔸control 对象属性说明

属性名说明类型默认值
cols列数number24
gutter栅格间距number0
justify主轴对齐方式string"start"
align侧轴对齐方式string"top"
示例
{
  "type": "grid",
  "name": "gridLayout",
  "control": {
    "cols": 4,
    "gutter": 10,
    "justify": "start",
    "align": "top"
  },
  "formItem": {},
  "customRules": [],
  "config": {}
}

div(容器)

用于包裹内容的容器。

🔸type 固定值:"div"(容器组件)

🔸control 对象属性说明

属性名说明类型默认值
style容器自定义样式object{}
示例
{
  "type": "div",
  "name": "contentWrapper",
  "control": {
    "style": {
      "padding": "10px",
      "backgroundColor": "#f5f5f5"
    }
  },
  "formItem": {},
  "customRules": [],
  "config": {}
}

表单配置 form

属性名说明类型默认值
name表单标识,可根据此标识使用 get[formName]ControlByName 获取其他选项数据string
labelWidth表单标签宽度,如 "100px"string
class表单样式名称,可快速选择内置好的表单布局类名,或自定义类名string
showColon统一设置表单 label 是否添加冒号booleanfalse
size组件尺寸"default" | "small" | "large""default"
form: {
  name: "testForm",           // 表单标识
  labelWidth: "100px",        // 表单标签宽度
  class: "custom-form",       // 表单样式名称
  showColon: true,            // 字段名后添加冒号
  size: "default"             // 组件尺寸
}

补充说明:

  • form.name:表单的唯一标识,可用于通过 get[formName]ControlByName 方法获取表单中其他控件的值
  • form.labelWidth:统一设置所有表单项标签的宽度,支持 px% 等单位
  • form.class:支持传入内置类名或自定义 CSS 类名,用于快速调整表单布局样式
  • form.showColon:全局控制表单标签后是否显示冒号,优先级低于 formItem 级别的配置
  • form.size:统一设置表单内所有组件的尺寸,可被单个组件的 size 属性覆盖

事件 events

用于控制表单在 联动、校验、提交、请求生命周期 中的行为。

事件名作用是否必须 return说明
change字段变化联动❌ 可选字段值变化时触发,适用于表单联动、自动填充、计算、副作用(请求/提示/UI控制)。支持 直接修改 context.modelreturn 新对象 两种方式。不 return 时手动修改 model 仍生效。
validate校验结果回调❌ 不需要表单整体校验完成后触发,一般用于 统一错误提示。可从 fields 中提取第一条错误信息并展示。
before请求发送前拦截✅ 必须请求发送前的统一入口。用于注入 token、修改 headers、请求参数加密/签名、按 type 分支处理等。不 return 则请求不会发送。
after请求响应后处理✅ 必须请求完成后统一处理响应,用于 格式标准化,将不同后端数据结构统一转换为 { code, data, msg } 格式。

change(instance)

  • instance {Object}
    • name {string} 当前变化字段名(唯一标识)
    • value {any} 当前字段值
    • prop {string} 字段标识(子表 / flex 时等同 name)
    • options {Object} 当前组件配置(schema)
    • env {Object} 运行环境(ElMessage / request 等)
    • context {Object} 表单上下文
      • context.model {Object} 当前表单数据(核心)
      • context.props {Object} 组件参数
  • 返回 {Object | void}

说明

字段值发生变化时触发,是表单联动的核心入口。

常见业务场景

  • 字段联动:选择省份后自动填充城市下拉选项
  • 自动计算:输入单价和数量后自动计算总价
  • 数据回填:选择用户后自动填充手机号、邮箱等信息
  • 副作用操作:字段变化时发请求、显示提示、控制其他组件显隐

返回值行为规范

行为说明
不 return不触发系统自动更新,但通过 context.model.xxx = value 手动修改数据仍然生效,适用于简单赋值或副作用逻辑
return 新对象整体覆盖 model,适用于多字段联动或复杂条件逻辑

⚠️ 注意:不建议同时使用 returncontext.model 混合修改,会产生数据覆盖问题。

示例
change: (instance) =>
{

  const
  {
    name,
    value,
    model,
    prop,
    options,
    env,
    context
  } = instance;

  // ================= 调试日志 =================
  console.groupCollapsed("🔄 [change] " + name);
  console.log("instance:", instance);
  console.groupEnd();

  /**
   * =========================================================
   * 📌 示例1:仅监听(不修改数据)
   * =========================================================
   */

  if (name === "xxx")
  {
    env?.runtime?.ElMessage?.info("字段变化(仅监听)");

    // ❗ 不 return
    // ❗ 不修改 context.model
  }

  /**
   * =========================================================
   * 📌 示例2:使用 context.model 修改(推荐方式2)
   * =========================================================
   *
   * 👉 适用于:
   * - 简单赋值
   * - 副作用逻辑
   */

  if (name === "xxx")
  {
    context.model.otherField = value;

    // ❗ 不 return
  }


  /**
   * =========================================================
   * 📌 示例3:return object(复杂联动)
   * =========================================================
   *
   * 👉 适用于多字段 / 条件逻辑
   */

  if (name === "xxx")
  {
    const newModel = {
      ...context.model,
      // otherField: value,
      // anotherField: "xxx"
    };

    // return newModel;
  }

  /**
   * =========================================================
   * 📌 示例4:副作用(请求 / 计算)
   * =========================================================
   *
   * 👉 不需要 return
   */

  if (name === "xxx")
  {
    // 示例:发请求
    // const response = await env.runtime.request({
    //   url: "【请替换为你的接口地址】/api/xxx",
    //   method: "post",
    //   data: {
    //     model: context.model
    //   }
    // });

    // console.log("📦 response:", response);
  }

  /**
   * =========================================================
   * 📌 默认行为(无返回)
   * =========================================================
   *
   * 👉 不 return:
   * - 表示仅监听或手动处理
   * - 系统不会自动修改数据
   */

}

validate(instance)

  • instance {Object}
    • valid {boolean} 是否通过校验(true / false
    • fields {Object} 校验失败字段集合
    • env {Object} 运行环境
    • context {Object} 表单上下文
  • 返回 {void}

说明

表单整体校验完成后触发,无论校验成功或失败都会执行。

常见业务场景

  • 提取第一条错误信息并统一展示
  • 自定义错误提示样式或位置
  • 校验通过后执行额外逻辑(如日志上报)

⚠️ 注意:fields 结构为:

{
  fieldName: [
    { message: "错误信息" }
  ]
}
示例
validate: (instance) =>
{

  const
  {
    valid,
    fields,
    env,
    context
  } = instance;

  console.warn("【validate】执行", instance);

  /**
   * 📌 安全提取错误提示(只取第一条)
   */
  const showError = (fields, defaultMsg = "表单校验失败") =>
  {
    try
    {
      if (!fields || typeof fields !== "object")
      {
        env.runtime.ElMessage.error(defaultMsg);
        return;
      }

      const errorList = Object.values(fields);

      if (!errorList.length)
      {
        env.runtime.ElMessage.error(defaultMsg);
        return;
      }

      const firstItem = errorList[0];

      if (!Array.isArray(firstItem) || !firstItem.length)
      {
        env.runtime.ElMessage.error(defaultMsg);
        return;
      }

      const msg = firstItem[0]?.message;

      env.runtime.ElMessage.error(msg || defaultMsg);
    }
    catch (e)
    {
      env.runtime.ElMessage.error(defaultMsg);
    }
  };

  // ❌ 校验失败 → 自动提示
  if (!valid)
  {
    showError(fields);
  }

}

before(instance)

  • instance {Object}
    • type {string} 请求类型
      • get 获取表单数据(详情回显)
      • add 新增提交
      • edit 编辑提交
    • headers {Object} 请求头(可修改)
    • data {Object} 请求体数据(可修改)
    • env {Object} 运行环境(包含 userruntimerouter 等)
    • context {Object} 表单上下文(包含 model 等)
  • 返回 {Object} 完整的 axios 请求配置

说明

请求发送前的统一拦截入口,所有表单请求都会经过这里

常见业务场景

  • 注入 token 到请求头
  • 修改请求参数格式(过滤、加密、签名)
  • type 分支处理不同请求类型
  • 统一显示 loading 或提示信息

⚠️ 注意:

  • 必须 return 完整的请求配置对象
  • return 或返回 undefined → 请求不会发送
示例
before: (instance) =>
{
  const
  {
    type,
    headers,
    data,
    env,
    context
  } = instance;

  // ================= 调试日志 =================
  console.groupCollapsed("🚀 [before] " + type);
  console.log("instance:", instance);
  console.groupEnd();

  // ================= 请求头重构 =================
  const newHeaders = {
    ...headers,
    Authorization: "Bearer " + (env?.user?.token || ""),
    "Content-Type": "application/json"
  };

  // ================= 请求数据处理 =================
  let newData = {

  };

  // ================= 请求前处理(按 type 分发) =================
  switch (type)
  {
    case "get":
    {
      env?.runtime?.ElMessage?.info(
        "正在加载表单数据(可在此处处理字段映射 / 默认值)"
      );

      newData = {
        ...data
      };

      break;
    }

    case "add":
    {
      env?.runtime?.ElMessage?.info(
        "正在提交新增表单(可在此处处理提交参数格式)"
      );

      newData = {
        ...data
      };

      break;
    }

    case "edit":
    {
      env?.runtime?.ElMessage?.info(
        "正在提交编辑表单(可在此处处理提交参数格式)"
      );

      newData = {
        ...data
      };

      break;
    }

    default:
    {
      newData = {
        ...data
      };
      break;
    }
  }

  // ================= 返回 axios 配置 =================
  return {
    url: instance.url,
    method: instance.method || "post",
    headers: newHeaders,
    timeout: instance.timeout || 30000,
    data: newData
  };
}

after(instance)

  • instance {Object}
    • response {Object} 接口原始返回(axios response)
    • type {string} 请求类型(get / add / edit
    • success {boolean} 请求是否成功
    • env {Object} 运行环境
    • context {Object} 表单上下文
  • 返回 {Object} 标准结构 { code, data, msg }

说明

请求完成后统一处理响应数据,所有接口返回都会经过这里

核心职责

  • 数据结构标准化:将不同后端接口的返回结构统一转换为 { code, data, msg } 格式
  • 统一提示处理(成功/失败消息)
  • type 分支处理不同请求类型的后续逻辑

标准返回格式

{
  code: number,   // 200 成功,400 业务失败,401 未授权
  data: any,      // 业务数据
  msg: string     // 提示信息
}

⚠️ 注意:

  • 无论后端返回什么结构(对象、JSON字符串、普通字符串),最终都必须转换为标准格式
  • 否则前端无法统一处理数据结构
示例
after: (instance) =>
{
  const
  {
    type,
    success,
    response,
    env,
    context
  } = instance;

  // ================= 调试日志 =================
  console.groupCollapsed("📦 [after] " + type);
  console.log("instance:", instance);
  console.groupEnd();

  // ================= 默认提示(演示用) =================
  if (success)
  {
    switch (type)
    {

      // ================= 表单数据加载处理 =================
      case "get":
      {
        env?.runtime?.ElMessage?.info(
          "get 数据处理区:可在此处处理表单数据加载 / 字段映射 / 默认值填充"
        );

        break;
      }

      // ================= 表单数据新增处理 =================
      case "add":
      {
        env?.runtime?.ElMessage?.info(
          "add 数据处理区:可在此处处理新增提交后的返回结构 / 状态处理"
        );

        break;
      }

      // ================= 表单数据编辑处理 =================
      case "edit":
      {
        env?.runtime?.ElMessage?.info(
          "edit 数据处理区:可在此处处理编辑提交后的返回结构 / 字段同步"
        );

        break;
      }

      default:
      {
        env?.runtime?.ElMessage?.info(
          "未知 type:" + type + ",可在此处扩展表单处理逻辑"
        );
        break;
      }
    }
  }

  return {
    code: 200,
    data: response?.data?.data,
    msg: response?.data?.msg
  };
}

接口行为配置 config

config: {
  submitCancel: boolean, // 是否显示提交/取消
  addUrl: string,     // 新增接口
  editUrl: string,       // 编辑接口
  getUrl: string     // 查看详情接口
}

⚠️ 注意: 接口请求可能会涉及跨域问题。例如:当前页面运行在云控官网后台域名(如 http://cloud.jsdevhub.com),而接口地址是 http://47.94.105.29:66,会因浏览器同源策略被拦截。解决方式建议:后端开启 CORS 并允许跨域

平台内置接口

作为平台方,我们提供了两个内置接口,方便您在表单中获取设备列表用户列表。这两个接口无需额外开发,直接在表单配置中引用即可。

设备列表接口

用于获取当前账户及其下级账户绑定的所有设备数据。

项目内容
接口地址http://180.76.145.80/api/getDeviceList
请求方式POST
返回格式{ code: 200, msg: "成功", data: [{ id, label }] }
适用场景设备选择、任务分配等

返回数据示例:

{
  "code": 200,
  "msg": "成功",
  "data": [
    { "id": 58870, "label": "android7" },
    { "id": 10384, "label": "qwe001" },
    { "id": 10504, "label": "qwert1235" }
  ]
}

字段说明:

字段说明
id设备 ID(存储值)
label设备名称(显示值)

用户列表接口

用于获取当前账户及其下级账户的所有用户数据。

项目内容
接口地址http://180.76.145.80/api/getUserList
请求方式POST
返回格式{ code: 200, msg: "成功", data: [{ id, label }] }
适用场景用户选择、用户关联等

返回数据示例:

{
  "code": 200,
  "msg": "成功",
  "data": [
    { "id": 382, "label": "ceshi3" },
    { "id": 7750, "label": "ceshi22" }
  ]
}

字段说明:

字段说明
id用户 ID(存储值)
label用户名(显示值)

在表单中引用

在表单字段的 config 中配置 optionsType: 1(远程接口),optionsFun 填入对应的接口地址即可。

设备选择示例:

{
  type: "select",
  name: "device_id",
  control: {
    modelValue: "",
    placeholder: "请选择设备",
    appendToBody: true
  },
  options: [],
  config: {
    optionsType: 1,
    optionsFun: "http://180.76.145.80/api/getDeviceList",
    method: "post",
    value: "id"       // 指定 value 字段为 id
  },
  formItem: {
    label: "设备"
  }
}

用户选择示例:

{
  type: "select",
  name: "user_id",
  control: {
    modelValue: "",
    placeholder: "请选择用户",
    appendToBody: true
  },
  options: [],
  config: {
    optionsType: 1,
    optionsFun: "http://180.76.145.80/api/getUserList",
    method: "post",
    value: "id"
  },
  formItem: {
    label: "用户"
  }
}

💡 说明:这两个接口已内置支持,返回数据中的 id 对应选项值,label 对应选项显示文本。配置时需指定 value: "id" 以正确映射数据。


示例

列表添加/编辑表单

适用于列表页的数据新增/编辑场景,包含各类常用字段、校验、下拉动态加载、上传、时间联动及完整的请求拦截与响应处理。

opt = {
  list: [
  {
    type: "input",
    control:
    {
      modelValue: "",
      placeholder: "请输入标题"
    },
    config:
    {},
    name: "label",
    formItem:
    {
      label: "标题"
    }
  },
  {
    type: "selectPlus",
    control:
    {
      modelValue: "",
      appendToBody: true,
      valueKey: "id",
      filterable: true,
      props:
      {
        label: "label",
        value: "id"
      }
    },
    options: [],
    config:
    {
      optionsType: 1,
      optionsFun: "http://47.94.105.29:66/api/DataListCaseCategoryList",
      method: "post",
      addUrl: "http://47.94.105.29:66/api/addDataListCaseCategory",
      editUrl: "http://47.94.105.29:66/api/editDataListCaseCategory",
      deleteUrl: "http://47.94.105.29:66/api/deleteDataListCaseCategory"
    },
    name: "category_id",
    formItem:
    {
      label: "分类"
    }
  },
  {
    type: "input",
    control:
    {
      modelValue: "",
      placeholder: "请输入链接"
    },
    config:
    {},
    name: "link",
    formItem:
    {
      label: "链接"
    }
  },
  {
    type: "input",
    control:
    {
      modelValue: "",
      placeholder: "请输入uid"
    },
    config:
    {},
    name: "uid",
    formItem:
    {
      label: "UID"
    }
  },
  {
    type: "select",
    control:
    {
      modelValue: "",
      appendToBody: true,
      placeholder: "请选择任务类型"
    },
    options: [],
    config:
    {
      optionsType: 1,
      optionsFun: "http://47.94.105.29:66/api/getFieldTaskTypeIdDict",
      method: "post"
    },
    name: "task_type_id",
    formItem:
    {
      label: "任务类型"
    },
    events:
    {
      after: (instance) =>
      {
        const
        {
          type,
          success,
          response,
          env,
          context
        } = instance;

        // ================= 调试日志 =================
        console.groupCollapsed("📦 [after] " + type);
        console.log("instance:", instance);
        console.groupEnd();

        return {
          code: 200,
          data: response?.data?.data?.list,
          msg: response?.data?.msg
        };
      }
    }
  },
  {
    type: "select",
    control:
    {
      modelValue: "",
      appendToBody: true
    },
    options: [],
    config:
    {
      optionsType: 1,
      optionsFun: "http://180.76.145.80/api/getDeviceList",
      method: "post",
      value: "id"
    },
    name: "device_id",
    formItem:
    {
      label: "设备"
    }
  },
  {
    type: "select",
    control:
    {
      modelValue: "",
      appendToBody: true
    },
    options: [],
    config:
    {
      optionsType: 1,
      optionsFun: "http://180.76.145.80/api/getUserList",
      method: "post",
      value: "id"
    },
    name: "user_id",
    formItem:
    {
      label: "用户"
    }
  },
  {
    type: "upload",
    control:
    {
      modelValue: "",
      action: "http://47.94.105.29:66/api/upload",
      multiple: true,
      limit: 2,
      listType: "picture-card"
    },
    config:
    {
      tip: "",
      btnText: ""
    },
    name: "upload",
    formItem:
    {
      label: "图片文件上传"
    }
  },
  {
    type: "datePicker",
    control:
    {
      modelValue: "",
      type: "datetime"
    },
    config:
    {},
    name: "datePicker",
    formItem:
    {
      label: "日期选择器"
    }
  },
  {
    type: "timePicker",
    control:
    {
      modelValue: ""
    },
    config:
    {},
    name: "timePicker",
    formItem:
    {
      label: "时间选择器",
      rules: [
      {
        required: true,
        message: "请选择结束时间",
        trigger: "change"
      },
      {
        validator: (rule, value, callback) =>
        {
          const val = getTestDemoValueByName('datePicker')
          if (value <= val)
          {
            callback(new Error('结束时间必须大于开始时间'))
          }
          else
          {
            callback()
          }
        },
        trigger: "blur"
      }]
    }
  },
  {
    type: "colorPicker",
    control:
    {
      modelValue: ""
    },
    config:
    {},
    name: "colorPicker",
    formItem:
    {
      label: "取色器"
    }
  },
  {
    type: "rate",
    control:
    {
      modelValue: 0
    },
    config:
    {},
    name: "rate",
    formItem:
    {
      label: "评分"
    }
  },
  {
    type: "slider",
    control:
    {
      modelValue: 0
    },
    config:
    {},
    name: "slider",
    formItem:
    {
      label: "滑块"
    }
  },
  {
    type: "inputNumber",
    control:
    {
      modelValue: 0
    },
    config:
    {},
    name: "inputNumber",
    formItem:
    {
      label: "计数器"
    }
  },
  {
    type: "button",
    control:
    {
      label: "AI 内容生成",
      style:
      {
        "margin-left": "100px",
        "margin-bottom": "10px"
      },
      key: "none",
      type: "info"
    },
    config:
    {
      source: 497,
      openType: "drawer",
      width: "100%"
    },
    events:
    {
      submit: (instance) =>
      {
        console.warn("📌 submit来源组件 / 行为:", instance);
        const
        {
          selected,
          model,
          env,
          context
        } = instance;


        var aiList = selected.articleTable || [];

        var aiText = "";

        if (Array.isArray(aiList) && aiList.length > 0)
        {
          aiText = aiList
            .filter(function(item)
            {
              return item && item.content;
            })
            .map(function(item)
            {
              return String(item.content);
            })
            .join("\n\n"); // 👈 关键:双换行
        }

        var oldText = model.textarea || "";

        // ❗ 不要 trim(重点)
        if (oldText && oldText.trim() !== "")
        {
          context.model.textarea = oldText + "\n\n" + aiText;
        }
        else
        {
          context.model.textarea = aiText;
        }


        //   api.ElMessage({
        //     message: "回填成功",
        //     type: "success"
        //   });
      },
      cancel: (instance) =>
      {
        console.log("取消了");
        console.log("🚀 [cancel instance]:", instance);
      }
    }
  },
  {
    type: "textarea",
    control:
    {
      modelValue: "",
      placeholder: "请输入多行文本,或者使用上方按钮通过AI快捷输入",
      autosize:
      {
        minRows: 5,
        maxRows: 8
      }
    },
    config:
    {},
    name: "textarea",
    formItem:
    {
      label: "多行文本"
    }
  },
  {
    type: "switch",
    control:
    {
      modelValue: false,
      activeValue: 1,
      inactiveValue: 0
    },
    config:
    {},
    name: "switch",
    formItem:
    {
      label: "开关"
    }
  },
  {
    type: "upload",
    control:
    {
      modelValue: "",
      action: "http://47.94.105.29:66/api/upload"
    },
    config:
    {},
    name: "play",
    formItem:
    {
      label: "播放"
    }
  },
  {
    type: "upload",
    control:
    {
      modelValue: "",
      action: "http://47.94.105.29:66/api/upload"
    },
    config:
    {},
    name: "download",
    formItem:
    {
      label: "下载链接"
    }
  },
  {
    type: "upload",
    control:
    {
      modelValue: "",
      action: "http://47.94.105.29:66/api/upload",
      multiple: true,
      limit: 2,
      listType: "picture-card"
    },
    config:
    {},
    name: "image",
    formItem:
    {
      label: "图片/文件"
    }
  },
  {
    type: "upload",
    control:
    {
      modelValue: "",
      action: "http://47.94.105.29:66/api/upload",
      limit: 1,
      drag: true
    },
    config:
    {},
    name: "video",
    formItem:
    {
      label: "视频文件"
    }
  },
  {
    type: "input",
    control:
    {
      modelValue: ""
    },
    config:
    {},
    name: "copy",
    formItem:
    {
      label: "复制文本"
    }
  }],
  form:
  {
    size: "default",
    labelWidth: "100px",
    name: "TestDemo"
  },
  events:
  {
    validate: (instance) =>
    {
      /**
       * ===============================
       * 📌 表单校验结果回调
       * ===============================
       *
       * valid   -> 是否通过校验(true / false)
       * fields  -> 校验失败字段集合(用于获取错误信息)
       * env     -> 运行环境(可调用 ElMessage 等能力)
       * context -> 当前表单上下文数据
       */
      const
      {
        valid,
        fields,
        env,
        context
      } = instance;

      console.warn("【validate】执行", instance);

      /**
       * 📌 安全提取错误提示(只取第一条)
       */
      const showError = (fields, defaultMsg = "表单校验失败") =>
      {
        try
        {
          if (!fields || typeof fields !== "object")
          {
            env.runtime.ElMessage.error(defaultMsg);
            return;
          }

          const errorList = Object.values(fields);

          if (!errorList.length)
          {
            env.runtime.ElMessage.error(defaultMsg);
            return;
          }

          const firstItem = errorList[0];

          if (!Array.isArray(firstItem) || !firstItem.length)
          {
            env.runtime.ElMessage.error(defaultMsg);
            return;
          }

          const msg = firstItem[0]?.message;

          env.runtime.ElMessage.error(msg || defaultMsg);
        }
        catch (e)
        {
          env.runtime.ElMessage.error(defaultMsg);
        }
      };

      // ❌ 校验失败 → 自动提示
      if (!valid)
      {
        showError(fields);
      }

    },
    before: (instance) =>
    {
      /**
       * =========================================================
       * 🔧 before:请求发送前处理钩子(核心能力)
       * =========================================================
       *
       * 👉 作用:
       * - 统一修改请求参数(headers / data / config)
       * - 注入 token / 鉴权信息
       * - 请求预处理(日志 / 过滤 / 加密等)
       *
       *
       * =========================================================
       * 📦 instance:请求上下文
       * =========================================================
       * headers -> 请求头(可修改)
       * data    -> 请求体数据(可修改)
       * type    -> 请求类型(get / add / edit)
       * env     -> 运行环境(工具集合)
       * context -> 表单页上下文(运行时数据)
       *
       * =========================================================
       * 🧭 type:请求类型
       * =========================================================
       *
       * get  - 获取表单数据
       * add  - 新增表单数据
       * edit - 编辑表单数据
       *
       * 💡 说明:
       * - type 用于区分不同数据来源与操作行为
       * - 可在 before / after 中做分支处理
       *
       * =========================================================
       * 🌍 env:运行环境能力
       * =========================================================
       *
       * env.runtime:
       *   - request
       *   - ElMessage
       *   - ElNotification
       *   - ElMessageBox
       *
       * env.user:
       *   - id
       *   - uname
       *   - token
       *
       * env.router:
       *   - 路由实例
       *
       * =========================================================
       * 🌍 context:表单页上下文(运行时数据)
       * =========================================================
       *
       * 👉 说明:
       * context 表示当前表单页面的“运行时状态”,
       * 可用于获取或修改表单数据
       *
       *
       * ---------------------------------------------------------
       * 📄 context.model:表单数据模型(核心)
       * ---------------------------------------------------------
       * - 当前表单的所有字段数据
       * - 类型:object
       *
       * 
       * =========================================================
       * 💡 默认行为说明
       * =========================================================
       * before 负责“修改请求”
       * after 负责“处理响应”
       */

      const
      {
        type,
        headers,
        data,
        env,
        context
      } = instance;

      // ================= 调试日志 =================
      console.groupCollapsed("🚀 [before] " + type);
      console.log("instance:", instance);
      console.groupEnd();

      // ================= 请求头重构 =================
      const newHeaders = {
        ...headers,
        Authorization: "Bearer " + (env?.user?.token || ""),
        "Content-Type": "application/json"
      };

      // ================= 请求数据处理 =================
      let newData = {

      };

      // ================= 请求前处理(按 type 分发) =================
      switch (type)
      {
        case "get":
        {
          env?.runtime?.ElMessage?.info(
            "正在加载表单数据(可在此处处理字段映射 / 默认值)"
          );

          newData = {
            ...data
          };

          break;
        }

        case "add":
        {
          env?.runtime?.ElMessage?.info(
            "正在提交新增表单(可在此处处理提交参数格式)"
          );

          newData = {
            ...data
          };

          break;
        }

        case "edit":
        {
          env?.runtime?.ElMessage?.info(
            "正在提交编辑表单(可在此处处理提交参数格式)"
          );

          newData = {
            ...data
          };

          break;
        }

        default:
        {
          newData = {
            ...data
          };
          break;
        }
      }

      // ================= 返回 axios 配置 =================
      return {
        url: instance.url,
        method: instance.method || "post",
        headers: newHeaders,
        timeout: instance.timeout || 30000,
        data: newData
      };
    },
    after: (instance) =>
    {
      /**
       * =========================================================
       * 🔧 after:请求结果后处理钩子(核心能力)
       * =========================================================
       *
       * 👉 作用:
       * - 统一接口返回结构(核心)
       * - 提供默认行为(如提示)
       * - 支持用户自定义扩展逻辑
       *
       *
       * =========================================================
       * 📦 instance:请求上下文(after 阶段)
       * =========================================================
       *
       * response-> 接口返回结果(axios response)
       * type    -> 当前操作类型(get / add / edit)
       * success -> 请求是否成功(boolean)
       * env     -> 运行环境(工具集合)
       * context -> 表单页上下文(运行时数据)
       *
       *
       * =========================================================
       * 📄 response:接口响应数据(核心)
       * =========================================================
       * - 原始接口返回结果(通常为 axios response)
       * - 常用访问方式:
       *
       * response.data       -> 后端返回体
       *
       *
       * =========================================================
       * 🧭 type:当前操作类型
       * =========================================================
       * get  -> 获取表单数据(回显)
       * add  -> 新增提交
       * edit -> 编辑提交
       *
       *
       * =========================================================
       * ✅ success:请求是否成功
       * =========================================================
       * true  -> 请求成功(进入 after 逻辑)
       * false -> 请求失败(已由底层统一处理)
       *
       *
       * =========================================================
       * 🌍 env:运行环境
       * =========================================================
       * env.runtime:
       *   - request        -> 网络请求方法(axios 封装)
       *   - ElMessage      -> 消息提示
       *   - ElNotification -> 通知提示
       *   - ElMessageBox   -> 弹窗
       *
       * env.user:
       *   - id
       *   - uname
       *   - token
       *
       * env.router:
       *   - 路由实例
       *
       *
       * =========================================================
       * 🌍 context:表单页上下文(运行时数据)
       * =========================================================
       *
       * 👉 说明:
       * context 表示当前表单页面的“运行时状态”,
       * 可用于获取或修改表单数据
       *
       *
       * ---------------------------------------------------------
       * 📄 context.model:表单数据模型(核心)
       * ---------------------------------------------------------
       * - 当前表单的所有字段数据
       * - 类型:object
       *
       *
       * =========================================================
       * 💡 默认行为(可删除)
       * =========================================================
       * - 根据 type 自动提示
       * - 仅用于演示,实际项目可自行修改或删除
       */

      const
      {
        type,
        success,
        response,
        env,
        context
      } = instance;

      // ================= 调试日志 =================
      console.groupCollapsed("📦 [after] " + type);
      console.log("instance:", instance);
      console.groupEnd();

      // ================= 默认提示(演示用) =================
      if (success)
      {
        switch (type)
        {

          // ================= 表单数据加载处理 =================
          case "get":
          {
            env?.runtime?.ElMessage?.info(
              "get 数据处理区:可在此处处理表单数据加载 / 字段映射 / 默认值填充"
            );

            break;
          }

          // ================= 表单数据新增处理 =================
          case "add":
          {
            env?.runtime?.ElMessage?.info(
              "add 数据处理区:可在此处处理新增提交后的返回结构 / 状态处理"
            );

            break;
          }

          // ================= 表单数据编辑处理 =================
          case "edit":
          {
            env?.runtime?.ElMessage?.info(
              "edit 数据处理区:可在此处处理编辑提交后的返回结构 / 字段同步"
            );

            break;
          }

          default:
          {
            env?.runtime?.ElMessage?.info(
              "未知 type:" + type + ",可在此处扩展表单处理逻辑"
            );
            break;
          }
        }
      }

      /**
       * =========================================================
       * 📦 统一返回数据格式(核心规范)
       * =========================================================
       *
       * 👉 所有请求最终都会被转换为:
       *
       * {
       *   code: number,
       *   data: any,
       *   msg: string
       * }
       *
       *
       * ---------------------------------------------------------
       * 🔢 code:状态码
       * ---------------------------------------------------------
       * 200 -> 请求成功
       * 400 -> 业务失败(如参数错误)
       * 401 -> 用户异常(登录失效,自动处理)
       *
       * 👉 用法:
       * if (response.code === 200) { ... }
       *
       *
       * ---------------------------------------------------------
       * 📄 data:业务数据
       * ---------------------------------------------------------
       * - 接口核心数据
       * - 类型:对象 或 数组
       *
       * 💡 示例:
       * data = { id: 1, name: "张三" }
       * data = [ { id: 1, name: "张三" }, { id: 2, name: "李四" } ]
       *
       *
       * ---------------------------------------------------------
       * 💬 msg:提示信息
       * ---------------------------------------------------------
       * - 用于 UI 提示
       * - 一般来自后端
       *
       * 👉 用法:
       * env.runtime.ElMessage.success(msg)
       *
       *
       * =========================================================
       * 💡 扩展说明(重要)
       * =========================================================
       * 不同后端接口返回结构可能不一致,
       * 你需要在 after 中将数据“统一规范化”为标准格式:
       *
       * 👉 标准格式:
       * {
       *   code: number,
       *   data: object,
       *   msg: string
       * }
       *
       *
       * =========================================================
       * 📌 示例1:字段结构不一致(基础映射)
       * =========================================================
       *
       * 后端返回:
       * {
       *   code: 0,
       *   result: {...},
       *   message: "success"
       * }
       *
       * 👉 转换:
       * return {
       *   code: response.data.code,
       *   data: response.data.result,
       *   msg: response.data.message
       * }
       *
       *
       * =========================================================
       * 📌 示例2:data 是 JSON 字符串(常见)
       * =========================================================
       *
       * 后端返回:
       * {
       *   code: 200,
       *   result: "{"id":1,"name":"张三"}",
       *   message: "ok"
       * }
       *
       * 👉 转换:
       * return {
       *   code: response.data.code,
       *   data: JSON.parse(response.data.result), // 字符串 → 对象
       *   msg: response.data.message
       * }
       *
       *
       * =========================================================
       * 📌 示例3:复杂字符串解析
       * =========================================================
       *
       * 后端返回:
       * {
       *   code: 200,
       *   result: "id=1,name=张三,age=18"
       * }
       *
       * 👉 转换:
       * const obj = Object.fromEntries(
       *   response.data.result.split(",").map(item => item.split("="))
       * );
       *
       * return {
       *   code: response.data.code,
       *   data: obj,
       *   msg: response.data.message
       * }
       *
       *
       * =========================================================
       * ⚠️ 核心原则(非常重要)
       * =========================================================
       * 无论后端返回:
       * - 对象
       * - JSON字符串
       * - 普通字符串
       * - 拼接字符串
       *
       * 👉 最终都必须转换为:
       * {
       *   code,
       *   data,
       *   msg
       * }
       *
       * ❗否则前端无法统一处理数据结构
       */

      return {
        code: 200,
        data: response?.data?.data,
        msg: response?.data?.msg
      };
    },
    change: (instance) =>
    {
      /**
       * =========================================================
       * 🔧 change:表单字段变化回调(核心能力)
       * =========================================================
       *
       * 👉 作用:
       * - 监听字段变化
       * - 表单联动(自动填充 / 计算)
       * - 执行副作用(请求 / 提示 / 控制UI)
       *
       *
       * =========================================================
       * 📦 instance:变化上下文(统一结构)
       * =========================================================
       *
       * name    -> 当前变化字段名
       * value   -> 当前字段值
       * prop    -> 字段标识(子表或flex时的prop 同 name)
       * options -> 组件配置
       *
       * env     -> 运行环境(工具集合)
       * context -> 表单上下文(推荐使用)
       *
       *
       * =========================================================
       * 🌍 context(推荐使用)
       * =========================================================
       *
       * context.model -> 当前表单数据(核心)
       * context.props -> 组件参数
       *
       *
       * =========================================================
       * 💡 返回值行为规范(非常重要)
       * =========================================================
       *
       * 👉 不 return:
       * - 不触发系统自动更新
       * - ✅ 可以通过 context.model 手动修改数据
       *
       * 👉 return object:
       * - 覆盖整个 model(复杂联动)
       *
       * ⚠️ 注意:
       * - 不建议同时使用 return + context.model
       * - 避免数据冲突
       */

      const
      {
        name,
        value,
        model,
        prop,
        options,
        env,
        context
      } = instance;

      // ================= 调试日志 =================
      console.groupCollapsed("🔄 [change] " + name);
      console.log("instance:", instance);
      console.groupEnd();

      /**
       * =========================================================
       * 📌 示例1:仅监听(不修改数据)
       * =========================================================
       */

      if (name === "xxx")
      {
        env?.runtime?.ElMessage?.info("字段变化(仅监听)");

        // ❗ 不 return
        // ❗ 不修改 context.model
      }

      /**
       * =========================================================
       * 📌 示例2:使用 context.model 修改(推荐方式2)
       * =========================================================
       *
       * 👉 适用于:
       * - 简单赋值
       * - 副作用逻辑
       */

      if (name === "xxx")
      {
        context.model.otherField = value;

        // ❗ 不 return
      }


      /**
       * =========================================================
       * 📌 示例3:return object(复杂联动)
       * =========================================================
       *
       * 👉 适用于多字段 / 条件逻辑
       */

      if (name === "xxx")
      {
        const newModel = {
          ...context.model,
          // otherField: value,
          // anotherField: "xxx"
        };

        // return newModel;
      }

      /**
       * =========================================================
       * 📌 示例4:副作用(请求 / 计算)
       * =========================================================
       *
       * 👉 不需要 return
       */

      if (name === "xxx")
      {
        // 示例:发请求
        // const response = await env.runtime.request({
        //   url: "【请替换为你的接口地址】/api/xxx",
        //   method: "post",
        //   data: {
        //     model: context.model
        //   }
        // });

        // console.log("📦 response:", response);
      }

      /**
       * =========================================================
       * 📌 默认行为(无返回)
       * =========================================================
       *
       * 👉 不 return:
       * - 表示仅监听或手动处理
       * - 系统不会自动修改数据
       */

    }
  },
  config:
  {
    submitCancel: true,
    addUrl: "http://47.94.105.29:66/api/addDataListCase",
    editUrl: "http://47.94.105.29:66/api/editDataListCase",
    getUrl: "http://47.94.105.29:66/api/getDataListCase"
  }
}

列表搜索表单

适用于列表页的搜索条件表单,仅包含搜索字段,无提交接口,通常与列表数据请求配合使用。

opt = {
  list: [
    {
      type: "input",
      control: {
        modelValue: "",
        placeholder: "请输入标题"
      },
      config: {},
      name: "label",
      formItem: {
        label: "标题"
      }
    },
    {
      type: "input",
      control: {
        modelValue: "",
        placeholder: "请输入链接"
      },
      config: {},
      name: "link",
      formItem: {
        label: "链接"
      }
    },
    {
      type: "input",
      control: {
        modelValue: "",
        placeholder: "请输入uid"
      },
      config: {},
      name: "uid",
      formItem: {
        label: "UID"
      }
    },
    {
      type: "select",
      control: {
        modelValue: "",
        appendToBody: true,
        placeholder: "请选择任务类型"
      },
      options: [
        { label: "任务类型1", value: "1" },
        { label: "任务类型2", value: "2" },
        { label: "任务类型3", value: "3" },
        { label: "任务类型4", value: "4" }
      ],
      config: {
        optionsType: 0
      },
      name: "task_type_id",
      formItem: {
        label: "任务类型"
      }
    },
    {
      type: "select",
      control: {
        modelValue: "",
        appendToBody: true
      },
      options: [],
      config: {
        optionsType: 1,
        optionsFun: "http://47.94.105.29:66/api/DataListCaseCategoryTree",
        method: "post",
        value: "id",
        label: ""
      },
      name: "category_id",
      formItem: {
        label: "选择分类"
      }
    },
    {
      type: "select",
      control: {
        modelValue: "",
        appendToBody: true
      },
      options: [],
      config: {
        optionsType: 1,
        optionsFun: "http://180.76.145.80/api/getDeviceAllList",
        method: "post",
        value: "id",
        label: ""
      },
      name: "device_id",
      formItem: {
        label: "选择设备"
      }
    },
    {
      type: "select",
      control: {
        modelValue: "",
        appendToBody: true
      },
      options: [],
      config: {
        optionsType: 1,
        optionsFun: "http://180.76.145.80/api/getUserList",
        method: "post",
        label: "",
        value: "id"
      },
      name: "user_id",
      formItem: {
        label: "选择用户"
      }
    }
  ],
  form: {
    size: "default",
    labelWidth: "100px"
  },
  config: {
    submitCancel: true
  }
}

表单嵌套(打开另一个表单)

主表单中通过 button 按钮组件打开另一个表单(例如 AI 内容生成),并实现数据回填。配置时,config 中的 source 属性值(如下文的 497)即为子表单在“表单设计”列表页中的唯一记录 ID。您只需在表单设计列表中找到目标子表单对应的 ID 数字并填入,即可实现主表单与任意子表单的嵌套联动。下面展示主表单与子表单(ID = 497)的完整配置。

主表单(包含打开子表单的按钮)

opt = {
  list: [
  {
    type: "button",
    control:
    {
      label: "AI 内容生成",
      style:
      {
        "margin-left": "100px",
        "margin-bottom": "10px"
      },
      key: "none",
      type: "info"
    },
    config:
    {
      source: 497,          // 子表单的ID
      openType: "drawer",   // 打开方式
      width: "100%"         // 抽屉宽度
    },
    events:
    {
      submit: (instance) =>
      {
        console.warn("📌 submit来源组件 / 行为:", instance);
        const
        {
          selected,
          model,
          env,
          context
        } = instance;


        let aiList = selected.articleTable || [];

        let aiText = "";

        if (Array.isArray(aiList) && aiList.length > 0)
        {
          aiText = aiList
            .filter(function(item)
            {
              return item && item.content;
            })
            .map(function(item)
            {
              return String(item.content);
            })
            .join("\n\n"); // 👈 关键:双换行
        }

        let oldText = model.article_content || "";

        // ❗ 不要 trim(重点)
        if (oldText && oldText.trim() !== "")
        {
          context.model.article_content = oldText + "\n\n" + aiText;
        }
        else
        {
          context.model.article_content = aiText;
        }


        env.runtime.ElMessage(
        {
          message: "回填成功",
          type: "success"
        });
      },
      cancel: (instance) =>
      {
        console.log("取消了");
        console.log("🚀 [cancel instance]:", instance);
      }
    }
  },
  {
    type: "textarea",
    control:
    {
      modelValue: "",
      placeholder: "请输入内容(多条内容用间隔一空行)",
      autosize:
      {
        minRows: 30,
        maxRows: 33
      }
    },
    config:
    {},
    name: "article_content",
    formItem:
    {
      label: "文章段落"
    }
  }],
  form:
  {
    size: "default",
    labelWidth: "100px"
  },
  config:
  {
    submitCancel: true
  }
}

子表单(ID = 497,AI 内容生成)

opt = {
  list: [
  {
    type: "div",
    control:
    {
      marginBottom: "16px"
    },
    list: [
    {
      type: "input",
      name: "article_topic",
      control:
      {
        modelValue: "如何提高学习效率",
        placeholder: "请输入文章主题"
      },
      formItem:
      {
        label: "文章主题"
      }
    },
    {
      type: "input",
      name: "target_audience",
      control:
      {
        modelValue: "大学生",
        placeholder: "请输入目标读者"
      },
      formItem:
      {
        label: "目标人群"
      }
    },
    {
      type: "input",
      name: "writing_style",
      control:
      {
        modelValue: "通俗易懂",
        placeholder: "请输入写作风格"
      },
      formItem:
      {
        label: "写作风格"
      }
    },
    {
      type: "inputNumber",
      name: "paragraph_count",
      control:
      {
        modelValue: 3,
        placeholder: "请输入段落数量"
      },
      formItem:
      {
        label: "段落数量"
      }
    },
    {
      type: "button",
      control:
      {
        label: "生成文章段落",
        style:
        {
          marginLeft: "100px",
          marginBottom: "10px"
        },
        loading: false,
        key: "none"
      },
      events:
      {
        click: async (instance) =>
        {
          const
          {
            schema,
            env,
            context
          } = instance;

          try
          {
            // ===== loading =====
            schema.control.loading = true;

            env.runtime.ElMessage(
            {
              message: "正在生成内容(演示接口)...",
              type: "info"
            });

            /**
             * =========================================================
             * 📌 模拟接口(演示用)
             * 👉 这个地址一看就是假的,用户必须自己改
             * =========================================================
             */
            const response = await env.runtime.request(
            {
              url: "http://47.94.105.29:66/api/generateByStyle", // 👈 必须替换
              method: "post",
              data:
              {
                topic: context.model.article_topic,
                audience: context.model.target_audience,
                style: context.model.writing_style,
                count: context.model.paragraph_count
              },
              timeout: 2000
            });

            console.log("📦 response:", response);

            /**
             * =========================================================
             * 📌 数据处理(演示)
             * =========================================================
             */
            const list =
              response?.data?.data || [
                "这是示例段落1(未接入真实接口)",
                "这是示例段落2(用于演示效果)",
                "这是示例段落3(可自行替换接口)"
              ];

            context.model.articleTable = list.map((text, index) => (
            {
              id: index,
              content: text
            }));

            env.runtime.ElMessage.success("生成成功(演示数据)");

          }
          catch (err)
          {
            console.error(err);
            env.runtime.ElMessage.error("请求失败(演示)");
          }
          finally
          {
            schema.control.loading = false;
          }
        }
      }
    }]
  },
  {
    type: "div",
    list: [
    {
      type: "table",
      name: "articleTable",
      control:
      {
        border: true,
        height: "300",
        style: "width: 100%"
      },
      config:
      {
        addBtnText: "新增段落",
        delBtnText: "删除",
        disabledEdit: true
      },
      list: [
      {
        type: "selection",
        width: 60
      },
      {
        name: "content",
        type: "input",
        formItem:
        {
          label: "文章内容"
        },
        control:
        {
          modelValue: "",
          placeholder: "生成的内容会显示在这里"
        },
        column:
        {
          minWidth: 300
        }
      }]
    }]
  }],
  form:
  {
    size: "default",
    labelWidth: "100px"
  },
  config:
  {
    submitCancel: true,
    getUrl: "",
    editUrl: ""
  }
}