最近在做系统中的流程管理功能,对比了各大流程设计器,很多都要结合脚本进行实现。作为一名追求完美用户体验的全栈设计师,这种方式一定要不得。其实对于我们系统来说也不必要那么复杂的操作体验。寻觅一番,发现钉钉的请假流程体验很好。
界面简单明确,适合固定流程类型的系统。于是开始对其进行解剖,看看他是如何去管控流程的,并联系我这边的系统进行移植和优化。
功能设计分析
钉钉这个流程设计器将审批流程的节点分为三类:
- 审批节点
- 条件分支
- 抄送
其中“审批节点”的审批类型分为:指定成员、主管、角色、发起人自选、发起人自己、表单里的联系人、连续多级主管、……,和这些类型的更细分的属性操作。
然后“条件分支”是对“请假”(这个只有请假流程设计)内一些指定字段的大于、等于、小于、大于等于……的判断然后根据判断结果输出多个分支,后面再跟上审批节点。
“抄送”这里其实可以融合到任何一个节点里面去,但钉钉团队选择分出来也是很好的选择,操作人员理解起来比较直观。我的系统不是基于IM基础的所以抄送功能就变得不太重要了,但确确实我在做做用户调研时拿出钉钉的抄送功能让用户对比,很多用户反馈这个功能很好(他们可能没用过邮件)。
钉钉的流程设计器还做了容错判断,比如发布流程时需要判断各节点内容是否完整、合法。问题就出在这里,我们后文会讲到。
UI实现
钉钉这个流程设计器采用的是DIV+CSS方式实现,可以说这位老兄的css功底很了得。听说阿里的技术选型是React,所以这里应该是一个组件递归,数据结构也就是类似树结构,像下面这样:
把这个树结构转成流程形状有很多种办法。但是要编辑这个就和传统的树结构编辑有点区别了。比如当用户在两个节点之间增加了一个节点,那么下面的节点的父级就变成了这个新增的节点,上面的下级也变成了这个新增的节点。
也有一种办法,就是服务端返回的就是一个展开的树数据,像这样:
1 | { |
然后就可以写一个操作的构造函数(不考虑DOM生成),大致结构和设计思路可以看看下面的:
1 | class TreeOperate { |
缺点
像钉钉这样在编辑完成后再提交整体数据结构,那么各节点ID生成的重担就放到了前端开发人员的肩上,而且这样提交后的数据,后端必须清空现有流程节点再重新解析新数据填入表中,费事费力(如果不清空就要去重删除,那样更麻烦),这样也不太安全的。
我就在想钉钉这样做是为啥呢??实在没有道理,虽然钉钉细节上的东西很多,但不至于要这样做,难道仅仅是为了全盘校验?!如果是这样,那下面这样的流程通过合法性校验就有点匪夷所思了,请看下图:
这样一个明显不合法的流程被认定为合法。试想没有审批,条件分支以后直接结束流程,这? @钉钉前端工程师
本土化改进版
设计思路
发现了这些缺点后,我这边的系统采用的是vue进行前端编写,看下实现效果:
因为没有抄送,所以就只有两种节点类型:“审批节点”、“条件分支”。
看看审批节点的选项,理解一下我是怎样的思路:
重点来了
这里点击保存按钮就会直接提交节点内容到服务端,服务端会自动重新组装返回数据结构给我,那我只需要再渲染一次就OK了!
删除也一样,我只把当前节点ID传给后端就可以了,然后后端返回删除后的流程节点数据给我,再重新渲染就是了。用一张图来对比一下这两种方法:
问题
这种逐个操作法,总大的问题就是不能验证整体流程的合法性,很可能用户因此提交一个错误的流程,导致业务进程受阻,但通过对比正反向用例,发现担心是多余的,因为只有一种上面提到的“条件节点后不能没有审批”的这种合法性校验,这种逐个校验逐个提交的方式可以handle所有用例(这种合法性校验顶顶虽然使用了全局提交,但也没有做)。
终归问题还是要解决的,万一用户弄了这么一个流程怎么办?很简单,新流程提交的时候如果流程不合法就为用户返回“流程设计出现问题,请联系流程设计相关人员修改!”并阻断流程提交。
实现
看看文件结构
1 | |-workFlow.vue |
利用组件递归方法,进行流程树渲染。下面重点看看node.vue的代码:
1 | <template> |
重点的样式
盒模型如下所示:
连线采用before
和after
伪类,优点是控制灵活。
看下面一段代码:
1 | .work-flow-item{ |
OK 本文结束~