钉钉宜搭开发助手
钉钉宜搭低代码开发助手。用于创建表单和自定义页面、编写 JS 动作面板、使用 JS-API、配置数据源、设计流程自动化。适用于宜搭表单开发、JS 代码调试、API 集成等场景。
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install clawskills:yize~yida-devcURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/clawskills%3Ayize~yida-dev/file -o yida-dev.mdGit 仓库获取源码
git clone https://github.com/openclaw/skills/commit/6129affdbc3efaf4de355faaf9d7a1cbaa452f4d## ⚠️ 重要:宜搭开发模式
**与传统前端不同,宜搭有独特的开发模式:**
1. **页面不是代码写的** - 页面通过宜搭可视化拖拽创建,不是 JSX/HTML 声明
2. **不要写组件声明代码** - ❌ 禁止 `import Button`、❌ 禁止 `const Page = () => {...}`
3. **只有 JS 动作面板** - 宜搭的 JS 代码是"动作面板",只能写函数,不能写组件
4. **组件通过 fieldId 引用** - 使用 `this.$('textField_xxx')` 操作已存在的组件
## 组件 fieldId 命名规范
宜搭组件的 fieldId 格式为:`组件类型_随机后缀`
| 组件类型 | fieldId 示例 |
|---------|-------------|
| 单行文本 | `textField_m2iqeyip` |
| 多行文本/文本域 | `textareaField_lu7rqky5` |
| 单选 | `radioField_m2l8tqxr` |
| 流水号 | `serialNumberField_lr76bpi4` |
| 数字 | `numberField_mbhl6h58` |
| 下拉选择 | `selectField_mbhjt4zb` |
| 日期 | `dateField_ll0bcdf1` |
| 附件 | `attachmentField_mbhjt4zd` |
| 图片 | `imageField_mbhjt4zl` |
| 人员选择 | `employeeField_mbhjt4zr` |
| 人员多选 | `employeeField_xxx` + `multiple: true` |
| 部门选择 | `departmentSelectField_lu7qx4i5` |
| 子表单/明细表 | `tableField_mbhjt4zy` |
| 地址 | `addressField_mbhjt508` |
| 关联表单 | `associationFormField_mbhjt50s` |
| 区块 | `pageSection_m2vthls5` |
| 按钮 | `button_invoiceAdd` |
| 发票组件 | `ccInvoiceFieldComponentView_m2vv4aux` |
| 多列布局 | `columnsLayout_m2k6t8hx` |
| 标签页 | `tabsLayout_lkcfmpjv` |
## 常见开发模式
### 条件显示
- 组件属性 → 高级 → 是否渲染 → 绑定变量 `state.sta`
- 或 JS 设置:`this.$('fieldId').setBehavior('HIDDEN')`
### 事件函数命名
- `export function onChange({ value }) { }` - 值变化事件
- `export function didMount() { }` - 页面加载完成
### setTimeout 延迟
宜搭组件 onChange 事件中修改状态需要延迟:
```js
export function onChange({ value }) {
setTimeout(() => {
this.setState({ sta: value === '价款合同' })
}, 200)
}
```
### 隐藏字段
组件属性中设置 `behavior: "HIDDEN"` 可隐藏字段(可用于数据传递)
### 只读字段
组件属性中设置 `behavior: "READONLY"` 可设为只读
### 公式字段
在组件属性中设置 `valueType: "formula"` + `formula: "#{textField_xxx}"`
```json
{
"valueType": "formula",
"formula": "CONCATENATE(\"XMBH\",TEXT(TODAY(),\"yyMMdd\"),MID(TEXT(TIMESTAMP(NOW())),9,5))"
}
```
### TableField 事件
新增行时获取行数:
```js
export function onAddClick(newGroupId) {
const count = this.$('tableField_xxx').getValue().length
this.$('textField_count').setValue(count + '条')
}
```
### TableField onChange 计算不重复值
遍历子表单行,计算某列的不重复值数量:
```js
export function onChange({ value, extra }) {
const subFormInst = this.$('tableField_xxx')
const items = subFormInst.getItems()
let distinctNum = []
items.forEach(item => {
const rowData = subFormInst.getItemValue(item)
if (rowData['textField_col'] && !distinctNum.includes(rowData['textField_col'])) {
distinctNum.push(rowData['textField_col'])
}
})
this.$('numberField_count').setValue(distinctNum.length)
}
```
### EmployeeField onChange
人员选择变化时获取人员信息:
```js
export function onChange({ value }) {
// value 是人员对象 { name, userId, ... }
this.$('textField_name').setValue(value.name)
}
```
### PageSection 区块
用于分组显示,有标题头:
```json
{
"componentName": "PageSection",
"props": {
"title": { "zh_CN": "基本信息" },
"behavior": "NORMAL", // 或 "HIDDEN" 隐藏整个区块
"showHeader": true
}
}
```
### 关联表单数据填充
选择关联表单时自动填充其他字段:
```json
{
"dataFillingRules": [
{ "sourceType": "SelectField", "targetType": "TextField", "source": "selectField_src", "target": "textField_target" }
]
}
```
### 联动字段
设置 `valueType: "linkage"` + `linkage` 属性从其他表单获取数据
### SUM 汇总公式
汇总子表单某列:
```json
{
"valueType": "formula",
"formula": "SUM(#{numberField_column})"
}
```
### RadioField 联动
单选切换时显示/隐藏字段(配置选项的联动规则)
### onBlur 事件
失焦时执行校验(如手机号验证):
```js
export function onBlur() {
let phone = this.$('textField_xxx').getValue()
if (!phone) return
if (!this.isPhoneNumber(phone)) {
this.utils.toast({ title: '请输入正确的手机号', type: 'warning' })
this.$('textField_xxx').setValue('')
}
}
export function isPhoneNumber(input) {
return /^1\d{10}$/.test(input.replace(/\D/g, ''))
}
```
### NumberField 校验
设置 minValue 最小值:
```json
{ "validation": [{ "type": "minValue", "param": "0" }] }
```
## 组件属性参考
### SelectField 下拉选择
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| dataSource | 选项数据 | DataSource[] | [] |
| onChange | 值变化事件 | (value: string) => void | - |
| showSearch | 展开后能搜索 | boolean | true |
| filterLocal | 本地过滤 | boolean | - |
| mode | single/multi | string | single |
| hasClear | 清除按钮 | boolean | true |
| autoWidth | 菜单对齐 | boolean | true |
### TableField 明细表
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| onChange | 值变化事件 | ({value, extra}) => void | - |
| onAddClick | 新增行事件 | (newGroupId) => void | - |
| onDelClick | 删除行事件 | (groupId, item) => void | - |
| maxItems | 最大条数 | number | 50 |
| addButtonPosition | 新增位置 | 'top' \| 'bottom' | bottom |
| layoutSetting.layout | 排列方式 | 'TILED' \| 'TABLE' | TABLE |
| layoutSetting.theme | 主题 | 'zebra' \| 'split' \| 'border' | split |
| showIndex | 显示序号 | boolean | true |
### TableField JS 操作
```js
const table = this.$('tableField_xxx')
table.getValue() // 获取所有行数据
table.getItems() // 获取行实例数组
table.getItemValue(item) // 获取某行数据
table.addItem() // 新增一行
table.removeItem(item) // 删除一行
```
### NumberField
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| precision | 小数位数 (0-20) | number | 0 |
| thousandsSeparators | 千分位 | boolean | false |
| innerAfter | 单位 | string | - |
| innerBefore | 前缀 | string | - |
### RadioField
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| dataSource | 选项 | DataSource[] | [] |
| onChange | 值变化 | (value) => void | - |
| shape | 形状 | 'default' \| 'button' | default |
| itemDirection | 排列 | 'hoz' \| 'ver' | hoz |
| supportInverse | 反选 | boolean | false |
### ColumnsLayout 多列布局
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| layout | 分栏配置 | string | '6:6' |
| columnGap | 列间距 | number | 0 |
| rowGap | 行间距 | number | 0 |
| display | 手机排列 | 'VERTICAL' \| 'HORIZONTAL' | VERTICAL |
布局格式: `2:2:2:2:4` (总和=12), 多行: `4:4:4\|6:6`
### Button 按钮
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| type | 按钮类型 | 'primary'\|'normal'\|'secondary' | primary |
| content | 按钮文案 | string | 按钮 |
| size | 尺寸 | 'small'\|'medium'\|'large' | medium |
| behavior | 显示状态 | 'NORMAL'\|'DISABLED'\|'HIDDEN' | NORMAL |
| loading | 加载状态 | boolean | false |
### Icon 图标
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| baseType | 基础图标 | string | smile |
| size | 尺寸 | 'xxs'\|'xs'\|'small'\|'medium'\|'large' | medium |
| useType | 使用自定义 | boolean | false |
### EmployeeField 人员选择
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| multiple | 多选 | boolean | false |
| showEmplId | 显示工号 | boolean | false |
| showAvater | 显示头像 | boolean | true |
| closeOnSelect | 选中后关闭 | boolean | false |
| onChange | 值变化 | ({value}) => void | - |
### DateField 日期选择
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| format | 日期格式 | string | YYYY-MM-DD |
| type | 限制范围 | 'none'\|'beforeToday'\|'afterToday' | none |
| hasClear | 清除按钮 | boolean | true |
| returnType | 返回类型 | 'timestamp'\|'string'\|'moment' | timestamp |
| onChange | 值变化 | ({value}) => void | - |
### TextField 单行输入
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| validationType | 格式 | 'text'\|'mobile'\|'email'\|'chineseID' | text |
| maxLength | 字数上限 | number | 200 |
| hasClear | 清除按钮 | boolean | true |
| hasLimitHint | 计数器 | boolean | false |
| trim | 去空格 | boolean | false |
| onChange | 值变化 | ({value}) => void | - |
### TextareaField 多行输入
| 属性 | 说明 | 类型 | 默认值 |
|-----|------|-----|-------|
| rows | 行数 | number | 4 |
| autoHeight | 自动高度 | boolean | false |
| maxLength | 字数上限 | number | - |
### USER() 公式
人员字段自动填充当前登录人:
```json
{ "valueType": "formula", "formula": "USER()" }
```
### 关联表单数据过滤
设置 dataFilterRules 过滤可选数据
### 页面级校验器
在页面属性 → 数据校验 中配置,检测重复数据:
```json
{
"displayRule": "EXIST(角色名称)",
"rule": "EXIST(#{formUuid}, \"textField_lenz6y7q\", #{textField_lenz6y7q})",
"message": "角色名称不能重复"
}
## 核心概念
### 全局变量 (State)
类似 React state,用于页面全局状态管理:
- 创建:在数据源面板 → 添加变量
- 读取:`this.state.name` 或 `state.name`(变量绑定时)
- 更改:`this.setState({ name: 'Jack' })`
- 特殊变量:`urlParams` - 获取 URL 参数
⚠️ 注意:setState 后可立即获取新值(不同于 React),但无回调函数
### 远程数据源
配置远程 API 进行异步请求:
```js
// 手动加载
this.dataSourceMap.apiName.load({ params }).then(res => {})
// 重新加载所有自动加载的数据源
this.reloadDataSource()
```
数据处理函