经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Vue.js » 查看文章
Type Script 在流程设计器的落地实践
来源:cnblogs  作者:暗夜余晖  时间:2022/12/5 8:51:13  对本文有异议

流程设计器项目介绍

从事过BPM行业的大佬必然对流程建模工具非常熟悉,做为WFMC三大体系结构模型中的核心模块,它是工作流的能力模型,其他模块都围绕工作流定义来构建。

成熟的建模工具通过可视化的操作界面和行业BPMN规范描述用户容易理解的工作流的各种构成图元,例如圆圈表示事件,方框表示活动。

流程设计器技术选型

前端框架

VUE3 + TS + Ant Design Vue

选择TS做为首选语言我们是经过充分考虑和验证的,并不是单纯的因为TS比较流行、时髦而去无脑应用。流程设计器是对流程的建模,必然涉及到大量的业务属性数据建模,这些属性可以通过类的方式抽象、继承、维护,也就是面向对象开发,而这恰好是TS的优势。我们的项目中大概有80多个业务模型,如果用JS去表示,那将是何种场景!在验证的过程中我们发现,使用TS开发可以简化开发复杂度和提高产品的成功率。

VUE3 + TS 使用的过程中并不是很顺畅,主要是类型检查方面做的并不是很好。如 vuex、混入 等。

图编辑组件

AntV X6

对于流程图基本的图形绘制能力,我们调研过多个开源的框架,最终选择了 X6。下面附上调研结果,仅当参考(作者对这些框架都带着敬畏之心,并没有恶意,如有不适,勿喷)。

底层技术 浏览器支持情况 事件处理 渲染效果
SVG IE9++、Edge、Chrome、Safari、Opera、360、Firefox 友好 适合复杂度低的流程图
Canvas IE9++、Edge、Chrome、Safari、Opera、360、Firefox 基于位置的定位事件不友好 更适合图像密集型的游戏应用
框架 底层技术 文档地址 协议 点评
SVG.JS SVG https://svgjs.dev/docs/3.0/shape-elements/#svg-line MIT license 仅支持基础的图形绘制能力
G6 图可视化引擎 canvas https://g6.antv.vision/zh MIT license 上手容易,功能面广
X6 图可视化引擎 SVG https://x6.antv.vision/zh/examples/showcase/practices#bpmn MIT license 上手容易,比较专注流程图领域
D3.js SVG https://d3js.org/ https://github.com/d3/d3/wiki/API--中文手册 BSD license 复杂度高,难上手。
logic-flow SVG http://logic-flow.org/ Apache-2.0 License 上手容易,更专注流程图领域,功能不全,较为粗超
bpmn.js SVG https://bpmn.io/toolkit/bpmn-js/ Apache-2.0 License 专业的流程绘制框架,没文档,完全遵循BPMN2.0

辅助框架

class-transformer

普通JS对象与TS对象互转利器

class-validator

流程模型验证利器,类似 C# 中 Attribute,java 中的注解,通过在属性上加注解实现验证。

扩展图元

BPMN2.0规范中对图元做了定义,如圆圈表示事件、方框表示人工任务、菱形表示网关。但是我们的BPM产品主要面对的是国内的客户,规范中的图元太抽象,不适合国内,基于X6基础图形我们定义了一套新图元。

混入实现组件递归重置

右侧的属性面板是配置业务的区域,右下角有保存和重置两个按钮。点击重置后需要对属性面板内所有组件的内容进行重新初始化,因为组件不止一个,多是多级嵌套的,所以需要递归重置。
项目中我们采用vue局部混入的方式,在每个组件上传递 currentUUID props 的方式,层层下钻通知子组件重新初始化内容。

vue3 + ts 使用混入比较繁琐恶心,下面是核心代码:

点击查看代码
  1. declare module 'vue' {
  2. interface ComponentCustomProperties {
  3. /* 定义更新当前组件ID的混入方法 */
  4. updateCurrentUUID: (from: string) => void
  5. }
  6. }
  7. export default defineComponent({
  8. props: {
  9. /** 父组件的UUID */
  10. parentUUID: {
  11. type: Object
  12. }
  13. },
  14. data () {
  15. return {
  16. /** 当前组件的UUID */
  17. currentUUID: {
  18. uuid: v4(),
  19. from: '' // 驱动来源
  20. },
  21. /** 支持的级联更新来源 */
  22. supportFroms: [
  23. 'propertyReset', // 属性面板重置
  24. 'ruleChange'
  25. ]
  26. }
  27. },
  28. methods: {
  29. /** 初始化数据,要求所有子组件的初始化都放到该方法内 */
  30. initComponentData () {
  31. /* 子组件数据初始化的方法 */
  32. },
  33. /** 更新当前组件UUID */
  34. updateCurrentUUID (from: string) {
  35. this.currentUUID.from = from
  36. this.currentUUID.uuid = v4()
  37. }
  38. },
  39. watch: {
  40. /** */
  41. parentUUID: {
  42. handler: function (val) {
  43. // 如果来源在 supportFroms 集合中,才支持重新初始化
  44. if (this.supportFroms.indexOf(val.from) > -1) {
  45. this.initComponentData()
  46. this.$forceUpdate()
  47. this.$nextTick(() => {
  48. this.updateCurrentUUID(val.from)
  49. })
  50. }
  51. },
  52. deep: true
  53. }
  54. }
  55. })

