mcpField
C
camunda-forms

camunda-forms

github.com/camunda开发26123 次安装今天更新
代码仓库

关于 camunda-forms

camunda-forms 是用于 Camunda 8.8+ 的表单 JSON 架构编写技能,面向构建用户任务和启动事件表单的开发者。它涵盖字段绑定、布局、校验及提交前的模式验证。

主要功能

  1. 01生成 .form 表单架构
  2. 02配置输入、展示和布局组件
  3. 03绑定流程变量并设置默认值
  4. 04设置校验与条件可见性
  5. 05使用官方架构验证表单

适用场景

  1. 01为用户任务创建表单
  2. 02为流程启动事件创建表单
  3. 03按流程变量预填并保存字段
  4. 04部署前检查表单架构

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/camunda/skills --skill camunda-forms

安装后在 Claude Code 中输入/camunda-forms确认已加载。

附带文件portability.jsonreferences/component-reference.md

详细介绍

Camunda 表单

为 Camunda 8.8+ 中的用户任务和开始事件创建 Camunda 表单 JSON 架构。

前提条件

  • Camunda 8.8+ 集群

交叉引用

  • camunda-bpmn:通过 <zeebe:formDefinition formId="..."/> 将表单关联到用户任务时使用
  • camunda-feel:用于表单验证表达式和条件可见性逻辑

说明

表单基础

Camunda 表单是扩展名为 .form(而不是 .json)的 JSON 文件。通过表单的 id 字段将表单关联到 BPMN 用户任务;该字段必须与用户任务内 <zeebe:formDefinition formId="..."/> 的 formId 属性匹配。用户任务本身还必须包含 <zeebe:userTask/>(Camunda 用户任务实现)。不要通过旧版 formKey 属性关联表单——该属性用于已弃用的作业工作者用户任务,并已在 Camunda 8.10 中移除。BPMN 相关内容请参阅 camunda-bpmn § 表单定义。

表单结构

示例——最简表单骨架:

{
  "components": [],
  "executionPlatform": "Camunda Cloud",
  "executionPlatformVersion": "8.8.0",
  "exporter": { "name": "Camunda Modeler", "version": "5.34.0" },
  "schemaVersion": 18,
  "id": "my-form-id",
  "type": "default"
}

所有元数据字段均为必填项。请使用 schemaVersion: 18 和 executionPlatformVersion: "8.8.0"。

组件

每个组件都必须包含 type、id 和 layout。输入组件还需要 key(映射到流程变量名称)和 label。

{
  "type": "textfield",
  "id": "Field_Name",
  "key": "customerName",
  "label": "Customer Name",
  "layout": { "row": "row_0", "columns": null }
}

输入组件:textfield、textarea、number、checkbox、checklist、radio、select、taglist、datetime

显示组件:text(markdown)、html、image、separator、button

布局组件:group、spacer

请严格使用架构中的属性名称:

  • 使用 defaultValue 设置输入项的初始值。不要在组件上使用 value;value 仅用于选项对象内部,例如 { "label": "High", "value": "high" }。
  • 提交控件是 action: "submit" 的 button 组件。不要使用 type: "submit",也不要为按钮添加 key。
{
  "type": "textfield",
  "id": "Field_Name",
  "key": "customerName",
  "label": "Customer Name",
  "defaultValue": "Ada",
  "layout": { "row": "row_0", "columns": null }
}
{
  "type": "button",
  "id": "Button_submit",
  "label": "Submit",
  "action": "submit",
  "layout": { "row": "row_1", "columns": null }
}

各组件类型的完整属性请参阅 references/component-reference.md。

布局

组件按行排列。将组件放在同一行即可并排显示:

{ "type": "textfield", "id": "F1", "key": "firstName", "label": "First Name", "layout": { "row": "row_0", "columns": null } },
{ "type": "textfield", "id": "F2", "key": "lastName", "label": "Last Name", "layout": { "row": "row_0", "columns": null } }
变量绑定

key 属性将表单字段映射到流程变量:

  • 加载时:如果变量存在,字段会使用该变量预填充
  • 提交时:字段值会写回变量
验证
{
  "validate": {
    "required": true,
    "minLength": 2,
    "maxLength": 100,
    "min": 0,
    "max": 10000,
    "pattern": "^[A-Z]{2}[0-9]+$",
    "validationExpression": "=amount <= budget"
  }
}

自定义错误消息:requiredErrorMessage、patternErrorMessage。

条件可见性

使用 FEEL,根据其他字段的值隐藏或显示字段:

{
  "conditional": {
    "hide": "=approved = false"
  }
}

该表达式会根据所有表单字段值和流程变量进行求值。

选择框/单选框/清单选项

静态值:

{
  "type": "select",
  "values": [
    { "label": "Low", "value": "low" },
    { "label": "Medium", "value": "medium" },
    { "label": "High", "value": "high" }
  ]
}

来自流程变量的动态值:

{
  "type": "select",
  "valuesExpression": "=departments"
}

该变量应为由 {label, value} 对象组成的列表。

只读字段

显示数据但不允许编辑:

{
  "type": "textfield",
  "key": "orderId",
  "label": "Order ID",
  "readonly": true
}
文本/Markdown

使用 markdown 显示静态文本或说明:

