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

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

1.简单操作如下

在这里插入图片描述

2.弹框中使用组件:

 	<vfdref="vfd"style="background-color: white;":needShow="true":fieldNames="fieldNames"@openUser="openUser"@openRole="openRole"></vfd>

3.组件的文件结构:

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

<template><div style="height: 60vh"><a-layout class="container"><a-layout-siderv-show="needShow"width="200"theme="light"class="select-area"><a-row style="padding:5px"><a-checkable-tagv-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-buttonv-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-tagv-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-itemv-for="(commonNode, index) in field.commonNodes":key="index"><divclass="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-tagv-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-itemv-for="(laneNode, index) in field.laneNodes":key="index"><divclass="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-headerv-show="needShow"class="header-option"style="background-color:#fff;padding-right: 10px;"><a-popconfirmtitle="确认要重新绘制吗?"placement="bottom"okText="确认"cancelText="取消"@confirm="clear"><a-tooltiptitle="重新绘制"placement="bottom"><a-buttonclass="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-tooltiptitle="设置"placement="bottom"><a-button@click="setting"class="header-option-button"size="small"icon="setting"></a-button></a-tooltip><a-tooltiptitle="JSON"placement="bottom"><a-button@click="openTest"class="header-option-button"size="small"icon="save"></a-button></a-tooltip><a-popconfirmtitle="请选择帮助项:"placement="bottom"okType="default"okText="快捷键大全"cancelText="使用文档"@confirm="shortcutHelper"@cancel="usingDoc"><a-iconslot="icon"type="question-circle-o"style="color: red"/><a-tooltiptitle="帮助"placement="bottom"><a-buttonclass="header-option-button"size="small"icon="book"></a-button></a-tooltip></a-popconfirm></a-layout-header><a-layout-content class="flowContent"><flow-arearef="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-menuclass="customMenuClass":contextMenuData="linkContextMenuData"@deleteLink="deleteLink"></vue-context-menu></a-layout-content></a-layout><a-layout-siderwidth="300"theme="light"class="attr-area"@mousedown.stop="loseShortcut"><flow-attrref="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-modalref="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 = thisthat.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.userAgentlet isOpera = userAgent.indexOf('Opera') > -1if (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 = thisthat.browserType = that.getBrowserType()if (that.browserType == 2) {flowConfig.shortcut.scaleContainer = {code: 16,codeName: 'SHIFT(chrome下为ALT)',shortcutName: '画布缩放',}}},initJsPlumb() {const that = thisthat.plumb = jsPlumb.getInstance(flowConfig.jsPlumbInsConfig)that.plumb.bind('beforeDrop', function (info) {let sourceId = info.sourceIdlet targetId = info.targetIdif (sourceId == targetId) return falselet 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.canvaslet o = {},id,labelif (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.idlabel = l.label}connObj.id = ido.type = 'link'o.id = ido.sourceId = conn.sourceIdo.targetId = conn.targetIdo.label = labelo.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 || eevent.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 = thisdocument.onkeydown = function (e) {let event = window.event || eif (!that.activeShortcut) returnlet key = event.keyCodeswitch (key) {case flowConfig.shortcut.multiple.code:that.$refs.flowArea.rectangleMultiple.flag = truebreakcase flowConfig.shortcut.dragContainer.code:that.$refs.flowArea.container.dragFlag = truebreakcase flowConfig.shortcut.scaleContainer.code:that.$refs.flowArea.container.scaleFlag = truebreakcase flowConfig.shortcut.dragTool.code:that.selectTool('drag')breakcase flowConfig.shortcut.connTool.code:that.selectTool('connection')breakcase flowConfig.shortcut.zoomInTool.code:that.selectTool('zoom-in')breakcase flowConfig.shortcut.zoomOutTool.code:that.selectTool('zoom-out')breakcase 37:that.moveNode('left')breakcase 38:that.moveNode('up')breakcase 39:that.moveNode('right')breakcase 40:that.moveNode('down')break}}document.onkeyup = function (e) {let event = window.event || elet key = event.keyCodeif (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.eventif (e) {e.returnValue = '关闭提示'}return '关闭提示'}},initFlow() {const that = thisif (that.flowData.status == flowConfig.flowStatus.CREATE) {that.flowData.attr.id = 'flow-' + ZFSN.getId()} else {that.loadFlow()}ZFSN.consoleLog(['初始化流程图成功...'])},loadFlow(json) {const that = thissetTimeout(() => {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.attrthat.flowData.config = loadData.configthat.flowData.status = flowConfig.flowStatus.LOADINGthat.plumb.batch(function () {let nodeList = loadData.nodeListlet areaList = loadData.areaListnodeList.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.linkListthat.$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 = nullswitch (belongto) {case 'commonNodes':node = commonNodes.filter((n) => n.type == type)breakcase '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()breakcase 'connection':this.changeToConnection()breakcase 'zoom-in':this.changeToZoomIn()breakcase 'zoom-out':this.changeToZoomOut()break}},changeToDrag() {const that = thisthat.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 = thisthat.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 = thislet nodeList = that.flowData.nodeListlet linkList = that.flowData.linkListlet 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 = areaListlinkList.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 = thisif (!that.checkFlow()) returnlet flowObj = Object.assign({}, that.flowData)flowObj.status = flowConfig.flowStatus.SAVElet d = JSON.stringify(flowObj)//this.$message.success('保存流程成功!请查看控制台。');return d},cancelDownLoadFlowPicture() {this.flowPicture.url = ''this.flowPicture.modalVisible = false},clear() {const that = thisthat.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.showGridif (flag) {this.flowData.config.showGrid = falsethis.flowData.config.showGridText = '显示网格'this.flowData.config.showGridIcon = 'eye-invisible'} else {this.flowData.config.showGrid = truethis.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 || eevent.preventDefault()event.stopPropagation()$('.vue-contextmenuName-flow-menu').css('display', 'none')$('.vue-contextmenuName-node-menu').css('display', 'none')let x = event.clientXlet y = event.clientYthis.linkContextMenuData.axis = { x, y }},deleteLink() {const that = thislet sourceId = that.currentSelect.sourceIdlet targetId = that.currentSelect.targetIdthat.plumb.deleteConnection(that.plumb.getConnections({source: sourceId,target: targetId,})[0])let linkList = that.flowData.linkListlinkList.splice(linkList.findIndex((link) => link.sourceId == sourceId || link.targetId == targetId),1)that.currentSelect = {}},loseShortcut() {this.activeShortcut = false},getShortcut() {this.activeShortcut = true},openTest() {const that = thislet flowObj = Object.assign({}, that.flowData)that.$refs.testModal.flowData = flowObjthat.$refs.testModal.testVisible = true},moveNode(type) {const that = thislet m = flowConfig.defaultStyle.movePx,isX = trueswitch (type) {case 'left':m = -mbreakcase 'up':m = -misX = falsebreakcase 'right':breakcase '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>

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

FlowArea.vue代码如下

<template><div style="width: 100%; height: 100%; overflow: hidden; position: relative;"><divv-if="container.auxiliaryLine.isOpen && container.auxiliaryLine.isShowXLine"class="auxiliary-line-x":style="{ top: auxiliaryLinePos.y + 'px' }"></div><divv-if="container.auxiliaryLine.isOpen && container.auxiliaryLine.isShowYLine"class="auxiliary-line-y":style="{ left: auxiliaryLinePos.x + 'px' }"></div><divid="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-nodev-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><divclass="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-menuclass="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-menuclass="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: {//每个框架不同,不能用-3000top: -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 = thisthat.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 = thislet event = window.event || eif (event.button == 0) {if (that.container.dragFlag) {that.mouse.tempPos = that.mouse.positionthat.container.draging = true}that.currentSelectGroup = []if (that.rectangleMultiple.flag) {that.mouse.tempPos = that.mouse.positionthat.rectangleMultiple.multipling = true}}},mousemoveHandler(e) {const that = thislet event = window.event || eif (event.target.id == 'flowContainer') {that.mouse.position = {x: event.offsetX,y: event.offsetY,}} else {let cn = event.target.classNamelet tn = event.target.tagNameif (cn != 'lane-text' && cn != 'lane-text-div' && tn != 'svg' && tn != 'path' && tn != 'I') {that.mouse.position.x = event.target.offsetLeft + event.offsetXthat.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 = 0if (nLeft >= 0) nLeft = 0that.container.pos = {top: nTop,left: nLeft,}}if (that.rectangleMultiple.multipling) {let h = that.mouse.position.y - that.mouse.tempPos.ylet w = that.mouse.position.x - that.mouse.tempPos.xlet t = that.mouse.tempPos.ylet l = that.mouse.tempPos.xif (h >= 0 && w < 0) {w = -wl -= w} else if (h < 0 && w >= 0) {h = -ht -= h} else if (h < 0 && w < 0) {h = -hw = -wt -= hl -= w}that.rectangleMultiple.height = hthat.rectangleMultiple.width = wthat.rectangleMultiple.position.top = tthat.rectangleMultiple.position.left = l}},mouseupHandler() {const that = thisif (that.container.draging) that.container.draging = falseif (that.rectangleMultiple.multipling) {that.judgeSelectedNode()that.rectangleMultiple.multipling = falsethat.rectangleMultiple.width = 0that.rectangleMultiple.height = 0}},judgeSelectedNode() {const that = thislet ay = that.rectangleMultiple.position.toplet ax = that.rectangleMultiple.position.leftlet by = ay + that.rectangleMultiple.heightlet bx = ax + that.rectangleMultiple.widthlet nodeList = that.flowData.nodeListnodeList.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 = thislet event = window.event || eif (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 = thisthat.container.scaleOrigin.x = that.mouse.position.xthat.container.scaleOrigin.y = that.mouse.position.ylet newScale = ZFSN.add(that.container.scale, flowConfig.defaultStyle.containerScale.onceEnlarge)if (newScale <= flowConfig.defaultStyle.containerScale.max) {that.container.scale = newScalethat.container.scaleShow = ZFSN.mul(that.container.scale, 100)that.plumb.setZoom(that.container.scale)}},narrowContainer() {const that = thisthat.container.scaleOrigin.x = that.mouse.position.xthat.container.scaleOrigin.y = that.mouse.position.ylet newScale = ZFSN.sub(that.container.scale, flowConfig.defaultStyle.containerScale.onceNarrow)if (newScale >= flowConfig.defaultStyle.containerScale.min) {that.container.scale = newScalethat.container.scaleShow = ZFSN.mul(that.container.scale, 100)that.plumb.setZoom(that.container.scale)}},showContainerContextMenu(e) {let event = window.event || eevent.preventDefault()$('.vue-contextmenuName-node-menu').css('display', 'none')$('.vue-contextmenuName-link-menu').css('display', 'none')this.selectContainer()let x = event.clientXlet y = event.clientYthis.containerContextMenuData.axis = { x, y }},showNodeContextMenu(e) {let event = window.event || eevent.preventDefault()$('.vue-contextmenuName-flow-menu').css('display', 'none')$('.vue-contextmenuName-link-menu').css('display', 'none')let x = event.clientXlet y = event.clientYthis.nodeContextMenuData.axis = { x, y }},flowInfo() {const that = thislet nodeList = that.flowData.nodeListlet linkList = that.flowData.linkListalert('当前流程图中有 ' + nodeList.length + ' 个节点,有 ' + linkList.length + ' 条连线。')},paste() {const that = thislet dis = 0that.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.xnewNode.y = nodePos.ydis += 20that.flowData.nodeList.push(newNode)})},selectAll() {const that = thisthat.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 = thisif (!that.checkAlign()) returnlet nodeList = that.flowData.nodeListlet selectGroup = that.currentSelectGrouplet baseX = selectGroup[0].xlet baseY = selectGroup[0].yfor (let i = 1; i < selectGroup.length; i++) {baseY = baseY + selectGroup[i - 1].height + flowConfig.defaultStyle.alignSpacing.verticallet f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]f.tx = baseXf.ty = baseYthat.plumb.animate(selectGroup[i].id,{ top: baseY, left: baseX },{duration: flowConfig.defaultStyle.alignDuration,complete: function () {f.x = f.txf.y = f.ty},})}},verticalCenter() {const that = thisif (!that.checkAlign()) returnlet nodeList = that.flowData.nodeListlet selectGroup = that.currentSelectGrouplet baseX = selectGroup[0].xlet baseY = selectGroup[0].ylet firstX = baseXfor (let i = 1; i < selectGroup.length; i++) {baseY = baseY + selectGroup[i - 1].height + flowConfig.defaultStyle.alignSpacing.verticalbaseX = 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 = baseXf.ty = baseYthat.plumb.animate(selectGroup[i].id,{ top: baseY, left: baseX },{duration: flowConfig.defaultStyle.alignDuration,complete: function () {f.x = f.txf.y = f.ty},})}},verticalRight() {const that = thisif (!that.checkAlign()) returnlet nodeList = that.flowData.nodeListlet selectGroup = that.currentSelectGrouplet baseX = selectGroup[0].xlet baseY = selectGroup[0].ylet firstX = baseXfor (let i = 1; i < selectGroup.length; i++) {baseY = baseY + selectGroup[i - 1].height + flowConfig.defaultStyle.alignSpacing.verticalbaseX = firstX + selectGroup[0].width - selectGroup[i].widthlet f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]f.tx = baseXf.ty = baseYthat.plumb.animate(selectGroup[i].id,{ top: baseY, left: baseX },{duration: flowConfig.defaultStyle.alignDuration,complete: function () {f.x = f.txf.y = f.ty},})}},levelUp() {const that = thisif (!that.checkAlign()) returnlet nodeList = that.flowData.nodeListlet selectGroup = that.currentSelectGrouplet baseX = selectGroup[0].xlet baseY = selectGroup[0].yfor (let i = 1; i < selectGroup.length; i++) {baseX = baseX + selectGroup[i - 1].width + flowConfig.defaultStyle.alignSpacing.levellet f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]f.tx = baseXf.ty = baseYthat.plumb.animate(selectGroup[i].id,{ top: baseY, left: baseX },{duration: flowConfig.defaultStyle.alignDuration,complete: function () {f.x = f.txf.y = f.ty},})}},levelCenter() {const that = thisif (!that.checkAlign()) returnlet nodeList = that.flowData.nodeListlet selectGroup = that.currentSelectGrouplet baseX = selectGroup[0].xlet baseY = selectGroup[0].ylet firstY = baseYfor (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.levellet f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]f.tx = baseXf.ty = baseYthat.plumb.animate(selectGroup[i].id,{ top: baseY, left: baseX },{duration: flowConfig.defaultStyle.alignDuration,complete: function () {f.x = f.txf.y = f.ty},})}},levelDown() {const that = thisif (!that.checkAlign()) returnlet nodeList = that.flowData.nodeListlet selectGroup = that.currentSelectGrouplet baseX = selectGroup[0].xlet baseY = selectGroup[0].ylet firstY = baseYfor (let i = 1; i < selectGroup.length; i++) {baseY = firstY + selectGroup[0].height - selectGroup[i].heightbaseX = baseX + selectGroup[i - 1].width + flowConfig.defaultStyle.alignSpacing.levellet f = nodeList.filter((n) => n.id == selectGroup[i].id)[0]f.tx = baseXf.ty = baseYthat.plumb.animate(selectGroup[i].id,{ top: baseY, left: baseX },{duration: flowConfig.defaultStyle.alignDuration,complete: function () {f.x = f.txf.y = f.ty},})}},addRemark() {const that = thisalert('添加备注(待完善)...')},copyNode() {const that = thisthat.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 = thislet conns1 = that.plumb.getConnections({source: nodeId,})let conns2 = that.plumb.getConnections({target: nodeId,})return conns1.concat(conns2)},deleteNode() {const that = thislet nodeList = that.flowData.nodeListlet linkList = that.flowData.linkListlet 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 = thislet x = that.mouse.position.xlet y = that.mouse.position.ylet nodePos = that.computeNodePos(x, y)x = nodePos.xy = nodePos.ylet newNode = Object.assign({}, node)newNode.id = newNode.type + '-' + ZFSN.getId()newNode.height = 50if (newNode.type == 'start' || newNode.type == 'end' || newNode.type == 'event' || newNode.type == 'gateway') {newNode.x = x - 25newNode.width = 50} else {newNode.x = x - 60newNode.width = 120}newNode.y = y - 25if (newNode.type == 'x-lane') {newNode.height = 200newNode.width = 400} else if (newNode.type == 'y-lane') {newNode.height = 400newNode.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) + xif (y % pxy) y = pxy - (y % pxy) + yreturn {x: x,y: y,}},containerHandler() {const that = thisthat.selectContainer()let toolType = that.currentTool.typeif (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 = thislet nodeList = that.flowData.nodeListthat.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 = lf.y = t})},alignForLine(e) {const that = thisif (that.selectGroup.length > 1) returnif (that.container.auxiliaryLine.controlFnTimesFlag) {let elId = e.el.idlet nodeList = that.flowData.nodeListnodeList.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.yif ((disX >= -dis && disX <= dis) || (disX + elW >= -dis && disX + elW <= dis)) {that.container.auxiliaryLine.isShowYLine = truethat.auxiliaryLinePos.x = node.x + that.container.pos.leftlet nodeMidPointX = node.x + node.width / 2if (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 = truethat.auxiliaryLinePos.y = node.y + that.container.pos.toplet nodeMidPointY = node.y + node.height / 2if (nodeMidPointY == elPos[1] + elH / 2) {that.auxiliaryLinePos.y = nodeMidPointY + that.container.pos.left}}}})that.container.auxiliaryLine.controlFnTimesFlag = falsesetTimeout(function () {that.container.auxiliaryLine.controlFnTimesFlag = true}, 200)}},hideAlignLine() {if (this.container.auxiliaryLine.isOpen) {this.container.auxiliaryLine.isShowXLine = falsethis.container.auxiliaryLine.isShowYLine = false}},},watch: {select(val) {this.currentSelect = valif (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 = valif (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>

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

<template><div><a-tabssize="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-itemlabel="流程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-itemlabel="类型":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-tag color="purple">{{ currentSelect.type }}</a-tag></a-form-item><a-form-itemlabel="id":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="currentSelect.id"disabled/></a-form-item><a-form-itemlabel="名称":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-inputplaceholder="请输入节点名称":value="currentSelect.name"@change="nameChange"/></a-form-item></a-form></template><template v-if="currentSelect.type == 'end round'"><a-form layout="horizontal"><a-form-itemlabel="类型":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-tag color="purple">{{ currentSelect.type }}</a-tag></a-form-item><a-form-itemlabel="id":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="currentSelect.id"disabled/></a-form-item><a-form-itemlabel="名称":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-inputplaceholder="请输入节点名称":value="currentSelect.name"@change="nameChange"/></a-form-item></a-form></template><template v-if="currentSelect.type == 'node'"><a-form layout="horizontal"><a-form-itemlabel="类型":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-tag color="purple">{{ currentSelect.type }}</a-tag></a-form-item><a-form-itemlabel="id":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="currentSelect.id"disabled/></a-form-item><a-form-itemlabel="名称":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-inputplaceholder="请输入节点名称":value="currentSelect.name"@change="nameChange"/></a-form-item><!-- <a-form-itemlabel="驳回类型":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-selectv-model="setInfo.nodeRejectType"@change="e => nodeRejectTypeChange(e)"><a-select-optionv-for="(item,index) in nodeRejectType":key="index":value="item.id">{{ item.name }}</a-select-option></a-select></a-form-item> --><a-form-itemlabel="驳回节点":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-selectv-model="setInfo.nodeRejectStep"@change="e => nodeRejectStepChange(e)"><a-select-optionv-for="(item,index) in allNodeList":key="index":value="item.id">{{ item.name }}</a-select-option></a-select></a-form-item><!--  --><a-form-itemlabel="会签方式":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-selectv-model="setInfo.nodeConfluenceType"@change="e => nodeConfluenceTypeChange(e)"><a-select-optionv-for="(item,index) in nodeConfluenceType":key="index":value="item.id">{{ item.name }}</a-select-option></a-select></a-form-item><a-form-itemlabel="回调URL":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="setInfo.thirdPartyUrl "@change="linkThirdPartyUrlChange"/></a-form-item><a-form-itemlabel="执行权限":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-select:default-value="setInfo.nodeDesignate"v-model="setInfo.nodeDesignate"@change="e => nodeDesignateChange(e)"><a-select-optionv-for="(item,index) in nodeDesignateData":key="index":value="item.id">{{ item.name }}</a-select-option></a-select></a-form-item><a-form-itemv-show="specialShow"v-if="setInfo.nodeDesignate=='SPECIAL_USER'"label="指定用户":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-col:md="18":sm="18"><a-inputdisabled="disabled"v-model="specialName"/></a-col><a-col:md="6":sm="6"><a-buttonicon="search"@click="setUser()"/></a-col></a-form-item><a-form-itemv-show="specialShow"v-elselabel="指定角色":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-col:md="18":sm="18"><a-inputdisabled="disabled"v-model="specialName"/></a-col><a-col:md="6":sm="6"><a-buttonicon="search"@click="setRole()"/></a-col></a-form-item><!-- <a-form-itemlabel="当前部门"v-if="setInfo.nodeDesignate=='SPECIAL_ROLE'":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-switchcheckedChildren="是"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-itemlabel="类型":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-tag color="purple">{{ currentSelect.type }}</a-tag></a-form-item><a-form-itemlabel="id":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="currentSelect.id"disabled/></a-form-item><a-form-itemlabel="名称":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-inputplaceholder="请输入节点名称":value="currentSelect.name"@change="nameChange"/></a-form-item></a-form></template><template v-else-if="currentSelect.type == 'join'"><a-form layout="horizontal"><a-form-itemlabel="类型":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-tag color="purple">{{ currentSelect.type }}</a-tag></a-form-item><a-form-itemlabel="id":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="currentSelect.id"disabled/></a-form-item><a-form-itemlabel="名称":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-inputplaceholder="请输入节点名称":value="currentSelect.name"@change="nameChange"/></a-form-item><!-- <a-form-itemlabel="驳回类型":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-selectv-model="setInfo.nodeRejectType"@change="e => nodeRejectTypeChange(e)"><a-select-optionv-for="(item,index) in nodeRejectType":key="index":value="item.id">{{ item.name }}</a-select-option></a-select></a-form-item> --><a-form-itemlabel="驳回节点":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-selectv-model="setInfo.nodeRejectStep"@change="e => nodeRejectStepChange(e)"><a-select-optionv-for="(item,index) in allNodeList":key="index":value="item.id">{{ item.name }}</a-select-option></a-select></a-form-item><a-form-itemlabel="会签方式":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-selectv-model="setInfo.nodeConfluenceType"@change="e => nodeConfluenceTypeChange(e)"><a-select-optionv-for="(item,index) in nodeConfluenceType":key="index":value="item.id">{{ item.name }}</a-select-option></a-select></a-form-item><a-form-itemlabel="回调URL":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="setInfo.thirdPartyUrl"@change="linkThirdPartyUrlChange"/></a-form-item><a-form-itemlabel="执行权限":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-select:default-value="setInfo.nodeDesignate"v-model="setInfo.nodeDesignate"@change="e => nodeDesignateChange(e)"><a-select-optionv-for="(item,index) in nodeDesignateData":key="index":value="item.id">{{ item.name }}</a-select-option></a-select></a-form-item><a-form-itemv-show="specialShow"v-if="setInfo.nodeDesignate=='SPECIAL_USER'"label="指定用户":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-col:md="18":sm="18"><a-inputdisabled="disabled"v-model="specialName"/></a-col><a-col:md="6":sm="6"><a-buttonicon="search"@click="setUser()"/></a-col></a-form-item><a-form-itemv-show="specialShow"v-elselabel="指定角色":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-col:md="18":sm="18"><a-inputdisabled="disabled"v-model="specialName"/></a-col><a-col:md="6":sm="6"><a-buttonicon="search"@click="setRole()"/></a-col></a-form-item><!-- <a-form-itemlabel="当前部门"v-if="setInfo.nodeDesignate=='SPECIAL_ROLE'":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-switchcheckedChildren="是"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-itemlabel="类型":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-tag color="purple">{{ currentSelect.type }}</a-tag></a-form-item><a-form-itemlabel="id":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="currentSelect.id"disabled/></a-form-item><a-form-itemlabel="名称":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-inputplaceholder="请输入节点名称":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-itemlabel="id":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="currentSelect.id"disabled/></a-form-item><a-form-itemlabel="源节点":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="currentSelect.sourceId"disabled/></a-form-item><a-form-itemlabel="目标节点":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="currentSelect.targetId"disabled/></a-form-item><a-form-itemlabel="文本":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-input:value="currentSelect.label"@change="linkLabelChange"/></a-form-item><a-form-itemlabel="添加条件":label-col="formItemLayout.labelCol":wrapper-col="formItemLayout.wrapperCol"><a-buttonicon="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-selectplaceholder="关系"v-model="compares[i].condition"@change="e => conditionChange(i,e)"><a-select-optionv-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-selectplaceholder="属性"v-model="compares[i].fieldName"@change="e => fieldNameChange(i,e)"><a-select-optionv-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-buttonicon="minus"@click="subList(i)"v-if="compares.length>0"/></a-col><a-col:md="10":sm="10"><a-selectplaceholder="比较"v-model="compares[i].operation"@change="e => operationChange(i,e)"><a-select-optionv-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"><spanv-if="compares[i].valueName"slot="title">{{ compares[i].valueName }}</span><templatev-elseslot="title"></template><div><a-input:disabled="true"v-model="compares[i].valueName"clearableplaceholder="值"/></div></a-tooltip></a-col><a-col:md="10":sm="10"v-else><a-inputv-model="compares[i].value"clearableplaceholder="值"@change="e => valueChange(i,e)"/></a-col><a-col:md="4":sm="4"v-if="compares[i].fieldName=='CreatedUserId'"><a-buttonicon="search"@click="setUser(i)"v-if="compares.length>0"/></a-col><a-col:md="4":sm="4"v-if="compares[i].fieldName=='CreatedOrgId'"><a-buttonicon="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.valuethis.currentSelect.setInfo.nodeName = this.currentSelect.namethis.currentSelect.setInfo.nodeCode = this.currentSelect.name},linkLabelChange(e) {const that = thislet label = e.target.valuethat.currentSelect.label = labellet 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 = thislet thirdPartyUrl = e.target.valuethat.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 = thislet nodeRejectStep = ethat.setInfo.nodeRejectStep = nodeRejectStepthat.currentSelect.setInfo.nodeRejectStep = nodeRejectStep},nodeConfluenceTypeChange(e) {const that = thislet nodeConfluenceType = ethat.setInfo.nodeConfluenceType = nodeConfluenceTypethat.currentSelect.setInfo.nodeConfluenceType = nodeConfluenceType},addList() {const that = thislet compares = that.comparescompares.push({ fieldType: 'form', value: '', name: '', condition: 'and', valueName: '', operation: '=' })that.compares = comparesthat.currentSelect.compares = compares},subList(e) {const that = thislet compares = that.comparesif (compares.length == 1) {compares = [{ fieldType: 'form', value: '', name: '', condition: 'and', valueName: '', operation: '=' }]} else {compares.splice(e, 1)}that.compares = comparesthat.currentSelect.compares = compares},fieldNameChange(i, e) {const that = thisconst compares = that.comparescompares[i].fieldName = ethat.currentSelect.compares = compares},conditionChange(i, e) {const that = thisconst compares = that.comparescompares[i].condition = ethat.currentSelect.compares = compares},operationChange(i, e) {const that = thisconst compares = that.comparescompares[i].operation = ethat.currentSelect.compares = compares},valueChange(i, e) {const that = thisconst compares = that.comparesthat.currentSelect.compares = compares},//打开选择用户界面setUser(value) {const that = thisif (that.currentSelect.type == 'link') {that.currentCompare = valuethis.$emit('openUser', null)} else {that.currentCompare = nullthis.$emit('openUser', {rowKeyList: that.setInfo.nodeDesignateData,rowDataList: this.setInfo.selectRows || [],})}},//打开选择角色界面setRole(value) {const that = thisif (that.currentSelect.type == 'link') {that.currentCompare = valuethis.$emit('openUser', null)} else {that.currentCompare = nullthis.$emit('openRole', {rowKeyList: that.setInfo.nodeDesignateData,rowDataList: this.setInfo.selectRows || [],})}},setFlowAttrForm(record, type) {const that = thisconst 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 = nodeDesignateDatathat.setInfo.nodeDesignateName = nodeDesignateNamethat.currentSelect.setInfo.nodeDesignateName = nodeDesignateNamethat.currentSelect.setInfo.nodeDesignateData = nodeDesignateDataif (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 = thislet nodeDesignate = ethat.setInfo.nodeDesignate = nodeDesignatethat.setInfo.nodeDesignateData = []that.setInfo.nodeDesignateName = []that.setInfo.selectRows = []// that.setInfo.currentDepart = false// that.currentDepart = falsethat.specialName = ''if (nodeDesignate == 'SPECIAL_USER') {that.specialShow = true} else if (nodeDesignate == 'SPECIAL_ROLE') {that.specialShow = true} else {that.specialShow = false}that.currentSelect.setInfo.nodeDesignate = nodeDesignatethat.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 = valif (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.namethis.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 = falsethis.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 = truethis.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.nodeListif (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>

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

<template><divv-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><divv-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><divv-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><divv-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><divv-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><divv-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') }"><divclass="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><divv-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') }"><divclass="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 = thisthat.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.heightthat.node.width = ui.size.width},})}that.currentSelect = that.nodethat.currentSelectGroup = []},selectNode() {const that = thisthat.currentSelect = this.nodethat.$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 = thisif (that.currentSelect.id == that.node.id) return truelet f = that.currentSelectGroup.filter((n) => n.id == that.node.id)if (f.length > 0) return truereturn 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>

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

<template><div><a-drawertitle="设置"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>

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

<template><a-modal title="快捷键大全"width="50%":visible="modalVisible"okText="确认"cancelText="取消"@ok="saveSetting"@cancel="cancel"><a-tablerowKey="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>

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

<template><div><a-drawertitle="JSON"placement="right":width="600":visible="testVisible"@close="onClose"><div>当前的flowData:</div><json-view :value="flowData":expand-depth=3boxedcopyable/><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>

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:'所属组织'}]//连线条件额外参数
};

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'}
];

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));}
};

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;//   }// }
}

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;}}
}

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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/73386.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

