宜搭表单公式编写规范
触发条件
正向触发(以下场景必须使用本技能):
- 用户说"配置公式"、"计算字段"、"自动计算"、"字段联动"
- 用户说"求和"、"平均值"、"条件判断"、"IF 公式"
- 用户需要在表单字段上配置默认值公式、计算公式
- 用户需要配置字段的自定义校验规则
- 用户需要了解宜搭公式函数的用法和语法
概述
宜搭公式可以:
- 自动计算字段默认值:在数值、单行文本、日期、成员等字段上配置公式,根据其他字段自动计算出值
- 配置校验规则:在提交时校验数据是否符合规则(在表单属性的「校验」中配置)
- 识别字段公式适用范围:字段公式只处理字段默认值、计算值和自定义校验,不处理提交后跨表写入动作。
完整函数列表参见 ../../references/formula-functions.md
官方示例中心的公式类示例基本落在普通表单或流程表单 schema 中,而不是自定义页面。遇到“日期转换、流水号、登录人、主管、相隔时间、求和”等能力时,默认先配置字段公式或字段联动;只有公式无法表达、且需要跨表提交后动作时,再用提交后编排能力实现。
⚠️ 重要:公式配置方式说明
宜搭没有独立的"公式字段"组件。公式是配置在普通字段(NumberField、TextField、DateField、EmployeeField 等)的属性上的:
| 配置位置 |
说明 |
典型场景 |
| 字段的「默认值」→「公式」 |
字段打开时自动计算并填入值 |
总金额 = 单价 × 数量 |
| 字段的「校验」→「自定义校验」 |
提交时校验字段值是否合法 |
结束日期必须晚于开始日期 |
| 表单设置 → 表单事件 → 公式执行 → 添加业务关联规则 |
提交后触发跨表数据操作 |
不属于字段公式 |
公式字段的 Schema 结构
通过 openyida create-form 的 create 或 update 模式,可以直接在字段上配置公式。
字段引用格式
公式中引用其他字段时,使用 #{fieldId} 格式(不是直接写 fieldId):
# ✅ 正确:用 #{} 包裹 fieldId
ROUND(#{numberField_abc} * #{numberField_xyz}, 2)
# ❌ 错误:直接写 fieldId
ROUND(numberField_abc * numberField_xyz, 2)
字段 Schema 中的公式属性
需要同时设置以下三个属性:
| 属性 |
值 |
说明 |
valueType |
"formula" |
声明该字段值由公式计算 |
complexValue |
{"complexType":"formula","formula":"<公式字符串>"} |
公式配置对象 |
formula |
"<公式字符串>" |
与 complexValue.formula 相同的公式字符串 |
create 模式:创建带公式的字段
[
{
"type": "NumberField",
"label": "总金额",
"behavior": "READONLY",
"valueType": "formula",
"complexValue": {
"complexType": "formula",
"formula": "ROUND(#{numberField_price} * #{numberField_qty}, 2)"
},
"formula": "ROUND(#{numberField_price} * #{numberField_qty}, 2)"
}
]
update 模式:给已有字段配置公式
[
{
"action": "update",
"label": "总金额",
"changes": {
"valueType": "formula",
"complexValue": {
"complexType": "formula",
"formula": "ROUND(#{numberField_price} * #{numberField_qty}, 2)"
},
"formula": "ROUND(#{numberField_price} * #{numberField_qty}, 2)"
}
}
]
⚠️ 重要:公式中的 fieldId 必须是真实 ID
公式中引用的 fieldId(如 numberField_abc123)必须是表单中真实存在的字段 ID,不能猜测。正确工作流程:
Step 1: create 模式创建基础字段(不含公式)
↓
Step 2: openyida get-schema 获取各字段的真实 fieldId
↓
Step 3: create 或 update 模式添加/更新带公式的字段,引用真实 #{fieldId}
公式语法规则
基本规则
- 函数名必须全大写:
SUM、IF、CONCATENATE,不能写成 sum、if
- 所有符号必须是英文:括号
()、逗号 ,、引号 "",不能用中文符号
- 字符串常量用双引号:
"优秀"、"已完成"
- 支持基本算术运算符:
+(加)、-(减)、*(乘)、/(除)
- 比较运算必须用函数,不能用符号:禁止使用
>=、<=、>、<、==、!=,必须改用 GE()、LE()、GT()、LT()、EQ()、NE() 函数
- 隐藏字段需开启「始终提交」:否则隐藏字段不参与公式计算
字段引用规则
公式中引用表单字段时,使用 #{fieldId} 格式(必须用 #{} 包裹):
# 引用主表字段(用 #{} 包裹 fieldId)
#{textField_abc123}
# 引用子表(TableField)内的字段
#{tableField_xxx.numberField_yyy}
# 引用当前登录用户(无需字段 ID)
USER()
# 引用当前时间(无需字段 ID)
NOW()
TODAY()
如何获取 fieldId:使用 openyida get-schema <appType> <formUuid> 获取表单 Schema,其中每个字段的 fieldId 属性即为字段 ID。
赋值类型限制
公式结果只能赋值给同类型的组件:
| 公式/来源类型 |
可赋值的目标组件 |
| 文本函数结果 |
单行文本、多行文本 |
| 数值计算结果 |
数值、单行文本、多行文本 |
| 日期函数结果 |
日期 |
| 人员函数结果 |
成员 |
| 单选/下拉单选 |
单选、下拉单选 |
| 复选/下拉复选 |
复选、下拉复选 |
业务关联规则说明
业务关联规则、高级函数、INSERT/UPDATE/DELETE/UPSERT 不属于字段公式。本技能只处理普通字段公式、默认值公式和自定义校验公式。
函数分类速查
完整函数参数说明见 ../../references/formula-functions.md
文本函数(表单场域)
| 函数 |
用途 |
示例 |
CONCATENATE(text1, text2, ...) |
拼接多个文本 |
CONCATENATE(#{textField_firstName}, #{textField_lastName}) |
LEFT(text, n) |
取左侧 n 个字符 |
LEFT(#{textField_code}, 4) |
RIGHT(text, n) |
取右侧 n 个字符 |
RIGHT(#{textField_idCard}, 4) |
MID(text, start, n) |
取中间字符 |
MID(#{textField_code}, 3, 4) |
LEN(text) |
获取字符串长度 |
LEN(#{textField_content}) |
TRIM(text) |
去除首尾空格 |
TRIM(#{textField_name}) |
UPPER(text) |
转大写 |
UPPER(#{textField_code}) |
LOWER(text) |
转小写 |
LOWER(#{textField_email}) |
REPLACE(text, start, n, newText) |
替换指定位置字符 |
REPLACE(#{textField_phone}, 4, 4, "****") |
TEXT(value, format) |
数值格式化为文本 |
TEXT(#{numberField_amount}, "0.00") |
VALUE(text) |
文本转数字 |
VALUE(#{textField_numStr}) |
UUID() |
生成唯一字符串 |
UUID() |
RMBFORMAT(number) |
格式化为人民币 |
RMBFORMAT(#{numberField_amount}) |
SPLIT(text, delimiter) |
按分隔符分割为数组 |
SPLIT(#{textField_tags}, ",") |
ARRAYGET(array, index) |
取数组第 n 个元素 |
ARRAYGET(SPLIT(#{textField_tags}, ","), 1) |
时间函数(表单场域)
| 函数 |
用途 |
示例 |
TODAY() |
今天日期 |
TODAY() |
NOW() |
当前时间 |
NOW() |
YEAR(date) |
取年份 |
YEAR(#{dateField_birthday}) |
MONTH(date) |
取月份 |
MONTH(#{dateField_birthday}) |
DAY(date) |
取天数 |
DAY(#{dateField_birthday}) |
DAYS(date1, date2) |
两日期相差天数 |
DAYS(#{dateField_end}, #{dateField_start}) |
DATEDELTA(date, n) |
日期加减 n 天 |
DATEDELTA(#{dateField_start}, 30) |
NETWORKDAYS(start, end) |
计算工作日天数 |
NETWORKDAYS(#{dateField_start}, #{dateField_end}) |
TIMESTAMP(dateObj) |
日期对象转时间戳 |
TIMESTAMP(TODAY()) |
DATE(timestamp) |
时间戳转日期对象 |
DATE(#{numberField_ts}) |
CASCADEDATEINTERVAL(field) |
日期区间天数 |
CASCADEDATEINTERVAL(#{cascadeDateField_range}) |
逻辑函数(表单场域)
| 函数 |
用途 |
示例 |
IF(cond, trueVal, falseVal) |
条件判断 |
IF(GE(#{numberField_score}, 90), "优秀", "良好") |
AND(cond1, cond2, ...) |
多条件同时成立 |
AND(GE(#{numberField_age}, 18), LE(#{numberField_age}, 60)) |
OR(cond1, cond2, ...) |
任一条件成立 |
OR(EQ(#{radioField_status}, "完成"), EQ(#{radioField_status}, "关闭")) |
NOT(cond) |
条件取反 |
NOT(ISEMPTY(#{textField_name})) |
EQ(val1, val2) |
判断相等 |
EQ(#{radioField_type}, "A类") |
NE(val1, val2) |
判断不等 |
NE(#{radioField_status}, "已取消") |
GT(val1, val2) |
大于 |
GT(#{numberField_amount}, 10000) |
GE(val1, val2) |
大于等于 |
GE(#{numberField_score}, 60) |
LT(val1, val2) |
小于 |
LT(#{numberField_stock}, 10) |
LE(val1, val2) |
小于等于 |
LE(#{numberField_age}, 18) |
ISEMPTY(field) |
判断字段是否为空 |
ISEMPTY(#{textField_remark}) |
TIMECOMPARE(date1, date2) |
比较日期大小 |
TIMECOMPARE(#{dateField_end}, #{dateField_start}) |
数学函数(表单场域)
| 函数 |
用途 |
示例 |
SUM(n1, n2, ...) |
求和 |
SUM(#{tableField_items.numberField_amount}) |
AVERAGE(n1, n2, ...) |
平均值 |
AVERAGE(#{numberField_q1}, #{numberField_q2}, #{numberField_q3}) |
MAX(n1, n2, ...) |
最大值 |
MAX(#{numberField_a}, #{numberField_b}) |
MIN(n1, n2, ...) |
最小值 |
MIN(#{numberField_a}, #{numberField_b}) |
ROUND(n, digits) |
四舍五入 |
ROUND(#{numberField_price} * #{numberField_qty}, 2) |
INT(n) |
向下取整 |
INT(#{numberField_total} / 30) |
ABS(n) |
绝对值 |
ABS(#{numberField_diff}) |
MOD(n, divisor) |
取余 |
MOD(#{numberField_count}, 7) |
PRODUCT(n1, n2, ...) |
乘积 |
PRODUCT(#{numberField_price}, #{numberField_qty}) |
SUMPRODUCT(arr1, arr2) |
数组对应元素相乘后求和 |
SUMPRODUCT(#{tableField_items.numberField_qty}, #{tableField_items.numberField_price}) |
SQRT(n) |
平方根 |
SQRT(#{numberField_area}) |
POWER(n, p) |
乘幂 |
POWER(#{numberField_base}, 2) |
COUNT(field) |
统计数据总数 |
COUNT(#{tableField_items}) |
人员函数(表单场域)
| 函数 |
用途 |
示例 |
USER() |
当前登录人(赋值给成员字段) |
USER() |
USER(level) |
当前登录人的第 level 级主管 |
USER(1) |
GETUSERNAME() |
当前登录人昵称(赋值给文本字段) |
GETUSERNAME() |
LOGINUSERWORKNO() |
当前登录人员工 ID |
LOGINUSERWORKNO() |
DEPTNAME(userId) |
指定用户所在部门名称 |
DEPTNAME(LOGINUSERWORKNO()) |
DIRECTOR() |
当前登录人的主管名称 |
DIRECTOR() |
集合函数(表单场域)
| 函数 |
用途 |
示例 |
UNIONSET(set1, set2) |
两集合并集 |
UNIONSET(#{checkboxField_a}, #{checkboxField_b}) |
INTERSECTIONSET(set1, set2) |
两集合交集 |
INTERSECTIONSET(#{checkboxField_a}, #{checkboxField_b}) |
DIFFERENCESET(set1, set2) |
两集合差集 |
DIFFERENCESET(#{checkboxField_all}, #{checkboxField_selected}) |
EXIST(val, set) |
判断值是否在集合中 |
EXIST(#{textField_tag}, #{checkboxField_tags}) |
校验函数(表单场域)
| 函数 |
用途 |
示例 |
EXACT(text1, text2) |
严格比较字符串(区分大小写) |
EXACT(#{textField_password}, #{textField_confirm}) |
ARRAYREPEATED(array) |
判断数组是否有重复 |
ARRAYREPEATED(#{tableField_items.textField_code}) |
常见场景示例
场景 1:子表金额求和
SUM(#{tableField_items.numberField_amount})
场景 2:单价 × 数量计算总价(保留2位小数)
ROUND(#{numberField_price} * #{numberField_qty}, 2)
场景 3:子表多列乘积求和(SUMPRODUCT)
SUMPRODUCT(#{tableField_items.numberField_qty}, #{tableField_items.numberField_price})
场景 4:IF 条件判断等级
IF(GE(#{numberField_score}, 90), "A", IF(GE(#{numberField_score}, 75), "B", IF(GE(#{numberField_score}, 60), "C", "D")))
场景 5:多条件 AND 判断
IF(AND(GE(#{numberField_age}, 18), LE(#{numberField_age}, 60)), "适龄员工", "不符合条件")
场景 6:计算两个日期相差天数
DAYS(#{dateField_endDate}, #{dateField_startDate})
场景 7:在入职日期基础上加 90 天(试用期结束日)
DATEDELTA(#{dateField_joinDate}, 90)
场景 8:计算工龄(年,向下取整)
INT(DAYS(TODAY(), #{dateField_joinDate}) / 365)
场景 9:自动填充当前登录人(成员字段)
USER()
场景 10:自动填充当前登录人昵称(文本字段)
GETUSERNAME()
场景 11:自动填充当前登录人部门
DEPTNAME(LOGINUSERWORKNO())
场景 12:拼接姓名和工号
CONCATENATE(#{textField_name}, "(", #{textField_workNo}, ")")
场景 13:手机号中间4位打码
REPLACE(#{textField_phone}, 4, 4, "****")
场景 14:判断字段是否为空,为空时显示默认值
IF(ISEMPTY(#{textField_remark}), "无备注", #{textField_remark})
场景 15:生成唯一 ID
UUID()
场景 16:计算两个日期区间的工作日天数
NETWORKDAYS(#{dateField_startDate}, #{dateField_endDate})
场景 17:格式化金额为人民币大写
RMBFORMAT(#{numberField_amount})
场景 18:按逗号分割标签字符串,取第一个标签
ARRAYGET(SPLIT(#{textField_tags}, ","), 1)
注意事项
⚠️ 循环依赖
公式中不能引用当前正在配置公式的字段本身,否则会报「表单中的公式存在循环依赖」错误。
错误示例:在 numberField_total 的公式中引用 numberField_total 自身。
⚠️ 隐藏字段参与计算
隐藏字段(behavior: "HIDDEN")默认不参与公式计算。若需要隐藏字段参与计算,必须在字段配置中开启「始终提交」选项。
⚠️ 日期字段不建议作为判断条件
日期字段的底层值是时间戳,直接用时间戳做判断条件不准确。推荐做法:
- 用一个单行文本字段通过公式接收日期值
- 用该单行文本字段作为判断条件
⚠️ 业务关联规则单独处理
INSERT/UPDATE/DELETE/UPSERT 属于表单事件里的业务关联规则高级函数,不属于普通字段公式。遇到这类需求时切换到 yida-business-rule。
异常处理
| 异常场景 |
处理方式 |
| 公式报"函数不存在" |
只能使用 formula-functions.md 中列出的函数,检查函数名拼写和大小写 |
| 公式报"循环依赖" |
公式中不能引用当前字段本身,检查是否存在循环引用 |
| 字段值未自动计算 |
确认字段已设置 valueType: "formula",隐藏字段需开启「始终提交」 |
| 比较运算符报错 |
禁止使用 >=、<= 等符号,必须改用 GE()、LE() 等函数 |
| 误把高级函数写到字段公式里 |
切换到 yida-business-rule,在表单事件的业务关联规则中配置 |
| 字段 ID 引用错误 |
先用 openyida get-schema 获取真实 fieldId,公式中用 #{fieldId} 格式引用 |
Memory 策略
本技能不读写 memory。公式配置通过 openyida create-form 命令写入宜搭平台,fieldId 等技术信息写入 .cache/ 临时文件,不依赖跨会话的 memory 状态。
1---2name: yida-formula3description: 宜搭表单公式编写规范,包含 60+ 内置函数速查、语法规则和常见场景示例。适用于编写表单字段公式、校验规则和计算逻辑时。4---56# 宜搭表单公式编写规范78## 触发条件910**正向触发**(以下场景必须使用本技能):11- 用户说"配置公式"、"计算字段"、"自动计算"、"字段联动"12- 用户说"求和"、"平均值"、"条件判断"、"IF 公式"13- 用户需要在表单字段上配置默认值公式、计算公式14- 用户需要配置字段的自定义校验规则15- 用户需要了解宜搭公式函数的用法和语法1617## 概述1819宜搭公式可以:201. **自动计算字段默认值**:在数值、单行文本、日期、成员等字段上配置公式,根据其他字段自动计算出值212. **配置校验规则**:在提交时校验数据是否符合规则(在表单属性的「校验」中配置)223. **识别字段公式适用范围**:字段公式只处理字段默认值、计算值和自定义校验,不处理提交后跨表写入动作。2324> 完整函数列表参见 `../../references/formula-functions.md`2526官方示例中心的公式类示例基本落在普通表单或流程表单 schema 中,而不是自定义页面。遇到“日期转换、流水号、登录人、主管、相隔时间、求和”等能力时,默认先配置字段公式或字段联动;只有公式无法表达、且需要跨表提交后动作时,再用提交后编排能力实现。2728---2930## ⚠️ 重要:公式配置方式说明3132**宜搭没有独立的"公式字段"组件**。公式是配置在普通字段(`NumberField`、`TextField`、`DateField`、`EmployeeField` 等)的属性上的:3334| 配置位置 | 说明 | 典型场景 |35|---------|------|---------|36| 字段的「默认值」→「公式」 | 字段打开时自动计算并填入值 | 总金额 = 单价 × 数量 |37| 字段的「校验」→「自定义校验」 | 提交时校验字段值是否合法 | 结束日期必须晚于开始日期 |38| 表单设置 → 表单事件 → 公式执行 → 添加业务关联规则 | 提交后触发跨表数据操作 | 不属于字段公式 |3940---4142## 公式字段的 Schema 结构4344通过 `openyida create-form` 的 create 或 update 模式,可以直接在字段上配置公式。4546### 字段引用格式4748公式中引用其他字段时,使用 **`#{fieldId}`** 格式(不是直接写 fieldId):4950```51# ✅ 正确:用 #{} 包裹 fieldId52ROUND(#{numberField_abc} * #{numberField_xyz}, 2)5354# ❌ 错误:直接写 fieldId55ROUND(numberField_abc * numberField_xyz, 2)56```5758### 字段 Schema 中的公式属性5960需要同时设置以下三个属性:6162| 属性 | 值 | 说明 |63|------|-----|------|64| `valueType` | `"formula"` | 声明该字段值由公式计算 |65| `complexValue` | `{"complexType":"formula","formula":"<公式字符串>"}` | 公式配置对象 |66| `formula` | `"<公式字符串>"` | 与 complexValue.formula 相同的公式字符串 |6768### create 模式:创建带公式的字段6970```json71[72 {73 "type": "NumberField",74 "label": "总金额",75 "behavior": "READONLY",76 "valueType": "formula",77 "complexValue": {78 "complexType": "formula",79 "formula": "ROUND(#{numberField_price} * #{numberField_qty}, 2)"80 },81 "formula": "ROUND(#{numberField_price} * #{numberField_qty}, 2)"82 }83]84```8586### update 模式:给已有字段配置公式8788```json89[90 {91 "action": "update",92 "label": "总金额",93 "changes": {94 "valueType": "formula",95 "complexValue": {96 "complexType": "formula",97 "formula": "ROUND(#{numberField_price} * #{numberField_qty}, 2)"98 },99 "formula": "ROUND(#{numberField_price} * #{numberField_qty}, 2)"100 }101 }102]103```104105### ⚠️ 重要:公式中的 fieldId 必须是真实 ID106107公式中引用的 `fieldId`(如 `numberField_abc123`)必须是表单中真实存在的字段 ID,不能猜测。**正确工作流程**:108109```110Step 1: create 模式创建基础字段(不含公式)111 ↓112Step 2: openyida get-schema 获取各字段的真实 fieldId113 ↓114Step 3: create 或 update 模式添加/更新带公式的字段,引用真实 #{fieldId}115```116117---118119## 公式语法规则120121### 基本规则1221231. **函数名必须全大写**:`SUM`、`IF`、`CONCATENATE`,不能写成 `sum`、`if`1242. **所有符号必须是英文**:括号 `()`、逗号 `,`、引号 `""`,不能用中文符号1253. **字符串常量用双引号**:`"优秀"`、`"已完成"`1264. **支持基本算术运算符**:`+`(加)、`-`(减)、`*`(乘)、`/`(除)1275. **比较运算必须用函数,不能用符号**:禁止使用 `>=`、`<=`、`>`、`<`、`==`、`!=`,必须改用 `GE()`、`LE()`、`GT()`、`LT()`、`EQ()`、`NE()` 函数1286. **隐藏字段需开启「始终提交」**:否则隐藏字段不参与公式计算129130### 字段引用规则131132公式中引用表单字段时,使用 **`#{fieldId}`** 格式(必须用 `#{}` 包裹):133134```135# 引用主表字段(用 #{} 包裹 fieldId)136#{textField_abc123}137138# 引用子表(TableField)内的字段139#{tableField_xxx.numberField_yyy}140141# 引用当前登录用户(无需字段 ID)142USER()143144# 引用当前时间(无需字段 ID)145NOW()146TODAY()147```148149> **如何获取 fieldId**:使用 `openyida get-schema <appType> <formUuid>` 获取表单 Schema,其中每个字段的 `fieldId` 属性即为字段 ID。150151### 赋值类型限制152153公式结果只能赋值给**同类型**的组件:154155| 公式/来源类型 | 可赋值的目标组件 |156|-------------|----------------|157| 文本函数结果 | 单行文本、多行文本 |158| 数值计算结果 | 数值、单行文本、多行文本 |159| 日期函数结果 | 日期 |160| 人员函数结果 | 成员 |161| 单选/下拉单选 | 单选、下拉单选 |162| 复选/下拉复选 | 复选、下拉复选 |163164---165166## 业务关联规则说明167168业务关联规则、高级函数、`INSERT`/`UPDATE`/`DELETE`/`UPSERT` 不属于字段公式。本技能只处理普通字段公式、默认值公式和自定义校验公式。169170---171172## 函数分类速查173174> 完整函数参数说明见 `../../references/formula-functions.md`175176### 文本函数(表单场域)177178| 函数 | 用途 | 示例 |179|------|------|------|180| `CONCATENATE(text1, text2, ...)` | 拼接多个文本 | `CONCATENATE(#{textField_firstName}, #{textField_lastName})` |181| `LEFT(text, n)` | 取左侧 n 个字符 | `LEFT(#{textField_code}, 4)` |182| `RIGHT(text, n)` | 取右侧 n 个字符 | `RIGHT(#{textField_idCard}, 4)` |183| `MID(text, start, n)` | 取中间字符 | `MID(#{textField_code}, 3, 4)` |184| `LEN(text)` | 获取字符串长度 | `LEN(#{textField_content})` |185| `TRIM(text)` | 去除首尾空格 | `TRIM(#{textField_name})` |186| `UPPER(text)` | 转大写 | `UPPER(#{textField_code})` |187| `LOWER(text)` | 转小写 | `LOWER(#{textField_email})` |188| `REPLACE(text, start, n, newText)` | 替换指定位置字符 | `REPLACE(#{textField_phone}, 4, 4, "****")` |189| `TEXT(value, format)` | 数值格式化为文本 | `TEXT(#{numberField_amount}, "0.00")` |190| `VALUE(text)` | 文本转数字 | `VALUE(#{textField_numStr})` |191| `UUID()` | 生成唯一字符串 | `UUID()` |192| `RMBFORMAT(number)` | 格式化为人民币 | `RMBFORMAT(#{numberField_amount})` |193| `SPLIT(text, delimiter)` | 按分隔符分割为数组 | `SPLIT(#{textField_tags}, ",")` |194| `ARRAYGET(array, index)` | 取数组第 n 个元素 | `ARRAYGET(SPLIT(#{textField_tags}, ","), 1)` |195196### 时间函数(表单场域)197198| 函数 | 用途 | 示例 |199|------|------|------|200| `TODAY()` | 今天日期 | `TODAY()` |201| `NOW()` | 当前时间 | `NOW()` |202| `YEAR(date)` | 取年份 | `YEAR(#{dateField_birthday})` |203| `MONTH(date)` | 取月份 | `MONTH(#{dateField_birthday})` |204| `DAY(date)` | 取天数 | `DAY(#{dateField_birthday})` |205| `DAYS(date1, date2)` | 两日期相差天数 | `DAYS(#{dateField_end}, #{dateField_start})` |206| `DATEDELTA(date, n)` | 日期加减 n 天 | `DATEDELTA(#{dateField_start}, 30)` |207| `NETWORKDAYS(start, end)` | 计算工作日天数 | `NETWORKDAYS(#{dateField_start}, #{dateField_end})` |208| `TIMESTAMP(dateObj)` | 日期对象转时间戳 | `TIMESTAMP(TODAY())` |209| `DATE(timestamp)` | 时间戳转日期对象 | `DATE(#{numberField_ts})` |210| `CASCADEDATEINTERVAL(field)` | 日期区间天数 | `CASCADEDATEINTERVAL(#{cascadeDateField_range})` |211212### 逻辑函数(表单场域)213214| 函数 | 用途 | 示例 |215|------|------|------|216| `IF(cond, trueVal, falseVal)` | 条件判断 | `IF(GE(#{numberField_score}, 90), "优秀", "良好")` |217| `AND(cond1, cond2, ...)` | 多条件同时成立 | `AND(GE(#{numberField_age}, 18), LE(#{numberField_age}, 60))` |218| `OR(cond1, cond2, ...)` | 任一条件成立 | `OR(EQ(#{radioField_status}, "完成"), EQ(#{radioField_status}, "关闭"))` |219| `NOT(cond)` | 条件取反 | `NOT(ISEMPTY(#{textField_name}))` |220| `EQ(val1, val2)` | 判断相等 | `EQ(#{radioField_type}, "A类")` |221| `NE(val1, val2)` | 判断不等 | `NE(#{radioField_status}, "已取消")` |222| `GT(val1, val2)` | 大于 | `GT(#{numberField_amount}, 10000)` |223| `GE(val1, val2)` | 大于等于 | `GE(#{numberField_score}, 60)` |224| `LT(val1, val2)` | 小于 | `LT(#{numberField_stock}, 10)` |225| `LE(val1, val2)` | 小于等于 | `LE(#{numberField_age}, 18)` |226| `ISEMPTY(field)` | 判断字段是否为空 | `ISEMPTY(#{textField_remark})` |227| `TIMECOMPARE(date1, date2)` | 比较日期大小 | `TIMECOMPARE(#{dateField_end}, #{dateField_start})` |228229### 数学函数(表单场域)230231| 函数 | 用途 | 示例 |232|------|------|------|233| `SUM(n1, n2, ...)` | 求和 | `SUM(#{tableField_items.numberField_amount})` |234| `AVERAGE(n1, n2, ...)` | 平均值 | `AVERAGE(#{numberField_q1}, #{numberField_q2}, #{numberField_q3})` |235| `MAX(n1, n2, ...)` | 最大值 | `MAX(#{numberField_a}, #{numberField_b})` |236| `MIN(n1, n2, ...)` | 最小值 | `MIN(#{numberField_a}, #{numberField_b})` |237| `ROUND(n, digits)` | 四舍五入 | `ROUND(#{numberField_price} * #{numberField_qty}, 2)` |238| `INT(n)` | 向下取整 | `INT(#{numberField_total} / 30)` |239| `ABS(n)` | 绝对值 | `ABS(#{numberField_diff})` |240| `MOD(n, divisor)` | 取余 | `MOD(#{numberField_count}, 7)` |241| `PRODUCT(n1, n2, ...)` | 乘积 | `PRODUCT(#{numberField_price}, #{numberField_qty})` |242| `SUMPRODUCT(arr1, arr2)` | 数组对应元素相乘后求和 | `SUMPRODUCT(#{tableField_items.numberField_qty}, #{tableField_items.numberField_price})` |243| `SQRT(n)` | 平方根 | `SQRT(#{numberField_area})` |244| `POWER(n, p)` | 乘幂 | `POWER(#{numberField_base}, 2)` |245| `COUNT(field)` | 统计数据总数 | `COUNT(#{tableField_items})` |246247### 人员函数(表单场域)248249| 函数 | 用途 | 示例 |250|------|------|------|251| `USER()` | 当前登录人(赋值给成员字段) | `USER()` |252| `USER(level)` | 当前登录人的第 level 级主管 | `USER(1)` |253| `GETUSERNAME()` | 当前登录人昵称(赋值给文本字段) | `GETUSERNAME()` |254| `LOGINUSERWORKNO()` | 当前登录人员工 ID | `LOGINUSERWORKNO()` |255| `DEPTNAME(userId)` | 指定用户所在部门名称 | `DEPTNAME(LOGINUSERWORKNO())` |256| `DIRECTOR()` | 当前登录人的主管名称 | `DIRECTOR()` |257258### 集合函数(表单场域)259260| 函数 | 用途 | 示例 |261|------|------|------|262| `UNIONSET(set1, set2)` | 两集合并集 | `UNIONSET(#{checkboxField_a}, #{checkboxField_b})` |263| `INTERSECTIONSET(set1, set2)` | 两集合交集 | `INTERSECTIONSET(#{checkboxField_a}, #{checkboxField_b})` |264| `DIFFERENCESET(set1, set2)` | 两集合差集 | `DIFFERENCESET(#{checkboxField_all}, #{checkboxField_selected})` |265| `EXIST(val, set)` | 判断值是否在集合中 | `EXIST(#{textField_tag}, #{checkboxField_tags})` |266267### 校验函数(表单场域)268269| 函数 | 用途 | 示例 |270|------|------|------|271| `EXACT(text1, text2)` | 严格比较字符串(区分大小写) | `EXACT(#{textField_password}, #{textField_confirm})` |272| `ARRAYREPEATED(array)` | 判断数组是否有重复 | `ARRAYREPEATED(#{tableField_items.textField_code})` |273274---275276## 常见场景示例277278### 场景 1:子表金额求和279280```281SUM(#{tableField_items.numberField_amount})282```283284### 场景 2:单价 × 数量计算总价(保留2位小数)285286```287ROUND(#{numberField_price} * #{numberField_qty}, 2)288```289290### 场景 3:子表多列乘积求和(SUMPRODUCT)291292```293SUMPRODUCT(#{tableField_items.numberField_qty}, #{tableField_items.numberField_price})294```295296### 场景 4:IF 条件判断等级297298```299IF(GE(#{numberField_score}, 90), "A", IF(GE(#{numberField_score}, 75), "B", IF(GE(#{numberField_score}, 60), "C", "D")))300```301302### 场景 5:多条件 AND 判断303304```305IF(AND(GE(#{numberField_age}, 18), LE(#{numberField_age}, 60)), "适龄员工", "不符合条件")306```307308### 场景 6:计算两个日期相差天数309310```311DAYS(#{dateField_endDate}, #{dateField_startDate})312```313314### 场景 7:在入职日期基础上加 90 天(试用期结束日)315316```317DATEDELTA(#{dateField_joinDate}, 90)318```319320### 场景 8:计算工龄(年,向下取整)321322```323INT(DAYS(TODAY(), #{dateField_joinDate}) / 365)324```325326### 场景 9:自动填充当前登录人(成员字段)327328```329USER()330```331332### 场景 10:自动填充当前登录人昵称(文本字段)333334```335GETUSERNAME()336```337338### 场景 11:自动填充当前登录人部门339340```341DEPTNAME(LOGINUSERWORKNO())342```343344### 场景 12:拼接姓名和工号345346```347CONCATENATE(#{textField_name}, "(", #{textField_workNo}, ")")348```349350### 场景 13:手机号中间4位打码351352```353REPLACE(#{textField_phone}, 4, 4, "****")354```355356### 场景 14:判断字段是否为空,为空时显示默认值357358```359IF(ISEMPTY(#{textField_remark}), "无备注", #{textField_remark})360```361362### 场景 15:生成唯一 ID363364```365UUID()366```367368### 场景 16:计算两个日期区间的工作日天数369370```371NETWORKDAYS(#{dateField_startDate}, #{dateField_endDate})372```373374### 场景 17:格式化金额为人民币大写375376```377RMBFORMAT(#{numberField_amount})378```379380### 场景 18:按逗号分割标签字符串,取第一个标签381382```383ARRAYGET(SPLIT(#{textField_tags}, ","), 1)384```385386---387388## 注意事项389390### ⚠️ 循环依赖391392公式中不能引用当前正在配置公式的字段本身,否则会报「表单中的公式存在循环依赖」错误。393394**错误示例**:在 `numberField_total` 的公式中引用 `numberField_total` 自身。395396### ⚠️ 隐藏字段参与计算397398隐藏字段(`behavior: "HIDDEN"`)默认不参与公式计算。若需要隐藏字段参与计算,必须在字段配置中开启「始终提交」选项。399400### ⚠️ 日期字段不建议作为判断条件401402日期字段的底层值是时间戳,直接用时间戳做判断条件不准确。推荐做法:4031. 用一个单行文本字段通过公式接收日期值4042. 用该单行文本字段作为判断条件405406### ⚠️ 业务关联规则单独处理407408`INSERT`/`UPDATE`/`DELETE`/`UPSERT` 属于表单事件里的业务关联规则高级函数,不属于普通字段公式。遇到这类需求时切换到 `yida-business-rule`。409410---411412## 异常处理413414| 异常场景 | 处理方式 |415|---------|----------|416| 公式报"函数不存在" | 只能使用 `formula-functions.md` 中列出的函数,检查函数名拼写和大小写 |417| 公式报"循环依赖" | 公式中不能引用当前字段本身,检查是否存在循环引用 |418| 字段值未自动计算 | 确认字段已设置 `valueType: "formula"`,隐藏字段需开启「始终提交」 |419| 比较运算符报错 | 禁止使用 `>=`、`<=` 等符号,必须改用 `GE()`、`LE()` 等函数 |420| 误把高级函数写到字段公式里 | 切换到 `yida-business-rule`,在表单事件的业务关联规则中配置 |421| 字段 ID 引用错误 | 先用 `openyida get-schema` 获取真实 fieldId,公式中用 `#{fieldId}` 格式引用 |422423## Memory 策略424425本技能不读写 memory。公式配置通过 `openyida create-form` 命令写入宜搭平台,fieldId 等技术信息写入 `.cache/` 临时文件,不依赖跨会话的 memory 状态。