smart-power-plant文档
文章目录
一、指标公式管理
1.主公式
主公式是指由多个子公式拼接而成的公式,如:
SUM(GROUP(4#脱硫高压设备电耗[1292990924636815361]),GROUP(4#脱硫高压公用设备电耗[1292990924636815361]),GROUP(4#脱硫低压设备电耗[1292990924636815361]),GROUP(4#脱硫低压公用设备电耗[1292990924636815361]),GROUP(4#脱硫系统压降折算电耗[1292990924636815361]))
2.子公式
接口返回的公式结构为字符串,如:formula: "MUL(K(9.275),DIV(POINT(机组实际负荷[DCS1_EA01]),SUM(POINT(机组实际负荷[DCS1_EA01]),POINT(机组实际负荷[DCS2_EA01]),POINT(机组实际负荷[DCS3_EA01]),POINT(机组实际负荷[DCS4_EA01]))),SUM(POINT(A湿式球磨机B相电流[TL12_A20SQABI]),POINT(B湿式球磨机B相电流[TL12_A20SQBBI]),POINT(C湿式球磨机B相电流[TL12_A20SQCBI])))
运算符:Add、Sub、Mul、Div、Avage
常量:K
前端需要将字符串的公式转换为对象,转换逻辑跟后端 go 保持一致,具体实现代码在 /flow/expression.ts 、/flow/expression_parse.ts、flow/parseElement.ts; 这三个文件里面的代码是根据 go 语言转换而来,具体文档:go代码文档。
3.公式解析代码
expression_parse.ts
用于将字符串公式转换为 class 结构体,从ParseExpr方法开始转换,如果为子公式则直接转换,如为主公式即不包含Add、Sub、Mul、Div、Avage、K 等前缀,则调用自定义转换器,定义在parseElement.ts文件
parseElement.ts
定义了Formula、IndexElement、DevGroupFormula、DeviceElement类,主公式的解析为遍历当前主公式引用的子公式,然后从localstorage 中获取具体子公式的 formula,最近将所有子公式合并在一起得到主公式。
expression.ts
各运算符的 class 实现,每个运算符需要实现 ExprString()方法,ExprString 用于将对象转换为字符串
4.公式渲染
公式的渲染插件为 Antv G6 的TreeGraph,代码入口文件在/flow/index.ts FlowEditor组件, 首先需要将字符串的公式转换为class 结构体,再将 class 结构体数据转换为 TreeGraph 需要的数据格式(tree 格式,通过 children 一级一级连接),得到的数据通过 Flow.tsx组件渲染为树图。
Node(节点)
G6系统默认节点无法满足项目需求,因此使用自定义节点,通过registerNode进行自定义节点样式。
Edge(边 || 连接线)
如果直接渲染树图结构会是这样子的
可以发现他的 edge 都是父节点连各个子节点,但是我们是渲染公式因此需要将树图修改为尽量跟数学公式一样,子节点应该互相连接,子节点的收尾连接父节点标明下面的子节点都属于父节点
因此我们就要在 edge 渲染前进行修改,阻止默认渲染逻辑,通过 graph.current?.edge方法获取渲染前每条边,通过return 数据修改每条边的 source、target。
graph.current?.edge((e: {
source: string; target: string }) => {
// 根据业务需求重新定义连接线关系, 在同一级的元素左右相连, 并添加父元素所属的运算符, 模拟算术运算的方式进行
const sourceData = graph.current?.findById(e.source); // 根据 id 查找数据
const sourceDataChildren = sourceData?.get("model").children;
const sourceIndex = sourceHistory.current.findIndex((item) => item.source === e.source);
if (sourceIndex === -1) {
// 未遍历过此节点 新增
sourceHistory.current