基于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;
}
相关文章:
基于antd+vue2来实现一个简单的绘画流程图功能
简单流程图的实现(基于antdvue2的)代码很多哦~ 实现页面如下 1.简单操作如下 2.弹框中使用组件: <vfdref"vfd"style"background-color: white;":needShow"true":fieldNames"fieldNames"openUse…...
【小吉送书—第二期】阿里后端开发:抽象建模经典案例
文章目录 0.引言1.抽象思维2.软件世界中的抽象2.1 命名抽象2.2 分层抽象2.3 原则抽象 3. 经典抽象案例3.1 方案一:战术抽象,多快好省,跑步前进3.2 方案二:深入分析,透过表象,探寻本质 5. 推荐一本书&#x…...
深度学习常用的Python库(核心库、可视化、NLP、计算机视觉、深度学习等)
(1)核心库与统计:Numpy、Scipy、Pandas、StatsModels。 (2)可视化:Matplotlib、Seaborn、Plotly、Bokeh、Pydot、Scikit-learn、XGBoost/LightGBM/CatBoost、Eli5。 (3)深度学习&a…...
Android菜单(上下文菜单)(选项菜单)
菜单资源文件通常放置在res\menu目录下,在创建项目时,默认不自动创建menu目录,所以需要手动创建。Android Resource Directory->value menu 菜单资源根元素通常是<menu></menu>标记,子元素为<item></ite…...
l8-d11 TCP连接管理与UDP协议
一、三次握手 TCP 建立连接的过程叫做握手。 采用三报文握手:在客户和服务器之间交换三个 TCP 报文段,以防止已失效的连接请求报文段突然又传送到了,因而产生 TCP 连接建立错误。 二、四次挥手 TCP 连接释放过程比较复杂。 数据传输结束后…...
Python+Requests+Pytest+Excel+Allure 接口自动化测试项目实战【框架之间的对比】
--------UnitTest框架和PyTest框架的简单认识对比与项目实战-------- 定义: Unittest是Python标准库中自带的单元测试框架,Unittest有时候也被称为PyUnit,就像JUnit是Java语言的标准单元测试框架一样,Unittest则是Python语言的标…...
商业航天进展迅速:中国航天科工三院成功完成电磁发射试验
商业航天进展迅速!中国航天科工三院成功完成了商业航天电磁发射高温超导电动悬浮试验,打破了国内高温超导电动悬浮航行速度纪录。在380米线路上,实现了234公里/小时的试验速度。这项技术突破标志着商业航天电磁发射技术已具备了系统研制和试验…...
MySQL和Oracle数据库引擎
MYSQL数据库: 在mysql数据库中,常用到的引擎主要就是2个:Innodb和MyIASM。 Innodb:它提供了对数据库ACID事务的支持,并且还提供行级锁和外键的约束。它被设计的目的就是处理大数据容器的数据库系统,它本身…...
CloudQuery X PolarDB:让数据库管理更简单
前言:8 月 15 日,CloudQuery 数据操作管控平台与阿里云 PolarDB 数据库管理软件,完成产品集成认证测试。也在以下功能上完善了用户使用 PolarDB 的体验,使数据库的管理更加安全高效。 支持在 CloudQuery 中创建连接,便…...
机器学习开源工具BatteryML,一站式分析与预测电池性能
编者按:天下苦锂电池寿命久矣,时闻“开车出,推车回”,又闻“充电两小时,待机两分钟”,亦闻“气温骤降,请注意电池保暖”……随着以锂离子电池为动力源的产品,如手机、电脑、新能源汽…...
TypeScript:赋予JavaScript数据类型新的力量,提升编程效率!
🎬 岸边的风:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想,就是为了理想的生活 ! 📚 前言 TypeScript:扩展JavaScript数据类型,赋予编程更强大的表达能力!…...
LLMs之Baichuan 2:《Baichuan 2: Open Large-scale Language Models》翻译与解读
LLMs之Baichuan 2:《Baichuan 2: Open Large-scale Language Models》翻译与解读 导读:2023年9月6日,百川智能重磅发布Baichuan 2。科技论文主要介绍了Baichuan 2,一个开源的大规模语言模型,以及其在多个领域的性能表现…...
听书网站模板源码 懒人书院网站源码 苹果cms手机听书网站模版源码 支持手机端
苹果cms超漂亮UI高仿芒果TV听书网站模板带手机端。 手机版修改logo,ting_wap/images/logo.png 电脑版修改logo,ting_pc/img/logo.png 编辑推荐后台推荐5颗星。 新势力/热播榜单后台推荐9颗星。...
算法 数据结构 斐波那契数列 递归实现斐波那契数列 斐波那契递归的优化 斐波那契数列递归求解 多路递归实现 斐波那契算法系列 数据结构(十一)
1. 什么是斐波那契数列: 之前的例子是每个递归函数只包含一个自身的调用,这称之为 single recursion 如果每个递归函数例包含多个自身调用,称之为 multi recursion 递推关系 下面的表格列出了数列的前几项 F0F1F2F3F4F5F6F7F8F9F10F11F12…...
【面试经典150 | 双指针】两数之和
文章目录 写在前面Tag题目来源题目解读解题思路方法一:暴力枚举方法二:哈希表方法三:二分法方法四:双指针 知识回顾写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢…...
桥接模式简介
概念: 桥接模式是一种结构型设计模式,它将抽象和实现分离,使它们可以独立地变化。通过使用桥接模式,可以将一个类的抽象部分与其具体实现部分解耦,并且可以在运行时动态地选择不同的实现。 特点: 将抽象…...
零钱兑换00
题目链接 零钱兑换 题目描述 注意点 如果没有任何一种硬币组合能组成总金额,返回 -1可以认为每种硬币的数量是无限的 解答思路 动态规划从总金额1开始推出目标金额所需的最少硬币个数,任意某个金额所需的最少硬币个数可以由当前金额减去每种面额的硬…...
JavaScipt中如何实现函数缓存?函数缓存有哪些场景?
1、函数缓存是什么? 函数缓存就是将函数运行的结果进行缓存。本质上就是用空间(缓存存储)换时间(计算过程) 常用于缓存数据计算结果和缓存对象。 缓存只是一个临时的数据存储,它保存数据,以便将…...
android studio的Android Drawable Preview
Android Drawable Preview 应用后,如下图: 再也不用一个一个点开去看了 其他学习资料: 1、付费专栏《Android kotlin入门到进阶系列讲解》:https://blog.csdn.net/qq_35091074/category_11036895.html 2、免费专栏《Android kot…...
基于云计算的区域LIS系统系统源码
在医疗机构内部,院内实验室主要负责本院临床科室的检验,院内LIS系统必须满足实验室日常的标本处理入库、仪器联机、检验结果处理、报告打印、报告发布、检验信息统计、检验信息报告发布、标本流程、外部医疗机构检验报告调阅等工作。 在医疗机构间&#…...
VR农学虚拟仿真情景实训教学演示
首先,VR农学虚拟仿真情景实训教学提供了更为真实的实践环境。传统的农学实训往往受制于时间、空间和资源的限制,学生只能通过观察或简单的模拟来学习农业知识和技能。而借助虚拟现实技术,学生可以进入虚拟农场,与各种农作物、工具…...
sklearn中make_blobs方法:聚类数据生成器
sklearn中make_blobs()方法参数: n_samples:表示数据样本点个数,默认值100 n_features:是每个样本的特征(或属性)数,也表示数据的维度,默认值是2。默认为 2 维数据,测试选取 2 维数据也方便进行可视化展示…...
Win11自带微软输入法怎么输入π及其他希腊字母
如果用搜狗等第三方输入法的话就没有这些问题了,各种符号很方便。 自带的输入法输入 pi 和 pai 都不能正常输入 π \pi π 参考文章 https://www.cnblogs.com/qq-757617012/p/14078133.html 如果用自带的输入法可以采用以下方式 输入uuxl xl表示“希腊”&#x…...
关于MyBatisPlus框架下出现xml里面定义的方法无法被正确识别以及提示调用mysql存储过程时参数无效的问题
第一个问题:xml里面明明定义了方法A,但是通过IService接口调用A的时候,总提示无法将接口中定义的函数绑定到xml中的同名方法中(“Invalid bound statement (not found): com.aircas.sqlservice.mapper.SysTempIndexMapper.getRemo…...
vscode路径别名文件跳转解决办法
第一步:下载 1.在jsconfig.json中配置: {"compilerOptions": {"target": "es5","module": "esnext","baseUrl": "./","moduleResolution": "node","p…...
layui 富文本编辑器layedit 以及 图片转base64前端页面显示
js var index layui.layedit.build(noticeInformationContent, {area: [500px, 400px],uploadImage: {url: NI/uploadconimage //接口url, type: POST //默认post},hideTool: [image]});layui.form.verify({content: function (val) {layui.layedit.sync(index);var content …...
服务器给前端实时推送数据轻量化解决方案eventSource+Springboot
一、前端代码 body代码 <div id"result"></div>js代码 $(function(){if(typeof(EventSource) ! "undefined"){var source new EventSource("/demo/getTime");source.onmessage function(event) {console.log(event.data);$(&qu…...
数据结构与算法:数据结构基础
目录 数组 定义 形式 顺序存储 基本操作 读取元素 更新元素 插入元素 删除元素 扩容 初始化 时机 步骤 优劣势 链表 定义 单向链表 特点 双向链表 随机存储 基本操作 查找节点 更新节点 插入节点 删除元素 数组VS链表 栈与队列 栈 定义 基本操作…...
virtualbox虚拟机中安装FreeDOS系统和DJGPP编译环境
一、安装FreeDOS系统 1、从官网下载FreeDOS系统镜像,下载的压缩包中包含两个文件:后缀为.iso和.img的镜像 下载页面 http://www.freedos.org/download/ 直接下载链接 https://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/distributions/1.…...
JAVASE事件监听
代码: import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Scanner;import javax.swing.JButton; import javax.…...
广告创意设计说明/seo优化便宜
1 JavaScript变量作用域 1.1 函数作用域 没有块作用域:即作用域不是以{}包围的,其作用域完成由函数来决定,因而if /for等语句中的花括号不是独立的作用域。 如前述,JS的在函数中定义的局部变量只对这个函数内部可见,称…...
六安人事考试网/排名sem优化软件
抽空制作的一个取前一月份和后一月份脚本 #!/bin/bash usage() {echo "Usage: $0 201401"exit 0 }if [ x$1 x ];thenusage fi yearecho $1|cut -c 1-4 monthecho $1|cut -c 5-6next_month() {if [ $2 12 ];thenl_month01l_yearexpr $1 1echo "$l_year$l_mon…...
动态网站和静态网站区别/b站视频推广的方法有哪些
原文 拉兹万 预览开关 Razvan一直在查看-previewnosharedaccess报告的问题,但只从atila那里找到了少数几个.表明或有个没有很多错误的良好实现,或它没有大量使用它.阿蒂拉认为没人用它. Razvan指出,atila报告的一个错误是试实例化共享类会导致错误. 如果不工作,则有其他问题…...
河北建设工程网站/seo关键词搜索和优化
使用最新版本的百度地图需要注意的几个地方: 1、libs文件夹下要有android-support-v4.jar、baidumapapi_v2_1_0.jar、locSDK_3.1.jar三个jar包和armeabi文件夹。 2、布局文件要写成<com.baidu.mapapi.map.MapView />,旧版本是写作<com.baidu.ma…...
手机网站在线生成/6个好用的bt种子搜索引擎
目录一、文件目录二、实现效果三、实现3.1 跳转页面api3.2 页面组件跳转四、示例demo源码4.1 wxml4.2 wxss4.3 js一、文件目录 二、实现效果 三、实现 点击test页面中的按钮,跳转至页面other; 3.1 跳转页面api 3.1.1 navigateTo 保留当前页面&#x…...
360网站收录/搜索引擎付费推广
分布式事务以及解决方法参考文章: (1)分布式事务以及解决方法 (2)https://www.cnblogs.com/aoshicangqiong/p/7726323.html 备忘一下。...