地图作业平台低代码实战(搭建能力提升)

2022-10-09  本文已影响0人  Java码农

背景

1、地图数据作业平台由大型的WebGIS"综合作业"逐步转换为人机结合,所见即所得的流水化"简单作业";

图1-1 综合作业与流水化作业

2、流水化作业的特点是单一车间交互简单,但每个车间都有定制的业务逻辑(难以配置化实现,适合有扩展能力的低代码方式);

3、作业平台低代码建设过程中,即使是任何一个简单作业车间也存在数据校验,组件联动,保存结果转换等逻辑(下图标牌场景车间为例);

4、作业平台低代码的建设目标是让产品,工艺等非研发同学能独立搭建车间,因而要尽可能将逻辑操作可视化,少写或不写逻辑代码;

5、非前端研发同学并不能很好地理解一些前端的基本概念:例如事件驱动,数据不可变 immutable原则, 数据双向绑定,组件(非)受控等;

问题与分析

一个简单的联动示例

图2-1 标牌场景判定车间

涉及组件:7个

组件联动说明:初始化时第二、三个作业项置灰禁用;当前一个作业项选"否"时,激活下一个作业项;当前一个作业项选"是"时,之后的作业项清空;

问题: 对于这样一个最基础的组件间联动,低代码引擎的解决方案是WebIDE中绑定事件回调函数,在函数中通过写代码来实现逻辑。这样的方案对于前端研发来说,十几行代码很快就可以完成,但是对于非研发的同学(产品、工艺)等,他们需要理解事件驱动,数据不可变原则等,实现起来就非常困难,因此我们需要探索一个更加友好的方案:无须代码或一个表达式便可以实现以上联动功能。

示例中代码分析

// 以上示例的伪代码实现 

class Main extends PurComponents {
  constructor() {
    this.state = {
      A: '',
      B: '',
      C: '',
    }
  }

  // 响应逻辑
  handleAChange = (e) => {
    // 1.数据源筛选
    const { target: { value } } = e;
    // 2.双向绑定,组织数据结构
    let stateOptions = {
      A: value;
    };

    // 3.数据联动
    if (value === '1') {
      stateOptions = {
         ...stateOptions,
        B: '',
        C: '',
      }
    } 
    // 4.更新数据
    this.setState(stateOptions);
  };

  // UI组件
  render() {
    <div className="pic-wrapper">
      <PicPlayer ... />
    </div>
    <div className="task-oper">
      <Text>标牌是否是施工场景</Text>
      <ButtonGroup onChange={(e) => this.handleAChange(e)} />
      ...
      <ButtonGroup disabled={A !== '2'} ... />
      ...
      <ButtonGroup disabled={B !== '2'} ... />
    </div>
    ... bla bla bla
  }
}

示例中基本概念如何简化地思考

如何让非研发同学忽略前端的基本概念与语法,可视化的实现组件通信与联动,是降低可视化搭建难度的关键。为此,我们将函数主体的四个部分(数据筛选,双向绑定,业务逻辑联动,数据更新)分开来看:

图2-1 搭建页面中的数据筛器

一个"副作用"对象由三部分构成

{

  // 源数据

  fromPath: 'e.target.value', 

  // 目标数据

  toPath: 'state.B',

  // 转换逻辑

  formatFunc: 'function switchStoreValue(value, state) { return A == '1' ? '' : state.B };'

}
// saveEffect 副作用对象的简单示例

// 变更前全局数据

state = {

  temp: {

    imageIndex: 0,

  },

  workResult: {

    imageList: [

      {

        attr1: 1,

        attr2: 2,

      },

      ...

    ]

  }

}

// 用户确定的saveEffect对象

{

  // 源数据

  fromPath: 'value' // 1

  // 目标数据

  toPath: 'workResult.imageList[state.temp.imageIndex].activeKey';

  // 默认值,用户无须书写

  formatFunc: 'function switchStoreValue(value, state) { return value }';

}

// 无转换逻辑,则经过插件解析后会生成以下结构并merge到state中

{

  temp: {

    imageIndex: 0,

  },

  workResult: {

    imageList: [

      {

        attr1: 1,

        attr2: 2,

        ...

        activeKey:1

      },

      ...

    ]

  }

}

以上saveEffect对象,用户仅需指定目标值路径,插件会自动解析路径的语法,并将activeKey所有父级结构生成新的引用,最后自动调用setState实现组件更新;

图 2-2 插件将解析路径自动更新为新引用

使用效果

一个线上车间的例子

使用saveEffect设置器节省代码的前后对比,以引导线内容车间为例,我们需要为一个引导线方向赋值一个属性,UI操作如下图,选中车道,更新车道的类型

图 3-1 更新车道属性

原生低代码引擎需要在页面JS中自行实现如下代码:

function handleButtonGroupClick(value) {

  // 获取当前选中的箭头选项

  const { arrowList, currentIndex } = this.state;

  const currentArrow = arrowList[currentIndex];

  // 数据更新

  const newArrow = {

    ...currentArrow,

    type: value

  };

  // 数据不可变;

  const newArrowList = arrowList.slice(0, currentIndex).concat([newArrow]).concat(arrowList.slice(currentIndex + 1));

  // lowcode API更新数据

  this.setState({

    arrowList: newArrowList

  });

}

使用saveEffect对象结合语法解析插件,使用者仅需在目标值中填写一句即可(大部分情况下转换函数是不用修改的);

state.arrowList[state.currentIndex].type = value

对应的setter UI 如下:

procode组件如何接入saveEffect

了解saveEffect原理后,如果想将普通的ui组件接入saveEffect, 该如何改造, 改造成本是否很大?

由上图可以看到

总结与展望

这篇文章主要介绍了我们通过自定义插件,设置器,组件标准化等一些方式,降低了作业平台内组件间联动,数据处理的难度,实现了让非研发同学可以独立搭建我们小粒度车间的目标。除此之外,我们还在可视化方面开发了for循环组件if/else 等逻辑组件,意图用可视化组件的方式实现一些基本的模板语法,结合我们开发的车间模板,使得用户只需在页面内完成少量定制逻辑可以实现车间开发。

未来我们计划在低代码平台中加入逻辑编排能力,最终实现逻辑代码的图形化表达,进一步支持更为复杂的车间搭建。

上一篇 下一篇

猜你喜欢

热点阅读