宜搭低代码开发师(高级)认证实操:待办列表管理
钉钉宜搭低代码开发师(高级)认证中待办列表功能的实操实现。主要内容包括创建普通表单定义字段,构建自定义页面集成表格组件,并通过 JavaScript 调用宜搭 API 实现数据的展示、分页、搜索、新增、编辑、删除及状态流转。教程涵盖了从表单设计到自定义页面逻辑开发的完整流程,适用于需要掌握宜搭二次开发能力的开发者。

钉钉宜搭低代码开发师(高级)认证中待办列表功能的实操实现。主要内容包括创建普通表单定义字段,构建自定义页面集成表格组件,并通过 JavaScript 调用宜搭 API 实现数据的展示、分页、搜索、新增、编辑、删除及状态流转。教程涵盖了从表单设计到自定义页面逻辑开发的完整流程,适用于需要掌握宜搭二次开发能力的开发者。

需要扫描二维码加入组织,如果二维码失效,可通过以下方法加入组织:
步骤 1:打开手机钉钉右下角点击【我的】,找到【客服与帮助】。
步骤 2:在【客服与帮助】页面下滑找到【快捷工具】,选择【加入团队】即可根据名称搜索加入组织。



(1)创建如下字段:

(2)设置重要度的默认值为 1
步骤 1:获取组件唯一标识,复制 rateField_me2n0yf0(每个人创建的组件标识都不一样,按照自己创建的即可)

步骤 2:在左侧动作面板中使用如下代码设置默认值
that.$('组件唯一标识').setValue()

点击进行中待办表单旁边的⚙按钮,复制表单,并修改页面名称为【已完成待办】。


点击+,新建自定义页面,在弹出的页面中【从模板中新建】,找到【工作台模板 -01】,点击使用。


删除无关组件,按照如下操作依次删除两个布局容器。

选中"我的资产管理"修改内容为"待办列表"。

创建进行中待办表格,进行一些字段/样式设置(拖拽两个组件分组、子表格,如下展示)。







