Vue仿钉钉审批流程:从零搭建可视化工作流引擎

张开发
2026/4/18 7:22:20 15 分钟阅读

分享文章

Vue仿钉钉审批流程:从零搭建可视化工作流引擎
1. 为什么需要可视化审批流程最近在做一个企业内部管理系统客户明确提出要仿照钉钉的审批流程功能。刚开始我觉得这有什么难的不就是几个表单提交吗真正动手做的时候才发现钉钉的审批流设计确实精妙。比如部门经理审批后自动流转到财务金额超过1万需要总经理签字这些规则配置起来非常灵活。传统审批流程的代码通常硬编码在系统里每次业务规则变更都需要开发人员修改代码。而可视化工作流引擎允许非技术人员通过拖拽方式配置流程就像搭积木一样简单。我见过最夸张的例子是某公司HR小姐姐自己配置了20多种请假审批流程完全没麻烦技术部门。用Vue来实现这类功能特别合适它的响应式特性和组件化开发模式能让我们快速构建可交互的节点元素。下面这个最简单的审批流示例包含开始、审批人和结束三个节点template div classworkflow-container StartNode / ApproverNode :approvers[张三,李四] / EndNode / /div /template2. 项目初始化与基础结构搭建2.1 创建Vue项目与安装依赖建议使用Vue CLI脚手架初始化项目我习惯用Vite因为它启动速度更快。必须安装的依赖有vuedraggable实现节点拖拽功能的核心库element-ui采用它的弹窗和表单组件jsplumb连接线的绘制工具npm create vitelatest workflow-engine --template vue cd workflow-engine npm install vuedraggable element-plus jsplumb2.2 设计页面布局结构参考钉钉的界面我把工作区划分为三个区域左侧面板存放各种节点类型的组件中间画布拖拽编排流程的主要区域右侧配置面板点击节点时显示详细设置关键CSS技巧是给画布容器设置transform-origin: 0 0配合缩放控制这样放大缩小时所有元素能保持一致比例。下面是核心布局代码div classdesigner-container div classnode-panel NodeItem v-foritem in nodeTypes :typeitem.type / /div div classflow-canvas refcanvas Draggable v-modelnodes endonDragEnd TransitionGroup NodeWrapper v-fornode in nodes :nodenode / /TransitionGroup /Draggable /div div classconfig-panel v-ifselectedNode NodeConfig :nodeselectedNode / /div /div3. 核心功能实现细节3.1 实现节点拖拽与连线拖拽功能用vuedraggable实现起来特别简单但有几个坑我踩过需要给拖拽容器设置group属性区分来源拖拽结束时需要计算在画布上的准确位置用jsplumb连线时要等DOM渲染完成节点连线的核心代码import { jsPlumb } from jsplumb export default { mounted() { this.jsPlumb jsPlumb.getInstance() this.jsPlumb.ready(() { this.jsPlumb.setContainer(this.$refs.canvas) // 设置连线样式 this.jsPlumb.importDefaults({ Connector: [Flowchart, { stub: 20 }], PaintStyle: { strokeWidth: 2 } }) }) }, methods: { connectNodes(sourceId, targetId) { this.jsPlumb.connect({ source: sourceId, target: targetId, anchors: [Bottom, Top] }) } } }3.2 审批人设置模块开发钉钉最实用的功能是可以按组织架构选择审批人我们简化实现如下功能指定具体人员按角色选择如部门主管连续多级审批用Element UI的Tree组件展示组织架构el-tree :datadeptTree show-checkbox node-keyid :props{label: name} check-changehandleCheckChange /后台需要返回这样的树形数据[ { id: 1, name: 研发部, children: [ {id: 101, name: 前端组, type: dept}, {id: 102, name: 后端组, type: dept} ] } ]4. 条件分支与流程控制4.1 实现条件分支逻辑钉钉的条件分支可以基于表单字段值进行路由判断比如请假类型为年假 → 人事备案金额大于5000 → 财务审核我们通过动态渲染条件表单来实现template v-ifnode.type condition el-form el-form-item label条件名称 el-input v-modelnode.name / /el-form-item el-form-item label判断字段 el-select v-modelnode.field el-option v-forfield in formFields :labelfield.label :valuefield.prop / /el-select /el-form-item el-form-item label比较方式 el-select v-modelnode.operator el-option value label大于 / el-option value label小于 / /el-select /el-form-item /el-form /template4.2 流程校验与保存在保存前需要做这些验证所有审批节点必须设置审批人条件分支必须有默认路由不能存在孤立节点校验通过后生成的流程数据格式示例{ nodes: [ { id: node1, type: approver, approvers: [user1, user2], position: { x: 100, y: 50 } } ], edges: [ { source: node1, target: node2, condition: amount 5000 } ] }5. 性能优化与实践建议5.1 大型流程的性能问题当节点超过50个时我遇到过这些性能瓶颈jsPlumb连线渲染卡顿Vue响应式数据更新变慢缩放操作不流畅优化方案使用v-memo缓存静态节点对jsPlumb采用批量渲染缩放时隐藏连线const onZoom (scale) { this.jsPlumb.setSuspendDrawing(true) this.scale scale this.$nextTick(() { this.jsPlumb.setSuspendDrawing(false) }) }5.2 与后端交互的注意事项前后端协作时容易出问题的地方节点ID生成策略建议前端生成UUID位置信息保存比例而非绝对值版本控制机制推荐的后端接口设计// 保存流程 POST /api/workflow/:id { name: 请假审批, nodes: [...], edges: [...], version: 2023-08-20 } // 获取流程 GET /api/workflow/:id/version/:version6. 扩展功能开发思路6.1 抄送与通知功能除了审批节点还可以实现邮件通知抄送人企业微信消息推送审批超时提醒通知配置组件示例el-form-item label通知方式 el-checkbox-group v-modelnotifyTypes el-checkbox labelemail邮件/el-checkbox el-checkbox labelsms短信/el-checkbox /el-checkbox-group /el-form-item6.2 移动端适配方案为了让流程在手机上也能配置需要简化拖拽操作改为点击添加优化连线显示方式使用手势缩放媒体查询示例media (max-width: 768px) { .node { width: 80px; padding: 5px; } .node-config { position: fixed; top: 0; width: 100%; } }这个项目从零开始搭建用了两周时间最复杂的部分是条件分支的逻辑处理。建议先用简单的直线流程跑通核心功能再逐步添加高级特性。如果遇到jsPlumb连线异常的问题记住一定要在DOM更新完成后调用repaintEverything方法。

更多文章