转载

移动端计算字段及规则解析

1、计算字段

1.1 获取及处理计算字段表达式

移动端计算字段及规则解析

field        //字段对象
expression   //计算字段表达式
childrenCode //字段code
functions    //API函数要用到的url及参数

移动端计算字段及规则解析

遍历所有字段时找出type为 calculation 的就是计算字段,调用 resolveCalculation 统一处理所有计算字段,并将结果存储在名叫 sub_calculation 的集合内;

sub_calculation数据格式如下:

[{
    "code":"js1", //计算字段code
    "childrenCode":"zb_cod", // 子表code
    "dependenceFields":["num2","zb_cod.num"], //计算表达式中涉及到的字段,这些字段值变化时将触发计算字段计算
    "execFn":execFn(data) //计算函数,传入当前行数据键值集合,返回计算结果
}]

1.2 计算字段表达式解析

表达式解析基本都在web/mobile/src/utils/parser.js这个文件中完成

第一步:调用 parse 方法开始解析表达式,使用 getFields 方法获取到表达式中参与计算的所有字段,然后用 replaceFields 方法将表达式中字段code替换成value值。如SUN([main.num1],[main.num2])转换后为SUM(1,2);

移动端计算字段及规则解析

第二步:拆分表达式,使用正则按照运算优先级依次解析函数,直到匹配不到函数,如下:

