好用的低代码可视化表单设计器 FcDesigner 是一款基于 Vue 的开源工具(设计器项目名 form-create-designer),通过数据驱动表单渲染。可以拖拽生成表单规则,再由配套渲染器 form-create 加载 JSON 并渲染。面向政务、OA、ERP、电商、流程管理里要做动态表单的开发者和业务配置同学。
审批单要按「申请人」拉部门下拉、录入页提交要带登录 Token、嵌进 OA 后所有接口都得改请求头------这些都是远程请求。FcDesigner 把请求收成一份 FetchConfig:action 是地址,method 只区分 GET / POST,query 走 GET 参数,data 是携带数据,JSON body 要声明 dataType: 'json',鉴权放 headers。组件事件里用 api.fetch 当场发;表单事件 beforeFetch 在真正发出前改 config;也可以重写内置 fetch,让设计器和渲染器走同一套请求头。

选中组件后打开「设置事件」,左侧能建 change 这类事件。右侧「自定义」里拿到 $inject.api,就可以 api.fetch。截图里是值变化时请求 /api/change,成功后打日志。预览时改这个组件的值,就会发出这条请求。
FcDesigner 的远程请求 FetchConfig 怎么写?
数据结构
ts
type FetchConfig = {
//请求地址
action: String;
//请求方式
method?: 'GET' | 'POST';
//GET 参数
query?: Object;
//发送请求时携带的数据
data?: Object;
//携带数据的发送方式
dataType?: 'json' | 'formData';
//发送请求的请求头
headers?: Object;
//后置数据数据回调
parse?: Function;
//请求成功后的回调
onSuccess: (body: any) => void
//请求失败后的回调
onError?: (e: Error | ProgressEvent) => void;
}
action 必填。method 不写时,后面 GET 示例就只配 query。query 和 data 不要混用:GET 参数走 query,POST 携带的数据走 data。要把 body 做成 JSON,必须把 dataType 写成 'json',不要只改 headers。parse 在请求完成后处理返回值。类型里还有 onSuccess / onError;本页可运行示例走的是 api.fetch(...).then(...)。
审批单里怎么发 GET,录入页怎么发 POST?
基本示例:值变化时请求接口
场景: 审批单上有一个输入框。业务同学改完值(失焦或回车)就要打接口,把当前值带给后端。
按下面做:
- 选中这个输入框,打开「设置事件」。
- 「创建事件」里选值变化对应的
change。 - 在「自定义」里写入下面这段,保存后点确定。
- 点顶部「预览」,改这个字段的值,不要只看画布。
js
function change($inject) {
const api = $inject.api;
api.fetch({
action: '/api/change?value=' + $inject.args[0]
}).then(res=>{
console.log('请求成功')
})
}
$inject.api 是当前表单的 api。$inject.args[0] 是这次变化带出来的值。预览后:改字段并发出 GET(地址里拼了当前值);请求成功会在控制台看到「请求成功」。嵌进 OA 时把 /api/change 换成你们的校验或查询地址。
再一个示例:按姓名拉 Select 选项
场景: 录入页已经填了 name。要根据这个姓名去拉「所属部门」下拉的 options,不能写死在设计器里。
把这段写进会跑 api.fetch 的事件(同样是「设置事件」里,事件函数里已经有 api):
js
const formData = api.formData();
api.fetch({
action: '/api/getdata',
query: {
name: formData.name
}
}).then(res=>{
api.getRule('select').props.options = res.data;
});
api.formData() 取出整表当前值。query.name 用的是字段 name。预览后:请求变成 GET /api/getdata,带查询参数 name;返回的 res.data 写进名为 select 的规则的 props.options。把 'select' 换成你画布上那个下拉的标识,把 name 换成申请人字段。
值变化那条把参数拼进 action 字符串;这条用 query 对象。都是 GET,但 query 不用自己写 ?。预览后应发出 GET /api/getdata 并带上 name,下拉选项变成接口返回的 res.data。
POST 提交并带 Token
场景: 嵌进 OA 的录入页要点提交。整份 formData 以 JSON POST 出去,请求头带登录态。Token 来自外部变量 globalToken。
js
const formData = api.formData();
//外部变量
const token = api.getData('globalToken');
api.fetch({
action: '/api/submit',
method: 'POST',
dataType: 'json',
data: formData,
headers: {
token: token
}
}).then(res=>{
// 表单提交成功
});
预览后:发出 POST /api/submit,data 是当前整份表单值,headers.token 等于 api.getData('globalToken')。不要漏 dataType: 'json',否则 body 不是 JSON。globalToken 是外部变量,本页只用 api.getData 读取,不展开它是怎么挂上的。提交事件里写这段,点预览再提交,才能看到这次 POST。
请求 URL 和 Header 里怎么写变量?
配置请求时可以用双大括号 {``{ }} 引用变量,链接、请求头、数据里都能写。例如 {``{token}} 会在请求时换成变量 token 的值;值是对象时,用 {``{variableName.attributeName}} 取属性。

