公式计算属性
1 简介
公式计算属性是ONES针对工作项的属性类型,由用户自定义公式,可以用于进度汇算,资源投入汇算,数据统计等多种业务场景,帮助用户在度量和报表之外,多了一种便捷查看指标的能力。
2 功能入口
方法1: 配置中心--工作项属性--新建工作项属性--属性类型选择公式计算 创建后的字段根据需要,添加到相应的工作项中

方法2:直接在某个工作项的详情表单页进行新建属性。


工作项属性字段的添加需要有权限的管理员可前往配置中心进行配置或直接在具体工作项的详情表单进行创建。
3 什么是公式计算属性

图1 一个公式计算属性是如何构成的
通过上图我们可以看出构成一个公式属性的三要素:1)作为计算结果的“公式计算属性” 2)参与构成公式的各个属性字段 3)构成公式的运算符和函数
- 参与构成公式的各个属性字段:
- 公式中仅支持以下数据类型的属性直接参与计算:“整数”,“浮点数”,“日期”,“时间”,“时间间隔”。
- “文本”“成员”等其他类型字段虽无法直接参与计算,但可以在filter函数中作为筛选条件,或者通过部分转换函数,如duration()转化成可直接参与计算的格式。
- 项目属性无法参与计算
- 构成公式的运算符和函数:
- 运算符:
- 基础算术运算符:加+,减-,乘*,除/
- 关系运算符:等于==,不等于!=,大于>,大于等于>=,小于<,小于等于<= 等等
- 运算符及其详细说明见附录1
- 函数:一个函数由函数名,入参,入参条件三部分组成。
- 运算符:
其大致结构如下:
- 函数名(入参1,入参2,...入参n ;入参1的筛选条件,...入参n的筛选条件)
- 根据特定的封装函数决定其能否接受多个入参,
- 入参与入参间用逗号,隔开。
- 配置公式计算时不建议3层以上的多层嵌套。例如:sum(map(filter()))
- 预封装函数及详细说明见附录1
- 作为计算结果的“公式计算属性”:
- 根据参与公式的属性字段类型,和函数的输出结果决定了最后计算结果的类型。目前分为日期,时间,时间间隔,浮点数字,整形数字。
- 计算属性字段的值可以被用来筛选(筛选的行为根据计算属性的结果来定,例如计算结果为“数字”,则其支持的筛选能力和“数字”类型的字段一致)
- 计算属性字段的值的变化会纳入报表的统计指标中
- 公式计算属性的结果类型一经确定将无法被修改。二次编辑公式时,若预期结果与公式原有结果类型不符将无法完成公式修改

4 配置公式计算属性
创建计算属性字段
管理员千万配置中心,选择工作项属性后,点击新建工作项属性,在属性类型中选择公式计算后

点击配置公式后,在弹出的公式编辑器中,进行公式的编辑

公式编辑器分为左右两大部分,左侧为公式编辑区域,用来输入公式必要元素。右侧为结果配置区,根据左侧配置公式,系统自动识别计算结果类型,配置人员再进行选择。

- 公式编辑区:
- 跟随用户输入,辅助弹窗即时显示推荐的函数,属性推荐列表。通过键盘上下键可以切换相应函数的帮助提示。
- 输入时虽不区分大小写,但需用户在即时匹配的列表中选中确定的计算元素。
- 计算结果配置区:
- 根据左侧用户配置的公式,进行自动匹配。若显示“暂无可选类型”,则证明左侧计算公式配置的有问题,请检查各函数输出的结果类型,以及直接参与计算的各属性类型是否可以正确计算。
- 字段一经创建成功后,计算结果类型就将固定。公式计算属性的结果类型一经确定将无法被修改。二次编辑公式时,若预期结果与公式原有结果类型不符将无法完成公式修改,需要变更结果类型的话需要重新创建一个公式计算字段

添加公式计算属性至工作项
若是在配置中心创建的字段,需要先将字段添加到具体的某类工作项下后,再添加至相应的详情表单生效。

若是在某类工作项的详情表单配置页下创建,则可以直接拖至详情表单页面生效即可

5 场景案例
场景1 :作为产品经理,我想要知道我一个需求有多少个客户反馈过:
目前的现状是:需要手动维护,每关联一个需要手动+1

使用公式计算属性后,自动统计关联工作项个数

首先我们创建一个字段:

进行公示编辑:
因为要统计数量,因此使用onesCount函数,如果筛选关联的工作项类型,可以继续嵌套filter函数。

配置完成后,将字段应用到“需求”工作项类型中:

查看计算结果:正确的被算出来

更复杂点的场景,比如我要统计负责人为某个人的关联的具体类型的工作项数量:

创建公式,使用filter函数进行过滤,过滤的条件为,关联的工作项类型是任务,并且负责人是claire。 点函数的使用是代表工作项类型和负责人都是“关联”的工作项的属性,而非计算属性应用的工作项属性


被正确的统计出来。
再把场景拓展下,比如我要统计需求关联的缺陷的修复率(定义某种工作项的修复率=已完成的工作项/改类工作项总数)

使用onesCount函数配合filter函数进行工作项筛选后的统计,然后配合除法符号,来实现修复率的计算


场景2 需求规划时的成本计算(计划完成日期-计划开始日期)*成本

通过两个日期做减法求出时间间隔后再转化成代表小时的数字。
除以24后转换为“天”。
然后用总时长乘以定义好的成本即可求出总的成本。

成本被计算出来了。
我们再复杂一点:需求的成本=关联的任务的全部已登记工时的总和*成本

首先我们要将关联的任务的已登记工时求和(sum函数不支持时间求和,因此要先用另一个计算属性,把时长转换为数字)。
我们定义8小时为一人天,不足8小时也记录为一人天,使用向上取整函数ceil来实现。
最后将计算出的总人天乘以成本即可算出。

