flow-control-expression
工作流路由控制公式解释器。
安装
yarn add @sinoform/flow-control-expression
如果在 IE 11 中使用,需要安装 Map
polyfill:
yarn add core-js
在代码中添加:
import 'core-js/es/map';
快速用法
控制公式的语法借鉴 JavaScript 表达式语法,形如:
流程发送人 in ["张三", "李四"] && 填报人 like "张%"
示例公式的语义是: 流程发送人是 张三
或者 李四
,并且填报人姓张。
在程序中,我们可以通过公式解释器计算公式的结果:
import interpreter from '@sinoform/flow-route-control-exprssion';
// 构建执行上下文。可以使用 [`@sinoform/flow-route-control-exec-context`模块](https://github.com/sinoui/sino-intellisense-form/tree/master/packages/flow-route-control-exec-context)快速构建基于表单数据的执行上下文
const testData = {
流程发送人: '张三',
填报人: '李四',
};
const execContext = {
get(name: string) {
return testData[name];
},
in(value: string, elements: string[]) {
return elements && elements.includes(value);
},
};
const expression = '流程发送人 in ["张三", "李四"] && 填报人 like "张%"';
const result = interpreter(expression, execContext);
在表单上下文中计算公式:
import interpreter from '@sinoform/flow-route-control-exprssion';
import buildExecContext from '@sinoform/flow-route-control-exec-context';
const expression = '流程发送人 in ["张三", "李四"] && 填报人 like "张%"';
const execContext = buildExecContext(formData);
const result = interpreter(expression, execContext);
控制公式语法
控制公式的语法在遵循 JavaScript 表达式语法子集的基础上扩展了关系运算符 in
和 like
。
对于下面的公式:
价格 > 10
其中价格需要通过execContext.get("价格")
的方式从执行上下文中获取到变量的值。如果获取到的价格是 11
,则公式执行结果是 true
;如果是 7
,则公式执行结果是false
。
在表单上下文中,类似“价格”这样的标识符往往表示表单字段的英文名称或者中文标题,或者表示流程信息的字段。先通过示例了解一下大致的用法,然后会列举出支持的比较关系运算符和流程信息字段。
示例
价格大于 10 元:
价格 > 10
价格在 10 到 20 元之间:
价格 >= 10 && 价格 < 20
价格在 10 到 20 元范围之外:
价格 < 10 || 价格 >= 20
支持
&&
、||
这两个逻辑运算符,也支持AND
、OR
关键字(大小写无关)。例如:
价格 < 10 OR 价格 >= 20
填报人单位是办公厅
或者人事司
:
填报人单位 in ["办公厅", "人事司"]
流程发起人是张三
:
流程发起人 in ["张三"]
流程发起人是张三
或者填报人单位是办公厅
,并且价格大于 100 元:
(流程发起人 in ["张三"] || 填报人单位 in ["办公厅"]) && 价格 > 100
通过小括号
(
、)
定义表达式之间的优先级。
流程发送人不是张三
和李四
的情况:
流程发送人 not in ["张三", "李四"]
支持使用
!
和关键字not
表示逻辑非运算。示例中是通过not
关键字表达逻辑非,等价于:!(流程发送人 in ["张三", "李四"])
上报内容包含测试
关键字:
上报内容 like "%测试%"
like
表示字符串匹配的比较关系。%
表示任意一个字符。语法与 SQL 中的 like 关键字一致。
比较关系运算符
支持以下关系运算符:
-
like
- 字符串匹配(字符串包含) -
in
- 数组包含 >
>=
<
<=
==
!=
-
is
- 严格相等 -
is not
- 严格不相等 -
is null
- 属性值为空(null、undefined)判断 -
is empty
- 字符串或者数组为空的判断 -
is not null
- 判断不为空
in
数组包含
value in [1, 2, 3]
value 可以是数字,也可以是数组:
-
value = 1
时,公式返回true
-
value = 4
时,公式返回false
-
value = [1, 7, 8]
时,公式返回true
-
value = [8, 9]
时,公式返回false
like
字符串匹配
userName like "张%"
规则如下:
"张三" like "张%" ====> TRUE
"李张三" like "张%" ====> FALSE
"李张三" like "%张%" ====> TRUE
"张三" like "张_" ====> TRUE
"张三2" like "张_" ====> FALSE
"张三2" like "张%" ====> TRUE
-
_
表示匹配一个任意字符 -
%
表示匹配零个、一个或者多个任意字符
逻辑关系运算符
支持以下关系运算符:
-
&&
、AND
-
||
、OR
-
!
、NOT
字面量
支持三种字面量。
字符串
:
"字符串值"
注意:必须使用双引号
"
表达字符串字面量。字符串不支持单引号。
数字
:
10
20.1
-10.5
.5
+0.15
数组
:
[1, "2", [3, "4"]]
内置的流程属性
- 填报人
- 填报人单位
- 填报时间
- 流程发起人
- 流程发起人单位
- 流程发送时间
它们的数据示例:
{
"填报人": "张三",
"填报人单位": ["公文处", "办公厅"],
"填报时间": "2020-02-10",
"流程发起人": "李四",
"流程发起人单位": ["公文处", "办公厅"],
"流程发送时间": "2020-02-18"
}
属性访问表达式
公式中的属性访问与 JavaScript 属性访问表达式一致的语法,但是目前不支持 ?.
和 ??
语法。
针对这样的数据:
const contextData = {
子表单: [
{
标题: '标题1',
},
{
标题: '标题2',
},
{
标题: '标题3',
},
],
};
属性访问表达式 | 输出结果 |
---|---|
子表单[0].标题 |
"标题1" |
子表单[2].标题 |
"标题3" |
子表单[10].标题 |
null |
子表单[0].不存在的属性.标题 |
null |
子表单.标题 |
['标题1', '标题2', '标题3'] |
从上面的表达式示例(最后两个表达式示例)可以看出,相对于 JavaScript 属性访问规则,有两个改进之处:
第一个:内置支持 可选链式调用 特性。比如:obj.prop1
是 null
或者 undefined
,则 obj.prop1.prop2
不会抛出异常,而是会返回 null
。相当于:
obj?.prop1?.prop2;
第二个:支持快速获取对象数组中的属性。上面的 子表单.标题
示例就是这样的情况。如果某个子项不是对象或者是对象中没有此属性,则略过,如下所示:
const contextData = {
子表单: [
{
age: 10,
},
{
标题: '标题1',
},
4,
{
标题: '标题2',
},
{
标题: '标题3',
},
],
};
则 子表单.标题
返回的数据是 ['标题1', '标题2', '标题3']
。