day-04 基于UDP的服务器端/客户端

一.理解UDP &#xff08;一&#xff09;UDP套接字的特点 UDP套接字具有以下特点&#xff1a; 无连接性&#xff1a;UDP是一种无连接的协议&#xff0c;这意味着在发送数据之前&#xff0c;不需要在发送方和接收方之间建立连接。每个UDP数据包都是独立的&#xff0c;它们可以独…

FOXBORO FBM232 P0926GW 自动化控制模块

Foxboro FBM232 P0926GW 是 Foxboro&#xff08;福克斯博罗&#xff09;自动化控制系统的一部分&#xff0c;通常用于监测和控制工业过程。以下是关于这种类型的自动化控制模块可能具有的一些常见功能&#xff1a; 数字输入通道&#xff1a; FBM232 P0926GW 控制模块通常具有多…

【漏洞库】Fastjson_1.2.24_rce

文章目录 漏洞描述漏洞编号漏洞评级影响版本漏洞复现- 利用工具- 漏洞环境- 漏洞扫描- 漏洞验证- 深度利用- GetShell- EXP 编写 漏洞挖掘- 指纹信息 修复建议- 漏洞修复 漏洞原理 漏洞描述 Fastjson 存在反序列化远程代码执行漏洞&#xff0c;当应用或系统使用 Fastjson 对由…

