• 基于antd+vue2来实现一个简单的绘画流程图功能


    简单流程图的实现(基于antd+vue2的)代码很多哦~
    实现页面如下
    在这里插入图片描述

    1.简单操作如下

    在这里插入图片描述

    2.弹框中使用组件:

     	<vfd
          ref="vfd"
          style="background-color: white;"
          :needShow="true"
          :fieldNames="fieldNames"
          @openUser="openUser"
          @openRole="openRole"
        ></vfd>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.组件的文件结构:

    在这里插入图片描述
    FlowDesigner.vue代码如下

    <template>
      <div style="height: 60vh">
        <a-layout class="container">
          <a-layout-sider
            v-show="needShow"
            width="200"
            theme="light"
            class="select-area"
          >
            <a-row style="padding:5px">
              <a-checkable-tag
                v-model="tag.checked0"
                @change="toggleNodeShow0"
                class="tag"
              >工具</a-checkable-tag>
              <div align="center">
                <a-list
                  :grid="{ gutter: 8, column: 1 }"
                  v-if="tag.toolShow"
                >
                  <a-list-item>
                    <a-button-group>
                      <a-button
                        v-for="(tool, index) in field.tools"
                        :key="index"
                        :icon="tool.icon"
                        :type="currentTool.type == tool.type ? 'primary': 'default'"
                        @click="selectTool(tool.type)"
                      >
                      </a-button>
                    </a-button-group>
                  </a-list-item>
                </a-list>
              </div>
            </a-row>
            <a-row style="padding:5px">
              <a-checkable-tag
                v-model="tag.checked1"
                @change="toggleNodeShow1"
                class="tag"
              >基础节点</a-checkable-tag>
              <div align="center">
                <a-list
                  :grid="{ gutter: 8, column: 2 }"
                  v-if="tag.commonNodeShow"
                >
                  <a-list-item
                    v-for="(commonNode, index) in field.commonNodes"
                    :key="index"
                  >
                    <div
                      class="node-item"
                      :type="commonNode.type"
                      belongto="commonNodes"
                    >
                      <a-icon :type="commonNode.icon" /> {{ commonNode.name }}
                    </div>
                  </a-list-item>
                </a-list>
              </div>
            </a-row>
            <a-row style="padding:5px">
              <a-checkable-tag
                v-model="tag.checked3"
                @change="toggleNodeShow3"
                class="tag"
              >泳道节点</a-checkable-tag>
              <div align="center">
                <a-list
                  :grid="{ gutter: 8, column: 2 }"
                  v-if="tag.laneNodeShow"
                >
                  <a-list-item
                    v-for="(laneNode, index) in field.laneNodes"
                    :key="index"
                  >
                    <div
                      class="node-item"
                      :type="laneNode.type"
                      belongto="laneNodes"
                    >
                      <a-icon :type="laneNode.icon" /> {{ laneNode.name }}
                    </div>
                  </a-list-item>
                </a-list>
              </div>
            </a-row>
          </a-layout-sider>
          <a-layout>
            <a-layout-header
              v-show="needShow"
              class="header-option"
              style="background-color:#fff;padding-right: 10px;"
            >
              <a-popconfirm
                title="确认要重新绘制吗?"
                placement="bottom"
                okText="确认"
                cancelText="取消"
                @confirm="clear"
              >
                <a-tooltip
                  title="重新绘制"
                  placement="bottom"
                >
                  <a-button
                    class="header-option-button"
                    size="small"
                    icon="sync"
                  ></a-button>
                </a-tooltip>
              </a-popconfirm>
              <a-tooltip
                :title="flowData.config.showGridText"
                placement="bottom"
              >
                <a-button
                  @click="toggleShowGrid"
                  class="header-option-button"
                  size="small"
                  :icon="flowData.config.showGridIcon"
                >
                </a-button>
              </a-tooltip>
              <a-tooltip
                title="设置"
                placement="bottom"
              >
                <a-button
                  @click="setting"
                  class="header-option-button"
                  size="small"
                  icon="setting"
                ></a-button>
              </a-tooltip>
              <a-tooltip
                title="JSON"
                placement="bottom"
              >
                <a-button
                  @click="openTest"
                  class="header-option-button"
                  size="small"
                  icon="save"
                ></a-button>
              </a-tooltip>
              <a-popconfirm
                title="请选择帮助项:"
                placement="bottom"
                okType="default"
                okText="快捷键大全"
                cancelText="使用文档"
                @confirm="shortcutHelper"
                @cancel="usingDoc"
              >
                <a-icon
                  slot="icon"
                  type="question-circle-o"
                  style="color: red"
                />
                <a-tooltip
                  title="帮助"
                  placement="bottom"
                >
                  <a-button
                    class="header-option-button"
                    size="small"
                    icon="book"
                  ></a-button>
                </a-tooltip>
              </a-popconfirm>
            </a-layout-header>
            <a-layout-content class="flowContent">
              <flow-area
                ref="flowArea"
                :browserType="browserType"
                :flowData="flowData"
                :select.sync="currentSelect"
                :selectGroup.sync="currentSelectGroup"
                :plumb="plumb"
                :currentTool="currentTool"
                :activityId="activityId"
                @findNodeConfig="findNodeConfig"
                @selectTool="selectTool"
                @getShortcut="getShortcut"
                @saveFlow="saveFlow"
              >
              </flow-area>
              <vue-context-menu
                class="customMenuClass"
                :contextMenuData="linkContextMenuData"
                @deleteLink="deleteLink"
              >
              </vue-context-menu>
            </a-layout-content>
          </a-layout>
          <a-layout-sider
            width="300"
            theme="light"
            class="attr-area"
            @mousedown.stop="loseShortcut"
          >
            <flow-attr
              ref="flowAttrForm"
              :plumb="plumb"
              :flowData="flowData"
              :needShow="needShow"
              :fieldNames.sync="fieldNames"
              :select.sync="currentSelect"
              @openUser="openUser"
              @openRole="openRole"
            ></flow-attr>
          </a-layout-sider>
        </a-layout>
        <setting-modal ref="settingModal"></setting-modal>
        <shortcut-modal ref="shortcutModal"></shortcut-modal>
        <test-modal
          ref="testModal"
          @loadFlow="loadFlow"
          @clear123="clear()"
        ></test-modal>
      </div>
    </template>
    
    <script>
    import jsplumb from 'jsplumb'
    import { tools, commonNodes, laneNodes } from './config/basic-node-config.js'
    import { flowConfig } from './config/args-config.js'
    import $ from 'jquery'
    import 'jquery-ui/ui/widgets/draggable'
    import 'jquery-ui/ui/widgets/droppable'
    import 'jquery-ui/ui/widgets/resizable'
    import { ZFSN } from './util/ZFSN.js'
    import FlowArea from './modules/FlowArea'
    import FlowAttr from './modules/FlowAttr'
    import SettingModal from './modules/SettingModal'
    import ShortcutModal from './modules/ShortcutModal'
    import UsingDocModal from './modules/UsingDocModal'
    import TestModal from './modules/TestModal'
    
    export default {
      name: 'vfd',
      components: {
        jsplumb,
        flowConfig,
        FlowArea,
        FlowAttr,
        SettingModal,
        ShortcutModal,
        UsingDocModal,
        TestModal,
      },
      //条件选择字段
      props: ['fieldNames', 'needShow', 'activityId'],
      mounted() {
        const that = this
        that.dealCompatibility()
        that.initNodeSelectArea()
        that.initJsPlumb()
        that.listenShortcut()
        that.initFlow()
        that.listenPage()
      },
      data() {
        return {
          tag: {
            checked0: true,
            checked1: true,
            checked2: true,
            checked3: true,
            toolShow: true,
            commonNodeShow: true,
            highNodeShow: true,
            laneNodeShow: true,
          },
          browserType: 3,
          plumb: {},
          field: {
            tools: tools,
            commonNodes: commonNodes,
            laneNodes: laneNodes,
          },
          flowData: {
            nodeList: [],
            linkList: [],
            attr: {
              id: '',
            },
            config: {
              showGrid: true,
              showGridText: '隐藏网格',
              showGridIcon: 'eye',
            },
            status: flowConfig.flowStatus.CREATE,
            remarks: [],
          },
          currentTool: {
            type: 'drag',
            icon: 'drag',
            name: '拖拽',
          },
          currentSelect: {},
          currentSelectGroup: [],
          activeShortcut: true,
          linkContextMenuData: flowConfig.contextMenu.link,
          flowPicture: {
            url: '',
            modalVisible: false,
            closable: false,
            maskClosable: false,
          },
          flowLineAdditions: flowConfig.flowLineAdditions,
        }
      },
      methods: {
        //用户选择界面
        openUser(value) {
          this.$emit('openUser', value)
        },
        //角色选择界面
        openRole(value) {
          this.$emit('openRole', value)
        },
        //角色用户设置必须包含id、name属性的数组
        setFlowAttrForm(value, type) {
          this.$refs.flowAttrForm.setFlowAttrForm(value, type)
        },
        toggleNodeShow0(flag) {
          if (!flag) {
            this.tag.toolShow = false
          } else {
            this.tag.toolShow = true
          }
        },
        toggleNodeShow1(flag) {
          if (!flag) {
            this.tag.commonNodeShow = false
          } else {
            this.tag.commonNodeShow = true
          }
        },
        toggleNodeShow2(flag) {
          if (!flag) {
            this.tag.highNodeShow = false
          } else {
            this.tag.highNodeShow = true
          }
        },
        toggleNodeShow3(flag) {
          if (!flag) {
            this.tag.laneNodeShow = false
          } else {
            this.tag.laneNodeShow = true
          }
        },
        getBrowserType() {
          let userAgent = navigator.userAgent
          let isOpera = userAgent.indexOf('Opera') > -1
          if (isOpera) {
            return 1
          }
          if (userAgent.indexOf('Firefox') > -1) {
            return 2
          }
          if (userAgent.indexOf('Chrome') > -1) {
            return 3
          }
          if (userAgent.indexOf('Safari') > -1) {
            return 4
          }
          if (userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1 && !isOpera) {
            alert('IE浏览器支持性较差,推荐使用Firefox或Chrome')
            return 5
          }
          if (userAgent.indexOf('Trident') > -1) {
            alert('Edge浏览器支持性较差,推荐使用Firefox或Chrome')
            return 6
          }
        },
        dealCompatibility() {
          const that = this
    
          that.browserType = that.getBrowserType()
          if (that.browserType == 2) {
            flowConfig.shortcut.scaleContainer = {
              code: 16,
              codeName: 'SHIFT(chrome下为ALT)',
              shortcutName: '画布缩放',
            }
          }
        },
        initJsPlumb() {
          const that = this
    
          that.plumb = jsPlumb.getInstance(flowConfig.jsPlumbInsConfig)
    
          that.plumb.bind('beforeDrop', function (info) {
            let sourceId = info.sourceId
            let targetId = info.targetId
    
            if (sourceId == targetId) return false
            let filter = that.flowData.linkList.filter((link) => link.sourceId == sourceId && link.targetId == targetId)
            if (filter.length > 0) {
              that.$message.error('同方向的两节点连线只能有一条!')
              return false
            }
            return true
          })
    
          that.plumb.bind('connection', function (conn, e) {
            let connObj = conn.connection.canvas
            let o = {},
              id,
              label
            if (
              that.flowData.status == flowConfig.flowStatus.CREATE ||
              that.flowData.status == flowConfig.flowStatus.MODIFY
            ) {
              id = 'link-' + ZFSN.getId()
              label = ''
            } else if (that.flowData.status == flowConfig.flowStatus.LOADING) {
              let l = that.flowData.linkList[that.flowData.linkList.length - 1]
              id = l.id
              label = l.label
            }
            connObj.id = id
            o.type = 'link'
            o.id = id
            o.sourceId = conn.sourceId
            o.targetId = conn.targetId
            o.label = label
            o.cls = {
              linkType: flowConfig.jsPlumbInsConfig.Connector[0],
              linkColor: flowConfig.jsPlumbInsConfig.PaintStyle.stroke,
              linkThickness: flowConfig.jsPlumbInsConfig.PaintStyle.strokeWidth,
            }
            $('#' + id).bind('contextmenu', function (e) {
              that.showLinkContextMenu(e)
              that.currentSelect = that.flowData.linkList.filter((l) => l.id == id)[0]
            })
            $('#' + id).bind('click', function (e) {
              let event = window.event || e
              event.stopPropagation()
              that.currentSelect = that.flowData.linkList.filter((l) => l.id == id)[0]
            })
            if (that.flowData.status != flowConfig.flowStatus.LOADING) that.flowData.linkList.push(o)
          })
    
          that.plumb.importDefaults({
            ConnectionsDetachable: flowConfig.jsPlumbConfig.conn.isDetachable,
          })
    
          ZFSN.consoleLog(['实例化JsPlumb成功...'])
        },
        initNodeSelectArea() {
          $(document).ready(function () {
            $('.node-item').draggable({
              opacity: flowConfig.defaultStyle.dragOpacity,
              helper: 'clone',
              cursorAt: {
                top: 16,
                left: 60,
              },
              containment: 'window',
              revert: 'invalid',
            })
            ZFSN.consoleLog(['初始化节点选择列表成功...'])
          })
        },
        listenShortcut() {
          const that = this
          document.onkeydown = function (e) {
            let event = window.event || e
    
            if (!that.activeShortcut) return
            let key = event.keyCode
    
            switch (key) {
              case flowConfig.shortcut.multiple.code:
                that.$refs.flowArea.rectangleMultiple.flag = true
                break
              case flowConfig.shortcut.dragContainer.code:
                that.$refs.flowArea.container.dragFlag = true
                break
              case flowConfig.shortcut.scaleContainer.code:
                that.$refs.flowArea.container.scaleFlag = true
                break
              case flowConfig.shortcut.dragTool.code:
                that.selectTool('drag')
                break
              case flowConfig.shortcut.connTool.code:
                that.selectTool('connection')
                break
              case flowConfig.shortcut.zoomInTool.code:
                that.selectTool('zoom-in')
                break
              case flowConfig.shortcut.zoomOutTool.code:
                that.selectTool('zoom-out')
                break
              case 37:
                that.moveNode('left')
                break
              case 38:
                that.moveNode('up')
                break
              case 39:
                that.moveNode('right')
                break
              case 40:
                that.moveNode('down')
                break
            }
          }
          document.onkeyup = function (e) {
            let event = window.event || e
    
            let key = event.keyCode
            if (key == flowConfig.shortcut.dragContainer.code) {
              that.$refs.flowArea.container.dragFlag = false
            } else if (key == flowConfig.shortcut.scaleContainer.code) {
              event.preventDefault()
              that.$refs.flowArea.container.scaleFlag = false
            } else if (key == flowConfig.shortcut.multiple.code) {
              that.$refs.flowArea.rectangleMultiple.flag = false
            }
          }
    
          ZFSN.consoleLog(['初始化快捷键成功...'])
        },
        listenPage() {
          window.onbeforeunload = function (e) {
            e = e || window.event
            if (e) {
              e.returnValue = '关闭提示'
            }
            return '关闭提示'
          }
        },
        initFlow() {
          const that = this
          if (that.flowData.status == flowConfig.flowStatus.CREATE) {
            that.flowData.attr.id = 'flow-' + ZFSN.getId()
          } else {
            that.loadFlow()
          }
          ZFSN.consoleLog(['初始化流程图成功...'])
        },
        loadFlow(json) {
          const that = this
          setTimeout(() => {
            that.flowLineAdditions.forEach((item) => {
              that.fieldNames.push(item)
            })
            const map = new Map()
            const list = that.fieldNames.filter((key) => !map.has(key.id) && map.set(key.id, 1))
            that.$emit('update:fieldNames', list)
          }, 100)
          that.clear()
          let loadData = JSON.parse(json)
          that.flowData.attr = loadData.attr
          that.flowData.config = loadData.config
          that.flowData.status = flowConfig.flowStatus.LOADING
          that.plumb.batch(function () {
            let nodeList = loadData.nodeList
            let areaList = loadData.areaList
            nodeList.forEach(function (node, index) {
              that.flowData.nodeList.push(node)
            })
            if (!!areaList && areaList.length > 0) {
              areaList.forEach(function (node, index) {
                that.flowData.nodeList.push(node)
              })
            }
            let linkList = loadData.linkList
            that.$nextTick(() => {
              linkList.forEach(function (link, index) {
                that.flowData.linkList.push(link)
                let conn = that.plumb.connect({
                  source: link.sourceId,
                  target: link.targetId,
                  anchor: flowConfig.jsPlumbConfig.anchor.default,
                  connector: [
                    link.cls.linkType,
                    {
                      gap: 5,
                      cornerRadius: 8,
                      alwaysRespectStubs: true,
                    },
                  ],
                  paintStyle: {
                    stroke: link.cls.linkColor,
                    strokeWidth: link.cls.linkThickness,
                  },
                })
                if (link.label != '') {
                  conn.setLabel({
                    label: link.label,
                    cssClass: 'linkLabel',
                  })
                }
              })
              that.currentSelect = {}
              that.currentSelectGroup = []
              that.flowData.status = flowConfig.flowStatus.MODIFY
            })
          }, true)
        },
        findNodeConfig(belongto, type, callback) {
          let node = null
          switch (belongto) {
            case 'commonNodes':
              node = commonNodes.filter((n) => n.type == type)
              break
            case 'laneNodes':
              node = laneNodes.filter((n) => n.type == type)
              break
          }
          if (node && node.length >= 0) node = node[0]
          callback(node)
        },
        selectTool(type) {
          let tool = tools.filter((t) => t.type == type)
          if (tool && tool.length >= 0) this.currentTool = tool[0]
    
          switch (type) {
            case 'drag':
              this.changeToDrag()
              break
            case 'connection':
              this.changeToConnection()
              break
            case 'zoom-in':
              this.changeToZoomIn()
              break
            case 'zoom-out':
              this.changeToZoomOut()
              break
          }
        },
        changeToDrag() {
          const that = this
    
          that.flowData.nodeList.forEach(function (node, index) {
            let f = that.plumb.toggleDraggable(node.id)
            if (!f) {
              that.plumb.toggleDraggable(node.id)
            }
            if (node.type != 'x-lane' && node.type != 'y-lane') {
              that.plumb.unmakeSource(node.id)
              that.plumb.unmakeTarget(node.id)
            }
          })
        },
        changeToConnection() {
          const that = this
    
          that.flowData.nodeList.forEach(function (node, index) {
            let f = that.plumb.toggleDraggable(node.id)
            if (f) {
              that.plumb.toggleDraggable(node.id)
            }
            if (node.type != 'x-lane' && node.type != 'y-lane') {
              that.plumb.makeSource(node.id, flowConfig.jsPlumbConfig.makeSourceConfig)
              that.plumb.makeTarget(node.id, flowConfig.jsPlumbConfig.makeTargetConfig)
            }
          })
    
          that.currentSelect = {}
          that.currentSelectGroup = []
        },
        changeToZoomIn() {
          console.log('切换到放大工具')
        },
        changeToZoomOut() {
          console.log('切换到缩小工具')
        },
        checkFlow() {
          const that = this
          let nodeList = that.flowData.nodeList
          let linkList = that.flowData.linkList
          let areaList = []
          for (let index = nodeList.length - 1; index >= 0; index--) {
            const item = nodeList[index]
            if (item.type == 'x-lane' || item.type == 'y-lane') {
              nodeList.splice(index, 1)
              areaList.push(item)
            }
            if (!!item.setInfo) {
              if (
                (item.setInfo.nodeDesignate == 'SPECIAL_USER' || item.setInfo.nodeDesignate == 'SPECIAL_ROLE') &&
                item.setInfo.nodeDesignateData.length == 0
              ) {
                this.$message.error('节点:' + item.setInfo.nodeName + ',执行权限需要配置!')
                return false
              }
            }
          }
          that.flowData.areaList = areaList
          linkList.forEach((item) => {
            if (!!item.compares) {
              for (let index = item.compares.length - 1; index >= 0; index--) {
                const compare = item.compares[index]
                //这些字段没有就去掉条件
                if (!compare.operation || !compare.fieldName || !compare.value) {
                  item.compares.splice(index, 1)
                }
              }
            }
          })
          if (nodeList.length <= 0) {
            this.$message.error('流程图中无任何节点!')
            return false
          }
          return true
        },
        saveFlow() {
          const that = this
          if (!that.checkFlow()) return
          let flowObj = Object.assign({}, that.flowData)
          flowObj.status = flowConfig.flowStatus.SAVE
          let d = JSON.stringify(flowObj)
          //this.$message.success('保存流程成功!请查看控制台。');
          return d
        },
        cancelDownLoadFlowPicture() {
          this.flowPicture.url = ''
          this.flowPicture.modalVisible = false
        },
        clear() {
          const that = this
          that.flowData.nodeList.forEach(function (node, index) {
            that.plumb.remove(node.id)
          })
          that.currentSelect = {}
          that.currentSelectGroup = []
          that.flowData.nodeList = []
          that.flowData.linkList = []
          that.flowData.remarks = []
        },
        toggleShowGrid() {
          let flag = this.flowData.config.showGrid
          if (flag) {
            this.flowData.config.showGrid = false
            this.flowData.config.showGridText = '显示网格'
            this.flowData.config.showGridIcon = 'eye-invisible'
          } else {
            this.flowData.config.showGrid = true
            this.flowData.config.showGridText = '隐藏网格'
            this.flowData.config.showGridIcon = 'eye'
          }
        },
        setting() {
          this.$refs.settingModal.open()
        },
        shortcutHelper() {
          this.$refs.shortcutModal.open()
        },
        usingDoc() {
          window.open('https://gitee.com/yjblogs/VFD?_from=gitee_search')
        },
        exit() {
          alert('退出流程设计器...')
        },
        showLinkContextMenu(e) {
          let event = window.event || e
    
          event.preventDefault()
          event.stopPropagation()
          $('.vue-contextmenuName-flow-menu').css('display', 'none')
          $('.vue-contextmenuName-node-menu').css('display', 'none')
          let x = event.clientX
          let y = event.clientY
          this.linkContextMenuData.axis = { x, y }
        },
        deleteLink() {
          const that = this
          let sourceId = that.currentSelect.sourceId
          let targetId = that.currentSelect.targetId
          that.plumb.deleteConnection(
            that.plumb.getConnections({
              source: sourceId,
              target: targetId,
            })[0]
          )
          let linkList = that.flowData.linkList
          linkList.splice(
            linkList.findIndex((link) => link.sourceId == sourceId || link.targetId == targetId),
            1
          )
          that.currentSelect = {}
        },
        loseShortcut() {
          this.activeShortcut = false
        },
        getShortcut() {
          this.activeShortcut = true
        },
        openTest() {
          const that = this
    
          let flowObj = Object.assign({}, that.flowData)
          that.$refs.testModal.flowData = flowObj
          that.$refs.testModal.testVisible = true
        },
        moveNode(type) {
          const that = this
    
          let m = flowConfig.defaultStyle.movePx,
            isX = true
          switch (type) {
            case 'left':
              m = -m
              break
            case 'up':
              m = -m
              isX = false
              break
            case 'right':
              break
            case 'down':
              isX = false
          }
    
          if (that.currentSelectGroup.length > 0) {
            that.currentSelectGroup.forEach(function (node, index) {
              if (isX) {
                node.x += m
              } else {
                node.y += m
              }
            })
            that.plumb.repaintEverything()
          } else if (that.currentSelect.id) {
            if (isX) {
              that.currentSelect.x += m
            } else {
              that.currentSelect.y += m
            }
            that.plumb.repaintEverything()
          }
        },
      },
    }
    </script>
    
    <style lang="less" scoped>
    @import './style/flow-designer.less';
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704
    • 705
    • 706
    • 707
    • 708
    • 709
    • 710
    • 711
    • 712
    • 713
    • 714
    • 715
    • 716
    • 717
    • 718
    • 719
    • 720
    • 721
    • 722
    • 723
    • 724
    • 725
    • 726
    • 727
    • 728
    • 729
    • 730
    • 731
    • 732
    • 733
    • 734
    • 735
    • 736
    • 737
    • 738
    • 739
    • 740
    • 741
    • 742
    • 743
    • 744
    • 745
    • 746
    • 747
    • 748
    • 749
    • 750
    • 751
    • 752
    • 753
    • 754
    • 755
    • 756
    • 757
    • 758
    • 759
    • 760
    • 761
    • 762
    • 763
    • 764
    • 765
    • 766
    • 767
    • 768
    • 769
    • 770
    • 771
    • 772
    • 773
    • 774
    • 775
    • 776
    • 777
    • 778
    • 779
    • 780
    • 781
    • 782
    • 783
    • 784
    • 785
    • 786
    • 787
    • 788
    • 789
    • 790
    • 791
    • 792
    • 793
    • 794
    • 795
    • 796
    • 797
    • 798
    • 799
    • 800
    • 801
    • 802
    • 803
    • 804
    • 805
    • 806
    • 807
    • 808
    • 809
    • 810
    • 811
    • 812
    • 813
    • 814
    • 815
    • 816
    • 817
    • 818
    • 819
    • 820
    • 821
    • 822
    • 823
    • 824
    • 825
    • 826
    • 827
    • 828
    • 829
    • 830
    • 831
    • 832
    • 833
    • 834
    • 835
    • 836
    • 837
    • 838
    • 839
    • 840
    • 841
    • 842
    • 843
    • 844
    • 845
    • 846
    • 847
    • 848
    • 849

    4.modules文件中的所有文件代码

    FlowArea.vue代码如下

    <template>
      <div style="width: 100%; height: 100%; overflow: hidden; position: relative;">
        <div
          v-if="container.auxiliaryLine.isOpen && container.auxiliaryLine.isShowXLine"
          class="auxiliary-line-x"
          :style="{ top: auxiliaryLinePos.y + 'px' }"
        ></div>
        <div
          v-if="container.auxiliaryLine.isOpen && container.auxiliaryLine.isShowYLine"
          class="auxiliary-line-y"
          :style="{ left: auxiliaryLinePos.x + 'px' }"
        ></div>
        <div
          id="flowContainer"
          class="flow-container"
          :class="{ grid: flowData.config.showGrid, zoomIn: currentTool.type == 'zoom-in', zoomOut: currentTool.type == 'zoom-out', canScale: container.scaleFlag, canDrag: container.dragFlag, canMultiple: rectangleMultiple.flag }"
          :style="{ top: container.pos.top + 'px', left: container.pos.left + 'px', transform: 'scale(' + container.scale + ')', transformOrigin: container.scaleOrigin.x + 'px ' + container.scaleOrigin.y + 'px' }"
          @click.stop="containerHandler"
          @mousedown="mousedownHandler"
          @mousemove="mousemoveHandler"
          @mouseup="mouseupHandler"
          @mousewheel="scaleContainer"
          @DOMMouseScroll="scaleContainer"
          @contextmenu="showContainerContextMenu"
        >
          <flow-node
            v-for="(node, index) in flowData.nodeList"
            :key="index"
            :node="node"
            :plumb="plumb"
            :select.sync="currentSelect"
            :selectGroup.sync="currentSelectGroup"
            :currentTool="currentTool"
            :activityId="activityId"
            @showNodeContextMenu="showNodeContextMenu"
            @isMultiple="isMultiple"
            @updateNodePos="updateNodePos"
            @alignForLine="alignForLine"
            @hideAlignLine="hideAlignLine"
          >
          </flow-node>
          <div
            class="rectangle-multiple"
            v-if="rectangleMultiple.flag && rectangleMultiple.multipling"
            :style="{ top: rectangleMultiple.position.top + 'px', left: rectangleMultiple.position.left + 'px', width: rectangleMultiple.width + 'px', height: rectangleMultiple.height + 'px' }"
          >
          </div>
        </div>
        <!-- <div class="container-scale">
    			缩放倍数:{{ container.scaleShow }}%
    		</div>
    		<div class="mouse-position">
    			x: {{ mouse.position.x }}, y: {{ mouse.position.y }}
    		</div> -->
        <vue-context-menu
          class="customMultiMenuClass"
          :contextMenuData="containerContextMenuData"
          @flowInfo="flowInfo"
          @paste="paste"
          @selectAll="selectAll"
          @saveFlow="saveFlow"
          @verticaLeft="verticaLeft"
          @verticalCenter="verticalCenter"
          @verticalRight="verticalRight"
          @levelUp="levelUp"
          @levelCenter="levelCenter"
          @levelDown="levelDown"
          @addRemark="addRemark"
        >
        </vue-context-menu>
        <!-- 节点右键操作 -->
        <vue-context-menu
          class="customMultiMenuClass"
          :contextMenuData="nodeContextMenuData"
          @copyNode="copyNode"
          @deleteNode="deleteNode"
        >
        </vue-context-menu>
      </div>
    </template>
    
    <script>
    import jsplumb from 'jsplumb'
    import { flowConfig } from '../config/args-config.js'
    import $ from 'jquery'
    import 'jquery-ui/ui/widgets/draggable'
    import 'jquery-ui/ui/widgets/droppable'
    import 'jquery-ui/ui/widgets/resizable'
    import { ZFSN } from '../util/ZFSN.js'
    import FlowNode from './FlowNode'
    
    export default {
      props: ['browserType', 'flowData', 'plumb', 'select', 'selectGroup', 'currentTool', 'activityId'],
      components: {
        jsplumb,
        FlowNode,
      },
      mounted() {
        this.initFlowArea()
      },
      data() {
        return {
          ctx: null,
          currentSelect: this.select,
          currentSelectGroup: this.selectGroup,
          container: {
            pos: {
              //每个框架不同,不能用-3000
              top: -500,
              left: -500,
            },
            dragFlag: false,
            draging: false,
            scale: flowConfig.defaultStyle.containerScale.init,
            scaleFlag: false,
            scaleOrigin: {
              x: 0,
              y: 0,
            },
            scaleShow: ZFSN.mul(flowConfig.defaultStyle.containerScale.init, 100),
            auxiliaryLine: {
              isOpen: flowConfig.defaultStyle.isOpenAuxiliaryLine,
              isShowXLine: false,
              isShowYLine: false,
              controlFnTimesFlag: true,
            },
          },
          auxiliaryLinePos: {
            x: 0,
            y: 0,
          },
          mouse: {
            position: {
              x: 0,
              y: 0,
            },
            tempPos: {
              x: 0,
              y: 0,
            },
          },
          rectangleMultiple: {
            flag: false,
            multipling: false,
            position: {
              top: 0,
              left: 0,
            },
            height: 0,
            width: 0,
          },
          containerContextMenuData: flowConfig.contextMenu.container,
          nodeContextMenuData: flowConfig.contextMenu.node,
          tempLinkId: '',
          clipboard: [],
        }
      },
      methods: {
        initFlowArea() {
          const that = this
          that.ctx = document.getElementById('flowContainer').parentNode
          $('.flow-container').droppable({
            accept: function (t) {
              if (t[0].className.indexOf('node-item') != -1) {
                let event = window.event || 'firefox'
                if (that.ctx.contains(event.srcElement) || event == 'firefox') {
                  return true
                }
              }
              return false
            },
            hoverClass: 'flow-container-active',
            drop: function (event, ui) {
              let belongto = ui.draggable.attr('belongto')
              let type = ui.draggable.attr('type')
              that.$emit('selectTool', 'drag')
              that.$emit('findNodeConfig', belongto, type, (node) => {
                if (!node) {
                  that.$message.error('未知的节点类型!')
                  return
                }
                that.addNewNode(node)
              })
            },
          })
        },
        mousedownHandler(e) {
          const that = this
    
          let event = window.event || e
    
          if (event.button == 0) {
            if (that.container.dragFlag) {
              that.mouse.tempPos = that.mouse.position
              that.container.draging = true
            }
    
            that.currentSelectGroup = []
            if (that.rectangleMultiple.flag) {
              that.mouse.tempPos = that.mouse.position
              that.rectangleMultiple.multipling = true
            }
          }
        },
        mousemoveHandler(e) {
          const that = this
    
          let event = window.event || e
    
          if (event.target.id == 'flowContainer') {
            that.mouse.position = {
              x: event.offsetX,
              y: event.offsetY,
            }
          } else {
            let cn = event.target.className
            let tn = event.target.tagName
            if (cn != 'lane-text' && cn != 'lane-text-div' && tn != 'svg' && tn != 'path' && tn != 'I') {
              that.mouse.position.x = event.target.offsetLeft + event.offsetX
              that.mouse.position.y = event.target.offsetTop + event.offsetY
            }
          }
          if (that.container.draging) {
            let nTop = that.container.pos.top + (that.mouse.position.y - that.mouse.tempPos.y)
            let nLeft = that.container.pos.left + (that.mouse.position.x - that.mouse.tempPos.x)
            if (nTop >= 0) nTop = 0
            if (nLeft >= 0) nLeft = 0
            that.container.pos = {
              top: nTop,
              left: nLeft,
            }
          }
          if (that.rectangleMultiple.multipling) {
            let h = that.mouse.position.y - that.mouse.tempPos.y
            let w = that.mouse.position.x - that.mouse.tempPos.x
            let t = that.mouse.tempPos.y
            let l = that.mouse.tempPos.x
            if (h >= 0 && w < 0) {
              w = -w
              l -= w
            } else if (h < 0 && w >= 0) {
              h = -h
              t -= h
            } else if (h < 0 && w < 0) {
              h = -h
              w = -w
              t -= h
              l -= w
            }
            that.rectangleMultiple.height = h
            that.rectangleMultiple.width = w
            that.rectangleMultiple.position.top = t
            that.rectangleMultiple.position.left = l
          }
        },
        mouseupHandler() {
          const that = this
    
          if (that.container.draging) that.container.draging = false
          if (that.rectangleMultiple.multipling) {
            that.judgeSelectedNode()
            that.rectangleMultiple.multipling = false
            that.rectangleMultiple.width = 0
            that.rectangleMultiple.height = 0
          }
        },
        judgeSelectedNode() {
          const that = this
    
          let ay = that.rectangleMultiple.position.top
          let ax = that.rectangleMultiple.position.left
          let by = ay + that.rectangleMultiple.height
          let bx = ax + that.rectangleMultiple.width
    
          let nodeList = that.flowData.nodeList
          nodeList.forEach(function (node, index) {
            if (node.y >= ay && node.x >= ax && node.y <= by && node.x <= bx) {
              that.plumb.addToDragSelection(noaddToDragSelectionde.id)
              that.currentSelectGroup.push(node)
            }
          })
        },
        scaleContainer(e) {
          const that = this
    
          let event = window.event || e
    
          if (that.container.scaleFlag) {
            if (that.browserType == 2) {
              if (event.detail < 0) {
                that.enlargeContainer()
              } else {
                that.narrowContainer()
              }
            } else {
              if (event.deltaY < 0) {
                that.enlargeContainer()
              } else if (that.container.scale) {
                that.narrowContainer()
              }
            }
          }
        },
        enlargeContainer() {
          const that = this
          that.container.scaleOrigin.x = that.mouse.position.x
          that.container.scaleOrigin.y = that.mouse.position.y
          let newScale = ZFSN.add(that.container.scale, flowConfig.defaultStyle.containerScale.onceEnlarge)
          if (newScale <= flowConfig.defaultStyle.containerScale.max) {
            that.container.scale = newScale
            that.container.scaleShow = ZFSN.mul(that.container.scale, 100)
            that.plumb.setZoom(that.container.scale)
          }
        },
        narrowContainer() {
          const that = this
          that.container.scaleOrigin.x = that.mouse.position.x
          that.container.scaleOrigin.y = that.mouse.position.y
          let newScale = ZFSN.sub(that.container.scale, flowConfig.defaultStyle.containerScale.onceNarrow)
          if (newScale >= flowConfig.defaultStyle.containerScale.min) {
            that.container.scale = newScale
            that.container.scaleShow = ZFSN.mul(that.container.scale, 100)
            that.plumb.setZoom(that.container.scale)
          }
        },
        showContainerContextMenu(e) {
          let event = window.event || e
    
          event.preventDefault()
          $('.vue-contextmenuName-node-menu').css('display', 'none')
          $('.vue-contextmenuName-link-menu').css('display', 'none')
          this.selectContainer()
          let x = event.clientX
          let y = event.clientY
          this.containerContextMenuData.axis = { x, y }
        },
        showNodeContextMenu(e) {
          let event = window.event || e
    
          event.preventDefault()
          $('.vue-contextmenuName-flow-menu').css('display', 'none')
          $('.vue-contextmenuName-link-menu').css('display', 'none')
          let x = event.clientX
          let y = event.clientY
          this.nodeContextMenuData.axis = { x, y }
        },
        flowInfo() {
          const that = this
    
          let nodeList = that.flowData.nodeList
          let linkList = that.flowData.linkList
          alert('当前流程图中有 ' + nodeList.length + ' 个节点,有 ' + linkList.length + ' 条连线。')
        },
        paste() {
          const that = this
          let dis = 0
          that.clipboard.forEach(function (node, index) {
            let newNode = Object.assign({}, node)
            newNode.id = newNode.type + '-' + ZFSN.getId()
            let nodePos = that.computeNodePos(that.mouse.position.x + dis, that.mouse.position.y + dis)
            newNode.x = nodePos.x
            newNode.y = nodePos.y
            dis += 20
            that.flowData.nodeList.push(newNode)
          })
        },
        selectAll() {
          const that = this
          that.flowData.nodeList.forEach(function (node, index) {
            that.plumb.addToDragSelection(node.id)
            that.currentSelectGroup.push(node)
          })
        },
        saveFlow() {
          this.$emit('saveFlow')
        },
        checkAlign() {
          if (this.currentSelectGroup.length < 2) {
            this.$message.error('请选择至少两个节点!')
            return false
          }
          return true
        },
        verticaLeft() {
          const that = this
    
          if (!that.checkAlign()) return
          let nodeList = that.flowData.nodeList
          let selectGroup = that.currentSelectGroup
          let baseX = selectGroup[0].x
          let baseY = selectGroup[0].y
          for (let i = 1; i < selectGroup.length; i++) {
            baseY = baseY + selectGroup[i - 1].height + flowConfig.defaultStyle.alignSpacing.vertical
            let f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]
            f.tx = baseX
            f.ty = baseY
            that.plumb.animate(
              selectGroup[i].id,
              { top: baseY, left: baseX },
              {
                duration: flowConfig.defaultStyle.alignDuration,
                complete: function () {
                  f.x = f.tx
                  f.y = f.ty
                },
              }
            )
          }
        },
        verticalCenter() {
          const that = this
    
          if (!that.checkAlign()) return
          let nodeList = that.flowData.nodeList
          let selectGroup = that.currentSelectGroup
          let baseX = selectGroup[0].x
          let baseY = selectGroup[0].y
          let firstX = baseX
          for (let i = 1; i < selectGroup.length; i++) {
            baseY = baseY + selectGroup[i - 1].height + flowConfig.defaultStyle.alignSpacing.vertical
            baseX = firstX + ZFSN.div(selectGroup[0].width, 2) - ZFSN.div(selectGroup[i].width, 2)
            let f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]
            f.tx = baseX
            f.ty = baseY
            that.plumb.animate(
              selectGroup[i].id,
              { top: baseY, left: baseX },
              {
                duration: flowConfig.defaultStyle.alignDuration,
                complete: function () {
                  f.x = f.tx
                  f.y = f.ty
                },
              }
            )
          }
        },
        verticalRight() {
          const that = this
    
          if (!that.checkAlign()) return
          let nodeList = that.flowData.nodeList
          let selectGroup = that.currentSelectGroup
          let baseX = selectGroup[0].x
          let baseY = selectGroup[0].y
          let firstX = baseX
          for (let i = 1; i < selectGroup.length; i++) {
            baseY = baseY + selectGroup[i - 1].height + flowConfig.defaultStyle.alignSpacing.vertical
            baseX = firstX + selectGroup[0].width - selectGroup[i].width
            let f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]
            f.tx = baseX
            f.ty = baseY
            that.plumb.animate(
              selectGroup[i].id,
              { top: baseY, left: baseX },
              {
                duration: flowConfig.defaultStyle.alignDuration,
                complete: function () {
                  f.x = f.tx
                  f.y = f.ty
                },
              }
            )
          }
        },
        levelUp() {
          const that = this
    
          if (!that.checkAlign()) return
          let nodeList = that.flowData.nodeList
          let selectGroup = that.currentSelectGroup
          let baseX = selectGroup[0].x
          let baseY = selectGroup[0].y
          for (let i = 1; i < selectGroup.length; i++) {
            baseX = baseX + selectGroup[i - 1].width + flowConfig.defaultStyle.alignSpacing.level
            let f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]
            f.tx = baseX
            f.ty = baseY
            that.plumb.animate(
              selectGroup[i].id,
              { top: baseY, left: baseX },
              {
                duration: flowConfig.defaultStyle.alignDuration,
                complete: function () {
                  f.x = f.tx
                  f.y = f.ty
                },
              }
            )
          }
        },
        levelCenter() {
          const that = this
    
          if (!that.checkAlign()) return
          let nodeList = that.flowData.nodeList
          let selectGroup = that.currentSelectGroup
          let baseX = selectGroup[0].x
          let baseY = selectGroup[0].y
          let firstY = baseY
          for (let i = 1; i < selectGroup.length; i++) {
            baseY = firstY + ZFSN.div(selectGroup[0].height, 2) - ZFSN.div(selectGroup[i].height, 2)
            baseX = baseX + selectGroup[i - 1].width + flowConfig.defaultStyle.alignSpacing.level
            let f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]
            f.tx = baseX
            f.ty = baseY
            that.plumb.animate(
              selectGroup[i].id,
              { top: baseY, left: baseX },
              {
                duration: flowConfig.defaultStyle.alignDuration,
                complete: function () {
                  f.x = f.tx
                  f.y = f.ty
                },
              }
            )
          }
        },
        levelDown() {
          const that = this
    
          if (!that.checkAlign()) return
          let nodeList = that.flowData.nodeList
          let selectGroup = that.currentSelectGroup
          let baseX = selectGroup[0].x
          let baseY = selectGroup[0].y
          let firstY = baseY
          for (let i = 1; i < selectGroup.length; i++) {
            baseY = firstY + selectGroup[0].height - selectGroup[i].height
            baseX = baseX + selectGroup[i - 1].width + flowConfig.defaultStyle.alignSpacing.level
            let f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]
            f.tx = baseX
            f.ty = baseY
            that.plumb.animate(
              selectGroup[i].id,
              { top: baseY, left: baseX },
              {
                duration: flowConfig.defaultStyle.alignDuration,
                complete: function () {
                  f.x = f.tx
                  f.y = f.ty
                },
              }
            )
          }
        },
        addRemark() {
          const that = this
          alert('添加备注(待完善)...')
        },
        copyNode() {
          const that = this
    
          that.clipboard = []
          if (that.currentSelectGroup.length > 0) {
            that.clipboard = Object.assign([], that.currentSelectGroup)
          } else if (that.currentSelect.id) {
            that.clipboard.push(that.currentSelect)
          }
        },
        getConnectionsByNodeId(nodeId) {
          const that = this
          let conns1 = that.plumb.getConnections({
            source: nodeId,
          })
          let conns2 = that.plumb.getConnections({
            target: nodeId,
          })
          return conns1.concat(conns2)
        },
        deleteNode() {
          const that = this
          let nodeList = that.flowData.nodeList
          let linkList = that.flowData.linkList
          let arr = []
    
          arr.push(Object.assign({}, that.currentSelect))
    
          arr.forEach(function (c, index) {
            let conns = that.getConnectionsByNodeId(c.id)
            conns.forEach(function (conn, index) {
              linkList.splice(
                linkList.findIndex((link) => link.sourceId == conn.sourceId || link.targetId == conn.targetId),
                1
              )
            })
            that.plumb.deleteEveryEndpoint()
            let inx = nodeList.findIndex((node) => node.id == c.id)
            nodeList.splice(inx, 1)
            that.$nextTick(() => {
              linkList.forEach(function (link, index) {
                let conn = that.plumb.connect({
                  source: link.sourceId,
                  target: link.targetId,
                  anchor: flowConfig.jsPlumbConfig.anchor.default,
                  connector: [
                    link.cls.linkType,
                    {
                      gap: 5,
                      cornerRadius: 8,
                      alwaysRespectStubs: true,
                    },
                  ],
                  paintStyle: {
                    stroke: link.cls.linkColor,
                    strokeWidth: link.cls.linkThickness,
                  },
                })
                if (link.label != '') {
                  conn.setLabel({
                    label: link.label,
                    cssClass: 'linkLabel',
                  })
                }
              })
            })
          })
          that.selectContainer()
        },
        addNewNode(node) {
          const that = this
    
          let x = that.mouse.position.x
          let y = that.mouse.position.y
          let nodePos = that.computeNodePos(x, y)
          x = nodePos.x
          y = nodePos.y
    
          let newNode = Object.assign({}, node)
          newNode.id = newNode.type + '-' + ZFSN.getId()
          newNode.height = 50
          if (newNode.type == 'start' || newNode.type == 'end' || newNode.type == 'event' || newNode.type == 'gateway') {
            newNode.x = x - 25
            newNode.width = 50
          } else {
            newNode.x = x - 60
            newNode.width = 120
          }
          newNode.y = y - 25
          if (newNode.type == 'x-lane') {
            newNode.height = 200
            newNode.width = 400
          } else if (newNode.type == 'y-lane') {
            newNode.height = 400
            newNode.width = 200
          }
          that.flowData.nodeList.push(newNode)
        },
        computeNodePos(x, y) {
          const pxx = flowConfig.defaultStyle.alignGridPX[0]
          const pxy = flowConfig.defaultStyle.alignGridPX[1]
          if (x % pxx) x = pxx - (x % pxx) + x
          if (y % pxy) y = pxy - (y % pxy) + y
          return {
            x: x,
            y: y,
          }
        },
        containerHandler() {
          const that = this
    
          that.selectContainer()
          let toolType = that.currentTool.type
          if (toolType == 'zoom-in') {
            that.enlargeContainer()
          } else if (toolType == 'zoom-out') {
            that.narrowContainer()
          }
        },
        selectContainer() {
          this.currentSelect = {}
          this.$emit('getShortcut')
        },
        isMultiple(callback) {
          callback(this.rectangleMultiple.flag)
        },
        updateNodePos() {
          const that = this
    
          let nodeList = that.flowData.nodeList
          that.currentSelectGroup.forEach(function (node, index) {
            let l = parseInt($('#' + node.id).css('left'))
            let t = parseInt($('#' + node.id).css('top'))
            let f = nodeList.filter((n) => n.id == node.id)[0]
            f.x = l
            f.y = t
          })
        },
        alignForLine(e) {
          const that = this
    
          if (that.selectGroup.length > 1) return
          if (that.container.auxiliaryLine.controlFnTimesFlag) {
            let elId = e.el.id
            let nodeList = that.flowData.nodeList
            nodeList.forEach(function (node, index) {
              if (elId != node.id) {
                let dis = flowConfig.defaultStyle.showAuxiliaryLineDistance,
                  elPos = e.pos,
                  elH = e.el.offsetHeight,
                  elW = e.el.offsetWidth,
                  disX = elPos[0] - node.x,
                  disY = elPos[1] - node.y
                if ((disX >= -dis && disX <= dis) || (disX + elW >= -dis && disX + elW <= dis)) {
                  that.container.auxiliaryLine.isShowYLine = true
                  that.auxiliaryLinePos.x = node.x + that.container.pos.left
                  let nodeMidPointX = node.x + node.width / 2
                  if (nodeMidPointX == elPos[0] + elW / 2) {
                    that.auxiliaryLinePos.x = nodeMidPointX + that.container.pos.left
                  }
                }
                if ((disY >= -dis && disY <= dis) || (disY + elH >= -dis && disY + elH <= dis)) {
                  that.container.auxiliaryLine.isShowXLine = true
                  that.auxiliaryLinePos.y = node.y + that.container.pos.top
                  let nodeMidPointY = node.y + node.height / 2
                  if (nodeMidPointY == elPos[1] + elH / 2) {
                    that.auxiliaryLinePos.y = nodeMidPointY + that.container.pos.left
                  }
                }
              }
            })
            that.container.auxiliaryLine.controlFnTimesFlag = false
            setTimeout(function () {
              that.container.auxiliaryLine.controlFnTimesFlag = true
            }, 200)
          }
        },
        hideAlignLine() {
          if (this.container.auxiliaryLine.isOpen) {
            this.container.auxiliaryLine.isShowXLine = false
            this.container.auxiliaryLine.isShowYLine = false
          }
        },
      },
      watch: {
        select(val) {
          this.currentSelect = val
          if (this.tempLinkId != '') {
            $('#' + this.tempLinkId).removeClass('link-active')
            this.tempLinkId = ''
          }
          if (this.currentSelect.type == 'link') {
            this.tempLinkId = this.currentSelect.id
            $('#' + this.currentSelect.id).addClass('link-active')
          }
        },
        currentSelect: {
          handler(val) {
            this.$emit('update:select', val)
          },
          deep: true,
        },
        selectGroup(val) {
          this.currentSelectGroup = val
          if (this.currentSelectGroup.length <= 0) this.plumb.clearDragSelection()
        },
        currentSelectGroup: {
          handler(val) {
            this.$emit('update:selectGroup', val)
          },
          deep: true,
        },
      },
    }
    </script>
    
    <style lang="less" scoped>
    @import '../style/flow-area.less';
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704
    • 705
    • 706
    • 707
    • 708
    • 709
    • 710
    • 711
    • 712
    • 713
    • 714
    • 715
    • 716
    • 717
    • 718
    • 719
    • 720
    • 721
    • 722
    • 723
    • 724
    • 725
    • 726
    • 727
    • 728
    • 729
    • 730
    • 731
    • 732
    • 733
    • 734
    • 735
    • 736
    • 737
    • 738
    • 739
    • 740
    • 741
    • 742
    • 743
    • 744
    • 745
    • 746
    • 747
    • 748
    • 749
    • 750
    • 751
    • 752
    • 753
    • 754
    • 755
    • 756
    • 757
    • 758
    • 759
    • 760
    • 761
    • 762
    • 763
    • 764
    • 765
    • 766
    • 767
    • 768
    • 769
    • 770
    • 771

    modules文件下的FlowAttr.vue文件代码如下

    <template>
      <div>
        <a-tabs
          size="small"
          defaultActiveKey="flow-attr"
          :activeKey="activeKey"
        >
          <a-tab-pane key="flow-attr">
            <span slot="tab">
              <a-icon type="cluster" />
              流程属性
            </span>
            <a-form layout="horizontal">
              <a-form-item
                label="流程id"
                :label-col="formItemLayout.labelCol"
                :wrapper-col="formItemLayout.wrapperCol"
              >
                <a-input
                  :value="flowData.attr.id"
                  disabled
                />
              </a-form-item>
            </a-form>
          </a-tab-pane>
          <a-tab-pane key="node-attr">
            <span slot="tab">
              <a-icon type="profile" />
              节点属性
            </span>
            <template v-if="currentSelect.type == 'start round mix'">
              <a-form layout="horizontal">
                <a-form-item
                  label="类型"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-tag color="purple">{{ currentSelect.type }}</a-tag>
                </a-form-item>
                <a-form-item
                  label="id"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    :value="currentSelect.id"
                    disabled
                  />
                </a-form-item>
                <a-form-item
                  label="名称"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    placeholder="请输入节点名称"
                    :value="currentSelect.name"
                    @change="nameChange"
                  />
                </a-form-item>
              </a-form>
            </template>
            <template v-if="currentSelect.type == 'end round'">
              <a-form layout="horizontal">
                <a-form-item
                  label="类型"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-tag color="purple">{{ currentSelect.type }}</a-tag>
                </a-form-item>
                <a-form-item
                  label="id"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    :value="currentSelect.id"
                    disabled
                  />
                </a-form-item>
                <a-form-item
                  label="名称"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    placeholder="请输入节点名称"
                    :value="currentSelect.name"
                    @change="nameChange"
                  />
                </a-form-item>
              </a-form>
            </template>
            <template v-if="currentSelect.type == 'node'">
              <a-form layout="horizontal">
                <a-form-item
                  label="类型"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-tag color="purple">{{ currentSelect.type }}</a-tag>
                </a-form-item>
                <a-form-item
                  label="id"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    :value="currentSelect.id"
                    disabled
                  />
                </a-form-item>
                <a-form-item
                  label="名称"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    placeholder="请输入节点名称"
                    :value="currentSelect.name"
                    @change="nameChange"
                  />
                </a-form-item>
                <!-- <a-form-item
                  label="驳回类型"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-select
                    v-model="setInfo.nodeRejectType"
                    @change="e => nodeRejectTypeChange(e)"
                  >
                    <a-select-option
                      v-for="(item,index) in nodeRejectType"
                      :key="index"
                      :value="item.id"
                    >{{ item.name }}</a-select-option>
                  </a-select>
                </a-form-item> -->
                <a-form-item
                  label="驳回节点"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-select
                    v-model="setInfo.nodeRejectStep"
                    @change="e => nodeRejectStepChange(e)"
                  >
                    <a-select-option
                      v-for="(item,index) in allNodeList"
                      :key="index"
                      :value="item.id"
                    >{{ item.name }}</a-select-option>
                  </a-select>
                </a-form-item>
                <!--  -->
                <a-form-item
                  label="会签方式"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-select
                    v-model="setInfo.nodeConfluenceType"
                    @change="e => nodeConfluenceTypeChange(e)"
                  >
                    <a-select-option
                      v-for="(item,index) in nodeConfluenceType"
                      :key="index"
                      :value="item.id"
                    >{{ item.name }}</a-select-option>
                  </a-select>
                </a-form-item>
                <a-form-item
                  label="回调URL"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    :value="setInfo.thirdPartyUrl "
                    @change="linkThirdPartyUrlChange"
                  />
                </a-form-item>
                <a-form-item
                  label="执行权限"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-select
                    :default-value="setInfo.nodeDesignate"
                    v-model="setInfo.nodeDesignate"
                    @change="e => nodeDesignateChange(e)"
                  >
                    <a-select-option
                      v-for="(item,index) in nodeDesignateData"
                      :key="index"
                      :value="item.id"
                    >{{ item.name }}</a-select-option>
                  </a-select>
                </a-form-item>
                <a-form-item
                  v-show="specialShow"
                  v-if="setInfo.nodeDesignate=='SPECIAL_USER'"
                  label="指定用户"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-col
                    :md="18"
                    :sm="18"
                  >
                    <a-input
                      disabled="disabled"
                      v-model="specialName"
                    />
                  </a-col>
                  <a-col
                    :md="6"
                    :sm="6"
                  >
                    <a-button
                      icon="search"
                      @click="setUser()"
                    />
                  </a-col>
                </a-form-item>
                <a-form-item
                  v-show="specialShow"
                  v-else
                  label="指定角色"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-col
                    :md="18"
                    :sm="18"
                  >
                    <a-input
                      disabled="disabled"
                      v-model="specialName"
                    />
                  </a-col>
                  <a-col
                    :md="6"
                    :sm="6"
                  >
                    <a-button
                      icon="search"
                      @click="setRole()"
                    />
                  </a-col>
                </a-form-item>
                <!-- <a-form-item
                  label="当前部门"
                  v-if="setInfo.nodeDesignate=='SPECIAL_ROLE'"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-switch
                    checkedChildren="是"
                    unCheckedChildren="否"
                    v-model="currentDepart"
                    @click="currentDepartChange"
                  />
                </a-form-item> -->
              </a-form>
            </template>
            <template v-else-if="currentSelect.type == 'fork'">
              <a-form layout="horizontal">
                <a-form-item
                  label="类型"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-tag color="purple">{{ currentSelect.type }}</a-tag>
                </a-form-item>
                <a-form-item
                  label="id"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    :value="currentSelect.id"
                    disabled
                  />
                </a-form-item>
                <a-form-item
                  label="名称"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    placeholder="请输入节点名称"
                    :value="currentSelect.name"
                    @change="nameChange"
                  />
                </a-form-item>
              </a-form>
            </template>
            <template v-else-if="currentSelect.type == 'join'">
              <a-form layout="horizontal">
                <a-form-item
                  label="类型"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-tag color="purple">{{ currentSelect.type }}</a-tag>
                </a-form-item>
                <a-form-item
                  label="id"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    :value="currentSelect.id"
                    disabled
                  />
                </a-form-item>
                <a-form-item
                  label="名称"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    placeholder="请输入节点名称"
                    :value="currentSelect.name"
                    @change="nameChange"
                  />
                </a-form-item>
                <!-- <a-form-item
                  label="驳回类型"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-select
                    v-model="setInfo.nodeRejectType"
                    @change="e => nodeRejectTypeChange(e)"
                  >
                    <a-select-option
                      v-for="(item,index) in nodeRejectType"
                      :key="index"
                      :value="item.id"
                    >{{ item.name }}</a-select-option>
                  </a-select>
                </a-form-item> -->
                <a-form-item
                  label="驳回节点"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-select
                    v-model="setInfo.nodeRejectStep"
                    @change="e => nodeRejectStepChange(e)"
                  >
                    <a-select-option
                      v-for="(item,index) in allNodeList"
                      :key="index"
                      :value="item.id"
                    >{{ item.name }}</a-select-option>
                  </a-select>
                </a-form-item>
                <a-form-item
                  label="会签方式"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-select
                    v-model="setInfo.nodeConfluenceType"
                    @change="e => nodeConfluenceTypeChange(e)"
                  >
                    <a-select-option
                      v-for="(item,index) in nodeConfluenceType"
                      :key="index"
                      :value="item.id"
                    >{{ item.name }}</a-select-option>
                  </a-select>
                </a-form-item>
                <a-form-item
                  label="回调URL"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    :value="setInfo.thirdPartyUrl"
                    @change="linkThirdPartyUrlChange"
                  />
                </a-form-item>
                <a-form-item
                  label="执行权限"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-select
                    :default-value="setInfo.nodeDesignate"
                    v-model="setInfo.nodeDesignate"
                    @change="e => nodeDesignateChange(e)"
                  >
                    <a-select-option
                      v-for="(item,index) in nodeDesignateData"
                      :key="index"
                      :value="item.id"
                    >{{ item.name }}</a-select-option>
                  </a-select>
                </a-form-item>
                <a-form-item
                  v-show="specialShow"
                  v-if="setInfo.nodeDesignate=='SPECIAL_USER'"
                  label="指定用户"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-col
                    :md="18"
                    :sm="18"
                  >
                    <a-input
                      disabled="disabled"
                      v-model="specialName"
                    />
                  </a-col>
                  <a-col
                    :md="6"
                    :sm="6"
                  >
                    <a-button
                      icon="search"
                      @click="setUser()"
                    />
                  </a-col>
                </a-form-item>
                <a-form-item
                  v-show="specialShow"
                  v-else
                  label="指定角色"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-col
                    :md="18"
                    :sm="18"
                  >
                    <a-input
                      disabled="disabled"
                      v-model="specialName"
                    />
                  </a-col>
                  <a-col
                    :md="6"
                    :sm="6"
                  >
                    <a-button
                      icon="search"
                      @click="setRole()"
                    />
                  </a-col>
                </a-form-item>
                <!-- <a-form-item
                  label="当前部门"
                  v-if="setInfo.nodeDesignate=='SPECIAL_ROLE'"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-switch
                    checkedChildren="是"
                    unCheckedChildren="否"
                    v-model="currentDepart"
                    @click="currentDepartChange"
                  />
                </a-form-item> -->
              </a-form>
            </template>
            <template v-else-if="currentSelect.type == 'x-lane' || currentSelect.type == 'y-lane'">
              <a-form layout="horizontal">
                <a-form-item
                  label="类型"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-tag color="purple">{{ currentSelect.type }}</a-tag>
                </a-form-item>
                <a-form-item
                  label="id"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    :value="currentSelect.id"
                    disabled
                  />
                </a-form-item>
                <a-form-item
                  label="名称"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-input
                    placeholder="请输入节点名称"
                    :value="currentSelect.name"
                    @change="nameChange"
                  />
                </a-form-item>
              </a-form>
            </template>
          </a-tab-pane>
          <a-tab-pane key="link-attr">
            <span slot="tab">
              <a-icon type="branches" />
              连线属性
            </span>
            <a-form layout="horizontal">
              <a-form-item
                label="id"
                :label-col="formItemLayout.labelCol"
                :wrapper-col="formItemLayout.wrapperCol"
              >
                <a-input
                  :value="currentSelect.id"
                  disabled
                />
              </a-form-item>
              <a-form-item
                label="源节点"
                :label-col="formItemLayout.labelCol"
                :wrapper-col="formItemLayout.wrapperCol"
              >
                <a-input
                  :value="currentSelect.sourceId"
                  disabled
                />
              </a-form-item>
              <a-form-item
                label="目标节点"
                :label-col="formItemLayout.labelCol"
                :wrapper-col="formItemLayout.wrapperCol"
              >
                <a-input
                  :value="currentSelect.targetId"
                  disabled
                />
              </a-form-item>
              <a-form-item
                label="文本"
                :label-col="formItemLayout.labelCol"
                :wrapper-col="formItemLayout.wrapperCol"
              >
                <a-input
                  :value="currentSelect.label"
                  @change="linkLabelChange"
                />
              </a-form-item>
              <a-form-item
                label="添加条件"
                :label-col="formItemLayout.labelCol"
                :wrapper-col="formItemLayout.wrapperCol"
              >
                <a-button
                  icon="plus"
                  @click="addList()"
                />
              </a-form-item>
              <div
                :key="i"
                v-for="(item,i) in compares"
              >
                <a-form-item
                  :label="'条件'+i"
                  :label-col="formItemLayout.labelCol"
                  :wrapper-col="formItemLayout.wrapperCol"
                >
                  <a-col
                    :md="10"
                    :sm="10"
                  >
                    <a-select
                      placeholder="关系"
                      v-model="compares[i].condition"
                      @change="e => conditionChange(i,e)"
                    >
                      <a-select-option
                        v-for="(condition,index) in conditions "
                        :key="index"
                        :value="condition.id"
                      >{{ condition.name }}</a-select-option>
                    </a-select>
                  </a-col>
                  <a-col
                    :md="10"
                    :sm="10"
                  >
                    <a-select
                      placeholder="属性"
                      v-model="compares[i].fieldName"
                      @change="e => fieldNameChange(i,e)"
                    >
                      <a-select-option
                        v-for="(fieldName,index) in fieldNames "
                        :key="index"
                        :value="fieldName.id"
                      >{{ fieldName.name }}</a-select-option>
                    </a-select>
                  </a-col>
                  <a-col
                    :md="4"
                    :sm="4"
                  >
                    <a-button
                      icon="minus"
                      @click="subList(i)"
                      v-if="compares.length>0"
                    />
                  </a-col>
                  <a-col
                    :md="10"
                    :sm="10"
                  >
                    <a-select
                      placeholder="比较"
                      v-model="compares[i].operation"
                      @change="e => operationChange(i,e)"
                    >
                      <a-select-option
                        v-for="(operation,index) in operations"
                        :key="index"
                        :value="operation.id"
                      >{{ operation.name }}</a-select-option>
                    </a-select>
                  </a-col>
                  <a-col
                    :md="10"
                    :sm="10"
                    v-if="compares[i].fieldName=='CreatedUserId'||compares[i].fieldName=='CreatedOrgId'"
                  >
                    <a-tooltip placement="topLeft">
                      <span
                        v-if="compares[i].valueName"
                        slot="title"
                      >
                        {{ compares[i].valueName }}
                      </span>
                      <template
                        v-else
                        slot="title"
                      ></template>
                      <div>
                        <a-input
                          :disabled="true"
                          v-model="compares[i].valueName"
                          clearable
                          placeholder="值"
                        />
                      </div>
                    </a-tooltip>
                  </a-col>
                  <a-col
                    :md="10"
                    :sm="10"
                    v-else
                  >
                    <a-input
                      v-model="compares[i].value"
                      clearable
                      placeholder="值"
                      @change="e => valueChange(i,e)"
                    />
                  </a-col>
                  <a-col
                    :md="4"
                    :sm="4"
                    v-if="compares[i].fieldName=='CreatedUserId'"
                  >
                    <a-button
                      icon="search"
                      @click="setUser(i)"
                      v-if="compares.length>0"
                    />
                  </a-col>
                  <a-col
                    :md="4"
                    :sm="4"
                    v-if="compares[i].fieldName=='CreatedOrgId'"
                  >
                    <a-button
                      icon="search"
                      @click="setRole(i)"
                      v-if="compares.length>0"
                    />
                  </a-col>
                </a-form-item>
              </div>
            </a-form>
          </a-tab-pane>
        </a-tabs>
      </div>
    </template>
    
    <script>
    import jsplumb from 'jsplumb'
    
    export default {
      props: ['plumb', 'flowData', 'select', 'fieldNames'],
      components: {
        jsplumb,
      },
      data() {
        return {
          currentSelect: this.select,
          formItemLayout: {
            labelCol: { span: 6 },
            wrapperCol: { span: 16 },
          },
          compares: this.select.compares,
          setInfo: this.select.setInfo,
          specialName: '',
          // currentDepart: false,
          operations: [
            { id: '>', name: '>' },
            { id: '<', name: '<' },
            { id: '>=', name: '>=' },
            { id: '<=', name: '<=' },
            { id: '=', name: '=' },
            { id: '!=', name: '!=' },
            { id: 'in', name: 'in' },
            { id: 'not in', name: 'not in' },
          ],
          conditions: [
            { id: 'and', name: '并且' },
            { id: 'or', name: '或者' },
          ],
          specialShow: false,
          nodeDesignateData: [
            { id: 'ALL_USER', name: '所有用户' },
            { id: 'SPECIAL_USER', name: '指定用户' },
            { id: 'SPECIAL_ROLE', name: '指定角色' },
            // { id: 'RUNTIME_SPECIAL_ROLE', name: '运行时指定角色' },
            // { id: 'RUNTIME_SPECIAL_USER', name: '运行时指定用户' },
          ],
          // 驳回类型
          // nodeRejectType: [
          //   { id: '0', name: '前一步' },
          //   { id: '1', name: '第一步' },
          // ],
          nodeConfluenceType: [
            { id: 'all', name: '全部通过' },
            { id: 'one', name: '至少有一个通过' },
          ],
          activeKey: 'flow-attr',
          currentCompare: null,
        }
      },
      methods: {
        nameChange(e) {
          this.currentSelect.name = e.target.value
          this.currentSelect.setInfo.nodeName = this.currentSelect.name
          this.currentSelect.setInfo.nodeCode = this.currentSelect.name
        },
        linkLabelChange(e) {
          const that = this
          let label = e.target.value
    
          that.currentSelect.label = label
          let conn = that.plumb.getConnections({
            source: that.currentSelect.sourceId,
            target: that.currentSelect.targetId,
          })[0]
          if (label != '') {
            conn.setLabel({
              label: label,
              cssClass: 'linkLabel',
            })
          } else {
            let labelOverlay = conn.getLabelOverlay()
            if (labelOverlay) conn.removeOverlay(labelOverlay.id)
          }
        },
        linkThirdPartyUrlChange(e) {
          const that = this
          let thirdPartyUrl = e.target.value
          that.currentSelect.setInfo.thirdPartyUrl = thirdPartyUrl
        },
        // 驳回类型切换
        // nodeRejectTypeChange(e) {
        //   const that = this
        //   let nodeRejectType = e
        //   that.setInfo.nodeRejectType = nodeRejectType
        //   that.currentSelect.setInfo.nodeRejectType = nodeRejectType
        // },
        nodeRejectStepChange(e) {
          const that = this
          let nodeRejectStep = e
          that.setInfo.nodeRejectStep = nodeRejectStep
          that.currentSelect.setInfo.nodeRejectStep = nodeRejectStep
        },
        nodeConfluenceTypeChange(e) {
          const that = this
          let nodeConfluenceType = e
          that.setInfo.nodeConfluenceType = nodeConfluenceType
          that.currentSelect.setInfo.nodeConfluenceType = nodeConfluenceType
        },
        addList() {
          const that = this
          let compares = that.compares
          compares.push({ fieldType: 'form', value: '', name: '', condition: 'and', valueName: '', operation: '=' })
          that.compares = compares
          that.currentSelect.compares = compares
        },
        subList(e) {
          const that = this
          let compares = that.compares
          if (compares.length == 1) {
            compares = [{ fieldType: 'form', value: '', name: '', condition: 'and', valueName: '', operation: '=' }]
          } else {
            compares.splice(e, 1)
          }
          that.compares = compares
          that.currentSelect.compares = compares
        },
        fieldNameChange(i, e) {
          const that = this
          const compares = that.compares
          compares[i].fieldName = e
          that.currentSelect.compares = compares
        },
        conditionChange(i, e) {
          const that = this
          const compares = that.compares
          compares[i].condition = e
          that.currentSelect.compares = compares
        },
        operationChange(i, e) {
          const that = this
          const compares = that.compares
          compares[i].operation = e
          that.currentSelect.compares = compares
        },
        valueChange(i, e) {
          const that = this
          const compares = that.compares
          that.currentSelect.compares = compares
        },
        //打开选择用户界面
        setUser(value) {
          const that = this
          if (that.currentSelect.type == 'link') {
            that.currentCompare = value
            this.$emit('openUser', null)
          } else {
            that.currentCompare = null
            this.$emit('openUser', {
              rowKeyList: that.setInfo.nodeDesignateData,
              rowDataList: this.setInfo.selectRows || [],
            })
          }
        },
        //打开选择角色界面
        setRole(value) {
          const that = this
          if (that.currentSelect.type == 'link') {
            that.currentCompare = value
            this.$emit('openUser', null)
          } else {
            that.currentCompare = null
            this.$emit('openRole', {
              rowKeyList: that.setInfo.nodeDesignateData,
              rowDataList: this.setInfo.selectRows || [],
            })
          }
        },
        setFlowAttrForm(record, type) {
          const that = this
          const nodeDesignateData = []
          const nodeDesignateName = []
          if (record.length) {
            record.forEach((item) => {
              nodeDesignateData.push(item.id)
              nodeDesignateName.push(item.name)
            })
          }
          if (that.currentSelect.type == 'link') {
            that.compares[that.currentCompare].value = nodeDesignateData.join(',')
            that.compares[that.currentCompare].valueName = nodeDesignateName.join(',')
            that.currentSelect.compares = that.compares
          } else {
            that.setInfo.selectRows = record.length > 0 ? record : []
            that.setInfo.nodeDesignateData = nodeDesignateData
            that.setInfo.nodeDesignateName = nodeDesignateName
            that.currentSelect.setInfo.nodeDesignateName = nodeDesignateName
            that.currentSelect.setInfo.nodeDesignateData = nodeDesignateData
            if (nodeDesignateName.length > 0) {
              that.specialName = nodeDesignateName.join(',')
            } else {
              that.specialName = ''
              that.setInfo.nodeDesignate = 'ALL_USER'
              this.currentSelect.setInfo.nodeDesignate = 'ALL_USER'
              this.specialShow = false
            }
          }
        },
        // currentDepartChange(e) {
        //   const that = this
        //   let currentDepart = e
        //   that.currentDepart = currentDepart
        //   that.setInfo.currentDepart = currentDepart
        //   that.currentSelect.setInfo = that.setInfo
        // },
        nodeDesignateChange(e) {
          const that = this
          let nodeDesignate = e
          that.setInfo.nodeDesignate = nodeDesignate
          that.setInfo.nodeDesignateData = []
          that.setInfo.nodeDesignateName = []
          that.setInfo.selectRows = []
          // that.setInfo.currentDepart = false
          // that.currentDepart = false
          that.specialName = ''
          if (nodeDesignate == 'SPECIAL_USER') {
            that.specialShow = true
          } else if (nodeDesignate == 'SPECIAL_ROLE') {
            that.specialShow = true
          } else {
            that.specialShow = false
          }
          that.currentSelect.setInfo.nodeDesignate = nodeDesignate
          that.currentSelect.setInfo.selectRows = []
        },
    
        // 线数据进行排序
        sortLinkList(linkList) {
          linkList.sort((next, pre) => {
            if (next.sourceId.includes('start')) {
              return -1 //next排到前面
            } else if (pre.targetId.includes('end')) {
              return -1 // pre排到后面
            } else if (next.targetId === pre.sourceId) {
              return -1 //pre排到前面
            } else {
              return 1 // 保持原有顺序
            }
          })
          return linkList
        },
    
        // 根据线数据顺序进行节点顺序排列
        sortNodeList(nodeList, linkList) {
          if (linkList.length) {
            const _newLinkList = linkList.map((item) => item.sourceId)
            _newLinkList.push(linkList[linkList.length - 1].targetId)
            nodeList.sort((next, pre) => {
              return _newLinkList.indexOf(next.id) - _newLinkList.indexOf(pre.id)
            })
            return nodeList
          }
        },
      },
      watch: {
        select(val) {
          console.log(val, '当前选择的节点')
          this.currentSelect = val
          if (this.currentSelect.type == 'link') {
            this.activeKey = 'link-attr'
            if (!this.currentSelect.compares || this.currentSelect.compares.length == 0) {
              this.currentSelect.compares = [
                { fieldType: 'form', value: '', name: '', condition: 'and', valueName: '', operation: '=' },
              ]
            }
            this.compares = this.currentSelect.compares
          } else if (!this.currentSelect.type) {
            this.activeKey = 'flow-attr'
          } else {
            this.activeKey = 'node-attr'
            if (this.currentSelect.type == 'node' || this.currentSelect.type == 'join') {
              if (!this.currentSelect.setInfo) {
                this.currentSelect.setInfo = {}
                this.currentSelect.setInfo.nodeCode = this.currentSelect.name
                this.currentSelect.setInfo.nodeName = this.currentSelect.name
              }
              if (!this.currentSelect.setInfo.nodeDesignate || this.currentSelect.setInfo.nodeDesignate == 'ALL_USER') {
                this.currentSelect.setInfo.nodeDesignate = 'ALL_USER'
                this.specialShow = false
                this.specialName = ''
              }
    
              // 驳回节点没有值 ---给默认值
              if (!this.currentSelect.setInfo.nodeRejectStep && this.allNodeList && this.allNodeList.length) {
                this.currentSelect.setInfo.nodeRejectStep = this.allNodeList[this.allNodeList.length - 1].id
              }
              if (!this.currentSelect.setInfo.nodeConfluenceType) {
                this.currentSelect.setInfo.nodeConfluenceType = 'all'
              }
              if (
                this.currentSelect.setInfo.nodeDesignate == 'SPECIAL_USER' ||
                this.currentSelect.setInfo.nodeDesignate == 'SPECIAL_ROLE'
              ) {
                this.specialShow = true
                this.specialName = this.currentSelect.setInfo.nodeDesignateName.join(',')
              }
              this.setInfo = this.currentSelect.setInfo
            }
          }
        },
        currentSelect: {
          handler(val) {
            this.$emit('update:select', val)
          },
          deep: true,
        },
      },
      computed: {
        allNodeList() {
          console.log(this.flowData, 'this.flowData---this.flowData')
          const linkList = this.sortLinkList(this.flowData.linkList)
          let nodeList = this.flowData.nodeList
          if (linkList.length) {
            const _newLinkList = linkList.map((item) => item.sourceId)
            _newLinkList.push(linkList[linkList.length - 1].targetId)
            nodeList.sort((next, pre) => {
              return _newLinkList.indexOf(next.id) - _newLinkList.indexOf(pre.id)
            })
            if (this.select && this.select.id) {
              const _index = nodeList.findIndex((v) => v.id === this.select.id)
              nodeList = nodeList.slice(0, _index)
            }
            console.log(nodeList, 'nodeList----nodeList')
            return nodeList
          }
        },
      },
    }
    </script>
    
    <style lang="less" scoped>
    @import '../style/flow-attr.less';
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704
    • 705
    • 706
    • 707
    • 708
    • 709
    • 710
    • 711
    • 712
    • 713
    • 714
    • 715
    • 716
    • 717
    • 718
    • 719
    • 720
    • 721
    • 722
    • 723
    • 724
    • 725
    • 726
    • 727
    • 728
    • 729
    • 730
    • 731
    • 732
    • 733
    • 734
    • 735
    • 736
    • 737
    • 738
    • 739
    • 740
    • 741
    • 742
    • 743
    • 744
    • 745
    • 746
    • 747
    • 748
    • 749
    • 750
    • 751
    • 752
    • 753
    • 754
    • 755
    • 756
    • 757
    • 758
    • 759
    • 760
    • 761
    • 762
    • 763
    • 764
    • 765
    • 766
    • 767
    • 768
    • 769
    • 770
    • 771
    • 772
    • 773
    • 774
    • 775
    • 776
    • 777
    • 778
    • 779
    • 780
    • 781
    • 782
    • 783
    • 784
    • 785
    • 786
    • 787
    • 788
    • 789
    • 790
    • 791
    • 792
    • 793
    • 794
    • 795
    • 796
    • 797
    • 798
    • 799
    • 800
    • 801
    • 802
    • 803
    • 804
    • 805
    • 806
    • 807
    • 808
    • 809
    • 810
    • 811
    • 812
    • 813
    • 814
    • 815
    • 816
    • 817
    • 818
    • 819
    • 820
    • 821
    • 822
    • 823
    • 824
    • 825
    • 826
    • 827
    • 828
    • 829
    • 830
    • 831
    • 832
    • 833
    • 834
    • 835
    • 836
    • 837
    • 838
    • 839
    • 840
    • 841
    • 842
    • 843
    • 844
    • 845
    • 846
    • 847
    • 848
    • 849
    • 850
    • 851
    • 852
    • 853
    • 854
    • 855
    • 856
    • 857
    • 858
    • 859
    • 860
    • 861
    • 862
    • 863
    • 864
    • 865
    • 866
    • 867
    • 868
    • 869
    • 870
    • 871
    • 872
    • 873
    • 874
    • 875
    • 876
    • 877
    • 878
    • 879
    • 880
    • 881
    • 882
    • 883
    • 884
    • 885
    • 886
    • 887
    • 888
    • 889
    • 890
    • 891
    • 892
    • 893
    • 894
    • 895
    • 896
    • 897
    • 898
    • 899
    • 900
    • 901
    • 902
    • 903
    • 904
    • 905
    • 906
    • 907
    • 908
    • 909
    • 910
    • 911
    • 912
    • 913
    • 914
    • 915
    • 916
    • 917
    • 918
    • 919
    • 920
    • 921
    • 922
    • 923
    • 924
    • 925
    • 926
    • 927
    • 928
    • 929
    • 930
    • 931
    • 932
    • 933
    • 934
    • 935
    • 936
    • 937
    • 938
    • 939
    • 940
    • 941
    • 942
    • 943
    • 944
    • 945
    • 946
    • 947
    • 948
    • 949
    • 950
    • 951
    • 952
    • 953
    • 954
    • 955
    • 956
    • 957
    • 958
    • 959
    • 960
    • 961
    • 962
    • 963
    • 964
    • 965
    • 966
    • 967
    • 968
    • 969
    • 970
    • 971
    • 972
    • 973
    • 974
    • 975
    • 976
    • 977
    • 978
    • 979
    • 980
    • 981
    • 982
    • 983
    • 984
    • 985
    • 986
    • 987
    • 988
    • 989
    • 990
    • 991
    • 992
    • 993
    • 994
    • 995
    • 996
    • 997
    • 998
    • 999
    • 1000
    • 1001
    • 1002
    • 1003
    • 1004
    • 1005
    • 1006
    • 1007
    • 1008
    • 1009
    • 1010
    • 1011
    • 1012
    • 1013
    • 1014
    • 1015
    • 1016
    • 1017
    • 1018
    • 1019
    • 1020
    • 1021
    • 1022
    • 1023
    • 1024
    • 1025
    • 1026
    • 1027
    • 1028
    • 1029
    • 1030
    • 1031
    • 1032
    • 1033
    • 1034
    • 1035

    modules文件下的FlowNode.vue文件代码如下

    <template>
      <div
        v-if="node.type == 'start round mix'"
        :id="node.id"
        class="common-circle-node"
        :class="{ active: isActive() }"
        :style="{ top: node.y + 'px', left: node.x + 'px',
        	cursor: currentTool.type == 'drag' ? 'move' : (currentTool.type == 'connection' ? 'crosshair' :
        																								(currentTool.type == 'zoom-in' ? 'zoom-in' :
        																								(currentTool.type == 'zoom-out' ? 'zoom-out' : 'default'))),
          background:verificationStyle[!!activityId?'1':'4'] }"
        @click.stop="selectNode"
        @contextmenu.stop="showNodeContextMenu"
      >
        <a-icon type="play-circle" />
        {{ node.name }}
      </div>
    
      <div
        v-else-if="node.type == 'end round'"
        :id="node.id"
        class="common-circle-node"
        :class="{ active: isActive() }"
        :style="{ top: node.y + 'px', left: node.x + 'px',
        	cursor: currentTool.type == 'drag' ? 'move' : (currentTool.type == 'connection' ? 'crosshair' :
        																								(currentTool.type == 'zoom-in' ? 'zoom-in' :
        																								(currentTool.type == 'zoom-out' ? 'zoom-out' : 'default'))),
          background:verificationStyle[!!activityId&&activityId==node.id?'0':(!!node.setInfo&&!!node.setInfo.Taged?node.setInfo.Taged.toString():'4')] }"
        @click.stop="selectNode"
        @contextmenu.stop="showNodeContextMenu"
      >
        <a-icon type="close-circle" />
        {{ node.name }}
      </div>
    
      <div
        v-else-if="node.type == 'node'"
        :id="node.id"
        class="common-rectangle-node"
        :class="{ active: isActive() }"
        :style="{ top: node.y + 'px', left: node.x + 'px',
        		cursor: currentTool.type == 'drag' ? 'move' : (currentTool.type == 'connection' ? 'crosshair' :
        																								(currentTool.type == 'zoom-in' ? 'zoom-in' :
        																								(currentTool.type == 'zoom-out' ? 'zoom-out' : 'default'))),
          background:verificationStyle[!!activityId&&activityId==node.id?'0':(!!node.setInfo&&!!node.setInfo.Taged?node.setInfo.Taged.toString():'4')] }"
        @click.stop="selectNode"
        @contextmenu.stop="showNodeContextMenu"
      >
        <a-icon type="setting" />
        {{ node.name }}
      </div>
    
      <div
        v-else-if="node.type == 'fork'"
        :id="node.id"
        class="common-rectangle-node"
        :class="{ active: isActive() }"
        :style="{ top: node.y + 'px', left: node.x + 'px',
        		cursor: currentTool.type == 'drag' ? 'move' : (currentTool.type == 'connection' ? 'crosshair' :
        																								(currentTool.type == 'zoom-in' ? 'zoom-in' :
        																								(currentTool.type == 'zoom-out' ? 'zoom-out' : 'default'))),
          background:verificationStyle[!!activityId&&activityId==node.id?'0':(!!node.setInfo&&!!node.setInfo.Taged?node.setInfo.Taged.toString():'4')] }"
        @click.stop="selectNode"
        @contextmenu.stop="showNodeContextMenu"
      >
        <a-icon type="fullscreen" />
        {{ node.name }}
      </div>
    
      <div
        v-else-if="node.type == 'join'"
        :id="node.id"
        class="common-rectangle-node"
        :class="{ active: isActive() }"
        :style="{ top: node.y + 'px', left: node.x + 'px',
        		cursor: currentTool.type == 'drag' ? 'move' : (currentTool.type == 'connection' ? 'crosshair' :
        																								(currentTool.type == 'zoom-in' ? 'zoom-in' :
        																								(currentTool.type == 'zoom-out' ? 'zoom-out' : 'default'))),
          background:verificationStyle[!!activityId&&activityId==node.id?'0':(!!node.setInfo&&!!node.setInfo.Taged?node.setInfo.Taged.toString():'4')] }"
        @click.stop="selectNode"
        @contextmenu.stop="showNodeContextMenu"
      >
        <a-icon type="fullscreen-exit" />
        {{ node.name }}
      </div>
    
      <div
        v-else-if="node.type == 'x-lane'"
        :id="node.id"
        class="common-x-lane-node"
        :class="{ active: isActive() }"
        :style="{ top: node.y + 'px', left: node.x + 'px', height: node.height + 'px', width: node.width + 'px',
        		cursor: currentTool.type == 'zoom-in' ? 'zoom-in' : (currentTool.type == 'zoom-out' ? 'zoom-out' : 'default') }"
      >
        <div
          class="lane-text-div"
          :style="{ cursor: currentTool.type == 'drag' ? 'move' : 'default' }"
          @click.stop="selectNode"
          @contextmenu.stop="showNodeContextMenu"
        >
          <span class="lane-text">{{ node.name }}</span>
        </div>
      </div>
    
      <div
        v-else-if="node.type == 'y-lane'"
        :id="node.id"
        class="common-y-lane-node"
        :class="{ active: isActive() }"
        :style="{ top: node.y + 'px', left: node.x + 'px', height: node.height + 'px', width: node.width + 'px',
        		cursor: currentTool.type == 'zoom-in' ? 'zoom-in' : (currentTool.type == 'zoom-out' ? 'zoom-out' : 'default') }"
      >
        <div
          class="lane-text-div"
          :style="{ cursor: currentTool.type == 'drag' ? 'move' : 'default' }"
          @click.stop="selectNode"
          @contextmenu.stop="showNodeContextMenu"
        >
          <span class="lane-text">{{ node.name }}</span>
        </div>
      </div>
    
      <div v-else></div>
    </template>
    
    
    <script>
    import jsplumb from 'jsplumb'
    import { flowConfig } from '../config/args-config.js'
    import $ from 'jquery'
    import 'jquery-ui/ui/widgets/draggable'
    import 'jquery-ui/ui/widgets/droppable'
    import 'jquery-ui/ui/widgets/resizable'
    import { ZFSN } from '../util/ZFSN.js'
    
    export default {
      props: ['select', 'selectGroup', 'node', 'plumb', 'currentTool', 'activityId'],
      components: {
        jsplumb,
      },
      mounted() {
        this.registerNode()
      },
      data() {
        return {
          currentSelect: this.select,
          currentSelectGroup: this.selectGroup,
          verificationStyle: flowConfig.verificationStyle,
        }
      },
      methods: {
        registerNode() {
          const that = this
          that.plumb.draggable(that.node.id, {
            containment: 'parent',
            handle: function (e, el) {
              var possibles = el.parentNode.querySelectorAll(
                '.common-circle-node,.common-rectangle-node,.common-diamond-node,.lane-text-div'
              )
              for (var i = 0; i < possibles.length; i++) {
                if (possibles[i] === el || e.target.className == 'lane-text') return true
              }
              return false
            },
            grid: flowConfig.defaultStyle.alignGridPX,
            drag: function (e) {
              if (flowConfig.defaultStyle.isOpenAuxiliaryLine) {
                that.$emit('alignForLine', e)
              }
            },
            stop: function (e) {
              that.node.x = e.pos[0]
              that.node.y = e.pos[1]
              if (that.currentSelectGroup.length > 1) {
                that.$emit('updateNodePos')
              }
              that.$emit('hideAlignLine')
            },
          })
    
          if (that.node.type == 'x-lane' || that.node.type == 'y-lane') {
            $('#' + that.node.id).resizable({
              minHeight: 200,
              minWidth: 200,
              maxHeight: 2000,
              maxWidth: 2000,
              stop: function (event, ui) {
                that.node.height = ui.size.height
                that.node.width = ui.size.width
              },
            })
          }
          that.currentSelect = that.node
          that.currentSelectGroup = []
        },
        selectNode() {
          const that = this
          that.currentSelect = this.node
          that.$emit('isMultiple', (flag) => {
            if (!flag) {
              that.currentSelectGroup = []
            } else {
              let f = that.currentSelectGroup.filter((s) => s.id == that.node.id)
              if (f.length <= 0) {
                that.plumb.addToDragSelection(that.node.id)
                that.currentSelectGroup.push(that.node)
              }
            }
          })
        },
        showNodeContextMenu(e) {
          this.$emit('showNodeContextMenu', e)
          this.selectNode()
        },
        isActive() {
          const that = this
          if (that.currentSelect.id == that.node.id) return true
          let f = that.currentSelectGroup.filter((n) => n.id == that.node.id)
          if (f.length > 0) return true
          return false
        },
      },
      watch: {
        select(val) {
          this.currentSelect = val
        },
        currentSelect: {
          handler(val) {
            this.$emit('update:select', val)
          },
          deep: true,
        },
        selectGroup(val) {
          this.currentSelectGroup = val
        },
        currentSelectGroup: {
          handler(val) {
            this.$emit('update:selectGroup', val)
          },
          deep: true,
        },
      },
    }
    </script>
    
    <style lang="less" scoped>
    @import '../style/flow-node.less';
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249

    modules文件下Settingmodal.vue文件代码如下

    <template>
    	<div>
    		<a-drawer
    			title="设置"
    			placement="left"
    			:width="600"
    			:visible="settingVisible"
    			@close="close">
    			
    			<a-form 
    				:form="settingForm"
    				layout="horizontal">
    				
    				<a-divider orientation="left">画布</a-divider>
    				<a-form-item label="缩小比例" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
    					<a-slider 
    						:min="0.05" 
    						:max="0.5"
    						:step="0.05" 
    						:tipFormatter="formatterContainerOnceNarrow" 
    						v-decorator="['containerOnceNarrow', {}]"
    						@afterChange="setContainerOnceNarrow" />
    				</a-form-item>
    				<a-form-item label="放大比例" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
    					<a-slider 
    						:min="0.05" 
    						:max="0.5"
    						:step="0.05" 
    						:tipFormatter="formatterContainerOnceEnlarge" 
    						v-decorator="['containerOnceEnlarge', {}]"
    						@afterChange="setContainerOnceEnlarge" />
    				</a-form-item>
    				
    				<a-divider orientation="left">连线</a-divider>
    				<a-form-item label="类型" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
    					<a-select v-decorator="['linkType', {}]" @change="setFlowType">
    						<a-select-option value="Bezier">贝塞尔曲线</a-select-option>
    						<a-select-option value="Straight">直线</a-select-option>
    						<a-select-option value="Flowchart">流程图线</a-select-option>
    						<a-select-option value="StateMachine">状态线</a-select-option>
    					</a-select>
    				</a-form-item>
    				<a-form-item label="颜色" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
    					<colorPicker v-model="linkColor" @change="setLinkColor" />
    				</a-form-item>
    				<a-form-item label="粗细" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
    					<a-slider 
    						:min="1" 
    						:max="10"
    						v-decorator="['linkThickness', {}]"
    						@afterChange="setStrokeWidth" />
    				</a-form-item>
    				
    				<a-divider orientation="left">默认样式</a-divider>
    				<a-form-item label="辅助线" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
    					<a-switch 
    						:checked="isOpenAuxiliaryLine"
    						v-decorator="['isOpenAuxiliaryLine', {}]" 
    						checkedChildren="开" 
    						unCheckedChildren="关" 
    						@change='toggleOpenAuxiliaryLine'/>
    				</a-form-item>
    				<a-form-item label="自动对齐水平间距" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
    					<a-slider 
    						:min="10" 
    						:max="800" 
    						:step="5" 
    						v-decorator="['alignLevelDistance', {}]" 
    						@afterChange="setAlignLevelDistance" />
    				</a-form-item>
    				<a-form-item label="自动对齐垂直间距" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
    					<a-slider 
    						:min="10" 
    						:max="800" 
    						:step="5" 
    						v-decorator="['alignVerticalDistance', {}]" 
    						@afterChange="setAlignVerticalDistance" />
    				</a-form-item>
    				<a-form-item label="微移距离" :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol">
    					<a-slider 
    						:min="1" 
    						v-decorator="['movePx', {}]" 
    						@afterChange="setMovePx" />
    				</a-form-item>
    			</a-form>
    		</a-drawer>
    	</div>
    </template>
    
    <script>
    	import { flowConfig } from '../config/args-config.js'
    	
    	export default {
    		data () {
    			return {
    				settingVisible: false,
    				formItemLayout: {
    					labelCol: { span: 6 },
    					wrapperCol: { span: 15 }
    				},
    				initFlag: false,
    				settingForm: this.$form.createForm(this),
    				isOpenAuxiliaryLine: flowConfig.defaultStyle.isOpenAuxiliaryLine,
    				linkColor: flowConfig.jsPlumbInsConfig.PaintStyle.stroke
    			}
    		},
    		methods: {
    			init () {
    				const that = this;
    				that.$nextTick(() => {
    					that.settingForm.setFieldsValue({
    						movePx: flowConfig.defaultStyle.movePx,
    						linkType: flowConfig.jsPlumbInsConfig.Connector[0],
    						linkThickness: flowConfig.jsPlumbInsConfig.PaintStyle.strokeWidth,
    						alignLevelDistance: flowConfig.defaultStyle.alignSpacing.level,
    						alignVerticalDistance: flowConfig.defaultStyle.alignSpacing.vertical,
    						containerOnceNarrow: flowConfig.defaultStyle.containerScale.onceNarrow,
    						containerOnceEnlarge: flowConfig.defaultStyle.containerScale.onceEnlarge
    					});
    				});
    			},
    			open () {
    				this.settingVisible = true;
    				if (!this.initFlag) {
    					this.init();
    					this.initFlag = true;
    				}
    			},
    			close () {
    				this.settingVisible = false;
    			},
    			setFlowType (v) {
    				flowConfig.jsPlumbInsConfig.Connector[0] = v;
    			},
    			toggleOpenAuxiliaryLine (flag) {
    				this.isOpenAuxiliaryLine = flag;
    				flowConfig.defaultStyle.isOpenAuxiliaryLine = flag;
    			},
    			setMovePx (v) {
    				flowConfig.defaultStyle.movePx = v;
    			},
    			setLinkColor (v) {
    				this.linkColor = v;
    				flowConfig.jsPlumbInsConfig.PaintStyle.stroke = v;
    			},
    			setStrokeWidth (v) {
    				flowConfig.jsPlumbInsConfig.PaintStyle.strokeWidth = v;
    			},
    			setAlignLevelDistance (v) {
    				flowConfig.defaultStyle.alignSpacing.level = v;
    			},
    			setAlignVerticalDistance (v) {
    				flowConfig.defaultStyle.alignSpacing.vertical = v;
    			},
    			formatterContainerOnceNarrow (v) {
    				return `${v*100}%`;
    			},
    			setContainerOnceNarrow (v) {
    				flowConfig.defaultStyle.containerScale.onceNarrow = v;
    			},
    			formatterContainerOnceEnlarge (v) {
    				return `${v*100}%`;
    			},
    			setContainerOnceEnlarge (v) {
    				flowConfig.defaultStyle.containerScale.onceEnlarge = v;
    			}
    		}
    	}
    </script>
    
    <style>
    	.m-colorPicker .box {
    		z-index: 9999 !important;
    		width: 220px !important;
    	}
    	
    	.ant-divider-horizontal.ant-divider-with-text, .ant-divider-horizontal.ant-divider-with-text-left, .ant-divider-horizontal.ant-divider-with-text-right {
    		font-weight: 800;
    		margin: 24px 0 4px;
    	}
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181

    modules文件下ShortcutModal.vue文件代码如下

    <template>
    	<a-modal 
    		title="快捷键大全"
    		width="50%"
    		:visible="modalVisible"
    		okText="确认"
    		cancelText="取消"
    		@ok="saveSetting"
    		@cancel="cancel">
    		<a-table
    			rowKey="code"
    			:columns="columns"
    			:dataSource="dataSource">
    		</a-table>
    	</a-modal>
    </template>
    
    <script>
    	import { flowConfig } from '../config/args-config.js'
    	
    	export default {
    		data () {
    			return {
    				modalVisible: false,
    				columns: [
    					{
    						title: '功能',
    						align: 'center',
    						key: 'shortcutName',
    						dataIndex: 'shortcutName',
    						width: '50%'
    					},
    					{
    						title: '快捷键',
    						align: 'center',
    						key: 'codeName',
    						dataIndex: 'codeName',
    						width: '50%'
    					}
    				],
    				dataSource: []
    			}
    		},
    		methods: {
    			open () {
    				const that = this;
    				
    				that.modalVisible = true;
    				let obj = Object.assign({}, flowConfig.shortcut);
    				for (let k in obj) {
    					that.dataSource.push(obj[k]);
    				}
    			},
    			close () {
    				this.dataSource = [];
    				this.modalVisible = false;
    			},
    			saveSetting () {
    				this.close();
    			},
    			cancel () {
    				this.close();
    			}
    		}
    	}
    </script>
    
    <style>
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    modules文件下TestModal.vue文件代码如下

    <template>
    	<div>
    		<a-drawer
    			title="JSON"
    			placement="right"
    			:width="600"
    			:visible="testVisible"
    			@close="onClose">
    			
    			<div>当前的flowData:</div>
    			<json-view 
    				:value="flowData"
    				:expand-depth=3
    				boxed
    				copyable/>
    			
    			<div style="margin-top: 12px;">暂存:</div>
    			<a-textarea :autosize="{ minRows: 10, maxRows: 100 }" :value="flowDataJson" @change="editFlowDataJson" />
    			
    			<a-divider />
    			<a-button @click="onLoad">加载</a-button>
    			<a-button @click="tempSave" :style="{ marginRight: '8px' }" type="primary">暂存</a-button>
    		</a-drawer>
    	</div>
    </template>
    
    <script>
    	import JsonView from 'vue-json-viewer'
    	import { flowConfig } from '../config/args-config.js'
    	
    	export default {
    		components: {
    			JsonView
    		},
    		data () {
    			return {
    				testVisible: false,
    				flowData: null,
    				flowDataJson: ''
    			}
    		},
    		methods: {
    			onClose () {
    				this.testVisible = false;
    			},
    			editFlowDataJson (e) {
    				this.flowDataJson = e.target.value;
    			},
    			tempSave () {
    				let tempObj = Object.assign({}, this.flowData);
    				tempObj.status = flowConfig.flowStatus.SAVE;
    				this.flowDataJson = JSON.stringify(tempObj);
    			},		
    			clearData () {
    				this.$emit('clear123',this.flowDataJson);
    			},
    			onLoad () {
    				this.clearData();
    				setTimeout(() => {
    					this.$emit('loadFlow', this.flowDataJson);
    					this.onClose();
    				}, 100)
    			}
    		}
    	}
    </script>
    
    <style>
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    config文件下args-config.js文件代码如下

    export let flowConfig = {
    	jsPlumbInsConfig: {
    		Connector: [
    			"Flowchart",
    			{
    				gap: 5,
    				cornerRadius: 8,
    				alwaysRespectStubs: true
    			}
    		],
    		ConnectionOverlays: [
    			[
    				'Arrow',
    				{
    					width: 10, 
    					length: 10, 
    					location: 1
    				}
    			]
    		],
    		PaintStyle: {
    			stroke: "#2a2929",
    			strokeWidth: 2
    		},
    		HoverPaintStyle: {
    			stroke: "#409EFF",
    			strokeWidth: 3
    		},
    		EndpointStyle: {
    			fill: "#456",
    			stroke: "#2a2929",
    			strokeWidth: 1,
    			radius: 3
    		},
    		EndpointHoverStyle: {
    			fill: "pink"
    		}
    	},
    	jsPlumbConfig: {
    		anchor: {
    			default: ["Bottom", "Right", "Top", "Left"]
    		},
    		conn: {
    			isDetachable: false
    		},
    		makeSourceConfig: {
    			filter: "a",
                filterExclude: true,
                maxConnections: -1,
                endpoint: [ "Dot", { radius: 7 } ],
                anchor: ["Bottom", "Right", "Top", "Left"]
    		},
    		makeTargetConfig: {
    			filter: "a",
                filterExclude: true,
                maxConnections: -1,
                endpoint: [ "Dot", { radius: 7 } ],
                anchor: ["Bottom", "Right", "Top", "Left"]
    		}
    	},
    	defaultStyle: {
    		dragOpacity: 0.7,
    		alignGridPX: [5, 5],
    		alignSpacing: {
    			level: 100,
    			vertical: 100
    		},
    		alignDuration: 300,
    		containerScale: {
    			init: 1,
    			min: 0.5,
    			max: 3,
    			onceNarrow: 0.1,
    			onceEnlarge: 0.1
    		},
    		isOpenAuxiliaryLine: true,
    		showAuxiliaryLineDistance: 20,
    		movePx: 5,
    		photoBlankDistance: 200
    	},
    	// ID的生成类型。1.uuid uuid 2.time_stamp 时间戳 3.sequence 序列 4.time_stamp_and_sequence 时间戳加序列 5.custom 自定义
    	idType: 'uuid',
    	flowStatus: {
    		CREATE: '0',
    		SAVE: '1',
    		MODIFY: '2',
    		LOADING: '3'
    	},
    	shortcut: {
    		multiple: {
    			code: 17,
    			codeName: 'CTRL',
    			shortcutName: '多选',
    		},
    		dragContainer: {
    			code: 32,
    			codeName: 'SPACE',
    			shortcutName: '画布拖拽',
    		},
    		scaleContainer: {
    			code: 18,
    			codeName: 'ALT(firefox下为SHIFT)',
    			shortcutName: '画布缩放',
    		},
    		dragTool: {
    			code: 68,
    			codeName: 'D',
    			shortcutName: '拖拽工具',
    		},
    		connTool: {
    			code: 76,
    			codeName: 'L',
    			shortcutName: '连线工具',
    		},
    		zoomInTool: {
    			code: 190,
    			codeName: '<',
    			shortcutName: '放大工具',
    		},
    		zoomOutTool: {
    			code: 188,
    			codeName: '>',
    			shortcutName: '缩小工具',
    		},
    		leftMove: {
    			code: 37,
    			codeName: '←',
    			shortcutName: '左移',
    		},
    		upMove: {
    			code: 38,
    			codeName: '↑',
    			shortcutName: '上移',
    		},
    		rightMove: {
    			code: 39,
    			codeName: '→',
    			shortcutName: '右移',
    		},
    		downMove: {
    			code: 40,
    			codeName: '↓',
    			shortcutName: '下移',
    		},
    		testModal: {
    			code: 84,
    			codeName: 'CTRL+ALT+P',
    			shortcutName: '打开测试页面',
    		}
    	},
    	contextMenu: {
    		container: {
    			menuName: 'flow-menu',
    			axis: {
    				x: null,
    				y: null
    			},
    			menulists: [
    				// {
    				// 	fnHandler: 'flowInfo',
    				// 	icoName: 'edit',
    				// 	btnName: '流程图信息'
    				// },
    				{
    					fnHandler: 'paste',
    					icoName: 'edit',
    					btnName: '粘贴'
    		        },
    		        {
    		        	fnHandler: 'selectAll',
    					icoName: 'edit',
    					btnName: '全选'
    		        },
    		        // {
    		        // 	fnHandler: 'saveFlow',
    				// 	icoName: 'edit',
    				// 	btnName: '保存流程'
    		        // },
    		        // {
    		        // 	iconName: 'edit',
    		        // 	fnHandler: 'addRemark',
    		        // 	btnName: '添加备注'
    		        // },
    		        {
    					icoName: 'edit',
    					btnName: '对齐方式',
    					children: [
    						{
    							icoName: 'edit',
    	                        fnHandler: 'verticaLeft',
    	                        btnName: '垂直左对齐'
    						},
    						{
    							icoName: 'edit',
    	                        fnHandler: 'verticalCenter',
    	                        btnName: '垂直居中'
    						},
    						{
    							icoName: 'edit',
    	                        fnHandler: 'verticalRight',
    	                        btnName: '垂直右对齐'
    						},
    						{
    							icoName: 'edit',
    	                        fnHandler: 'levelUp',
    	                        btnName: '水平上对齐'
    						},
    						{
    							icoName: 'edit',
    	                        fnHandler: 'levelCenter',
    	                        btnName: '水平居中'
    						},
    						{
    							icoName: 'edit',
    	                        fnHandler: 'levelDown',
    	                        btnName: '水平下对齐'
    						}
    					]
    		        }
    			]
    		},
    		node: {
    			menuName: 'node-menu',
    			axis: {
    				x: null,
    				y: null
    			},
    			menulists: [
    				{
    					fnHandler: 'copyNode',
    					icoName: 'edit',
    					btnName: '复制节点'
    				},
    				{
    					fnHandler: 'deleteNode',
    					icoName: 'edit',
    					btnName: '删除节点'
    				}
    			]
    		},
    		link: {
    			menuName: 'link-menu',
    			axis: {
    				x: null,
    				y: null
    			},
    			menulists: [
    				{
    					fnHandler: 'deleteLink',
    					icoName: 'edit',
    					btnName: '删除连线'
    				}
    			]
    		}
    	},
    	verificationStyle:{0:"#5bc0de",//正在处理
    								1:"#7ccb7c",//已完成
    								2:"#d9534f",//不同意
    								3:"#faad14",//驳回或者撤回
    								4:"#f4f6fc"},//还未处理
    	flowLineAdditions:[{id:'CreatedUserId',name:'申请人'},
    						{id:'CreatedOrgId',name:'所属组织'}]//连线条件额外参数
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264

    config文件下basic-node-config.js文件代码如下

    export const tools = [
    	{
    		type: 'drag',
    		icon: 'drag',
    		name: '拖拽'
    	},
    	{
    		type: 'connection',
    		icon: 'fork',
    		name: '连线'
    	},
    	{
    		type: 'zoom-in',
    		icon: 'zoom-in',
    		name: '放大'
    	},
    	{
    		type: 'zoom-out',
    		icon: 'zoom-out',
    		name: '缩小'
    	}
    ];
    
    export const commonNodes = [
    	{
    		type: 'start round mix',
    		name: '开始',
    		icon: 'play-circle'
    	},
    	{
    		type: 'end round',
    		name: '结束',
    		icon: 'close-circle'
    	},
    	{
    		type: 'node',
    		name: '任务节点',
    		icon: 'setting'
    	},
    	{
    		type: 'fork',
    		name: '会签开始',
    		icon: 'fullscreen'
    	},
    	{
    		type: 'join',
    		name: '会签结束',
    		icon: 'fullscreen-exit'
    	}
    ];
    
    export const laneNodes = [
    	{
    		type: 'x-lane',
    		name: '横向泳道',
    		icon: 'column-width'
    	},
    	{
    		type: 'y-lane',
    		name: '纵向泳道',
    		icon: 'column-height'
    	}
    ];
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    util文件下ZFSN.js文件代码如下

    import { flowConfig } from '../config/args-config.js'
    
    export let ZFSN = {
    	seqNo: 1,
    	consoleLog: function(strArr) {
    		let log = '';
    		for (let i = 0, len = strArr.length; i < len; i++) {
    			log += strArr[i] + '\n';
    		}
    		//console.log('%c' + log, 'color: red; font-weight: bold;');
    	},
    	getId: function() {
    		let idType = flowConfig.idType;
    		if (typeof idType == 'string') {
    			if (idType == 'uuid') {
    				return this.getUUID();
    			} else if (idType == 'time_stamp') {
    				return this.getTimeStamp();
    			}
    		} else if (idType instanceof Array) {
    			if (idType[0] == 'time_stamp_and_sequence') {
    				return this.getSequence(idType[1]);
    			} else if (idType[0] == 'time_stamp_and_sequence') {
    				return this.getTimeStampAndSequence(idType[1]);
    			} else if (idType[0] == 'custom') {
    				return idType[1]();
    			}
    		}
    	},
    	getUUID: function() {
    		let s = [];
    		let hexDigits = "0123456789abcdef";
    		for(let i = 0; i < 36; i++) {
    			s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    		}
    		s[14] = "4";
    		s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
    		s[8] = s[13] = s[18] = s[23] = "-";
    
    		let uuid = s.join("");
    		return uuid.replace(/-/g, '');
    	},
    	getTimeStamp: function() {
    		return new Date().getTime();
    	},
    	getSequence: function(seqNoLength) {
    		let zeroStr = new Array(seqNoLength).fill('0').join('');
    		return (zeroStr + (this.seqNo++)).slice(-seqNoLength);
    	},
    	getTimeStampAndSequence: function(seqNoLength) {
    		return this.getTimeStamp() + this.getSequence(seqNoLength);
    	},
    	add: function(a, b) {
    		let c, d, e;
    		try {
    			c = a.toString().split(".")[1].length;
    		} catch (f) {
    			c = 0;
    		}
    		try {
    			d = b.toString().split(".")[1].length;
    		} catch (f) {
    			d = 0;
    		}
    		return e = Math.pow(10, Math.max(c, d)), (this.mul(a, e) + this.mul(b, e)) / e;
    	},
    	sub: function(a, b) {
    		let c, d, e;
    		try {
    			c = a.toString().split(".")[1].length;
    		} catch (f) {
    			c = 0;
    		}
    		try {
    			d = b.toString().split(".")[1].length;
    		} catch (f) {
    			d = 0;
    		}
    		return e = Math.pow(10, Math.max(c, d)), (this.mul(a, e) - this.mul(b, e)) / e;
    	},
    	mul: function(a, b) {
    		let c = 0, d = a.toString(), e = b.toString();
    		try {
    			c += d.split(".")[1].length;
    		} catch (f) {}
    		try {
    			c += e.split(".")[1].length;
    		} catch (f) {}
    		return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
    	},
    	div: function(a, b) {
    		let c, d, e = 0, f = 0;
    		try {
    			e = a.toString().split(".")[1].length;
    		} catch (g) {}
    		try {
    			f = b.toString().split(".")[1].length;
    		} catch (g) {}
    		return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), this.mul(c / d, Math.pow(10, f - e));
    	}
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    style文件下flow-area.less文件代码如下

    @active-color: #409EFF;
    
    .btn-wrapper-simple {
        height: 24px !important;
        line-height: 24px !important;
    }
    .vue-contextmenu-listWrapper {
        padding-left: 1px !important;
    }
    .child-ul-wrapper {
        padding-left: 1px !important;
    }
    
    .flow-container {
        width: 1000%;
        height: 1000%;
        position: relative;
        transition: transform 0.5s ease 0s,transform-origin 0.5s ease 0s;
        
        &.grid {
            background-image: -webkit-linear-gradient(90deg, rgba(235, 235, 235, 1) 5%, rgba(0, 0, 0, 0) 5%);
            background-image: -moz-linear-gradient(90deg, rgba(235, 235, 235, 1) 5%, rgba(0, 0, 0, 0) 5%);
            background-image: -o-linear-gradient(90deg, rgba(235, 235, 235, 1) 5%, rgba(0, 0, 0, 0) 5%);
            background-image: -webkit-gradient(linear, 0 100%, 0 0, color-stop(0.05, rgba(235, 235, 235, 1)), color-stop(0.05, rgba(0, 0, 0, 0)));
            background-image: linear-gradient(90deg, rgba(235, 235, 235, 1) 5%, rgba(0, 0, 0, 0) 5%),linear-gradient(rgba(235, 235, 235, 1) 5%, rgba(0, 0, 0, 0) 5%);
            background-size: 1rem 1rem;
        }
        
        &.zoomIn {
            cursor: zoom-in;
        }
        &.zoomOut {
            cursor: zoom-out;
        }
        &.canScale {
            cursor: url(../assets/search.png), default;
        }
        &.canDrag {
            cursor: grab;
        }
        &.canMultiple {
            cursor: url(../assets/multip-pointer.png), default;
        }
    }
    
    .rectangle-multiple {
        position: absolute;
        border: 1px dashed #31676f;
        background-color: #0cceea29;
    }
    
    .flow-container-active {
        background-color: #e4e4e438;
        cursor: crosshair;
    }
    
    .auxiliary-line-x {
        position: absolute;
        border: 0.5px solid @active-color;
        width: 100%;
        z-index: 9999;
    }
    .auxiliary-line-y {
        position: absolute;
        border: 0.5px solid @active-color;
        height: 100%;
        z-index: 9999;
    }
    
    .link-active {
        outline: 2px dashed @active-color;
    }
    
    .container-scale {
        position: absolute;
        top: 0;
        left: 5px;
    }
    
    .mouse-position {
        position: absolute;
        bottom: 0;
        right: 5px;
    }
    
    .common-remarks {
        width: 100px;
        height: 150px;
        position: absolute;
        background-color: #ffffaa;
    }
    ::v-deep.customMultiMenuClass {
      .context-menu-list{
        .btn-wrapper-simple{
          height: auto;
        }
        .has-child{
          .float-status-2{
            padding-left: 0;
          }
        }
      }
      // .float-status-2 {
      //   padding-left: 0;
      //   .btn-wrapper-simple {
      //     height: auto;
      //   }
      // }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110

    style文件下flow-designer.less文件代码如下

    @primary-color: #409EFF;
    
    .container {
        border: 2px solid #e4e7ed;
        height: 100%;
        
        moz-user-select: -moz-none;
        -moz-user-select: none;
        -o-user-select:none;
        -khtml-user-select:none;
        -webkit-user-select:none;
        -ms-user-select:none;
        user-select:none;
    }
    
    .select-area {
        border-right: 1px solid #e4e7ed;
    }
    
    .header-option {
        background: white;
        height: 36px;
        line-height: 36px;
        border-bottom: 2px solid #e4e7ed;
        text-align: right;
    }
    
    .header-option-button {
        border: 0;
        margin-left: 8px;
    }
    
    .flowContent {
        background: #fafafa;
        height: 100%;
        border: 2px dashed rgba(170,170,170,0.7);
    }
    
    .ant-layout-footer {
        padding: 4px 8px;
    }
    .foot {
        height: auto;
        text-align: center;
    }
    
    .attr-area {
        border-left: 1px solid #e4e7ed;
        min-height:350px;
    }
    
    .tag {
        margin: 6px;
    }
    
    .tool-item {
        background: #f4f6fc;
        height: 32px;
        line-height: 32px;
        margin: 5px;
        padding-left: 8px;
        text-align: center;
        cursor: pointer;
        
        &:hover{
            background: #d2d3d6;
        }
        
        &.active {
            background: black;
        }
    }
    
    .node-item {
        background: #f4f6fc;
        height: 32px;
        line-height: 32px;
        margin: 5px;
        padding-left: 8px;
        text-align: left;
        cursor: move;
        min-width: 80px;
        
        &:hover{
            color: @primary-color;
            outline: 1px dashed @primary-color;
        }
    }
    
    .ant-list-grid .ant-list-item {
        margin-bottom: 8px;
    }
    
    .linkLabel {
        background-color: white;
        padding: 1px;
        border: 1px solid #346789;
        border-radius: 5px;
        opacity: 0.8;
        z-index: 3;
    }
    ::v-deep.customMenuClass {
      padding-left: 0;
    
      .context-menu-list {
        .btn-wrapper-simple {
          height: auto;
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110

    style文件下flow-node.less文件代码如下

    @common-node-bg: #f4f6fc;
    @common-node-bg-hover: #f4f6fcb0;
    @common-node-active: #409EFF;
    
    .common-circle-node {
        position: absolute;
        height: 50px;
        width: 100px;
        line-height: 50px;
        text-align: center;
        border: 1px solid #777;
        border-radius: 100px;
        background-color: @common-node-bg;
        white-space: nowrap;
        &:hover{
            background-color: @common-node-bg-hover;
            z-index: 2;
        }
    
        &.active {
            outline: 2px dashed @common-node-active;
            outline-offset: 0px;
        }
    }
    
    .common-rectangle-node {
        position: absolute;
        height: 50px;
        width: 120px;
        line-height: 50px;
        text-align: center;
        border: 1px solid #777;
        border-radius: 5px;
        background-color: @common-node-bg;
        white-space: nowrap;
    
        &:hover {
            background-color: @common-node-bg-hover;
            z-index: 2;
        }
    
        &.active {
            outline: 2px dashed @common-node-active;
            outline-offset: 0px;
        }
    }
    
    .common-diamond-node {
        position: absolute;
        height: 50px;
        width: 50px;
        line-height: 50px;
        text-align: center;
        border: 1px solid #777;
        border-radius: 3px;
        background-color: @common-node-bg;
        transform: rotate(45deg);
        white-space: nowrap;
    
        &:before {
            position: absolute;
            content: '网关';
            transform: rotate(-45deg);
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
        }
    
        &:hover {
            background-color: @common-node-bg-hover;
            z-index: 2;
        }
    
        &.active {
            outline: 2px dashed @common-node-active;
            outline-offset: 0px;
        }
    }
    
    .common-x-lane-node {
        position: absolute;
        text-align: center;
        border: 1px solid #777;
        border-radius: 2px;
        z-index: -1;
    
        &.active {
            outline: 2px dashed @common-node-active;
            outline-offset: 0px;
            .ui-resizable-se{
                z-index: 90;
                width: 8px;
                height: 8px;
                border: 1px;
                right: -5px;
                bottom: -5px;
                cursor: se-resize;
                position:absolute; 
            }
            .ui-resizable-s{
                z-index: 90;
                width: 100%;
                height: 15px;
                border: 1px;
                right: 5px;
                bottom: -5px;
                cursor: s-resize;
                position:absolute; 
            }
            .ui-resizable-e{
                z-index: 90;
                width: 15px;
                height: 100%;
                border: 1px;
                right: -5px;
                bottom: 5px;
                cursor: e-resize;
                position:absolute; 
            }
        }
    
        .lane-text-div {
            width: 18px;
            height: 100%;
            position: absolute;
            display: table;
            border-right: 1px solid #777;
            background-color: @common-node-bg;
    
            &:hover {
                z-index: 2;
            }
    
            .lane-text {
                word-wrap: break-word;
                display: table-cell;
                vertical-align: middle;
                font-size: 0.8em;
            }
        }
    }
    
    .common-y-lane-node {
        position: absolute;
        text-align: center;
        border: 1px solid #777;
        border-radius: 2px;
        z-index: -1;
    
        &.active {
            outline: 2px dashed @common-node-active;
            outline-offset: 0px;
            .ui-resizable-se{
                z-index: 90;
                width: 8px;
                height: 8px;
                border: 1px;
                right: -5px;
                bottom: -5px;
                cursor: se-resize;
                position:absolute; 
            }
            .ui-resizable-s{
                z-index: 90;
                width: 100%;
                height: 15px;
                border: 1px;
                right: 5px;
                bottom: -5px;
                cursor: s-resize;
                position:absolute; 
            }
            .ui-resizable-e{
                z-index: 90;
                width: 15px;
                height: 100%;
                border: 1px;
                right: -5px;
                bottom: 5px;
                cursor: e-resize;
                position:absolute; 
            }
        }
    
        .lane-text-div {
            width: 100%;
            height: 18px;
            position: absolute;
            display: table;
            border-bottom: 1px solid #777;
            background-color: @common-node-bg;
    
            &:hover {
                z-index: 2;
            }
    
            .lane-text {
                word-wrap: break-word;
                display: table-cell;
                font-size: 0.8em;
            }
        }
    }
    
    .node-icon {
        position: absolute;
        top: 3px;
        left: 3px;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
  • 相关阅读:
    AliLinux的使用Docker初始化服务(详细)
    Linux系统中安装Redis-7.0.4
    由于找不到packet.dll,无法继续执行代码的多种解决方法分享
    ns-3-model-library wifi 浅析_ns-3wifi部分解析_ns-3网络模拟器wifi部分文档分析_Part3
    Fish Shell 的使用特性和优势
    如何确保海外服务器的高可用性?
    Vue Router最佳实践,以确保你的Vue.js应用的路由管理清晰、可维护和高效
    第三十七章 构建数据库应用程序 - 在页面上使用对象
    webgl着色器学习 - webpack 打包glsl文件
    各大AI模型训练成本大比拼
  • 原文地址:https://blog.csdn.net/weixin_45324044/article/details/132764181