[ { "color": "grey", "text": "1", "value": 1, "__sid__": "serial_me9yvo5m" }, { "color": "blue", "text": "2", "value": 2, "__sid__": "serial_me9yvo5n" }, { "color": "yellow", "text": "3", "value": 3, "__sid__": "serial_me9yvo5o" }, { "color": "green",



功能实现前的说明:
比如在浏览器端想调用应用编码为 APP_X1X2X3X4 的「流程实例 - 流程发起」服务接口,则在数据面板里调用请求地址为(使用相对路径即可):
/dingtalk/web/APP_X1X2X3X4/v1/process/startInstance.json
获取应用编码的步骤,以我当前创建的项目为例,在浏览器上方复制如下,我此时的应用编码为:appType:APP_L0MRPK82DM5SNZ2UIHPM。

获取 formUuid 的步骤,以'进行中待办'表单为例,同样浏览器上方获取,我此时'进行中待办'的 formUuid 为:FORM-50859B5DAD37446FA143EDCB4CF3A44375VP,用于下面获取数据展示定义必填参数。

对于表格组件来说,我们主要在如下图所示,这两个地方进行配置。

**步骤 1:**选中左侧数据源,删除三个未被使用的远程数据源,并添加【getTodoData】远程 API,可选中下面这个参考文档,定位到 3.5 根据条件搜索表单实例 ID 列表,获取接口,请求类型,请求参数。


**步骤 2:**在数据处理部分,选中请求完成回调函数,修改如下代码,其中,字段名称都要跟表格字段对应一致。


function didFetch(content) {
// content.b = 1; 修改返回数据结构中的 b 字段为 1
const value = [];
const data = content.data.map((item) => {
let arr = {
textField_me2n0yey: item.formData.textField_me2n0yey,
radioField_me2n0yez: item.formData.radioField_me2n0yez,
rateField_me2n0yf0: item.formData.rateField_me2n0yf0,
dateField_me2n0yf1: item.formData.dateField_me2n0yf1,
textareaField_me2n0yf2: item.formData.textareaField_me2n0yf2,
instid: item.formInstId
};
value.push(arr);
});
let result = { "data": value, "currentPage": content.currentPage, "totalCount": content.totalCount };
return result; // 重要,需返回 content
}
**步骤 3:**点击进行中待办的表格,右侧数据源设置变量为 state.getTodoData,并且修改数据主键为:instid。
**步骤 4:**测试结果,在'进行中待办'页面新增一条数据,然后我们回到'TodoList 自定义页面'点击预览查看已新增一条待办事项为'测试 1'的数据,也可点击页面右上角选择'新窗口打开',此时数据展示功能完成。


**步骤 1:**在'进行中待办'页面新增 6 条数据。

**步骤 2:**在数据源新增两个变量 page 和 searchKey。

远程 getTodoData 中设置请求参数变量。


{
searchFieldJson: JSON.stringify({ radioField_me2n0yez: state.searchKey }),
formUuid: "FORM-50859B5DAD37446FA143EDCB4CF3A44375VP",
currentPage: state.page,
pageSize: 5
}
**步骤 3:**选中'进行中待办'的表格,滑到页面最底下选择'分页、搜索、排序时触发',定义函数名称为 onFetchTodoData,如果显示名称已存在,直接选中右侧的 onFetchTodoData 即可,现在我们动作面板编写代码。


// 点击进行中待办分页、搜索时触发
export function onFetchTodoData(params) {
if (params.from === 'search') {
params.currentPage = 1;
}
this.setState({ "searchKey": params.searchKey, "page": params.currentPage });
}
**步骤 4:**选择表格点击右侧分页设置,设置 pageSize 值为 5。


**步骤 5:**功能实现,查看效果。


**步骤 1:**选中表格,在右侧点击'顶部操作',删除原有的操作一,操作二,点击'添加一项'按钮,新增一个'新增待办'。



**步骤 2:**在右侧新增一个对话框组件,设置标题为'新增待办',并在对话框页面创建如下字段。

如下图,可点击这两个位置,对弹窗进行隐藏,以便我们后续写代码逻辑。

**步骤 3:**选中表格,在右侧点击'顶部操作',点击新增待办中编辑,添加回调函数为 onActionBarItemClick,然后返回 js 面板书写代码。


**步骤 4:**代码书写,打开弹窗,分别重置表单组件唯一标识的值。

export function onActionBarItemClick() {
// 打开弹窗,重置表单字段
this.$('dialog_me9xwn20').show(() => {
this.$('textField_me9xwn22').reset();
this.$('radioField_me9xwn23').reset();
this.$('rateField_me9xwn24').setValue(1);
this.$('dateField_me9xwn25').reset();
this.$('textareaField_me9xwn26').reset();
});
}
**步骤 5:**选中对话框组件,滑到最底下,选择 onOk 编写我们的代码逻辑。

export function onOk() {
// 需要校验组件的唯一标识集合
const createFieldList = [
'textField_me9xwn22',
'radioField_me9xwn23',
'rateField_me9xwn24',
'dateField_me9xwn25'
];
// 字段名:分别复制表格中设置的字段名称的唯一标识
// 字段值:分别复制对话框中设置的字段名称的唯一标识
const data1 = {
"textField_me2n0yey": this.$('textField_me9xwn22').getValue(),
"radioField_me2n0yez": this.$('radioField_me9xwn23').getValue(),
"rateField_me2n0yf0": this.$('rateField_me9xwn24').getValue(),
"dateField_me2n0yf1": this.$('dateField_me9xwn25').getValue(),
"textareaField_me2n0yf2": this.$('textareaField_me9xwn26').getValue()
};
const param = {
formUuid: "FORM-50859B5DAD37446FA143EDCB4CF3A44375VP",
appType: "APP_L0MRPK82DM5SNZ2UIHPM",
formDataJson: JSON.stringify(data1)
};
// 调用表单校验函数
this.fieldsValidate(createFieldList).then((errorList) => {
setTimeout( {
(errorList. > ) {
;
};
.[].(param).( {
..({ : , : , : });
});
.$().();
( {
.[].();
}, );
}, );
});
}
() {
result = [];
( i = ; i < fieldList.; i++) {
.$(fieldList[i]).( {
(!errors) {
;
};
result.({
: fieldList[i],
: ..() ? errors.[fieldList[i]]. : errors[fieldList[i]].
});
});
};
result;
}
**步骤 6:**添加 insert 远程数据源,关闭自动加载,请求方式为 post。

**步骤 7:**测试结果,新增成功,校验效果也生效。


**步骤 1:**新增一个对话框组件,并且设置标题为'确认删除',样式设置为一级标题;再嵌套一个文本组件,设置内容为'删除后无法撤销,数据会永久删除,是否确认删除?',设置样式为二级标题,padding 为 12px。因为我们要删除数据,所以需要获取到当前选择数据的 id,需要在对话框里增加一个输入框组件,设置为隐藏,用于存储当前数据的 id。


**步骤 2:**在页面右侧操作列中增加'删除',绑定回调函数 onDeleteClick,编写代码。

export function onDeleteClick(rowData) {
this.$('dialog_mea9fcvy').show(() => {
this.$('textField_mea9fcw0').setValue(rowData.instid);
});
}
**步骤 3:**当点击确认,调用 onDeleteTodoData,设置代码。

export function onDeleteTodoData() {
const param = {
// 这里需要修改为自己设置的输入框组件【实例 Id】的唯一标识
formInstId: this.$('textField_mea9fcw0').getValue(),
};
// 去远程数据源新增一个 deleteData 远程 API
this.dataSourceMap['deleteData'].load(param).then(res => {
this.utils.toast({ title: "删除成功", type: "success", size: "large" });
// 这里需要修改为自己删除【对话框】组件的唯一标识
this.$('dialog_mea9fcvy').hide();
setTimeout(() => {
this.dataSourceMap['getTodoData'].load();
}, 1000);
});
}
**步骤 4:**新增 deleteData 远程数据源,关闭自动加载,设置请求方式为 post。

**步骤 5:**测试结果,删除成功。

**步骤 1:**在页面右侧操作列中增加'编辑',绑定回调函数 onEditClick,打开新增待办的弹窗,回填数据。

export function onEditClick(rowData) {
this.$('dialog_me9xwn20').show(() => {
// 前面的 this.$('字段名'):字段名分别取的是对话框里组件的唯一标识
// rowData.字段名:字段名分别取的是 table 表格里面组件的唯一标识
this.$('textField_me9xwn22').setValue(rowData.textField_me2n0yey);
this.$('radioField_me9xwn23').setValue(rowData.radioField_me2n0yez);
this.$('rateField_me9xwn24').setValue(rowData.rateField_me2n0yf0);
this.$('dateField_me9xwn25').setValue(rowData.dateField_me2n0yf1);
this.$('textareaField_me9xwn26').setValue(rowData.textareaField_me2n0yf2);
});
}
**步骤 2:**操作列出现两个,导致页面效果换行,所以我们需要在右侧选择操作列→设置合适的宽度,如下图设置为 130px,页面显示效果正常。


**步骤 3:**编辑同样我们需要获取到当前数据 id,用于更新数据,刷新列表。所以需要在新增待办弹框创建一个实例 Id 用于存放当条数据 id,隐藏;在数据源增加一个 flag 变量,用于判断我们打开的是新增还是编辑操作;增加 updateData 远程数据源,关闭自动加载。


**步骤 4:**修改三处代码
(1)找到'新增待办'按钮触发的函数 onActionBarItemClick,设置 flag 值为 insert,并且重置输入框组件实例 ID 的值。
export function onActionBarItemClick() {
// 当点击新增的时候,设置 flag 为 insert
this.setState({ flag:'insert' });
this.$('dialog_me5mzrhu').show(() => {
this.$('textField_me5mzrhw').reset();
this.$('radioField_me5mzrhx').reset();
this.$('rateField_me5mzrhy').setValue(1);
this.$('dateField_me5mzrhz').reset();
this.$('textareaField_me5mzri0').reset();
// 重置实例 ID 的值
this.$('textField_mea9fcw1').reset();
});
}
(2)找到'编辑'按钮触发的函数 onEditClick,设置 flag 值为 edit,设置实例 ID 值为 rowData.instid。
export function onEditClick(rowData) {
// 设置 flag 值为 edit
this.setState({ flag: 'edit' });
this.$('dialog_me5mzrhu').show(() => {
this.$('textField_me5mzrhw').setValue(rowData.textField_me2n0yey);
this.$('radioField_me5mzrhx').setValue(rowData.radioField_me2n0yez);
this.$('rateField_me5mzrhy').setValue(rowData.rateField_me2n0yf0);
this.$('dateField_me5mzrhz').setValue(rowData.dateField_me2n0yf1);
this.$('textareaField_me5mzri0').setValue(rowData.textareaField_me2n0yf2);
// 设置实例 ID 唯一标识值为当前选择行的 instid
this.$('textField_mea9fcw1').setValue(rowData.instid);
});
}
(3)点击确定按钮,找到 onOk 函数修改代码,增加一个 if 判断,如果 flag 值为 insert,新增数据,反之修改数据。
export function onOk() {
// 需要校验组件的唯一标识集合
const createFieldList = [
'textField_me9xwn22',
'radioField_me9xwn23',
'rateField_me9xwn24',
'dateField_me9xwn25'
];
// 字段名:是表格中相对应的字段名称的唯一标识
// 字段值:是当前对话框中的字段名称的唯一标识
const data1 = {
"textField_me2n0yey": this.$('textField_me9xwn22').getValue(),
"radioField_me2n0yez": this.$('radioField_me9xwn23').getValue(),
"rateField_me2n0yf0": this.$('rateField_me9xwn24').getValue(),
"dateField_me2n0yf1": this.$('dateField_me9xwn25').getValue(),
"textareaField_me2n0yf2": this.$('textareaField_me9xwn26').getValue()
};
const param = {
formUuid: "FORM-50859B5DAD37446FA143EDCB4CF3A44375VP",
appType: "APP_L0MRPK82DM5SNZ2UIHPM",
formDataJson: JSON.stringify(data1)
};
// 调用表单校验函数
this.fieldsValidate(createFieldList).then((errorList) => {
setTimeout( {
(errorList. > ) {
;
};
(.. === ){
.[].(param).( {
..({ : , : , : });
});
.$().();
( {
.[].();
}, );
} {
param2 = {
: .$().(),
: .(data1)
};
.[].(param2).( {
..({ : , : , : });
.$().();
( {
.[].();
}, );
});
}
}, );
});
}
**步骤 5:**测试结果,编辑成功。

**步骤 1:**选择表格组件,在右侧页面设置中,找到顶部操作,删除操作 1,操作 2;操作列,将详情删除,新增一项删除。

**步骤 2:**新建远程 API,getDoneData,设置请求地址、参数值、请求方式,数据处理。

function didFetch(content) {
// content.b = 1; 修改返回数据结构中的 b 字段为 1
const value = [];
const data = content.data.map((item) => {
let arr = {
// item.formData.字段名:要跟已完成待办字段名对应上
textField_me2n0yey: item.formData.textField_me2ndu46,
radioField_me2n0yez: item.formData.radioField_me2ndu47,
rateField_me2n0yf0: item.formData.rateField_me2ndu48,
dateField_me2n0yf1: item.formData.dateField_me2ndu49,
textareaField_me2n0yf2: item.formData.textareaField_me2ndu4a,
instid: item.formInstId
};
value.push(arr);
});
let result = { "data": value, "currentPage": content.currentPage, "totalCount": content.totalCount };
return result; // 重要,需返回 content
}
**步骤 3:**设置已完成待办数据源变量、数据主键。

**步骤 4:**在已完成待办中新增 6 条数据,进行测试,已成功显示。

**步骤 1:**将已完成待办这里分页设置为 5,并且新增变量 donePage 和 doneSearchKey。


**步骤 2:**将远程数据源 getDoneData 绑定请求参数变量。

{
searchFieldJson: JSON.stringify({ radioField_me2ndu47: state.doneSearchKey }),
formUuid: "FORM-17BD995E61214B80BCEE9BB6EADF8DC8JNTV",
currentPage: state.donePage,
pageSize: 5
}
**步骤 3:**选中已完成待办表格,右侧动作选择分页,排序,搜索触发绑定 onFetchDoneData,编写代码。

// 点击已完成待办分页,搜索时触发
export function onFetchDoneData(params) {
if (params.from === 'search') {
params.currentPage = 1;
}
this.setState({ "doneSearchKey": params.searchKey, "donePage": params.currentPage });
}
**步骤 4:**测试结果。

**步骤 1:**操作列中为删除绑定 onDeleteClick,代码可以直接复用,不用再写。

**步骤 2:**在大纲树中打开删除的对话框,在右侧动作设置中直接定位到代码,增加一行,每次点击删除的时候会同时更新进行中待办,已完成待办表格数据,调用两次接口。
this.dataSourceMap['getDoneList'].load()

在页面设置中找到行选择器,开启显示,选择单选,在单行选择回调 onSelect 写逻辑代码。

export function onSelect(selected, rowData, selectedRows) {
const param1 = { formInstId: rowData.instid };
this.dataSourceMap['deleteData'].load(param1).then(res => {
setTimeout(() => {
this.dataSourceMap['getTodoData'].load();
}, 1000);
});
const data1 = {
// key:分别从已完成待办页面获取组件的唯一标识作为 key
// value:分别使用 rowData.字段名,获取当前选中'进行中待办'数据作为 value
"textField_me2ndu46": rowData.textField_me2n0yey,
"radioField_me2ndu47": rowData.radioField_me2n0yez,
"rateField_me2ndu48": rowData.rateField_me2n0yf0,
"dateField_me2ndu49": rowData.dateField_me2n0yf1,
"textareaField_me2ndu4a": rowData.textareaField_me2n0yf2
};
const param2 = {
// formUuid:取的是已完成待办页面中的 formUuid
formUuid: "FORM-1FA35C7CEE6548928D83CB89D8B9877D5GQR",
appType: "APP_L0MRPK82DM5SNZ2UIHPM",
formDataJson: JSON.stringify(data1)
};
this.dataSourceMap["insert"].load(param2).( {});
( {
.[].();
}, );
.(selected, rowData, selectedRows);
}
在'进行中待办'表单设置中,点击页面设置,再点击左侧'消息通知',新增完成此功能实现。

/**
* 尊敬的用户,你好:页面 JS 面板是高阶用法,一般不建议普通用户使用,如需使用,请确定你具备研发背景,能够自我排查问题。当然,你也可以咨询身边的技术顾问或者联系宜搭平台的技术支持获得服务(可能收费)。
* 我们可以用 JS 面板来开发一些定制度高功能,比如:调用阿里云接口用来做图像识别、上报用户使用数据(如加载完成打点)等等。
* 你可以点击面板上方的「使用帮助」了解。
*/
// 当页面渲染完毕后马上调用下面的函数,这个函数是在当前页面 - 设置 - 生命周期 - 页面加载完成时中被关联的。
export function didMount() {
console.log(`「页面 JS」:当前页面地址 ${location.href}`);
// console.log(`「页面 JS」:当前页面 id 参数为 ${this.state.urlParams.id}`);
// 更多 this 相关 API 请参考:https://aliwork.com/developer/API
// document.title = window.loginUser.userName + ' | 宜搭';
}
// 点击进行中待办分页、搜索时触发
export function onFetchTodoData(params) {
if (params.from === 'search') {
params.currentPage = 1;
}
this.setState({ "searchKey": params.searchKey, "page": params.currentPage });
}
export function onActionBarItemClick() {
this.setState({ flag:'insert' });
// 打开弹窗,重置表单字段
this.$('dialog_me9xwn20').show(() => {
this.$('textField_me9xwn22').reset();
this.$('radioField_me9xwn23').();
.$().();
.$().();
.$().();
.$().();
});
}
() {
createFieldList = [
,
,
,
];
data1 = {
: .$().(),
: .$().(),
: .$().(),
: .$().(),
: .$().()
};
param = {
: ,
: ,
: .(data1)
};
.(createFieldList).( {
( {
(errorList. > ) {
;
};
(.. === ){
.[].(param).( {
..({ : , : , : });
});
.$().();
( {
.[].();
}, );
} {
param2 = {
: .$().(),
: .(data1)
};
.[].(param2).( {
..({ : , : , : });
.$().();
( {
.[].();
}, );
});
}
}, );
});
}
() {
result = [];
( i = ; i < fieldList.; i++) {
.$(fieldList[i]).( {
(!errors) {
;
};
result.({
: fieldList[i],
: ..() ? errors.[fieldList[i]]. : errors[fieldList[i]].
});
});
};
result;
}
() {
.$().( {
.$().(rowData.);
});
}
() {
param = {
: .$().(),
};
.[].(param).( {
..({ : , : , : });
.$().();
( {
.[].();
.[].();
}, );
});
}
() {
.({ : });
.$().( {
.$().(rowData.);
.$().(rowData.);
.$().(rowData.);
.$().(rowData.);
.$().(rowData.);
.$().(rowData.);
});
}
() {
param1 = { : rowData. };
.[].(param1).( {
( {
.[].();
}, );
});
data1 = {
: rowData.,
: rowData.,
: rowData.,
: rowData.,
: rowData.
};
param2 = {
: ,
: ,
: .(data1)
};
.[].(param2).( {});
( {
.[].();
}, );
}
() {
(params. === ) {
params. = ;
}
.({ : params., : params. });
}

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online