{
  "type": "text",
  "text": "### Review Details\n\nPlease review the information below.",
  "id": "Text_Header",
  "layout": { "row": "row_0", "columns": null }
}
分组

组织相关字段:

{
  "type": "group",
  "label": "Contact Information",
  "components": [
    { "type": "textfield", "id": "F1", "key": "email", "label": "Email", "layout": { "row": "row_g0", "columns": null } },
    { "type": "textfield", "id": "F2", "key": "phone", "label": "Phone", "layout": { "row": "row_g1", "columns": null } }
  ],
  "id": "Group_Contact",
  "layout": { "row": "row_1", "columns": null }
}
输出格式

生成完整的 .form JSON 文件。确保:

  • 所有 id 值在表单内均唯一
  • key 值与预期的流程变量名称匹配
  • 输入默认值使用 defaultValue;提交控件使用 type: "button" 和 action: "submit",且不带 key
  • layout.row 值按顺序递增(row_0、row_1、……)
  • 元数据字段齐全且正确
Schema 验证循环(部署前检查)

创建或编辑 .form 文件后,在展示或部署前,先根据官方 Camunda 表单架构验证文件。直接使用 ajv 和 ajv-errors 插件。官方架构允许组件扩展属性,因此下面的辅助脚本还会拒绝已知的无效组件形态(value、type: "submit" 和按钮的 key)。由于此架构使用 errorMessage 关键字,直接调用 ajv-cli 会失败;如果使用 ajv-cli,请通过 --require 加载 ajv-errors。所有命令都从项目根目录运行:

npm install --save-dev ajv ajv-errors @bpmn-io/[email protected]

# Create the validation helper and commit it as a project tool
cat > validate-form.cjs << 'EOF'
const Ajv = require('ajv');
const addErrors = require('ajv-errors');
const fs = require('fs');
const schema = require('@bpmn-io/form-json-schema/resources/schema.json');
const file = process.argv[2];
if (!file) { console.error('Usage: node validate-form.cjs <path-to-form.form>'); process.exit(1); }
let form;
try { form = JSON.parse(fs.readFileSync(file, 'utf8')); }
catch (e) { console.error(`Cannot read/parse ${file}: ${e.message}`); process.exit(1); }
const ajv = new Ajv({ allErrors: true, strict: false });
addErrors(ajv);
const validate = ajv.compile(schema);
if (!validate(form)) { console.error(JSON.stringify(validate.errors, null, 2)); process.exit(1); }
function invalidComponentShapes(components, path = 'components') {
  if (!Array.isArray(components)) return [];
  const errors = [];
  for (const [index, component] of components.entries()) {
    if (!component || typeof component !== 'object' || Array.isArray(component)) continue;
    const location = `${path}[${index}]`;
    if (Object.prototype.hasOwnProperty.call(component, 'value')) {
      errors.push(`${location}: use defaultValue instead of value on a component`);
    }
    if (component.type === 'submit') {
      errors.push(`${location}: use type "button" with action "submit"`);
    }
    if (component.type === 'button' && Object.prototype.hasOwnProperty.call(component, 'key')) {
      errors.push(`${location}: buttons must not define key`);
    }
    errors.push(...invalidComponentShapes(component.components, `${location}.components`));
  }
  return errors;
}
const shapeErrors = invalidComponentShapes(form.components);
if (shapeErrors.length) { console.error(JSON.stringify(shapeErrors, null, 2)); process.exit(1); }
console.log('Valid ✓');
EOF

node validate-form.cjs path/to/form.form

对于多个表单(包括嵌套目录中的表单),遍历每个文件,并在退出前收集所有错误:

failed=0
# Use find for recursive discovery; replace with *.form for flat directories
while IFS= read -r f; do
  node validate-form.cjs "$f" || { echo "FAILED: $f"; failed=1; }
done < <(find . -name '*.form' -not -path '*/node_modules/*')
exit $failed

常见架构关键字及修复方法:

关键字常见含义常见修复方法
required缺少必需字段添加错误消息中指出的缺失属性
additionalProperties此对象包含未知属性删除不受支持的属性
typeJSON 值类型错误将值改为预期类型(string/number/boolean/object/array)
enum / const值不在允许的集合中替换为允许的值之一
pattern字符串格式无效(通常是 id/key)重命名,使其符合所需的正则表达式(通常为字母数字/下划线形式)

故障排除

  • 表单未在 Tasklist 中显示 — 检查 BPMN 中的用户任务是否包含 <zeebe:userTask/> 和与表单 id 字段匹配的 <zeebe:formDefinition formId="..."/>。旧版 formKey 属性已在 Camunda 8.10 中移除。
  • schemaVersion 不匹配错误 — 设置 schemaVersion: 18 和 executionPlatformVersion: "8.8.0";8.8+ 集群会拒绝较旧的值。
  • 条件字段始终隐藏 — conditional.hide 是一个 FEEL 表达式,返回 true 时隐藏字段。忘记添加 = 前缀会使其变成字面字符串。关于 FEEL 部分,请参阅 camunda-feel § 常见模式。

参考资料

如需详细参考资料,请阅读 references/ 中的内容:

  • component-reference.md — 每种组件类型(textfield、number、select、datetime 等)的完整属性和示例

评论

支持 Markdown