零代码新思路,基于LogicFlow的页面逻辑编排 - 滴滴技术
在滴滴客服业务里,通过零代码的方式来配置页面已有丰富的落地经验,大大提高了服务用户的效率和质量。但是传统零代码在页面逻辑配置上表现并不好,很难做到灵活扩展。因此,滴滴客服技术团队探索出一种新思路,用流程编排的方式来编排页面的逻辑,解决零代码的难扩展问题。本文将从复杂交互的难配置困境入手,介绍解决思路和方案,并详细展开如何利用客服技术团队已开源的流程图编辑框架LogicFlow,实现与研发过程中开发、运行、调试三个阶段相对应的编排器、执行器、调试器。
背景
客服业务是链接用户与公司各事业部的桥梁,为了快速响应事业部业务迭代、持续改进给到用户的服务体验,技术团队需要把客服业务中的多个系统建设成运营人员可配置,才能保障整个客服团队有很高的效率。
那么,要达成运营人员可配,零代码平台的拖拉拽式交互非常适用。运营所见即所得,客服业务中也有非常多的可落地场景,现在有多个系统已经做到可以让运营团队通过发布配置即可改变线上逻辑,给用户提供更便捷的智能客服,或者让人工客服按照运营人员制定的流程来解决、记录用户问题。
目前,滴滴客服内的多个系统在4年内已经配置超过12900个PC端页面和7900个H5页面,在整个服务链路中,通过多种方式,来解决用户的问题。
困境:零代码的不足
虽然滴滴客服内部的平台目前已经利用零代码配置了很多的页面,但随着业务的发展,我们感受到零代码的不足。假设有个表格修改操作需求,需要在点击表格某一列的修改时,先请求接口判断用户的权限,然后根据返回的权限,显示不同的编辑弹窗。如下表格修改示意图:
面对这种情况,如果使用以前的零代码方案,需要在表格组件的属性面板中增加请求和弹框相关的逻辑。这种在组件属性面板增加功能的迭代方式只会导致配置内容膨胀、配置难度增加、开发成本提高,最后反而不如写代码方便。
由于零代码配置页面在客服内部广泛应用,客服技术团队也期望找到一种更好的方式来解决零代码中无法灵活控制页面逻辑和复杂交互的问题,让不会编程的同学也能做出复杂交互的页面。
思路:页面逻辑编排
对于前面提到的表格编辑需求,如果通过写 JS 代码的方式实现,一般都是监听事件 -> 收集数据 -> 发起请求 -> 判断返回结果 -> 修改页面组件内容。那么我们是否可以将写代码的过程抽象为一个个简单的逻辑,然后利用流程串联起来,达到同样的效果?
利用这个思路,将前面的需求拆分为“表格触发编辑事件”、“请求获取权限”、“显示普通管理员编辑弹框”、“显示高级管理员弹框”这4个简单逻辑,然后在流程图上画出来,如下示意图:
上图为我们内部的零代码配置页面的系统配置一个基础表格的截图。其中左侧和大多数零代码平台一样,通过拖拽配置的页面。而右侧就是通过流程配置的方式,实现页面内复杂逻辑的串联。采用流程编排页面逻辑这种方式,我们可以通过自由组合节点实现页面逻辑的灵活配置。例如当请求接口返回比较慢时,在请求节点之前增加表格 loading 节点。
也可以通过组合来实现组件显隐,例如当单选框A选择a1时,显示组件B,隐藏组件C;当单选框A选择a2时,显示组件C,隐藏组件B。就可以拆分为“单选框值改变事件”、“显示组件B”、“显示组件C”、“隐藏组件B”、“隐藏组件C”5个节点,然后都在连线上分别增加条件“选框A选择a1”和“单选框A选择a2”。
通过上面的介绍可以看到,将复杂交互中每个组件的变化都抽象为一个单元逻辑,然后在流程图中用节点的编排体现,可以更好的解决零代码中难扩展的问题。接下来我们将给大家介绍页面逻辑编排的核心能力,并演示如何进行页面逻辑编排的开发、运行和调试。
方案:页面逻辑编排的三大核心能力
为了让流程编排替代写代码,我们实现了与研发过程相对应的编排器、执行器和调试器,以便进行开发、运行和调试。
由于整个过程都是围绕着流程图来实现,对于流程图的功能有很多特殊的要求。正好我们团队在流程图编辑上有很多沉淀,并且开源了流程图编辑框架 LogicFlow,借助 LogicFlow 强大的自定义能力,我们可以快速的实现页面逻辑编排中各种核心能力。
LogicFlow 整体架构图如下,核心包 @logicflow/core 提供了流程图编辑器基础的能力,右边的 @logicflow/extension 是基于 @logicflow/core 的拓展性开发的插件。
编排器
在传统的开发模式,开发的产物是 JS 代码,现在改用流程编排来作为可视化开发,开发产物就变成描述流程图的 JSON 数据。由于流程图主要是通过节点和连线组成,所以在编排器中也是通过自定义节点和边来实现页面逻辑编排功能。
自定义节点
在编排器的流程图上,支持配置多种类型的节点,包括事件节点、数据节点、行为节点、跳转节点等。每一个节点代表着一个最基础的页面逻辑单元,例如:
- 事件节点可以看做 JS 事件监听。
- 数据节点可以看做 ajax 请求。
- 行为节点可以看做修改页面组件属性。
- 跳转节点可以看做浏览器的跳转新页面。
对于不同功能的节点,都可以使用 LogicFlow 的自定义 html 节点实现所需的效果。在编排器中,需要高亮、悬浮按钮、hover 提示等小组件来提供丝滑的“开发”体验,利用 LogicFlow 的自定义 html 节点就可以完美支持。
在自定义 html 节点时,可以通过重写 html 节点的 setHtml 方法,通过挂载 vue 或者 react 组件的方式,实现自定义 html 内容。代码示例如下:
节点的具体内容在 vue 中写,写法也不变,还可以直接用 UI 组件库,示例代码如下:
自定义连线
在编排器中,连线控制着节点的执行顺序,默认情况下连线表示上一个节点执行完成后,继续执行下一个节点。可以通过在连线上配置条件,中断流程的执行,实现类似 JS 代码中的逻辑判断功能。
如何实现在连线上显示条件小图标?
使用 LogicFlow 在编排器实现连线会稍微复杂一点,由于连线不需要显示文字,而是用一个带有 popover 功能的图标代替。所以需要利用 LogicFlow 的自定义连线机制,重写默认文本逻辑,将文本替换为图标。
默认情况下,LogicFlow 的文本是 svg 元素,所以当我们需要在这上面提供更多的 html 内容是,可以利用 LogicFlow 的基于继承重写的自定义机制,重新实现文本。上面的代码示例就是通过重写 getText 方法,利用在 svg 中插入 foreignObject 的方式,实现 svg 内部嵌套 html 内容。
执行器
页面逻辑编排功能是基于配置流程图实现的,要让流程图按照编排的逻辑运行,最常见的方法是使用流程引擎。但是,市面上的流程引擎大多运行在服务端,如 activiti、flowable、Turbo 等,不适合在浏览器环境的逻辑执行。因此,我们选择实现一款在 JS 环境能运行的流程引擎 LogicFlow Engine,然后在这个流程引擎的基础上实现执行器。
下面我们一起来看 LogicFlow Engine 能力是如何支持执行器功能。
能力一:支持多种类型节点
执行器拥有事件节点、行为节点、数据节点、转换节点、页面跳转节点等节点,每一个节点都有独特的功能。
LogicFlow Engine 虽然只内置开始节点和任务节点,但在使用时可以继承这些节点实现定制的业务逻辑。以实现执行器请求数据节点为例,通过重写任务节点的 action 方法,在方法内容实现请求数据的逻辑即可。
能力二:支持并发执行
在编排逻辑时,常常会出现一个事件后要同时做多个事情的情况。例如当点击一个按钮后,既需要发起请求然后更新数据,又需要更新页面的某个文案。采用分支这种配置方式更符合大多数人的“直觉”,那么执行器就需要支持这种“并发”执行。
这个功能要求 LogicFlow Engine 默认为并行网关,当一个节点执行完成后,会以非阻塞的方式执行后面的所有节点,例如上图执行顺序为:搜索点击->请求数据和更新文案->更新数据。
上面的代码是 LogicFlow Engine 内部默认支持并行网关的逻辑,如果想要实现排他网关,可以重写节点的 getOutgoing 方法即可。
能力三:支持多个开始节点
大多数情况下,一个页面会存在多个可以绑定事件的组件。所以在逻辑编排时,一个流程图上也会有多个事件节点。在执行器中事件节点是流程开始执行的起点,这就要求 LogicFlow Engine支持一个流程图存在多个开始节点。
LogicFlow Engine 不止支持一个流程存在多个开始节点,还支持指定从流程中任意节点开始执行和从已执行的节点重新执行。例如在执行器中,当页面某个组件触发事件后,执行器会找到这个组件对应的节点,然后从这个节点开始执行。
能力四:流程重复执行
在表单里面经常会遇到选择不同的内容,显示不同组件的需求。例如单选框A选择 a1 时,设置组件B显示、组件C隐藏; 当选择单选框A的 a2 时,设置组件C显示、组件B隐藏。
为了满足用户不停的切换单选框选项,需要流程引擎能反复执行。
LogicFlow Engine 支持同一个流程实例,调用多次执行。
调试器
利用编排器和执行器,实现了页面逻辑的可视化编排与执行。但是,即使可视化“开发”降低了“代码”的难度,我们也难免会遇到错误。因此,我们还提供了“调试”功能,让我们在不修改代码的情况下直接运行和检查页面逻辑。
功能一:运行记录
每一个触发事件节点的操作都会生成一条运行记录,我们用流程图路径的方式显示运行记录,可以直观的看到每一次操作触发的流程节点。如下运行记录示意图:
功能二:元素详情
可以通过点击运行记录中执行的节点,查看节点的运行时内容,包括元素数据、错误的原因等。如下元素详情示意图:
功能三:页面数据
当前运行环境下全局的数据,全局数据既包含当前页面运行是产生的动态数据(例如 API 请求返回的数据,组件的值等)也包含页面初始化时传入的数据(宿主系统传入的数据、URL 数据等)。通过页面数据,可能协助配置人员排查页面错误的原因。总结
通过以上方式来实现页面逻辑的编排与执行,很大程度解决了传统零代码技术的难扩展问题,并且在这个架构设计之上,还可以继续封装一个更简易的编排器,让没那么复杂的运营场景既保障了可扩展性,还能降低系统本身的维护成本。
当然在零代码领域还有很多其它的难题需要解决,例如数据源、复杂的算法、数据转换等,在我们内部的零代码平台中都有很多不错的实践,也在基于实际使用不断的打磨和完善,争取在合适的时机将整个零代码平台开源出来,这里就不继续介绍了。
另外,我们已经将 LogicFlow Engine 作为 LogicFlow 的一个模块开源到官方代码仓库上,等不及的小伙伴可以尝试用它来实现自己的页面逻辑编排与执行。有任何使用上的问题都可以通过issue 反馈给我们,LogicFlow Engine 可以应用的场景远不止页面逻辑执行。同时也欢迎大家通过 LogicFlow 官方代码仓库给我们提 issue 和 PR。
也可添加LogicFlow官方微信号:logic-flow,该号会邀请你进微信用户群;或者扫描下方二维码进入LogicFlow的QQ用户群。
END