表单接口对接文档
表单接口对接文档
适用于通过 OpenAPI 拿到
user_token后调用表单相关业务接口的第三方系统。 所有接口前缀:/user/,需在 Header 中携带Authorization: Bearer <user_token>。
1. 概念说明
1.1 核心概念
| 概念 | 说明 |
|---|---|
| Form(表单) | 由表单设计器生成,包含字段定义 (rules)。每个表单有一个 id 和 title。 |
| FormData(表单数据) | 用户填写表单后产生的数据记录,存储在 form_data 表中。 |
| field(字段) | 表单中的输入项,如"申请人姓名"、"金额"等,由 field 标识。 |
| rules(规则 JSON) | 描述表单结构的 JSON 字符串,包含所有字段定义、布局、校验等。 |
| 内置字段 | 每条 FormData 默认包含 status(状态)、userId(提交人)、flowId(绑定流程) 三个直接列字段。 |
1.2 字段类型一览
rules 中常见的字段类型:
| Type | 说明 | 数据存储格式 |
|---|---|---|
input | 单行文本 | string |
textarea | 多行文本 | string |
inputNumber | 数字 | number |
select | 下拉单选/多选 | string 或 string[] |
radio | 单选 | string |
checkbox | 多选 | string[] |
datePicker | 日期 | string ("YYYY-MM-DD") |
timePicker | 时间 | string |
switch | 开关 | boolean |
upload | 文件上传 | object[](含 url/name) |
tableForm | 子表 | object[] |
subForm | 嵌套表单 | object |
布局类型(不存数据):row、col、tabPane、tabs、group、card、collapse、space、divider、alert、html、text、button。
2. 接口总览
| Method | 路径 | 说明 |
|---|---|---|
| GET | /user/forms | 获取启用的表单列表 |
| GET | /user/formfields | 获取指定表单的字段列表(下拉选项格式) |
| GET | /user/datalist | 获取表单数据列表(核心:高级查询) |
| POST | /user/editdata | 编辑用户个人资料(与表单数据无关,命名历史遗留) |
💡 提交表单数据请使用工作流接口
POST /workflow/adddata,详见 workflow.md。
3. 接口详解
3.1 获取表单列表
GET /user/forms
获取所有已启用(status=0)的表单。
请求参数:无
响应:
{
"code": 0, "msg": "success",
"data": [
{
"id": 12,
"title": "请假申请表",
"rules": "[{\"type\":\"input\",\"field\":\"reason\",\"title\":\"请假事由\",...}]"
},
{
"id": 15,
"title": "报销申请表",
"rules": "[...]"
}
]
}rules 是 JSON 字符串,第三方系统拿到后需 JSON.parse() 才能拿到字段树。
3.2 获取表单字段列表
GET /user/formfields?form_id=12
返回指定表单的所有"可查询字段",已自动加上内置字段。
请求参数:
| 参数 | 必填 | 说明 |
|---|---|---|
form_id | ✅ | 表单 ID |
响应:
{
"code": 0,
"data": [
{ "label": "状态", "value": "status" },
{ "label": "用户ID", "value": "userId" },
{ "label": "流程ID", "value": "flowId" },
{ "label": "请假事由 (reason)", "value": "reason" },
{ "label": "请假天数 (days)", "value": "days" },
{ "label": "开始日期 (start_date)", "value": "start_date" }
]
}返回的 value 即可作为 /user/datalist 接口 param 的字段名。
3.3 查询表单数据列表(重点)
GET /user/datalist
按条件检索表单数据,支持复杂查询表达式。
3.3.1 基础参数
| 参数 | 必填 | 默认 | 说明 |
|---|---|---|---|
form_id | ✅ | — | 表单 ID |
page | ❌ | 1 | 页码(从 1 开始) |
limit | ❌ | 10 | 每页条数 |
only_mine | ❌ | — | 1=仅查询当前用户提交的数据 |
param | ❌ | — | 高级查询条件(见下文) |
3.3.2 param 查询表达式
格式:field:op=value,多个条件用 & 拼接,需做 URL Encode 后整体作为 param 的值。
| 操作符 | 含义 | 示例 |
|---|---|---|
eq | 等于 | amount:eq=100 |
ne | 不等于 | status:ne=2 |
gt | 大于 | amount:gt=1000 |
gte | 大于等于 | amount:gte=500 |
lt | 小于 | amount:lt=100 |
lte | 小于等于 | days:lte=7 |
like | 模糊包含 | reason:like=出差 |
in | 属于(逗号分隔) | status:in=1,2,3 |
empty | 字段为空 | phone:empty=1 |
notempty | 字段非空 | phone:notempty=1 |
⚠️ 操作符是强制要求的:必须为
field:op=value格式,否则返回 400。 ⚠️ 数字比较(gt/gte/lt/lte)会自动CAST(... AS DECIMAL(20,6)),确保字段值是数字。
3.3.3 选项类字段(select / checkbox / radio)特殊规则
| 操作符 | 行为 |
|---|---|
eq | 使用 JSON_CONTAINS 匹配数组中包含该值 |
ne | 字段为 NULL 或不包含该值 |
in | 数组中包含任意一个候选值 |
后端会自动检测字段类型,无需第三方关心。
3.3.4 完整示例
查询:表单 12 中"金额 > 1000 且状态为审批中(1) 或 已通过(9)"的数据,仅看我自己的。
GET /user/datalist?form_id=12&page=1&limit=20&only_mine=1
¶m=amount%3Agt%3D1000%26status%3Ain%3D1%2C9
Authorization: Bearer <user_token>param 解码后:amount:gt=1000&status:in=1,9
响应:
{
"code": 0,
"data": {
"total": 3,
"list": [
{
"id": 1024,
"formId": 12,
"userId": 100,
"status": 1,
"flowId": 7,
"nodeId": "node_xxxx",
"workType": 0,
"data": "{\"reason\":\"出差北京\",\"amount\":2000,\"days\":3,...}",
"add_time": 1717150000,
"up_time": 1717150500
}
]
}
}data 字段是 JSON 字符串,需自行 JSON.parse()。
3.4 编辑用户个人资料
POST /user/editdata
⚠️ 注意:这个接口实际是修改当前登录用户的资料,命名因历史遗留与"表单"无关。
Body (JSON):
{
"nickname": "张三",
"phone": "13800138000",
"email": "zhangsan@example.com",
"avatar": "/avatars/100.png"
}响应:
{ "code": 0, "msg": "保存成功", "data": null }4. 字段解析示例(递归解析 rules)
rules 中字段可能嵌套在 children 或 props.rule 中(例如 row > col > input)。
Node.js 递归提取字段:
function collectFields(rules, out = []) {
const layoutTypes = new Set(['row','col','tabPane','tabs','group','subForm','card','collapse','collapseItem','space','divider','alert','html','text','button','tableForm','tableFormColumn'])
for (const item of rules) {
if (item.field && !layoutTypes.has(item.type)) {
out.push({ field: item.field, title: item.title, type: item.type })
}
if (item.children) collectFields(item.children, out)
if (item.props?.rule) collectFields(item.props.rule, out)
}
return out
}
// 使用
const forms = await api.get('/user/forms')
const fields = collectFields(JSON.parse(forms.data[0].rules))
console.log(fields)
// [{ field: 'reason', title: '请假事由', type: 'input' }, ...]5. 完整对接代码(Node.js)
const axios = require('axios')
const BASE = 'https://your-godocloud.com'
async function queryForm(userToken, formId) {
const http = axios.create({
baseURL: BASE,
headers: { Authorization: `Bearer ${userToken}` }
})
// 1. 获取所有可用表单
const { data: formsRes } = await http.get('/user/forms')
console.log('表单列表:', formsRes.data.map(f => `${f.id}:${f.title}`))
// 2. 获取字段
const { data: fieldsRes } = await http.get('/user/formfields', { params: { form_id: formId } })
console.log('可查字段:', fieldsRes.data)
// 3. 复杂查询:状态=1 且 金额 > 1000
const param = encodeURIComponent('status:eq=1&amount:gt=1000')
const { data: listRes } = await http.get('/user/datalist', {
params: { form_id: formId, page: 1, limit: 20, only_mine: 1, param }
})
for (const row of listRes.data.list) {
const fields = JSON.parse(row.data)
console.log(`#${row.id} status=${row.status}`, fields)
}
return listRes.data
}
queryForm('eyJhbGc...', 12).catch(console.error)6. 注意事项
form_id必填:不提供会直接返回 400。only_mine=1优先级最高:即便param中也指定了userId,only_mine会覆盖。paramURL 编码:注意整体 encode,否则&会被解释为新参数。- JSON 字段类型:
data是 JSON 字符串;客户端必须JSON.parse()后访问。 - 字段类型自适应:后端会自动识别选项类字段并使用
JSON_CONTAINS,无需第三方关心。 - 比较运算限制:
gt/gte/lt/lte仅对数字字段有意义;对字符串使用会按字典序比较。 - 不存在的字段:
param中传不存在的field不会报错,但查询为空。 - 创建表单数据:表单数据通常通过 工作流 提交,详见 workflow.md。
7. 常见问题
Q1:如何获取某个字段的所有可选值? A:调用 /user/forms,从 rules 中找到对应字段的 options 数组。
Q2:表单数据中的 flowId=0 是什么意思? A:未绑定工作流的表单数据(直接表单存储,未走审批)。
Q3:表单数据的 status 字段值含义? A:0=未审批 / 1=审批中 / 2=审批通过 / 3=驳回到上一节点 / 4=驳回到初始 / 9=全部通过。
Q4:如何对子表(tableForm)字段查询? A:当前不支持深层 JSON 路径查询;可拉取完整数据后在第三方系统侧二次筛选。
Q5:可以同时查多个表单数据吗? A:不可以。form_id 是必填且只能传一个;如需跨表查询,请多次请求合并。