截图是「全局数据源」的「请求配置」:请求链接写成 http://192.168.1.4:8081/id={``{$form.Fvixlz6gmhetc7c}},请求头 token 写成 {``{$cookie.token}}。魔棒会打开变量列表,当前表单字段在 $form 下面。你自己拖出来的字段 ID 和截图不同,以列表里的为准。
基本示例:GET 链接拼 userId,Header 带 Cookie
场景: 嵌进 OA 的审批单。详情接口路径里要带当前表单的 userId,鉴权走 Cookie 里的 token。
js
api.fetch({
action: 'https://api.example.com/user/{{$form.userId}}/details',
method: 'GET',
headers: {
'Authorization': 'Bearer {{$cookie.token}}'
},
data: {},
}).then(res=>{
//todo
});
预览后:真正发出时,{``{$form.userId}} 换成表单字段 userId 的值,{``{$cookie.token}} 换成 Cookie 的 token。字段名必须和画布上的一致,Cookie 键必须叫 token。
再一个示例:POST 的 data 引用表单字段
场景: 录入页更新资料。姓名、年龄已经在表单里,不要在事件里再手写一遍 api.formData()。
js
api.fetch({
action: 'https://api.example.com/update',
method: 'POST',
dataType: 'json',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{$cookie.token}}'
},
data: {
name: '{{$form.userName}}',
age: '{{$form.userAge}}'
},
}).then(res=>{
//todo
});
预览后:POST JSON 到 /update,name / age 分别是字段 userName、userAge 当时的值,Authorization 仍从 Cookie 取 token。本页列出的替换关系是:
{``{$cookie.token}}→ Cookie 中的 token 字段{``{$form.userId}}→ 表单中的 userId 字段{``{$form.userName}}→ 表单中的 userName 字段{``{$form.userAge}}→ 表单中的 userAge 字段
{``{变量名}} 还能读内置变量、全局变量和外部传入的数据。定义方式不在本课展开;请求配置里先用上面这组。
怎么用 beforeFetch 在发出前改请求?
beforeFetch 在远程请求真正发出前触发。可以在这里改请求头、改 URL、加查询参数。注意:这里拿到的是最终请求数据 ,不再做模板变量解析。配置里写的 {``{ }} 此时已经替换完了。
按这三步配:
- 打开表单事件配置弹窗:进入设计器,点配置面板里的「事件」(截图上这一块标题是「表单事件」),打开事件配置。
- 在弹窗左侧选
beforeFetch。说明是「远程数据请求发送前触发」,函数签名是function beforeFetch(config, data)。 - 在右侧改
config,保存。


基本示例:请求头加上 Cookie 里的 user-token
场景: 嵌进 OA 后,Select 远程选项、提交、上传都会发请求。不想每个组件事件里都手写 Token,统一从 Cookie user-token 塞进 headers.token。
js
function getCookie(name) {
name = name + '=';
const decodedCookie = decodeURIComponent(document.cookie);
const cookieArray = decodedCookie.split(';');
for (let i = 0; i < cookieArray.length; i++) {
let cookie = cookieArray[i];
while (cookie.charAt(0) === ' ') {
cookie = cookie.substring(1);
}
if (cookie.indexOf(name) === 0) {
cookie = cookie.substring(name.length, cookie.length);
try {
return JSON.parse(cookie);
} catch (e) {
return cookie;
}
}
}
return null;
}
config.headers.token = getCookie('user-token');
这段写在 beforeFetch(config, data) 函数体里。预览后:任意远程请求发出前,headers.token 都会变成 Cookie user-token 的值。Cookie 里没有这个键时,getCookie 返回 null。
再一个示例:URL 上拼 localStorage 的 user_id
场景: 审批单接口用查询参数区分当前登录人。人的 ID 在 localStorage.user_id,不想让业务同学在每个数据源里手填。