十一、做高并发内存池项目过程中遇到的bug以及调试bug的方法和心得

十一、做高并发内存池项目过程中遇到的bug以及调试bug的方法和心得 第一个bug是内存问题&#xff0c;程序直接崩溃&#xff0c;问题出现在&#xff1a;GetOneSpan函数中的切分span的时候结尾的span1的next没有置空。 第二个bug是还小内存块给span的时候找不到小内存所属的spa…

使用Android原生制作毛玻璃效果图片

毛玻璃效果&#xff0c;也被称为模糊效果&#xff0c;是许多现代应用中流行的一种视觉效果。在 Android 中&#xff0c;我们可以通过多种方式实现该效果。本文将探讨如何使用 Android 原生的 Bitmap 类和 RenderScript 来实现毛玻璃效果。 1. 准备工作 首先&#xff0c;你需要…

BLE Mesh蓝牙mesh网多跳大数据量高带宽传输数据方法

1、BLE Mesh数据传输现状 BLE Mesh网络技术是低功耗蓝牙的一个进阶版&#xff0c;Mesh扩大了蓝牙在应用中的规模和范围&#xff0c;因为它同时支持超过三万个网络节点&#xff0c;可以跨越大型建筑物&#xff0c;不仅可以使得医疗健康应用更加方便快捷&#xff0c;还能监测像学…