关联任务的总工时的人力成本就计算出来了
附录1:公式计算属性 运算符及函数说明
解释说明
| 元素类型 | 元素 | 解释说明 | 详细说明 |
|---|---|---|---|
| 运算符 | + | 加 | 用于求和:支持数字类型+数字类型,返回数字类型。示例:1 + 2 -> 3。支持时间类型+时长类型,返回时间类型,示例:2025-01-01 00:00:00 + 01:00:00 -> 2025-01-01 01:00:00。支持日期类型+时长类型,返回时间类型,示例:2025-01-01 + 01:00:00 -> 2025-01-01 01:00:00(系统此时会默认日期类型的时间为当日的0点0分0秒)。备注:示例中的参数仅代表参与计算的实际属性值,而非用户在编辑器中手动输入的值。 |
| - | 减 | 用于相减:支持数字类型-数字类型,返回数字类型。示例:6 - 5 -> 1。支持时间类型-时间类型,返回时长类型。示例:2025-01-01 01:00:00 - 2025-01-01 00:00:00 -> 01:00:00。支持时间类型-时长类型,返回时间类型。示例:2025-01-01 01:00:00 - 01:00:00 -> 2025-01-01 00:00:00。支持日期类型-日期类型,返回时长类型。示例:2025-01-02 - 2025-01-01 -> 1day 00:00:00。支持日期类型-时间间隔类型,返回时间类型。示例:2025-01-02 - 01:00:00 -> 2025-01-02 22:59:59(系统此时会默认日期类型的时间为当日的23点59分59秒)。备注:示例中的参数仅代表参与计算的实际属性值,而非用户在编辑器中手动输入的值。 | |
| * | 乘 | 用于相乘:支持数字类型数字类型,返回数字类型。示例:23 -> 6。备注:示例中的参数仅代表参与计算的实际属性值,而非用户在编辑器中手动输入的值。 | |
| / | 除 | 用于相除:支持数字类型/数字类型,返回数字类型。示例:6/3 -> 2。备注:示例中的参数仅代表参与计算的实际属性值,而非用户在编辑器中手动输入的值。 | |
| < | 小于 | 在条件表达式中,用于比较大小,例如 截止日期 < date(“2025-1-1”)会找到「截止日期」早于2025年1月1日的工作项。 | |
| <= | 小于等于 | 在条件表达式中,用于比较大小,例如 截止日期 <= date(“2025-1-1”)会找到「截止日期」早于或等于2025年1月1日的工作项。 | |
| > | 大于 | 在条件表达式中,用于比较大小,例如 截止日期 >= date(“2025-1-1”)会找到「截止日期」晚于2025年1月1日的工作项。 | |
| >= | 大于等于 | 在条件表达式中,用于比较大小,例如 截止日期 >= date(“2025-1-1”)会找到「截止日期」晚于或等于2025年1月1日的工作项。 | |
| == | 等于 | 在条件表达式中,用于精确匹配某个值,例如 filter(需求关联任务, .优先级==“高”) 会找到所有「优先级」为「高」的“需求关联任务”工作项。 | |
| != | 不等于 | 在条件表达式中,用于排除某个值,例如 filter(需求关联任务, .优先级!=“低”) 会过滤掉所有优先级为“低”的工作项。 | |
| contains | 包含 | 在条件表达式中,用于搜索属性值属于查询集合的工作项,例如 filter(需求关联任务, .标题 contains “abc”)会找到所有「标题」包含“abc”的工作项。仅用于字符串。 | |
| not | 非 | 在条件表达式中,not后表达式为真时返回为假,为假时返回为真。例如 filter(需求关联任务, not(.优先级==“高”))会找到所有优先级不为高的工作项。not后的表达式需写在括号内。 | |
| and | 且 | 在条件表达式中,and两侧条件均为真时返回为真。例如 filter(需求关联任务, .优先级==“高” and .负责人==“张三”) 会找到同时满足两个条件的工作项。 | |
| or | 或 | 在条件表达式中,or两侧条件只要有真就返回为真。例如 filter(需求关联任务, .优先级==“高” or .负责人==“张三”) 会找到至少满足一个条件的工作项。 | |
| ( | 左括号 | 无需备注说明 | |
| ) | 右括号 | 无需备注说明 | |
| 常量 | nil | 空值 | 表示空值,用于filter及map条件中搜索属性值为空或不为空的工作项。仅可以和==或!=一起使用。例如:onesCount(filter(需求关联的任务,.优先级==nil))。 |
| 函数 | onesCount() | 统计 | 用于获取数组中的元素个数。入参为数组,返回数字类型。允许嵌套filter和map函数。示例:需求关联的任务总数=onesCount(需求关联的任务);优先级为高的任务总数=onesCount(filter(需求关联的任务,.优先级=="高"))。 |
| sum() | 求和 | 用于将数字数组中的元素进行求和。入参为数字类型的数组,返回数字类型。允许嵌套filter和map函数。示例:sum(map(filter(需求关联任务, .优先级==“高”), .研发成本))。 | |
| mean() | 求均值 | 用于将数字数组中的元素进行求平均。入参为数字类型的数组,返回数字类型。允许嵌套filter和map函数。示例:mean(map(filter(需求关联任务, .负责人==“张三”), .研发成本))。 | |
| onesMax() | 求最大 | 用于找出数组中最大的元素。入参可以为数字/日期/时间类型数组,返回对应类型结果。允许嵌套filter和map函数。示例:onesMax(map(filter(需求关联任务, .优先级==“高”), .完成时间))。 | |
| onesMin() | 求最小 | 用于找出数组中最小的元素。入参可以为数字/日期/时间类型数组,返回对应类型结果。允许嵌套filter和map函数。示例:onesMin(map(filter(需求关联任务, .优先级==“高”), .完成时间))。 | |
| map() | 映射数组 | 将每个多选对象数组中的属性值映射为新的数组。map函数的返回值只能作为其他函数的入参,无法直接参与计算;不支持嵌套map函数。示例:sum(map(需求关联任务, .研发成本))。 | |
| filter() | 条件过滤 | 将多选对象数组根据条件进行过滤。filter(X1,X2)中入参X1是对象数组,X2是条件表达式,返回值为对象数组。示例:filter(需求关联工作项,.优先级==“高”)。 | |
| . | 查找对象数组的属性 | 用于继续查找对象的属性。多选对象用于filter或map函数,单选对象用来直接获取属性。例如 filter(需求关联任务,.优先级==“高”);单选对象可用“任务来源需求.优先级”获取属性。 | |
| round() | 四舍五入 | 仅保留数字的整数部分并对小数点之后进行四舍五入,返回整形数字。示例:round(3.14)-> 3;round(5.6)-> 6。 | |
| ceil() | 向上取整 | 仅保留数字的整数部分并向上取整,返回整形数字。示例:ceil(2.15) -> 3;ceil(-1.3) -> -1。 | |
| floor() | 向下取整 | 仅保留数字的整数部分并向下取整,返回整形数字。示例:floor(2.15) -> 2;floor(-1.3) -> -2。 | |
| date() | 文本转日期 | 将符合格式要求的文本转换为日期类型。入参必须是“YYYY-MM-DD”或“YYYY/MM/DD”格式,单月或单日前需补0。示例:date("2025-04-06") -> 2025-04-06。 | |
| duration() | 文本转时长 | 将符合格式要求的文本转换为时长类型,仅支持秒(s)、分钟(m)、小时(h)。示例:duration(“100s”);date("2025-04-06")+duration(“100s”)-> 2025-04-06 00:01:40。 | |
| .Year() | 获取日期/时间的年 | 日期字段.Year(),用来获取日期/时间字段中代表“年”的数字,返回数字类型。示例:日期字段A=2025-03-31,日期字段A.Year()-> 2025。 | |
| .Month() | 获取日期/时间的月 | 日期字段.Month(),用来获取日期/时间字段中代表“月”的数字,返回数字类型。示例:日期字段A=2025-03-31,日期字段A.Month()-> 3。 | |
| .Day() | 获取日期/时间的日 | 日期字段.Day(),用来获取日期/时间字段中代表“日”的数字,返回数字类型。示例:日期字段A=2025-03-31,日期字段A.Day()-> 31。 | |
| .Hours() | 时间间隔转换为代表小时的数字 | 时间间隔字段.Hours(),将时间间隔转化为小时的数字,返回数字类型。示例:时间间隔A=12小时30分钟,时间间隔A.Hours() -> 12.5。 | |
| [index] | 索引 | 按照索引将数组的对应元素取出,返回数组对应类型。示例:map(需求关联任务, .研发成本)[0] 会将“研发成本”数组中的第一个元素取出。 |
常见问题
1 点函数,map映射函数,及filter过滤函数的补充说明
点函数是用来获取对象的属性,在目前的ONES系统,你可以简单将关联属性,和层级属性都当作是对象属性。只不过如果是单选属性,他就是个单独对象,如果是多选属性,他就是个对象数组。比如