发布订阅模式实现组件递归验证

右侧的属性面板在点击保存时需要验证数据的完整性,而这些数据又分布在不同的子组件内,所以需要每个子组件自己完成数据验证。项目中我们采用混入 + 发布订阅设计模式完成该功能。

子组件在 mounted 时订阅验证事件,unmounted 时删除订阅,点击保存时发布验证事件,每个子组件完成自身的验证后返回一个 Promise,当所有子组件都验证完成后,再将数据保存到数据库。

点击查看代码
  1. declare module 'vue' {
  2. interface ComponentCustomProperties {
  3. componentValidate: (data?: any) => Promise<ValidateResult>
  4. }
  5. }
  6. /**
  7. * 组件验证结果
  8. */
  9. export interface ValidateResult {
  10. /** 是否验证通过 */
  11. isOk: boolean,
  12. /** 验证失败的消息 */
  13. msgs?: string[]
  14. }
  15. export default defineComponent({
  16. props: {
  17. },
  18. data () {
  19. return {
  20. }
  21. },
  22. mounted () {
  23. const pubSub = inject<PubSub>('pubSub')
  24. if (pubSub) {
  25. unref(pubSub).on(this.currentUUID.uuid, this.componentValidate)
  26. }
  27. },
  28. beforeUnmount () {
  29. const pubSub = inject<PubSub>('pubSub')
  30. if (pubSub) {
  31. unref(pubSub).off(this.currentUUID.uuid)
  32. }
  33. },
  34. unmounted () {
  35. const pubSub = inject<PubSub>('pubSub')
  36. if (pubSub) {
  37. unref(pubSub).off(this.currentUUID.uuid)
  38. }
  39. },
  40. methods: {
  41. /** 组件验证 */
  42. componentValidate (data?: any): Promise<ValidateResult> {
  43. return Promise.resolve({
  44. isOk: true
  45. })
  46. }
  47. }
  48. })
  49. <template>
  50. <div>
  51. </div>
  52. </template>
  53. <script lang="ts">
  54. export default defineComponent({
  55. name: 'BaseTabView',
  56. mixins: [resetMixin], // 混入组件验证模块
  57. props: {
  58. },
  59. data () {
  60. return {
  61. }
  62. },
  63. setup () {
  64. },
  65. mounted () {
  66. },
  67. methods: {
  68. componentValidate (data?: any): Promise<ValidateResult> {
  69. const result: ValidateResult = {
  70. isOk: true,
  71. msgs: []
  72. }
  73. return Promise.resolve(result)
  74. }
  75. }
  76. })
  77. </script>
  78. export class PubSub {
  79. // eslint-disable-next-line @typescript-eslint/ban-types
  80. handles: Map<string, Function> = new Map<string, Function>()
  81. /** 订阅事件 */
  82. on (eventType: string, handle: any) {
  83. if (this.handles.has(eventType)) {
  84. throw new Error('重复注册的事件')
  85. }
  86. if (!handle) {
  87. throw new Error('缺少回调函数')
  88. }
  89. this.handles.set(eventType, handle)
  90. return this
  91. }
  92. /** 发布事件 所有事件 */
  93. emitAll (data?: any): Promise<any[]> {
  94. const result: Promise<any>[] = []
  95. this.handles.forEach(item => {
  96. // eslint-disable-next-line prefer-spread
  97. result.push(item.apply(null, data))
  98. })
  99. return Promise.all(result)
  100. }
  101. /** 发布事件 */
  102. emit (eventType: string, data?: any) {
  103. if (!this.handles.has(eventType)) {
  104. throw new Error(`"${eventType}"事件未注册`)
  105. }
  106. const handle = this.handles.get(eventType)!
  107. // eslint-disable-next-line prefer-spread
  108. handle.apply(null, data)
  109. }
  110. /** 删除事件 */
  111. off (eventType: string) {
  112. this.handles.delete(eventType)
  113. }
  114. }

设计器产品展示

关于作者:本人从事BPM开发多年,欢迎有志同道合之友来扰!

原文链接:https://www.cnblogs.com/limitcode/p/16947187.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号