'1 - SUM(ROUND(1,2)) + CNMoney(ROUND(2,2))'.match(/(CNMoney/(|MIN/(|MAX/(|APIEVAL/(|ROUND/(|SUM/()[^/(/)]+/)/g)

["ROUND(1,2)", "ROUND(2,2)"]

然后算出函数值并进行值替换,替换后结果为:

'1 - SUM(1.00)) + CNMoney(2.00)'

最终结果为:

'1 - 1.00 + 贰元整'

第三步:四则运算

此时表达式就只剩四则运算了,将表达式转化成逆波兰表达式所需要的格式:

["1", "-", "1", ".", "0", "0", "+", "贰", "元", "整"]

根据四则运算优先级转换后的表达式为:

[1, 1, "-", "贰元整", "+"]

根据逆波兰表达式此算式运算过程如下:

从左往右依次取值,如果不是运算符则push到 stack 中存起来,遇到运算符取出 stack 中的值进行运算,运算结果插入表达式中

1       stack-->[1]             [1, "-", "贰元整", "+"]
1       stack-->[1,1]           ["-", "贰元整", "+"]
-       stack-->[]              ["0", "贰元整", "+"]
0       stack-->[0]             ["贰元整", "+"]
贰元整  stack-->[0,"贰元整"]    ["+"]
+       stack-->[]              ["0贰元整"]

当已经找不到运算符时,表达式如果是正确的,最终,栈⾥里里还有⼀一个元素,且正是表达式的计算结果
最后结果就是: "0贰元整"

1.3 触发计算字段计算

每个表单控件都设置了一个叫 dataChange 的监听事件,字段值一旦发生改变便会触发 dataChange 事件,该函数会返回触发事件的字段对象及修改后的value;

然后在 dataChange 函数内调用 setCalculationValue 方法获取计算字段值。 移动端计算字段及规则解析

setCalculationValue 方法内遍历刚刚处理好计算字段数据的sub_calculation集合,找出当前修改值的字段是否有被其他计算字段引用,如果有那么就执行execFn方法获取计算字段值。

this.sub_calculation.forEach(calculation => {
  if (calculation.dependenceFields.includes(fieldCode) && calculation.childrenCode == this.code) {
  let value = calculation.execFn(fieldsObj);
})

2、规则解析

2.1 获取规则表达式

遍历所有字段时找出设置有规则(rules)的字段,调用 resolveFieldRule 方法分别处理显示隐藏(hidden)、必填(required)、样式(style);

移动端计算字段及规则解析

resolveFieldRule 方法跟计算字段的 resolveCalculation 方法类似,它也会统一处理字段规则,最后将所有字段规则存储在一个叫 fRules 的集合中;

fRules 最终的数据格式如下:

[{
    "code":"rule1", //设置了规则字段code
    "group":"ruel_cod", // 设置规则的字段所在的表code
    "field",//当前字段数据对象
    "target": {
                rules: [], //规则集合
                symbol: "AND" //筛选逻辑
              },
    "type": 'is_show',// 规则类型(is_show:显示隐藏、required:必填、style:样式)
    "styleRule" :{color:red},//样式规则样式内容
    "dependenceFields":["num2","zb_cod.num"], //规则表达式中涉及到的字段,这些字段值变化时将规则解析
    "execFn":execFn(data) //规则解析函数,传入主表、子表数据键值集合,返回解析结果
}]

2.2 规则表达式解析

execFn 函数首先会拆分出业务对象规则和表达式规则,表达式规则解析同计算字段表达式解析,所有表达式解析计算后将结果替换至原规则表达式中,最后解析业务对象规则;

具体过程如下:

配置: 移动端计算字段及规则解析

调用 resolveFieldRule 方法后表达式解析如下:

'SUM(ROUND(1,2)) > [main.num2] AND f.equal([main.num],11)'

execFn 函数中它将被分成两部分

1、SUM(ROUND(1,2)) > [main.num2] (同计算字段表达式解析)

2、f.equal([main.num],11)

首先解析表达式1,如 main.num2 = 0 ;返回结果为 true ,然后替换原表达式为: 'true AND f.equal([main.num],11)'

在web/mobile/src/utils/converter.js这个文件夹中我们配置了一个解析大于等于小于包含不包含等等一些列的规则匹配对象;

移动端计算字段及规则解析

移动端计算字段及规则解析

然后将AND、OR转换为&&和||: 'true && f.equal([main.num],11)'

最后通过new Function的方法解析结果:

new Function('main', 'children' ,'f', return ${expression_fn.replace(/[/g, '').replace(/]/g, '')} );

main:           {num:11}
children:       {zb:[{num:0}]}
expression_fn   'true && f.equal([main.num],11)'
f               {equal:(lv,rl)=>{return lv===rv}}

函数最终解析结果为:

true && f.equal(11,11)

true && true

true

规则解析逻辑

比较逻辑

字段被删除时表达式返回false

文本:

等于 
    内容都为空或相等时返回true,其余返回false
    
不等于
    内容不相等时返回true,其余返回false

包含
   文本1包含文本2时返回true,其余返回false
   
不包含
   文本1不包含文本2时返回true,其余返回false
   
起始字符
    文本2为文本1起始字符返回true,其余返回false

为空
    文本1为空返回true,其余返回false
    
不为空
    文本1不为空返回true,其余返回false

多行文本、下拉、单选、复选、组织选择、人员选择、城市选择: 规则同文本

组织选择
    比较时取`org_id`
人员选择
    比较时取`auditor_id`
城市选择
    比较时取`CityEN`

数值、计算:

等于 
    同文本
    
不等于/大于等于/小于等于/大于/小于
    满足不等于/大于等于/小于等于/大于/小于时返回true,其余返回false

日期:

大于/大于等于
    日期1或日期2值为空时返回false,都有值且满足大于/大于等于返回true,其余返回false
    
小于/小于等于
    同大于/大于等于
    
其他规则同文本

函数计算逻辑

APIEVAL

接口返回值数据类型
    符合配置类型:  直接返回接口返回值

    不符合配置类型(或接口异常):
        配置类型为字符串则返回空字符串
        配置类型为数字则返回0
        配置类型为日期则返回空字符串

CNMoney

值异常或为空时返回零元整
值四舍五入保留两位小数

SUM

值异常或为空时返回0

ROUND

值异常或为空时按0处理

MIN/MAX

值异常或为空时返回0

+-*/

按四则运算优先级运算,遇到非数值类型时转字符串拼接
原文  https://segmentfault.com/a/1190000023016463
正文到此结束
Loading...