如果关系类型选择了一对多。那么此时父层级属性就是个单选类型的属性。 是不会出现在map和filter的首个入参的,因为它是单独对象而非对象数组 单独对象可以直接使用,例如“父工作项.优先级”来获取单独的父工作项的属性。 而对象数组必须配合map函数来获得子工作项的属性。map(子工作项, .优先级)

如果选择属性类型为单选关联工作项,是不会出现在map和filter的首个入参的,因为它是单独对象而非对象数组。 单独对象可以直接使用,例如“项目合同所属的供应商.优先级”来获取单独的父工作项的属性。 而对象数组必须配合map函数来获得子工作项的属性。map(供应商下的所有项目合同, .优先级)
2 属性的值显示暂无计算结果
- 当参与计算的参数出现空值时,会导致公式计算的结果显示为“暂无计算结果”
例如设置公式计算属性A=B/(C-D)
-
B,C,D任意为空都会导致无法计算。
-
C=D由于除数为0也将导致无法计算。
-
BCD曾经有值,但从工作项删除字段会导致无法计算
-
filter函数和map函数里为空的参数参与了“等于”之外的条件判断,会导致公式计算的结果显示为“暂无计算结果”
例如:onsCount( filter( 关联,. 优先级==“高” ))
若某一个关联工作项的优先级为设置,并不影响函数返回值。
但在此情况下:onsCount( filter( 关联,. 总金额<100 ))
如果有工作项的总金额没有填写,并且用于了“小于”运算(非“等于”预算),就会导致返回值为空。
3 工时和进度如何参与公式计算

如上图,工时在表单中显示为xx小时,进度显示为xx%。都是有单位的。
工时在公式编辑器中会被识别为“时间间隔”类型属性,需要通过.Hours()函数来将其转化为代表小时的数字。(例如显示为30小时,转化后为数字30。显示为2天,转化后为数字48)

进度在公式编辑器中会被识别为去除了百分号的“数字”类型的属性,例如,工时进度=70% 。在编辑器中会被直接识别为数字70。
4 多选类型的选项是不能出现在filter(A,B)函数中B的位置的。
编辑器因暂不支持多选对象的是否“包含”条件判断。因此B中暂无法出现“多选”类型的工作项属性字段。如“多选部门”,“所属模块”等。
5单选的关联关系是不能出现在filter(A,B)函数中A的位置的。
单选的关联关系因为不是数组结构,因此无法写入filter(A,.B)中A的位置

6 间隔时间类型的公式计算结果出现-0

如果我配置了一个公式=时间A-时间B。
因为对于计算结果的显示当前会截取到分钟,那么如果时间A比如是2025-01-01 00:00:00 时间B是2025-01-01 00:00:01。
那么真实计算结果本质是-1s。页面会显示为-0分钟。负号在此时代表时间B要比时间A更往后,A的时间从数值上更小。
6 间隔时间,停留时间,出现时间,停留次数无法参与计算
间隔时间,停留时间,出现时间,停留次数为系统原有的计算性质的工作项字段,因原有计算逻辑与新的公式计算属性的计算逻辑不同,因此这4个字段无法参与到公式计算属性的公式中。