IDea寻找冲突的依赖包

场景&#xff1a;boot项目运行时&#xff0c;提示log4j2依赖包冲突。 SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/D:/maven/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/Stati…

HTML5Plus

之前写过在 vue 中使用 mui 框架的方法&#xff0c;因为用 vue 开发后打包 5App 会有一些问题&#xff0c;所以当时用到了&#xff0c;最近又一次开发移动端&#xff0c;不同的是这次使用的是 vue3 开发的&#xff0c;导致之前使用的 vue-awesome-mui 依赖不能使用了&#xff0…

快速完成工信部APP备案流程_以阿里云APP备案为例

阿里云APP备案流程分为6步&#xff0c;APP备案成功后应用可以上架&#xff0c;登录阿里云账号填写APP信息&#xff0c;等待阿里云初审&#xff0c;初审通过后进行工信部短信核验&#xff0c;管局审核通过后APP即可备案成功&#xff0c;最后移动APP应用可以分发平台上架&#xf…

网络层重点协议-IP协议(结构分析)

IP协议数据报格式 一.4位版本号 用来表示IP协议的版本&#xff0c;现有的IP协议只有两个版本IPv4和IPv6 二.4位首部长度 IP协议数据报报头的长度 三.8位服务类型 3位优先权字段&#xff08;已经弃用&#xff09;&#xff0c;4位TOS字段&#xff0c;和1位保留 字段&#xff08;必…

