当前位置: 首页 > 后端技术 > Java

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

时间:2023-04-01 23:30:14 Java

背景1.地图数据操作平台逐渐从大型WebGIS“综合操作”转变为人机一体化、所见即所得的精简“简单手术”;图1-1集成化运营和流水线化运营2、流水线化运营的特点是单个车间交互简单,但每个车间都有定制化的业务逻辑(配置和实现难度大,适用于具有可扩展性的低代码方式);3、运营平台在低代码构建过程中,即使是任何一个简单的作业车间,都有数据校验、组件联动、保存结果转换等逻辑(下图中的标志场景车间为例);4.职位平台低代码建设的目标是做产品,技术等非研发同学可以独立搭建工坊,所以需要尽可能将逻辑操作可视化,少写或不写逻辑代码;5.非前端研发同学对一些前端基础概念了解不深:比如事件驱动、数据Immutable原理、数据双向绑定、组件(un)controlled等;问题与分析一个简单的联动例子图2-1标识场景确定工作坊涉及的组件:7个组件联动说明:初始化时第二个和第三个job项灰显禁用;当上一个作业项为“否”时,激活下一个作业项;当前一个作业项为“是”时,清除后续作业项;问题:对于这样一个组件间的基本联动,低代码引擎的解决方案是在WebIDE中绑定事件回调函数,通过在函数中编写代码实现逻辑。对于前端研发来说,这样的解决方案十几行代码就可以快速完成,但是对于非研发类的同学(产品、流程等),则需要了解事件驱动、数据不可变原理等,而且实施起来非常困难。因此,我们需要探索一种更友好的解决方案:无需代码或表达式即可实现上述联动功能。例子中代码分析//上面例子的伪代码实现classMainextendsPurComponents{constructor(){this.state={A:'',B:'',C:'',}}//响应逻辑handleAChange=(e)=>{//1.数据源筛选const{target:{value}}=e;//2.双向绑定,整理数据结构letstateOptions={A:value;};//3.数据联动if(value==='1'){stateOptions={...stateOptions,B:'',C:'',}}//4.更新数据this.setState(stateOptions);};//UI组件render(){

标志是否为建筑场景this.handleAChange(e)}/>......
...blablabla}}从上面的伪代码可以看出,一个workshop的实现分为:UI+逻辑中视觉构建、UI部分和简单交互由组件内部实现,跨组件逻辑部分由事件返回回调实现,回调函数可以拆分为以下四个主要函数及相关概念:数据过滤:从函数参数中过滤出需要的数据(涉及事件驱动概念)双向绑定:受控组件由外部数据、状态驱动changes之后需要更新依赖的数据源(受控组件,双向绑定,不可变原则)数据联动:其他数据更新,组件间联动通信;(业务逻辑)数据更新:前端框架Api;例子中的基本概念如何简化思考如何让非研发同学忽略前端的基本概念和语法,可视化实现组件通信和联动是降低可视化构建难度的关键为此,我们将函数体的四部分(数据过滤、双向绑定、业务逻辑联动、数据更新)分开:针对事件驱动回调函数中的数据过滤能力,我们开发了一个数据筛选。设计页面的组件setter采用树形结构静态声明函数参数。用户只需选择相应的参数,即可实现类似数据解构赋值的功能。Linkage,immutable不可变原则,我们约定了一个简洁的数据存储语法,并针对这个语法开发了一个具体的语法分析插件,具体设计如下:页面某个组件状态变化触发其他组件联动的场景组件状态变化,我们认为这是一个组件状态变化过程的“副作用”saveEffect;每个“副作用”包含三部分,即源数据、目标数据和转换逻辑。以上面的联动为例:源数据A,目标数据B,转换逻辑当A为1时,B清零,对应的数据结构为:一个“副作用”对象,由三部分组成{//源数据fromPath:'e.target.value',//目标数据toPath:'state.B',//转换逻辑formatFunc:'functionswitchStoreValue(value,state){returnA=='1'?'':state.B};'}我们在低代码组件中提供了saveEffectsetters,允许用户选择“副作用”的源数据,确定目标值,并编写转换逻辑。这部分逻辑注入到组件中,组件在回调函数中同时抛出输出值和saveEffect对象,最后由我们的语法分析插件解析。执行并实现组件联动;对于数据更新,我们认为用户根本不需要关注框架层的API,所以我们开发了一个自动绑定setter@ali/lowcode-setter-a-event-setter会绑定回调函数组件的saveState全局函数中,数据更新操作自动在saveState全局函数中进行。以下是链接“副作用”的示例//saveEffect副作用对象的简单示例//在更改全局数据状态之前={temp:{imageIndex:0,},workResult:{imageList:[{attr1:1,属性2:2,},...]}}//saveEffect对象由用户决定{//源数据fromPath:'value'//1//目标数据toPath:'workResult.imageList[state.temp.imageIndex].activeKey';//默认值,用户不需要写formatFunc:'functionswitchStoreValue(value,state){returnvalue}';}//没有转换逻辑,插件解析后会生成如下结构合并到state{temp:{imageIndex:0,},workResult:{imageList:[{attr1:1,attr2:2,...activeKey:1},...]}}对于上面的saveEffect对象,用户只需要指定目标值路径,插件会自动解析路径语法,并为activeKey的所有父结构生成新的引用,最后自动调用setState实现组件更新;图2-2插件自动将解析的路径更新为新的引用。在线工作坊示例使用saveEffectsetter保存代码以引导线内容工作坊为例,我们需要为引导线方向分配一个属性。UI操作如下图所示。选择车道并更新车道类型。图3-1更新车道属性。自己实现如下代码:functionhandleButtonGroupClick(value){//获取当前选中的箭头选项const{arrowList,currentIndex}=this.state;constcurrentArrow=arrowList[currentIndex];//数据更新constnewArrow={...currentArrow,type:value};//数据是不可变的;constnewArrowList=arrowList.slice(0,currentIndex).conc在([newArrow]).concat(arrowList.slice(currentIndex+1));//LowcodeAPI更新数据this.setState({arrowList:newArrowList});}使用saveEffect对象结合语法分析插件,用户只需要在目标值中填入一句话即可(大多数情况下,转换函数不需要修改);state.arrowList[state.currentIndex].type=value对应的setterUI如下:procode组件如何连接到saveEffect了解了saveEffect的原理后,如果想将普通的ui组件连接到saveEffect,怎么办你修改它们,修改的成本是不是太高了?从上图可以看出,一个普通的组件是由userInterface和api驱动运行组件内部逻辑;saveEffect可以通过lowcode的setter层以api(props)的形式动态注入,然后抛在外部接口如onChange中即可,完全不影响组件内部逻辑;组件抛出value和saveEffect后,系统会自动调用我们开发的分析插件对数据进行分析保存,实现组件“副作用”之间的联动效果;本文的总结与展望主要介绍我们通过自定义插件、setter、组件标准化等方式,降低了运营平台中组件之间的联动,降低了数据处理的难度,达到了让非-R&D学生独立搭建我们的小粒度工作坊。此外,我们还在可视化方面开发了for循环组件、if/else等逻辑组件,打算以可视化组件的形式实现一些基本的模板语法,结合我们开发的工坊模板,让用户只需要完成页面中的少量定制逻辑启用车间开发。未来我们计划在低代码平台中加入逻辑编排能力,最终实现逻辑代码的图形化表达,进一步支持更复杂的车间建设。