自定义 Widget 时,需要声明模板使用的变量及其类型。Zod Schema 通过代码描述这些变量的数据结构,例如标题是字符串、数量是数字、商品列表是数组。
Widget 的三个编辑区域分别承担以下职责:
编辑区域 | 填写内容 | 示例 |
Template(模板) | 组件布局及变量引用 | <Text value={message} /> |
Schema(数据结构) | 变量名称、类型及约束 | message: z.string() |
Default(默认值) | 用于预览的具体变量数据 | {"message": "操作成功"} |
快速入门
以下示例创建一个展示标题和提示信息的 Widget。请将三段代码分别填写到对应编辑区域;Schema 使用 Zod 格式。
Schema:声明变量
import { z } from "zod";const WidgetState = z.strictObject({title: z.string().describe("卡片标题"),message: z.string().describe("展示给用户的提示信息"),});export default WidgetState;
代码说明:
import { z } from "zod":引入 Zod,本文示例使用 Zod 4 写法。z.strictObject({...}):声明一个对象,其中每个字段对应一个变量。严格对象不接受未声明的额外字段。z.string():声明字符串类型。类似地,可以使用 z.number()、z.boolean() 声明数字和布尔值。.describe("..."):补充字段含义,例如用途、单位或取值说明;它不设置字段值,也不执行业务校验。export default WidgetState:将完整的数据结构作为默认导出。WidgetState 是示例中的名称,可以修改,但声明和导出的名称必须一致。Default:填写示例数据
{"title": "处理结果","message": "您的请求已处理完成"}
Template:引用变量
<Card size="sm"><Col gap={2}><Title value={title} /><Text value={message} /></Col></Card>
预览应显示标题“处理结果”和正文“您的请求已处理完成”。其中
{message} 表示读取变量;"message" 表示显示固定文本。变量直接按字段名引用,无需添加 WidgetState. 前缀。文本组件通过 value 属性接收文本,具体属性请参见 Title 标题 和 Text 文本。基本语法
以下是字段声明片段,应放在根对象
z.strictObject({...}) 内使用。数据类型或用途 | 字段声明示例 | 对应数据示例 |
字符串 | name: z.string() | "商品 A" |
数字 | price: z.number() | 29.9 |
整数 | quantity: z.number().int() | 2 |
布尔值 | paid: z.boolean() | true 或 false |
枚举 | status: z.enum(["pending", "completed"]) | "pending" |
固定值 | type: z.literal("order") | "order" |
字符串数组 | tags: z.array(z.string()) | ["新品", "推荐"] |
嵌套对象 | customer: z.strictObject({ name: z.string() }) | {"name": "小王"} |
对象数组 | items: z.array(z.strictObject({ name: z.string() })) | [{"name": "商品 A"}] |
数组需要声明元素类型。例如,
z.array(z.string()) 表示每一项都是字符串;列表中的每一项是对象时,应使用对象 Schema 作为数组元素类型。必填、可选与空值
对象字段默认必填。使用
.optional() 允许不提供字段,使用 .nullable() 允许字段值为 null。写法 | 是否允许缺少字段 | 是否允许 null | 是否允许空字符串 "" |
z.string() | 否 | 否 | 是 |
z.string().optional() | 是 | 否 | 是 |
z.string().nullable() | 否 | 是 | 是 |
z.string().nullable().optional() | 是 | 是 | 是 |
例如,
remark: z.string().optional() 允许数据中没有 remark,但不允许 "remark": null。如果业务中两种情况都可能出现,可使用 z.string().nullable().optional()。“必填”不等于“非空字符串”。不允许空字符串时,可声明为
z.string().min(1)。它仍允许只包含空格的字符串;如需处理这种情况,应在上游数据处理环节完成。常用约束和描述
需求 | 字段声明示例 | 含义 |
限制文本长度 | title: z.string().min(1).max(50) | 字符串长度为 1~50 |
限制数字范围 | score: z.number().min(0).max(100) | 数值在 0~100 之间,包含边界 |
正整数数量 | quantity: z.number().int().min(1) | 数量为不小于 1 的整数 |
至少一个列表项 | tags: z.array(z.string()).min(1) | 数组至少包含一项 |
说明单位 | price: z.number().min(0).describe("单价,单位:元") | 非负数字,并补充单位说明 |
这些约束用于描述数据要求,不会自动纠正错误数据。不要依赖字段描述代替类型或范围约束。
完整示例:订单信息卡片
本例包含字符串、数字、布尔值、枚举、嵌套对象、对象数组和可选字段。可将整个示例复制到一个新的 Widget 中体验。
Schema
import { z } from "zod";const OrderItem = z.strictObject({id: z.string().describe("商品项标识,同一订单内不重复"),name: z.string().describe("商品名称"),quantity: z.number().int().min(1).describe("购买数量"),price: z.number().min(0).describe("商品单价,单位:元"),});const WidgetState = z.strictObject({orderNo: z.string().describe("订单编号"),status: z.enum(["pending", "completed"]).describe("pending:处理中;completed:已完成"),paid: z.boolean().describe("是否已支付"),customer: z.strictObject({name: z.string().describe("客户姓名"),}),items: z.array(OrderItem).min(1).describe("订单商品列表"),remark: z.string().optional().describe("订单备注,可不提供"),});export default WidgetState;
可以像
OrderItem 一样,将重复使用或较复杂的结构单独声明,再由根对象引用。被引用的 Schema 应先声明;最终只默认导出完整的根对象。id 描述中的“不重复”是数据准备要求,.describe() 本身不会检查唯一性。Default
{"orderNo": "ORDER-1001","status": "pending","paid": true,"customer": {"name": "小王"},"items": [{"id": "item-1","name": "笔记本","quantity": 2,"price": 19.9},{"id": "item-2","name": "签字笔","quantity": 1,"price": 5}],"remark": "请妥善包装"}
Template
<Card size="md"><Col gap={2}><Title value={`订单 ${orderNo}`} /><Text value={`客户:${customer.name}`} /><Text value={status === "completed" ? "状态:已完成" : "状态:处理中"} /><Text value={paid ? "支付:已支付" : "支付:未支付"} />{items.map((item) => (<Textkey={item.id}value={`${item.name} × ${item.quantity},单价 ${item.price} 元`}/>))}<Text value={remark ? remark : "无备注"} /></Col></Card>
变量对应关系:
Schema 路径 | Default 中的数据 | Template 引用方式 |
orderNo | "ORDER-1001" | {orderNo} 或模板字符串 |
customer.name | "小王" | {customer.name} |
items | 商品对象数组 | items.map(...) |
items 中每一项的 name | "笔记本"、"签字笔" | 循环中的 item.name |
remark | "请妥善包装",也可省略 | 使用条件表达式提供缺省展示 |
预览应展示订单编号、客户姓名、处理状态、支付状态、两条商品信息和备注。删除 Default 中的
remark 后,应显示“无备注”。注意事项
1. 默认导出对象 Schema。根结构使用
z.strictObject({...}) 或 z.object({...}),并通过 export default 导出。不要直接导出字符串或数组 Schema;需要列表时,将数组放在根对象的一个字段中。建议使用 z.strictObject(),并使实际数据与声明字段保持一致。2. 区分 Zod 与 JSON Schema 格式。本文代码填写在 Zod 格式的 Schema 编辑区。Zod 使用
z.string() 等代码声明类型;JSON Schema 使用 type、properties 等 JSON 字段。不要将两种写法混在一起,也不要将 interface 或 type 类型声明当作 Schema。3. 变量名称和层级保持一致。建议使用英文字母开头、由字母、数字和下划线组成的字段名,避免空格和连字符。例如,
customer.name 对应嵌套对象,Default 应写成 "customer": {"name": "小王"}。模板中的固定文本无需声明为变量。4. 数据类型必须匹配。
29.9 是数字,"29.9" 是字符串;false 是布尔值,"false" 是字符串。数组和对象应填写为实际 JSON 数组、对象,不能填写成包含 JSON 的字符串。枚举值必须与声明完全一致,例如 "pending" 不能替换为 "处理中"。5. 可选字段需要考虑展示方式。
.optional() 允许字段缺失,不会自动提供展示文案。模板应处理缺失值或 null。如果数组允许为空,应考虑空列表的展示;如果不允许为空,可使用 .min(1)。6. 区分 Default 和
.default()。Widget 的 Default 编辑区提供具体示例数据;Zod 的 .default(value) 表示 Zod 解析缺失值时的默认值语义。二者不是同一个配置。请显式填写 Widget 的 Default,并在实际调用时准备所需字段,不要假设 Schema 中的 .default() 会自动补全运行时数据。7. 优先使用可表达为 JSON 数据结构的基础语法。Schema 只引入
import { z } from "zod",不引入其他库,不在其中编写网络请求或业务处理函数。不要依赖 .transform()、.preprocess()、自定义 .refine() 等逻辑在 Widget 中执行或完整保留校验;也应避免使用 z.date()、z.bigint()、z.map()、z.set() 等非 JSON 数据类型。日期可用字符串表达,例如 "2026-09-11",并在字段描述中约定格式。Zod 到 JSON Schema 的转换存在表达范围限制,详见 Zod JSON Schema 文档。8. 同时检查组件属性类型。Schema 中声明为数字的字段,在传给要求字符串的文本属性时,应通过模板字符串构造文本,如
<Text value={`数量:${quantity}`} />。Schema 正确不代表任意组件属性组合都正确。9. 修改后验证预览与实际调用。新增或重命名字段时,同步调整 Schema、Default、Template 和调用方传入的数据。用于工作流 Widget 节点时,在 Widget 编辑页声明 Schema,再在工作流节点中按变量名称和类型配置实际数据来源;节点输入传递的是变量数据,不是 Zod 代码。Default 预览成功不能替代工作流调试,配置步骤请参见 配置 Widget 节点。
常见问题
问题 | 检查和处理方式 |
提示需要默认导出 ZodObject | 检查是否有 export default WidgetState,且导出的变量是对象 Schema |
默认导出了 z.array(...),仍无法解析 | 将数组声明为对象内的字段,例如 z.strictObject({ items: z.array(z.string()) }) |
新增变量后没有正确显示 | 检查三处变量名称和层级是否一致,Default 是否提供数据,Template 是否使用 {变量名} |
数字或布尔值不符合 Schema | 去掉数据中多余的引号,或根据业务含义调整 Schema 类型 |
可选字段传 null 后不符合 Schema | .optional() 只允许缺少字段;允许 null 时需增加 .nullable() |
使用 z.strictObject() 后出现额外字段问题 | 删除未声明的数据字段,或在 Schema 中补充它们的定义 |
自定义转换或校验没有达到预期 | 改用基础类型和可转换的约束,将数据转换、复杂业务校验放在上游处理 |
预览正常,工作流中显示异常 | 检查节点实际输入的数据类型、字段层级、必填字段及枚举值是否与 Schema 一致 |