企业的固定资产管理怎么操作

企业是一家拥有多台大型设备的工厂&#xff0c;这些设备需要定期进行保养和维护&#xff0c;以确保其正常运转。而企业内部员工由于专业知识和技能的不同&#xff0c;需要分工协作才能更好地完成各项工作任务。因此&#xff0c;在设备资产管理方面&#xff0c;如何实现高效、便…

SpringBoot常用注解

SpringBoot常用注解 SpringBoot摒弃了xml配置方式&#xff0c;改为了全注解驱动。 准备 创建SpringBoot模块 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"ht…

使用JS实现一个简单的观察者模式(Observer)

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 手撸Observer⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领…

Unity之3D物理导航系统

一 介绍 Unity自带寻路(导航)系统是unity官方自带的一种寻路系统。我们可以通过它来制作简单的寻路&#xff0c;比如可以制作点击某个位置&#xff0c;让角色自动的绕开障碍走到目标点的效果&#xff0c;比如可以制作敌人AI&#xff0c;让它可以通过NavMesh绕开障碍追击我方单…

深入理解 JVM 之——字节码指令与执行引擎

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 类文件结构 Write Once&#xff0c;Run Anywhere 对于 C 语言从程序到运行需要经过编译的过程&#xff0c;只有经历了编译后&#xff0c;我们所编写的代码才能够翻译为机器可以直接运行的二进制代码&#x…