js
function getLocalStorage(name) {
const value = localStorage.getItem(name);
if (value) {
try {
return JSON.parse(value);
} catch (e) {
return value;
}
}
return null;
}
config.action += ('?=uid' + getLocalStorage('user_id'));
预览后:原来的 config.action 后面会接上 ?=uid 和 user_id。截图红框就是这一行。键名必须是 user_id。这里按官方示例拼接,不要改成自己发明的查询串格式。
把自定义 token 变量追加进 headers
场景: 录入页已经把 token 挂在表单能 getData 到的数据上,只想在现有 headers.token 后面再拼一段。
js
config.headers.token += data.api.getData('token');
beforeFetch 第二个参数是 data,上面用 data.api.getData('token')。预览后:请求头里的 token 会在原值后面追加这段。这条是 +=,要求 config.headers.token 事先已经有值(例如前面用 {``{$cookie.token}} 配过)。
返回数据怎么 parse?设计器里的 fetch 怎么统一改?
基本示例:把接口的 items 抽成组件能用的数组
场景: 审批单下拉要 {id, name}。后端却包了一层:
json
{
"status": "success",
"data": {
"items": [
{ "id": 1, "name": "Item 1" },
{ "id": 2, "name": "Item 2" }
],
"total": 2
}
}
parse 是后置回调,请求完成后先走它,再给组件用。

截图在「数据处理」页,最简单的写法是 return res.data。套了 status / items 时,用下面这段:
js
function parse (data) {
if (data.status === 'success') {
// 提取并格式化数据
return data.data.items.map(item => ({
id: item.id,
name: item.name
}));
} else {
throw new Error('请求失败');
}
}
预览后:status 为 success 时,组件拿到的是 [{id, name}, ...];否则抛「请求失败」。返回键名按示例是 id 和 name。截图里的 parse(res) 只 return res.data,适合接口已经是组件能直接吃的结构;包了 status 和 items 时用上面这段。
再一个示例:事件里手动 api.fetch
场景: 不走数据源配置,审批意见一变就按当前 name 再查一次。
js
api.fetch({
action: '/api/getdata',
query: {
name: api.getValue('name')
}
}).then(res=>{
//todo
});
和前面「按姓名拉 Select」那条的差别:这里用 api.getValue('name') 只取一个字段,而不是整份 formData。预览后:GET /api/getdata,查询参数是字段 name 的当前值。then 里按业务写后续赋值。
重写内置的请求方法
场景: 设计器画布、渲染器运行、文件上传都要带同一条 user-token。不想只靠某个表单的 beforeFetch。
文件上传同样会调用 fetch。重写时要一起改 FcDesigner.designerForm.fetch 和 FcDesigner.formCreate.fetch。
js
import FcDesigner from '@form-create/designer'
const globalFetch = FcDesigner.designerForm.fetch;
FcDesigner.designerForm.fetch = FcDesigner.formCreate.fetch = (config) => {
config.headers.token = getCookie('user-token');
return globalFetch(config);
}
getCookie 用前面 beforeFetch 示例里的那份即可。官方这段在 import FcDesigner 之后立刻覆盖两个 fetch:先把原函数存成 globalFetch,改完 config 必须 return globalFetch(config),不要丢掉内置实现。预览或运行后,所有走内置 fetch 的请求(含上传)都会先写入 headers.token,再交给原来的实现。只想改某一张审批单时,用该表的 beforeFetch,不要全局覆盖。
远程请求常见问题
Q: api.fetch 应该写在哪里?
A: 写在会拿到 api 的事件里。组件「设置事件」的 change 里用 const api = $inject.api,再 api.fetch。表单事件 beforeFetch 的参数是 (config, data),改的是即将发出的 config,不是再调一次 api.fetch。GET 拉选项那条用 api.formData() 和 api.getRule('select');只取一个字段时用 api.getValue('name')。
Q: GET 和 POST 差在哪?dataType 什么时候写?
A: GET 示例把参数放 query,method 可以不写。POST 必须写 method: 'POST',携带数据放 data。要把 body 做成 JSON,必须 dataType: 'json',只改 Content-Type 不够。Token 一类鉴权放 headers。method 的可选值在类型里只有 'GET' | 'POST'。
Q: {{ }} 变量和 beforeFetch 谁先生效?
A: 配置里的 {``{$form.userId}}、{``{$cookie.token}} 在请求执行时会被替换。beforeFetch 拿到的是替换之后的最终请求数据,不再解析模板变量。要改已经拼好的 URL 或 Header,在 beforeFetch 里改 config.action / config.headers。
Q: 为什么重写 fetch 之后上传也带上 Token 了?
A: 文件上传同样调用 fetch。把 FcDesigner.designerForm.fetch 和 FcDesigner.formCreate.fetch 一起换成你的函数后,设计器、渲染器、上传都会先经过你的 config.headers.token = getCookie('user-token'),再 return globalFetch(config)。只想改某张表的请求时,用该表的 beforeFetch,不要全局重写。