【web开发】4、JavaScript与jQuery

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、JavaScript与jQuery二、JavaScript常用的基本功能1.插入位置2.注释3.变量4.数组5.滚动字符 三、jQuery常用的基本功能1.引入jQuery2.寻找标签3.val、text、appe…

笔记 | 排序算法实现(Python)

排序算法 一、选择排序二、合并/归并排序三、快速排序四、计数排序 排序类型时间复杂度选择排序(Selection Sort) O ( n 2 ) O(n^{2} ) O(n2)合并/归并排序&#xff08;Merge Sort&#xff09; O ( n log ⁡ n ) O(n\log n ) O(nlogn)快速排序(Quick Sort)平均情况 O ( n log ⁡…

帧动画实现

背景&#xff1a; pag实现痛点 文档&#xff1a;libpag参考文档 1.打包依赖的类型缺失问题 2.pagview初始化文件过大,影响小程序打包 3.兼容性较差关键帧动画实现痛点: 当关键帧变化过多的时候&#xff0c;无法准确分辨出需要写出多少个关键帧&#xff0c;以及各个关键帧的具…

视频监控/视频汇聚/安防视频监控平台EasyCVR如何将默认快照的raw格式改为jpg/base64格式?

视频监控/视频汇聚/安防视频监控平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频云存储EasyCVR平台能在复…

身份识别与鉴权技术调研方案

对称加密算法 对称加密方式又称为私钥加密方式&#xff0c;该方式的加密和解密过程使用同一个密钥&#xff0c;因此该密钥又称为共享密钥。如图2.2所示&#xff0c;在对称加密方式中&#xff0c;发送方使用对称加密算法和共享密钥处理原始数据&#xff0c;得到一个加密后的密文…