[Feature-5498][JsonSplit-api] refactor of dolphin-scheduler-ui/dag (#6098)
* refactor of dolphin-scheduler-ui/dag * copy task feature and code optimization * fix review & ut bugs * add newline at end of file * add license header Co-authored-by: chenxiwei <cxwbeta@139.com> Co-authored-by: chenxiwei <chenxiwei_yewu@cmss.chinamobile.com>
@ -15,6 +15,8 @@
|
||||
"build:release": "npm run clean && cross-env NODE_ENV=production PUBLIC_PATH=/dolphinscheduler/ui webpack --config ./build/webpack.config.release.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/layout": "^0.1.18",
|
||||
"@antv/x6": "^1.25.5",
|
||||
"@form-create/element-ui": "^1.0.18",
|
||||
"@riophae/vue-treeselect": "^0.4.0",
|
||||
"axios": "^0.16.2",
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
.dag-canvas {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
height: calc(100% - 50px);
|
||||
padding: 10px 0 0 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
.dag-container {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.paper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.minimap {
|
||||
position: absolute;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
border: dashed 1px #e4e4e4;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.context-menu{
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,739 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
<template>
|
||||
<div class="dag-canvas">
|
||||
<dag-taskbar @on-drag-start="_onDragStart" />
|
||||
<div
|
||||
class="dag-container"
|
||||
ref="container"
|
||||
@dragenter.prevent
|
||||
@dragover.prevent
|
||||
@dragleave.prevent
|
||||
@drop.stop.prevent="_onDrop"
|
||||
>
|
||||
<div ref="paper" class="paper"></div>
|
||||
<div ref="minimap" class="minimap"></div>
|
||||
<context-menu ref="contextMenu" />
|
||||
<status-menu ref="statusMenu" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Graph, DataUri } from '@antv/x6'
|
||||
import dagTaskbar from './taskbar.vue'
|
||||
import contextMenu from './contextMenu.vue'
|
||||
import statusMenu from './statusMenu.vue'
|
||||
import {
|
||||
NODE_PROPS,
|
||||
EDGE_PROPS,
|
||||
PORT_PROPS,
|
||||
X6_NODE_NAME,
|
||||
X6_PORT_OUT_NAME,
|
||||
X6_PORT_IN_NAME,
|
||||
X6_EDGE_NAME,
|
||||
NODE_HIGHLIGHT_PROPS,
|
||||
PORT_HIGHLIGHT_PROPS,
|
||||
EDGE_HIGHLIGHT_PROPS
|
||||
} from './x6-helper'
|
||||
import { DagreLayout } from '@antv/layout'
|
||||
import { tasksType } from '../config'
|
||||
import _ from 'lodash'
|
||||
import { mapActions, mapMutations } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'dag-canvas',
|
||||
data () {
|
||||
return {
|
||||
graph: null,
|
||||
// Used to calculate the context menu location
|
||||
originalScrollPosition: {
|
||||
left: 0,
|
||||
top: 0
|
||||
},
|
||||
editable: true,
|
||||
dragging: {
|
||||
// Distance from the mouse to the top-left corner of the dragging element
|
||||
x: 0,
|
||||
y: 0,
|
||||
type: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
provide () {
|
||||
return {
|
||||
dagCanvas: this
|
||||
}
|
||||
},
|
||||
inject: ['dagChart'],
|
||||
components: {
|
||||
dagTaskbar,
|
||||
contextMenu,
|
||||
statusMenu
|
||||
},
|
||||
methods: {
|
||||
...mapActions('dag', ['genTaskCodeList']),
|
||||
...mapMutations('dag', ['removeTask']),
|
||||
/**
|
||||
* Recalculate the paper width and height
|
||||
*/
|
||||
paperResize () {
|
||||
const w = this.$el.offsetWidth
|
||||
const h = this.$el.offsetHeight
|
||||
this.graph.resize(w, h)
|
||||
},
|
||||
/**
|
||||
* Init graph
|
||||
* This will be called in the dag-chart mounted event
|
||||
* @param {boolean} uneditable
|
||||
*/
|
||||
graphInit (editable) {
|
||||
const self = this
|
||||
this.editable = !!editable
|
||||
const paper = this.$refs.paper
|
||||
const minimap = this.$refs.minimap
|
||||
const graph = (this.graph = new Graph({
|
||||
container: paper,
|
||||
selecting: {
|
||||
enabled: true,
|
||||
multiple: true,
|
||||
rubberband: true,
|
||||
rubberEdge: true,
|
||||
movable: true,
|
||||
showNodeSelectionBox: false
|
||||
},
|
||||
scroller: true,
|
||||
grid: {
|
||||
size: 10,
|
||||
visible: true
|
||||
},
|
||||
snapline: true,
|
||||
minimap: {
|
||||
enabled: true,
|
||||
container: minimap
|
||||
},
|
||||
interacting: {
|
||||
edgeLabelMovable: false,
|
||||
nodeMovable: !!editable,
|
||||
magnetConnectable: !!editable
|
||||
},
|
||||
connecting: {
|
||||
snap: {
|
||||
radius: 30
|
||||
},
|
||||
// Whether multiple edges can be created between the same start node and end
|
||||
allowMulti: false,
|
||||
// Whether a point is allowed to connect to a blank position on the canvas
|
||||
allowBlank: false,
|
||||
// The start node and the end node are the same node
|
||||
allowLoop: false,
|
||||
// Whether an edge is allowed to link to another edge
|
||||
allowEdge: false,
|
||||
// Whether edges are allowed to link to nodes
|
||||
allowNode: true,
|
||||
// Whether to allow edge links to ports
|
||||
allowPort: true,
|
||||
// Whether all available ports or nodes are highlighted when you drag the edge
|
||||
highlight: true,
|
||||
createEdge () {
|
||||
return graph.createEdge({ shape: X6_EDGE_NAME })
|
||||
},
|
||||
validateMagnet ({ magnet }) {
|
||||
return magnet.getAttribute('port-group') !== X6_PORT_IN_NAME
|
||||
},
|
||||
validateConnection (data) {
|
||||
const { sourceCell, targetCell, sourceMagnet, targetMagnet } = data
|
||||
// Connections can only be created from the output link post
|
||||
if (
|
||||
!sourceMagnet ||
|
||||
sourceMagnet.getAttribute('port-group') !== X6_PORT_OUT_NAME
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Can only be connected to the input link post
|
||||
if (
|
||||
!targetMagnet ||
|
||||
targetMagnet.getAttribute('port-group') !== X6_PORT_IN_NAME
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (
|
||||
sourceCell &&
|
||||
targetCell &&
|
||||
sourceCell.isNode() &&
|
||||
targetCell.isNode()
|
||||
) {
|
||||
const edgeData = {
|
||||
sourceId: Number(sourceCell.id),
|
||||
targetId: Number(targetCell.id)
|
||||
}
|
||||
if (!self.dagChart.edgeIsValid(edgeData)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
},
|
||||
highlighting: {
|
||||
nodeAvailable: {
|
||||
name: 'className',
|
||||
args: {
|
||||
className: 'available'
|
||||
}
|
||||
},
|
||||
magnetAvailable: {
|
||||
name: 'className',
|
||||
args: {
|
||||
className: 'available'
|
||||
}
|
||||
},
|
||||
magnetAdsorbed: {
|
||||
name: 'className',
|
||||
args: {
|
||||
className: 'adsorbed'
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
// TODO will be deleted
|
||||
window._graph = graph
|
||||
this.registerX6Shape()
|
||||
this.bindGraphEvent()
|
||||
this.originalScrollPosition = graph.getScrollbarPosition()
|
||||
},
|
||||
/**
|
||||
* Register custom shapes
|
||||
*/
|
||||
registerX6Shape () {
|
||||
Graph.unregisterNode(X6_NODE_NAME)
|
||||
Graph.unregisterEdge(X6_EDGE_NAME)
|
||||
Graph.registerNode(X6_NODE_NAME, { ...NODE_PROPS })
|
||||
Graph.registerEdge(X6_EDGE_NAME, { ...EDGE_PROPS })
|
||||
},
|
||||
/**
|
||||
* Bind grap event
|
||||
*/
|
||||
bindGraphEvent () {
|
||||
// nodes and edges hover
|
||||
this.graph.on('cell:mouseenter', (data) => {
|
||||
const { cell, e } = data
|
||||
const { left: cL, top: cT } =
|
||||
this.$refs.container.getBoundingClientRect()
|
||||
const cX = e.clientX - cL
|
||||
const cY = e.clientY - cT
|
||||
const isStatusIcon = (tagName) =>
|
||||
tagName && tagName.toLocaleLowerCase() === 'i'
|
||||
if (isStatusIcon(e.target.tagName)) {
|
||||
this.$refs.statusMenu.show(cX, cY)
|
||||
this.$refs.statusMenu.setCurrentTask({
|
||||
name: cell.data.taskName,
|
||||
type: cell.data.taskType,
|
||||
code: Number(cell.id)
|
||||
})
|
||||
} else {
|
||||
this.setHighlight(cell)
|
||||
}
|
||||
})
|
||||
this.graph.on('cell:mouseleave', ({ cell }) => {
|
||||
if (!this.graph.isSelected(cell)) {
|
||||
this.resetHighlight(cell)
|
||||
}
|
||||
this.$refs.statusMenu.hide()
|
||||
})
|
||||
// select
|
||||
this.graph.on('cell:selected', ({ cell }) => {
|
||||
this.setHighlight(cell)
|
||||
})
|
||||
this.graph.on('cell:unselected', ({ cell }) => {
|
||||
if (!this.graph.isSelected(cell)) {
|
||||
this.resetHighlight(cell)
|
||||
}
|
||||
})
|
||||
// right click
|
||||
this.graph.on('node:contextmenu', ({ x, y, cell }) => {
|
||||
const { left, top } = this.graph.getScrollbarPosition()
|
||||
const o = this.originalScrollPosition
|
||||
this.$refs.contextMenu.show(x + (o.left - left), y + (o.top - top))
|
||||
this.$refs.contextMenu.setCurrentTask({
|
||||
name: cell.data.taskName,
|
||||
type: cell.data.taskType,
|
||||
code: Number(cell.id)
|
||||
})
|
||||
})
|
||||
// node double click
|
||||
this.graph.on('node:dblclick', ({ cell }) => {
|
||||
this.dagChart.openFormModel(Number(cell.id), cell.data.taskType)
|
||||
})
|
||||
// create edge label
|
||||
this.graph.on('edge:dblclick', ({ cell }) => {
|
||||
const labelName = this.getEdgeLabelName(cell)
|
||||
this.dagChart.$refs.edgeEditModel.show({
|
||||
id: cell.id,
|
||||
label: labelName
|
||||
})
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @param {Edge|string} edge
|
||||
*/
|
||||
getEdgeLabelName (edge) {
|
||||
if (typeof edge === 'string') edge = this.graph.getCellById(edge)
|
||||
const labels = edge.getLabels()
|
||||
const labelName = _.get(labels, ['0', 'attrs', 'label', 'text'], '')
|
||||
return labelName
|
||||
},
|
||||
/**
|
||||
* Set edge label by id
|
||||
* @param {string} id
|
||||
* @param {string} label
|
||||
*/
|
||||
setEdgeLabel (id, label) {
|
||||
const edge = this.graph.getCellById(id)
|
||||
edge.setLabels(label)
|
||||
if (this.graph.isSelected(edge)) {
|
||||
this.setEdgeHighlight(edge)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {number} limit
|
||||
* @param {string} text
|
||||
* Each Chinese character is equal to two chars
|
||||
*/
|
||||
truncateText (text, n) {
|
||||
const exp = /[\u4E00-\u9FA5]/
|
||||
let res = ''
|
||||
let len = text.length
|
||||
let chinese = text.match(new RegExp(exp, 'g'))
|
||||
if (chinese) {
|
||||
len += chinese.length
|
||||
}
|
||||
if (len > n) {
|
||||
let i = 0
|
||||
let acc = 0
|
||||
while (true) {
|
||||
let char = text[i]
|
||||
if (exp.test(char)) {
|
||||
acc += 2
|
||||
} else {
|
||||
acc++
|
||||
}
|
||||
if (acc > n) break
|
||||
res += char
|
||||
i++
|
||||
}
|
||||
res += '...'
|
||||
} else {
|
||||
res = text
|
||||
}
|
||||
return res
|
||||
},
|
||||
/**
|
||||
* Set node name by id
|
||||
* @param {string|number} id
|
||||
* @param {string} name
|
||||
*/
|
||||
setNodeName (id, name) {
|
||||
id += ''
|
||||
const node = this.graph.getCellById(id)
|
||||
if (node) {
|
||||
const truncation = this.truncateText(name, 18)
|
||||
node.attr('title/text', truncation)
|
||||
node.setData({ taskName: name })
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Set node highlight
|
||||
* @param {Node} node
|
||||
*/
|
||||
setNodeHighlight (node) {
|
||||
const url = require(`../images/task-icos/${node.data.taskType.toLocaleLowerCase()}_hover.png`)
|
||||
node.setAttrs(NODE_HIGHLIGHT_PROPS.attrs)
|
||||
node.setAttrByPath('image/xlink:href', url)
|
||||
node.setPortProp(
|
||||
X6_PORT_OUT_NAME,
|
||||
'attrs',
|
||||
PORT_HIGHLIGHT_PROPS[X6_PORT_OUT_NAME].attrs
|
||||
)
|
||||
},
|
||||
/**
|
||||
* Reset node style
|
||||
* @param {Node} node
|
||||
*/
|
||||
resetNodeStyle (node) {
|
||||
const url = require(`../images/task-icos/${node.data.taskType.toLocaleLowerCase()}.png`)
|
||||
node.setAttrs(NODE_PROPS.attrs)
|
||||
node.setAttrByPath('image/xlink:href', url)
|
||||
node.setPortProp(
|
||||
X6_PORT_OUT_NAME,
|
||||
'attrs',
|
||||
PORT_PROPS.groups[X6_PORT_OUT_NAME].attrs
|
||||
)
|
||||
},
|
||||
/**
|
||||
* Set edge highlight
|
||||
* @param {Edge} edge
|
||||
*/
|
||||
setEdgeHighlight (edge) {
|
||||
edge.setAttrs(EDGE_HIGHLIGHT_PROPS.attrs)
|
||||
const labelName = this.getEdgeLabelName(edge)
|
||||
if (labelName) {
|
||||
edge.setLabels([
|
||||
_.merge(EDGE_HIGHLIGHT_PROPS.defaultLabel, {
|
||||
attrs: {
|
||||
label: {
|
||||
text: labelName
|
||||
}
|
||||
}
|
||||
})
|
||||
])
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Reset edge style
|
||||
* @param {Edge} edge
|
||||
*/
|
||||
resetEdgeStyle (edge) {
|
||||
edge.setAttrs(EDGE_PROPS.attrs)
|
||||
const labelName = this.getEdgeLabelName(edge)
|
||||
if (labelName) {
|
||||
edge.setLabels([
|
||||
{
|
||||
attrs: {
|
||||
label: {
|
||||
fill: EDGE_PROPS.defaultLabel.attrs.label.fill,
|
||||
text: labelName
|
||||
},
|
||||
body: {
|
||||
stroke: EDGE_PROPS.defaultLabel.attrs.body.stroke
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Set cell highlight
|
||||
* @param {Cell} cell
|
||||
*/
|
||||
setHighlight (cell) {
|
||||
if (cell.isEdge()) {
|
||||
this.setEdgeHighlight(cell)
|
||||
} else if (cell.isNode()) {
|
||||
this.setNodeHighlight(cell)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Reset cell highlight
|
||||
* @param {Cell} cell
|
||||
*/
|
||||
resetHighlight (cell) {
|
||||
if (cell.isEdge()) {
|
||||
this.resetEdgeStyle(cell)
|
||||
} else if (cell.isNode()) {
|
||||
this.resetNodeStyle(cell)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Convert the graph to JSON
|
||||
* @return {{cells:Cell[]}}
|
||||
*/
|
||||
toJSON () {
|
||||
return this.graph.toJSON()
|
||||
},
|
||||
/**
|
||||
* Generate graph with JSON
|
||||
*/
|
||||
fromJSON (json) {
|
||||
this.graph.fromJSON(json)
|
||||
},
|
||||
/**
|
||||
* getNodes
|
||||
* @return {Node[]}
|
||||
*/
|
||||
// interface Node {
|
||||
// id: number;
|
||||
// position: {x:number;y:number};
|
||||
// data: {taskType:string;taskName:string;}
|
||||
// }
|
||||
getNodes () {
|
||||
const nodes = this.graph.getNodes()
|
||||
return nodes.map((node) => {
|
||||
const position = node.getPosition()
|
||||
const data = node.getData()
|
||||
return {
|
||||
id: Number(node.id),
|
||||
position: position,
|
||||
data: data
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* getEdges
|
||||
* @return {Edge[]} Edge is inherited from the Cell
|
||||
*/
|
||||
// interface Edge {
|
||||
// label: string;
|
||||
// sourceId: number;
|
||||
// targetId: number;
|
||||
// }
|
||||
getEdges () {
|
||||
const edges = this.graph.getEdges()
|
||||
return edges.map((edge) => {
|
||||
const labelData = edge.getLabelAt(0)
|
||||
return {
|
||||
label: _.get(labelData, ['attrs', 'label', 'text'], ''),
|
||||
sourceId: Number(edge.getSourceCellId()),
|
||||
targetId: Number(edge.getTargetCellId())
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* downloadPNG
|
||||
* @param {string} filename
|
||||
*/
|
||||
downloadPNG (fileName = 'chart') {
|
||||
this.graph.toPNG(
|
||||
(dataUri) => {
|
||||
DataUri.downloadDataUri(dataUri, `${fileName}.png`)
|
||||
},
|
||||
{
|
||||
padding: {
|
||||
top: 50,
|
||||
right: 50,
|
||||
bottom: 50,
|
||||
left: 50
|
||||
},
|
||||
backgroundColor: '#f2f3f7'
|
||||
}
|
||||
)
|
||||
},
|
||||
/**
|
||||
* format
|
||||
* @desc Auto layout use @antv/layout
|
||||
*/
|
||||
format () {
|
||||
const dagreLayout = new DagreLayout({
|
||||
type: 'dagre',
|
||||
rankdir: 'LR',
|
||||
align: 'UL',
|
||||
// Calculate the node spacing based on the edge label length
|
||||
ranksepFunc: (d) => {
|
||||
const edges = this.graph.getOutgoingEdges(d.id)
|
||||
let max = 0
|
||||
if (edges && edges.length > 0) {
|
||||
edges.forEach((edge) => {
|
||||
const edgeView = this.graph.findViewByCell(edge)
|
||||
const labelWidth = +edgeView.findAttr(
|
||||
'width',
|
||||
_.get(edgeView, ['labelSelectors', '0', 'body'], null)
|
||||
)
|
||||
max = Math.max(max, labelWidth)
|
||||
})
|
||||
}
|
||||
return 50 + max
|
||||
},
|
||||
nodesep: 50,
|
||||
controlPoints: true
|
||||
})
|
||||
const json = this.toJSON()
|
||||
const nodes = json.cells.filter((cell) => cell.shape === X6_NODE_NAME)
|
||||
const edges = json.cells.filter((cell) => cell.shape === X6_EDGE_NAME)
|
||||
const newModel = dagreLayout.layout({
|
||||
nodes: nodes,
|
||||
edges: edges
|
||||
})
|
||||
this.fromJSON(newModel)
|
||||
},
|
||||
/**
|
||||
* add a node to the graph
|
||||
* @param {string|number} id
|
||||
* @param {string} taskType
|
||||
* @param {{x:number;y:number}} coordinate Default is { x: 100, y: 100 }
|
||||
*/
|
||||
addNode (id, taskType, coordinate = { x: 100, y: 100 }) {
|
||||
id += ''
|
||||
if (!tasksType[taskType]) {
|
||||
console.warn(`taskType:${taskType} is invalid!`)
|
||||
return
|
||||
}
|
||||
const node = this.genNodeJSON(id, taskType, '', coordinate)
|
||||
this.graph.addNode(node)
|
||||
},
|
||||
/**
|
||||
* generate node json
|
||||
* @param {number|string} id
|
||||
* @param {string} taskType
|
||||
* @param {{x:number;y:number}} coordinate Default is { x: 100, y: 100 }
|
||||
*/
|
||||
genNodeJSON (id, taskType, taskName, coordinate = { x: 100, y: 100 }) {
|
||||
id += ''
|
||||
const url = require(`../images/task-icos/${taskType.toLocaleLowerCase()}.png`)
|
||||
const truncation = taskName ? this.truncateText(taskName, 18) : id
|
||||
return {
|
||||
id: id,
|
||||
shape: X6_NODE_NAME,
|
||||
x: coordinate.x,
|
||||
y: coordinate.y,
|
||||
data: {
|
||||
taskType: taskType,
|
||||
taskName: taskName
|
||||
},
|
||||
attrs: {
|
||||
image: {
|
||||
// Use href instead of xlink:href, you may lose the icon when downloadPNG
|
||||
'xlink:href': url
|
||||
},
|
||||
title: {
|
||||
text: truncation
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* generate edge json
|
||||
* @param {number|string} sourceId
|
||||
* @param {number|string} targetId
|
||||
* @param {string} label
|
||||
*/
|
||||
genEdgeJSON (sourceId, targetId, label = '') {
|
||||
sourceId += ''
|
||||
targetId += ''
|
||||
return {
|
||||
shape: X6_EDGE_NAME,
|
||||
source: {
|
||||
cell: sourceId,
|
||||
port: X6_PORT_OUT_NAME
|
||||
},
|
||||
target: {
|
||||
cell: targetId,
|
||||
port: X6_PORT_IN_NAME
|
||||
},
|
||||
labels: label ? [label] : undefined
|
||||
}
|
||||
},
|
||||
/**
|
||||
* remove a node
|
||||
* @param {string|number} id NodeId
|
||||
*/
|
||||
removeNode (id) {
|
||||
id += ''
|
||||
this.graph.removeNode(id)
|
||||
this.removeTask(id)
|
||||
},
|
||||
/**
|
||||
* remove an edge
|
||||
* @param {string|number} id EdgeId
|
||||
*/
|
||||
removeEdge (id) {
|
||||
id += ''
|
||||
this.graph.removeEdge(id)
|
||||
},
|
||||
/**
|
||||
* remove multiple cells
|
||||
* @param {Cell[]} cells
|
||||
*/
|
||||
removeCells (cells) {
|
||||
this.graph.removeCells(cells)
|
||||
cells.forEach((cell) => {
|
||||
if (cell.isNode()) {
|
||||
this.removeTask(cell.id)
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* Gets the current selections
|
||||
* @return {Cell[]}
|
||||
*/
|
||||
getSelections () {
|
||||
return this.graph.getSelectedCells()
|
||||
},
|
||||
/**
|
||||
* Lock scroller
|
||||
*/
|
||||
lockScroller () {
|
||||
this.graph.lockScroller()
|
||||
},
|
||||
/**
|
||||
* Unlock scroller
|
||||
*/
|
||||
unlockScroller () {
|
||||
this.graph.unlockScroller()
|
||||
},
|
||||
/**
|
||||
* Drag && Drop Event
|
||||
*/
|
||||
_onDragStart (e, taskType) {
|
||||
if (!this.editable) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
this.dragging = {
|
||||
x: e.offsetX,
|
||||
y: e.offsetY,
|
||||
type: taskType.name
|
||||
}
|
||||
},
|
||||
calcGraphCoordinate (mClientX, mClientY) {
|
||||
// Distance from the mouse to the top-left corner of the container;
|
||||
const { left: cX, top: cY } =
|
||||
this.$refs.container.getBoundingClientRect()
|
||||
const mouseX = mClientX - cX
|
||||
const mouseY = mClientY - cY
|
||||
|
||||
// The distance that paper has been scrolled
|
||||
const { left: sLeft, top: sTop } = this.graph.getScrollbarPosition()
|
||||
const { left: oLeft, top: oTop } = this.originalScrollPosition
|
||||
const scrollX = sLeft - oLeft
|
||||
const scrollY = sTop - oTop
|
||||
|
||||
// Distance from the mouse to the top-left corner of the dragging element;
|
||||
const { x: eX, y: eY } = this.dragging
|
||||
|
||||
return {
|
||||
x: mouseX + scrollX - eX,
|
||||
y: mouseY + scrollY - eY
|
||||
}
|
||||
},
|
||||
_onDrop (e) {
|
||||
const { type } = this.dragging
|
||||
const { x, y } = this.calcGraphCoordinate(e.clientX, e.clientY)
|
||||
this.genTaskCodeList({
|
||||
genNum: 1
|
||||
})
|
||||
.then((res) => {
|
||||
const [code] = res
|
||||
this.addNode(code, type, { x, y })
|
||||
this.dagChart.openFormModel(code, type)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./canvas";
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./x6-style";
|
||||
</style>
|
@ -1,4 +1,3 @@
|
||||
import d3 from 'd3'
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
@ -15,24 +14,29 @@ import d3 from 'd3'
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
.dag-context-menu{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100px;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.12);
|
||||
|
||||
const DragZoom = function () {
|
||||
this.element = {}
|
||||
this.zoom = {}
|
||||
this.scale = 1
|
||||
.menu-item{
|
||||
padding: 5px 10px;
|
||||
border-bottom: solid 1px #f2f3f7;
|
||||
cursor: pointer;
|
||||
color: rgb(89, 89, 89);
|
||||
font-size: 12px;
|
||||
|
||||
&:hover:not(.disabled){
|
||||
color: #262626;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
&.disabled{
|
||||
cursor: not-allowed;
|
||||
color: rgba(89, 89, 89, .4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DragZoom.prototype.init = function () {
|
||||
const $canvas = $('#canvas')
|
||||
this.element = d3.select('#canvas')
|
||||
this.zoom = d3.behavior.zoom()
|
||||
.scaleExtent([0.5, 2])
|
||||
.on('zoom', () => {
|
||||
this.scale = d3.event.scale
|
||||
$canvas.css('transform', 'scale(' + this.scale + ')')
|
||||
$canvas.css('transform-origin', '0 0')
|
||||
})
|
||||
this.element.call(this.zoom).on('dblclick.zoom', null)
|
||||
}
|
||||
|
||||
export default new DragZoom()
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
<template>
|
||||
<div
|
||||
class="dag-context-menu"
|
||||
v-show="visible"
|
||||
:style="{
|
||||
left: `${left}px`,
|
||||
top: `${top}px`,
|
||||
}"
|
||||
>
|
||||
<menu-item :disabled="!startAvailable" @on-click="onStart">
|
||||
{{ $t("Start") }}
|
||||
</menu-item>
|
||||
<menu-item :disabled="readOnly" @on-click="onEdit">
|
||||
{{ $t("Edit") }}
|
||||
</menu-item>
|
||||
<menu-item :disabled="readOnly" @on-click="onCopy">
|
||||
{{ $t("Copy") }}
|
||||
</menu-item>
|
||||
<menu-item :disabled="readOnly" @on-click="onDelete">
|
||||
{{ $t("Delete") }}
|
||||
</menu-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapActions, mapMutations } from 'vuex'
|
||||
import { findComponentDownward, uuid } from '@/module/util/'
|
||||
import MenuItem from './menuItem.vue'
|
||||
|
||||
export default {
|
||||
name: 'dag-context-menu',
|
||||
inject: ['dagChart', 'dagCanvas'],
|
||||
components: {
|
||||
MenuItem
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
visible: false,
|
||||
left: 0,
|
||||
top: 0,
|
||||
canvasRef: null,
|
||||
currentTask: {
|
||||
code: 0,
|
||||
name: '',
|
||||
type: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('dag', ['isDetails', 'releaseState', 'tasks']),
|
||||
startAvailable () {
|
||||
return (
|
||||
this.$route.name === 'projects-definition-details' &&
|
||||
this.releaseState !== 'NOT_RELEASE'
|
||||
)
|
||||
},
|
||||
readOnly () {
|
||||
return this.isDetails
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
document.addEventListener('click', (e) => {
|
||||
this.hide()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
...mapActions('dag', ['genTaskCodeList']),
|
||||
...mapMutations('dag', ['addTask']),
|
||||
getDagCanvasRef () {
|
||||
if (this.canvasRef) {
|
||||
return this.canvasRef
|
||||
} else {
|
||||
const canvas = findComponentDownward(this.dagChart, 'dag-canvas')
|
||||
this.canvasRef = canvas
|
||||
return canvas
|
||||
}
|
||||
},
|
||||
setCurrentTask (task) {
|
||||
this.currentTask = { ...this.currentTask, ...task }
|
||||
},
|
||||
onStart () {
|
||||
this.dagChart.startRunning(this.currentTask.name)
|
||||
},
|
||||
onEdit () {
|
||||
this.dagChart.openFormModel(this.currentTask.code, this.currentTask.type)
|
||||
},
|
||||
onCopy () {
|
||||
const nodes = this.dagCanvas.getNodes()
|
||||
const targetNode = nodes.find(
|
||||
(node) => node.id === this.currentTask.code
|
||||
)
|
||||
const targetTask = this.tasks.find(
|
||||
(task) => task.code === this.currentTask.code
|
||||
)
|
||||
|
||||
if (!targetNode || !targetTask) return
|
||||
|
||||
this.genTaskCodeList({
|
||||
genNum: 1
|
||||
})
|
||||
.then((res) => {
|
||||
const [code] = res
|
||||
const taskName = uuid(targetTask.name + '_')
|
||||
const task = {
|
||||
...targetTask,
|
||||
code,
|
||||
name: taskName
|
||||
}
|
||||
this.dagCanvas.addNode(code, this.currentTask.type, {
|
||||
x: targetNode.position.x + 100,
|
||||
y: targetNode.position.y + 100
|
||||
})
|
||||
this.addTask(task)
|
||||
this.dagCanvas.setNodeName(code, taskName)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
},
|
||||
onDelete () {
|
||||
this.dagCanvas.removeNode(this.currentTask.code)
|
||||
},
|
||||
show (x = 0, y = 0) {
|
||||
this.dagCanvas.lockScroller()
|
||||
this.visible = true
|
||||
this.left = x + 10
|
||||
this.top = y + 10
|
||||
},
|
||||
hide () {
|
||||
this.dagCanvas.unlockScroller()
|
||||
this.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./contextMenu";
|
||||
</style>
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
<template>
|
||||
<div
|
||||
class="draggable-box"
|
||||
ref="draggable"
|
||||
draggable="true"
|
||||
@dragstart="onDragstart"
|
||||
@drag="onDrag"
|
||||
@dragend="onDragend"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'draggable-box',
|
||||
data () {
|
||||
return {
|
||||
tmp: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onDragstart (e) {
|
||||
this.$emit('onDragstart', e)
|
||||
},
|
||||
onDrag (e) {
|
||||
this.$emit('onDrag', e)
|
||||
},
|
||||
onDragend (e) {
|
||||
this.$emit('onDragend', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
<template>
|
||||
<el-drawer
|
||||
:visible.sync="drawerVisible"
|
||||
:wrapperClosable="false"
|
||||
size=""
|
||||
:with-header="false"
|
||||
>
|
||||
<div class="form-model-wrapper">
|
||||
<div class="title-box">
|
||||
<span class="name">{{ $t("Current connection settings") }}</span>
|
||||
</div>
|
||||
<div class="content-box">
|
||||
<div class="form-model">
|
||||
<!-- Node name -->
|
||||
<div class="clearfix list">
|
||||
<div class="text-box">
|
||||
<span>{{ $t("Connection name") }}</span>
|
||||
</div>
|
||||
<div class="cont-box">
|
||||
<label class="label-box">
|
||||
<el-input
|
||||
type="text"
|
||||
size="small"
|
||||
v-model="label"
|
||||
:disabled="isDetails"
|
||||
:placeholder="$t('Please enter name')"
|
||||
maxlength="100"
|
||||
>
|
||||
</el-input>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-box">
|
||||
<div class="submit" style="background: #fff">
|
||||
<el-button type="text" size="small" @click="cancel()">
|
||||
{{ $t("Cancel") }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="ok()"
|
||||
:disabled="isDetails"
|
||||
>{{ $t("Confirm add") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</template>
|
||||
<script>
|
||||
import disabledState from '@/module/mixin/disabledState'
|
||||
import { mapState } from 'vuex'
|
||||
import { findComponentDownward } from '@/module/util/'
|
||||
|
||||
export default {
|
||||
name: 'edge-edit-model',
|
||||
data () {
|
||||
return {
|
||||
id: '',
|
||||
label: '',
|
||||
drawerVisible: false
|
||||
}
|
||||
},
|
||||
inject: ['dagChart'],
|
||||
mixins: [disabledState],
|
||||
computed: {
|
||||
...mapState('dag', ['isDetails'])
|
||||
},
|
||||
methods: {
|
||||
getDagCanvasRef () {
|
||||
if (this.canvasRef) {
|
||||
return this.canvasRef
|
||||
} else {
|
||||
const canvas = findComponentDownward(this.dagChart, 'dag-canvas')
|
||||
this.canvasRef = canvas
|
||||
return canvas
|
||||
}
|
||||
},
|
||||
show ({ id, label }) {
|
||||
this.id = id
|
||||
this.label = label
|
||||
this.drawerVisible = true
|
||||
},
|
||||
cancel () {
|
||||
this.drawerVisible = false
|
||||
this.id = ''
|
||||
this.label = ''
|
||||
},
|
||||
ok () {
|
||||
const canvas = this.getDagCanvasRef()
|
||||
canvas.setEdgeLabel(this.id, this.label)
|
||||
this.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
<template>
|
||||
<div class="menu-item" :class="disabled ? 'disabled' : ''" @click="onClick">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'dag-context-menu-item',
|
||||
props: {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
onClick (e) {
|
||||
if (this.disabled) return
|
||||
this.$emit('on-click', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
<template>
|
||||
<div
|
||||
class="dag-status-menu"
|
||||
v-show="visible"
|
||||
:style="{
|
||||
left: `${left}px`,
|
||||
top: `${top}px`,
|
||||
}"
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'dag-status-menu',
|
||||
inject: ['dagChart', 'dagCanvas'],
|
||||
data () {
|
||||
return {
|
||||
visible: false,
|
||||
left: 0,
|
||||
top: 0,
|
||||
currentTask: {
|
||||
code: 0,
|
||||
name: '',
|
||||
type: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('dag', ['tasks'])
|
||||
},
|
||||
methods: {
|
||||
setCurrentTask (task) {
|
||||
this.currentTask = { ...this.currentTask, ...task }
|
||||
},
|
||||
show (x = 0, y = 0) {
|
||||
this.dagCanvas.lockScroller()
|
||||
this.visible = true
|
||||
this.left = x
|
||||
this.top = y
|
||||
},
|
||||
hide () {
|
||||
this.dagCanvas.unlockScroller()
|
||||
this.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./contextMenu";
|
||||
</style>
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
.dag-taskbar {
|
||||
width: 190px;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
margin-right: 20px;
|
||||
|
||||
.taskbar-title {
|
||||
display: flex;
|
||||
border-bottom: dashed 1px #e5e5e5;
|
||||
height: 42px;
|
||||
padding: 0 20px;
|
||||
align-items: center;
|
||||
|
||||
h4 {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.tasks {
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
box-sizing: border-box;
|
||||
max-height: calc(100% - 42px);
|
||||
overflow: auto;
|
||||
|
||||
.draggable-box {
|
||||
cursor: move;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.task-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px dashed #e4e4e4;
|
||||
padding: 0 10px;
|
||||
border-radius: 4px;
|
||||
|
||||
em {
|
||||
margin-right: 10px;
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-size: 100% 100%;
|
||||
&.icos-shell {
|
||||
background-image: url("../images/task-icos/shell.png");
|
||||
}
|
||||
&.icos-sub_process {
|
||||
background-image: url("../images/task-icos/sub_process.png");
|
||||
}
|
||||
&.icos-procedure {
|
||||
background-image: url("../images/task-icos/procedure.png");
|
||||
}
|
||||
&.icos-sql {
|
||||
background-image: url("../images/task-icos/sql.png");
|
||||
}
|
||||
&.icos-flink {
|
||||
background-image: url("../images/task-icos/flink.png");
|
||||
}
|
||||
&.icos-mr {
|
||||
background-image: url("../images/task-icos/mr.png");
|
||||
}
|
||||
&.icos-python {
|
||||
background-image: url("../images/task-icos/python.png");
|
||||
}
|
||||
&.icos-dependent {
|
||||
background-image: url("../images/task-icos/dependent.png");
|
||||
}
|
||||
&.icos-http {
|
||||
background-image: url("../images/task-icos/http.png");
|
||||
}
|
||||
&.icos-datax {
|
||||
background-image: url("../images/task-icos/datax.png");
|
||||
}
|
||||
&.icos-sqoop {
|
||||
background-image: url("../images/task-icos/sqoop.png");
|
||||
}
|
||||
&.icos-conditions {
|
||||
background-image: url("../images/task-icos/conditions.png");
|
||||
}
|
||||
&.icos-waterdrop {
|
||||
background-image: url("../images/task-icos/waterdrop.png");
|
||||
}
|
||||
&.icos-spark {
|
||||
background-image: url("../images/task-icos/spark.png");
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #288fff;
|
||||
border: 1px dashed #288fff;
|
||||
background-color: rgba(40, 143, 255, 0.1);
|
||||
|
||||
em {
|
||||
&.icos-shell {
|
||||
background-image: url("../images/task-icos/shell_hover.png");
|
||||
}
|
||||
&.icos-sub_process {
|
||||
background-image: url("../images/task-icos/sub_process_hover.png");
|
||||
}
|
||||
&.icos-procedure {
|
||||
background-image: url("../images/task-icos/procedure_hover.png");
|
||||
}
|
||||
&.icos-sql {
|
||||
background-image: url("../images/task-icos/sql_hover.png");
|
||||
}
|
||||
&.icos-flink {
|
||||
background-image: url("../images/task-icos/flink_hover.png");
|
||||
}
|
||||
&.icos-mr {
|
||||
background-image: url("../images/task-icos/mr_hover.png");
|
||||
}
|
||||
&.icos-python {
|
||||
background-image: url("../images/task-icos/python_hover.png");
|
||||
}
|
||||
&.icos-dependent {
|
||||
background-image: url("../images/task-icos/dependent_hover.png");
|
||||
}
|
||||
&.icos-http {
|
||||
background-image: url("../images/task-icos/http_hover.png");
|
||||
}
|
||||
&.icos-datax {
|
||||
background-image: url("../images/task-icos/datax_hover.png");
|
||||
}
|
||||
&.icos-sqoop {
|
||||
background-image: url("../images/task-icos/sqoop_hover.png");
|
||||
}
|
||||
&.icos-conditions {
|
||||
background-image: url("../images/task-icos/conditions_hover.png");
|
||||
}
|
||||
&.icos-waterdrop {
|
||||
background-image: url("../images/task-icos/waterdrop_hover.png");
|
||||
}
|
||||
&.icos-spark {
|
||||
background-image: url("../images/task-icos/spark_hover.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
<template>
|
||||
<div class="dag-taskbar">
|
||||
<div class="taskbar-title">
|
||||
<h4>{{$t('Toolbar')}}</h4>
|
||||
</div>
|
||||
<div class="tasks">
|
||||
<template v-for="taskType in tasksTypeList">
|
||||
<draggable-box
|
||||
:key="taskType.name"
|
||||
@onDragstart="(e) => $emit('on-drag-start', e, taskType)"
|
||||
>
|
||||
<div class="task-item">
|
||||
<em :class="`icos-${taskType.name.toLocaleLowerCase()}`"></em>
|
||||
<span>{{ taskType.name }}</span>
|
||||
</div>
|
||||
</draggable-box>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggableBox from './draggableBox.vue'
|
||||
import { tasksType } from '../config.js'
|
||||
|
||||
export default {
|
||||
name: 'dag-taskbar',
|
||||
components: {
|
||||
draggableBox
|
||||
},
|
||||
data () {
|
||||
const tasksTypeList = Object.keys(tasksType).map((type) => {
|
||||
return {
|
||||
name: type,
|
||||
desc: tasksType[type].desc
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
tasksTypeList
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./taskbar";
|
||||
</style>
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
.dag-toolbar {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background-color: #fff;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin: 0 10px 0 0;
|
||||
}
|
||||
|
||||
.transparent {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.toolbar-operation {
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
margin-left: 20px;
|
||||
color: #666666;
|
||||
&:hover {
|
||||
color: #288fff;
|
||||
}
|
||||
&.last{
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar-btn {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.toolbar-left {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.toolbar-right {
|
||||
justify-self: flex-end;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.toolbar-el-btn{
|
||||
margin-right: 0;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.custom-ico{
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-size: 100% 100%;
|
||||
|
||||
&.view-variables{
|
||||
background-image: url('../images/view-variables.png');
|
||||
&:hover{
|
||||
background-image: url('../images/view-variables_hover.png');
|
||||
}
|
||||
}
|
||||
|
||||
&.startup-parameters{
|
||||
background-image: url('../images/startup-params.png');
|
||||
&:hover{
|
||||
background-image: url('../images/startup-params_hover.png');
|
||||
}
|
||||
}
|
||||
|
||||
&.full-screen-open{
|
||||
background-image: url('../images/full-screen-open.png');
|
||||
&:hover{
|
||||
background-image: url('../images/full-screen-open_hover.png');
|
||||
}
|
||||
}
|
||||
|
||||
&.full-screen-close{
|
||||
background-image: url('../images/full-screen-close.png');
|
||||
&:hover{
|
||||
background-image: url('../images/full-screen-close_hover.png');
|
||||
}
|
||||
}
|
||||
|
||||
&.graph-format{
|
||||
background-image: url('../images/graph-format.png');
|
||||
&:hover{
|
||||
background-image: url('../images/graph-format_hover.png');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
<template>
|
||||
<div class="dag-toolbar">
|
||||
<h3>{{ dagChart.name || $t("Create process") }}</h3>
|
||||
<el-tooltip
|
||||
v-if="dagChart.name"
|
||||
class="toolbar-operation"
|
||||
:content="$t('Copy name')"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="el-icon-copy-document" @click="copyName"></i>
|
||||
</el-tooltip>
|
||||
<textarea ref="textarea" cols="30" rows="10" class="transparent"></textarea>
|
||||
<div class="toolbar-left">
|
||||
<el-tooltip
|
||||
:content="$t('View variables')"
|
||||
placement="bottom"
|
||||
class="toolbar-operation"
|
||||
>
|
||||
<i
|
||||
class="custom-ico view-variables"
|
||||
v-if="$route.name === 'projects-instance-details'"
|
||||
@click="toggleVariableView"
|
||||
></i>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
:content="$t('Startup parameter')"
|
||||
placement="bottom"
|
||||
class="toolbar-operation"
|
||||
>
|
||||
<i
|
||||
class="custom-ico startup-parameters"
|
||||
v-if="$route.name === 'projects-instance-details'"
|
||||
@click="toggleParamView"
|
||||
></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<el-tooltip
|
||||
class="toolbar-operation"
|
||||
:content="$t('Delete selected lines or nodes')"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="el-icon-delete" @click="removeCells"></i>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
class="toolbar-operation"
|
||||
:content="$t('Download')"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="el-icon-download" @click="downloadPNG"></i>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
class="toolbar-operation"
|
||||
:content="$t('Full Screen')"
|
||||
placement="bottom"
|
||||
>
|
||||
<i
|
||||
:class="[
|
||||
'custom-ico',
|
||||
dagChart.fullScreen
|
||||
? 'full-screen-close'
|
||||
: 'full-screen-open',
|
||||
]"
|
||||
@click="toggleFullScreen"
|
||||
></i>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
class="toolbar-operation last"
|
||||
:content="$t('Format DAG')"
|
||||
placement="bottom"
|
||||
>
|
||||
<i class="custom-ico graph-format" @click="chartFormat"></i>
|
||||
</el-tooltip>
|
||||
<el-button
|
||||
class="toolbar-el-btn"
|
||||
type="primary"
|
||||
size="mini"
|
||||
@click="saveProcess"
|
||||
>{{ $t("Save") }}</el-button
|
||||
>
|
||||
<el-button
|
||||
class="toolbar-el-btn"
|
||||
v-if="$route.query.subProcessCodes"
|
||||
type="primary"
|
||||
size="mini"
|
||||
icon="el-icon-back"
|
||||
@click="dagChart.returnToPrevProcess"
|
||||
>
|
||||
{{ $t("Return_1") }}
|
||||
</el-button>
|
||||
<el-button
|
||||
class="toolbar-el-btn"
|
||||
type="primary"
|
||||
icon="el-icon-switch-button"
|
||||
size="mini"
|
||||
v-if="type === 'instance' || 'definition'"
|
||||
@click="returnToListPage"
|
||||
>
|
||||
{{ $t("Close") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { findComponentDownward } from '@/module/util/'
|
||||
|
||||
export default {
|
||||
name: 'dag-toolbar',
|
||||
inject: ['dagChart'],
|
||||
data () {
|
||||
return {
|
||||
canvasRef: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDagCanvasRef () {
|
||||
if (this.canvasRef) {
|
||||
return this.canvasRef
|
||||
} else {
|
||||
const canvas = findComponentDownward(this.dagChart, 'dag-canvas')
|
||||
this.canvasRef = canvas
|
||||
return canvas
|
||||
}
|
||||
},
|
||||
toggleVariableView () {
|
||||
findComponentDownward(this.$root, 'assist-dag-index')._toggleView()
|
||||
},
|
||||
toggleParamView () {
|
||||
findComponentDownward(
|
||||
this.$root,
|
||||
'starting-params-dag-index'
|
||||
)._toggleParam()
|
||||
},
|
||||
toggleFullScreen () {
|
||||
this.dagChart.toggleFullScreen()
|
||||
},
|
||||
saveProcess () {
|
||||
const canvas = this.getDagCanvasRef()
|
||||
const nodes = canvas.getNodes()
|
||||
if (!nodes.length) {
|
||||
this.$message.error(this.$t('Failed to create node to save'))
|
||||
return
|
||||
}
|
||||
this.dagChart.toggleSaveDialog(true)
|
||||
},
|
||||
downloadPNG () {
|
||||
const canvas = this.getDagCanvasRef()
|
||||
canvas.downloadPNG(this.processName)
|
||||
},
|
||||
removeCells () {
|
||||
const canvas = this.getDagCanvasRef()
|
||||
const selections = canvas.getSelections()
|
||||
canvas.removeCells(selections)
|
||||
},
|
||||
copyName () {
|
||||
const textarea = this.$refs.textarea
|
||||
textarea.value = this.dagChart.name
|
||||
textarea.select()
|
||||
document.execCommand('copy')
|
||||
this.$message(this.$t('Copy success'))
|
||||
},
|
||||
chartFormat () {
|
||||
const canvas = this.getDagCanvasRef()
|
||||
canvas.format()
|
||||
},
|
||||
// TODO
|
||||
refreshTaskState () {},
|
||||
returnToListPage () {
|
||||
let $name = this.$route.name
|
||||
if ($name && $name.indexOf('definition') !== -1) {
|
||||
this.$router.push({ name: 'projects-definition-list' })
|
||||
} else {
|
||||
this.$router.push({ name: 'projects-instance-list' })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "./toolbar";
|
||||
</style>
|
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const X6_NODE_NAME = 'dag-task'
|
||||
export const X6_EDGE_NAME = 'dag-edge'
|
||||
export const X6_PORT_OUT_NAME = 'dag-port-out'
|
||||
export const X6_PORT_IN_NAME = 'dag-port-in'
|
||||
|
||||
const EDGE = '#999999'
|
||||
const BG_BLUE = 'rgba(40, 143, 255, 0.1)'
|
||||
const BG_WHITE = '#FFFFFF'
|
||||
const NODE_BORDER = '#e4e4e4'
|
||||
const TITLE = '#333'
|
||||
const STROKE_BLUE = '#288FFF'
|
||||
|
||||
export const PORT_PROPS = {
|
||||
groups: {
|
||||
[X6_PORT_OUT_NAME]: {
|
||||
position: {
|
||||
name: 'absolute',
|
||||
args: {
|
||||
x: 200,
|
||||
y: 24
|
||||
}
|
||||
},
|
||||
markup: [
|
||||
{
|
||||
tagName: 'g',
|
||||
selector: 'body',
|
||||
children: [
|
||||
{
|
||||
tagName: 'circle',
|
||||
selector: 'circle-outer'
|
||||
},
|
||||
{
|
||||
tagName: 'text',
|
||||
selector: 'plus-text'
|
||||
},
|
||||
{
|
||||
tagName: 'circle',
|
||||
selector: 'circle-inner'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
attrs: {
|
||||
body: {
|
||||
magnet: true
|
||||
},
|
||||
'plus-text': {
|
||||
fontSize: 12,
|
||||
fill: EDGE,
|
||||
text: '+',
|
||||
textAnchor: 'middle',
|
||||
x: 0,
|
||||
y: 3
|
||||
},
|
||||
'circle-outer': {
|
||||
stroke: EDGE,
|
||||
strokeWidth: 1,
|
||||
r: 6,
|
||||
fill: BG_WHITE
|
||||
},
|
||||
'circle-inner': {
|
||||
r: 4,
|
||||
fill: 'transparent'
|
||||
}
|
||||
}
|
||||
},
|
||||
[X6_PORT_IN_NAME]: {
|
||||
position: {
|
||||
name: 'absolute',
|
||||
args: {
|
||||
x: 0,
|
||||
y: 24
|
||||
}
|
||||
},
|
||||
markup: [
|
||||
{
|
||||
tagName: 'g',
|
||||
selector: 'body',
|
||||
className: 'in-port-body',
|
||||
children: [{
|
||||
tagName: 'circle',
|
||||
selector: 'circle',
|
||||
className: 'circle'
|
||||
}]
|
||||
}
|
||||
],
|
||||
attrs: {
|
||||
body: {
|
||||
magnet: true
|
||||
},
|
||||
circle: {
|
||||
r: 4,
|
||||
strokeWidth: 0,
|
||||
fill: 'transparent'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const PORT_HIGHLIGHT_PROPS = {
|
||||
[X6_PORT_OUT_NAME]: {
|
||||
attrs: {
|
||||
'circle-outer': {
|
||||
stroke: STROKE_BLUE,
|
||||
fill: BG_BLUE
|
||||
},
|
||||
'plus-text': {
|
||||
fill: STROKE_BLUE
|
||||
},
|
||||
'circle-inner': {
|
||||
fill: STROKE_BLUE
|
||||
}
|
||||
}
|
||||
},
|
||||
[X6_PORT_IN_NAME]: {}
|
||||
}
|
||||
|
||||
export const NODE_PROPS = {
|
||||
width: 220,
|
||||
height: 48,
|
||||
markup: [
|
||||
{
|
||||
tagName: 'rect',
|
||||
selector: 'body'
|
||||
},
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'image'
|
||||
},
|
||||
{
|
||||
tagName: 'text',
|
||||
selector: 'title'
|
||||
}
|
||||
// {
|
||||
// tagName: 'foreignObject',
|
||||
// selector: 'fo',
|
||||
// children: [
|
||||
// {
|
||||
// tagName: 'body',
|
||||
// selector: 'fo-body',
|
||||
// ns: 'http://www.w3.org/1999/xhtml',
|
||||
// children: [{
|
||||
// tagName: 'i',
|
||||
// selector: 'state',
|
||||
// className: 'state-icon el-icon-circle-check'
|
||||
// }]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
],
|
||||
attrs: {
|
||||
body: {
|
||||
refWidth: '100%',
|
||||
refHeight: '100%',
|
||||
rx: 6,
|
||||
ry: 6,
|
||||
pointerEvents: 'visiblePainted',
|
||||
fill: BG_WHITE,
|
||||
stroke: NODE_BORDER,
|
||||
strokeWidth: 1
|
||||
},
|
||||
image: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
refX: 12,
|
||||
refY: 9
|
||||
},
|
||||
title: {
|
||||
refX: 45,
|
||||
refY: 18,
|
||||
fontFamily: 'Microsoft Yahei',
|
||||
fontSize: 12,
|
||||
fontWeight: 'bold',
|
||||
fill: TITLE,
|
||||
strokeWidth: 0
|
||||
},
|
||||
fo: {
|
||||
refX: '46%',
|
||||
refY: -25,
|
||||
width: 18,
|
||||
height: 18
|
||||
},
|
||||
state: {
|
||||
style: {
|
||||
display: 'block',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
fontSize: '18px'
|
||||
}
|
||||
}
|
||||
},
|
||||
ports: {
|
||||
...PORT_PROPS,
|
||||
items: [
|
||||
{
|
||||
id: X6_PORT_OUT_NAME,
|
||||
group: X6_PORT_OUT_NAME
|
||||
},
|
||||
{
|
||||
id: X6_PORT_IN_NAME,
|
||||
group: X6_PORT_IN_NAME
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export const NODE_HIGHLIGHT_PROPS = {
|
||||
attrs: {
|
||||
body: {
|
||||
fill: BG_BLUE,
|
||||
stroke: STROKE_BLUE,
|
||||
strokeDasharray: '5,2'
|
||||
},
|
||||
title: {
|
||||
fill: STROKE_BLUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const EDGE_PROPS = {
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: EDGE,
|
||||
strokeWidth: 0.8,
|
||||
targetMarker: {
|
||||
tagName: 'path',
|
||||
fill: EDGE,
|
||||
strokeWidth: 0,
|
||||
d: 'M 6 -3 0 0 6 3 Z'
|
||||
}
|
||||
}
|
||||
},
|
||||
connector: {
|
||||
name: 'rounded'
|
||||
},
|
||||
router: {
|
||||
name: 'er',
|
||||
args: {
|
||||
offset: 20,
|
||||
min: 20,
|
||||
direction: 'L'
|
||||
}
|
||||
},
|
||||
defaultLabel: {
|
||||
markup: [
|
||||
{
|
||||
tagName: 'rect',
|
||||
selector: 'body'
|
||||
},
|
||||
{
|
||||
tagName: 'text',
|
||||
selector: 'label'
|
||||
}
|
||||
],
|
||||
attrs: {
|
||||
label: {
|
||||
fill: EDGE,
|
||||
fontSize: 14,
|
||||
textAnchor: 'middle',
|
||||
textVerticalAnchor: 'middle',
|
||||
pointerEvents: 'none'
|
||||
},
|
||||
body: {
|
||||
ref: 'label',
|
||||
fill: BG_WHITE,
|
||||
stroke: EDGE,
|
||||
strokeWidth: 1,
|
||||
rx: 4,
|
||||
ry: 4,
|
||||
refWidth: '140%',
|
||||
refHeight: '140%',
|
||||
refX: '-20%',
|
||||
refY: '-20%'
|
||||
}
|
||||
},
|
||||
position: {
|
||||
distance: 0.5,
|
||||
options: {
|
||||
absoluteDistance: true,
|
||||
reverseDistance: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const EDGE_HIGHLIGHT_PROPS = {
|
||||
attrs: {
|
||||
line: {
|
||||
stroke: STROKE_BLUE,
|
||||
targetMarker: {
|
||||
fill: STROKE_BLUE
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultLabel: {
|
||||
attrs: {
|
||||
label: {
|
||||
fill: STROKE_BLUE
|
||||
},
|
||||
body: {
|
||||
fill: BG_WHITE,
|
||||
stroke: STROKE_BLUE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
$STROKE_BLUE: #288FFF;
|
||||
$BG_WHITE: #FFFFFF;
|
||||
|
||||
.x6-node[data-shape="dag-task"]{
|
||||
.in-port-body{
|
||||
&.adsorbed,&.available{
|
||||
.circle {
|
||||
stroke: $STROKE_BLUE;
|
||||
stroke-width: 4;
|
||||
fill: $BG_WHITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import Vue from 'vue'
|
||||
import _ from 'lodash'
|
||||
import i18n from '@/module/i18n'
|
||||
import { jsPlumb } from 'jsplumb'
|
||||
import JSP from './plugIn/jsPlumbHandle'
|
||||
import DownChart from './plugIn/downChart'
|
||||
import store from '@/conf/home/store'
|
||||
import dagre from 'dagre'
|
||||
|
||||
/**
|
||||
* Prototype method
|
||||
*/
|
||||
const Dag = function () {
|
||||
this.dag = {}
|
||||
this.instance = {}
|
||||
}
|
||||
|
||||
/**
|
||||
* init
|
||||
* @dag dag vue instance
|
||||
*/
|
||||
Dag.prototype.init = function ({ dag, instance }) {
|
||||
this.dag = dag
|
||||
this.instance = instance
|
||||
}
|
||||
|
||||
/**
|
||||
* set init config
|
||||
*/
|
||||
Dag.prototype.setConfig = function (o) {
|
||||
JSP.setConfig(o)
|
||||
}
|
||||
|
||||
/**
|
||||
* create dag
|
||||
*/
|
||||
Dag.prototype.create = function () {
|
||||
const self = this
|
||||
const plumbIns = jsPlumb.getInstance()
|
||||
plumbIns.reset()
|
||||
plumbIns.ready(() => {
|
||||
JSP.init({
|
||||
dag: this.dag,
|
||||
instance: this.instance,
|
||||
options: {
|
||||
onRemoveNodes ($id) {
|
||||
self.dag.removeEventModelById($id)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// init event
|
||||
JSP.handleEvent()
|
||||
|
||||
// init draggable
|
||||
JSP.draggable()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Action event on the right side of the toolbar
|
||||
*/
|
||||
Dag.prototype.toolbarEvent = function ({ item, code, is }) {
|
||||
const self = this
|
||||
switch (code) {
|
||||
case 'pointer':
|
||||
JSP.handleEventPointer(is)
|
||||
break
|
||||
case 'line':
|
||||
JSP.handleEventLine(is)
|
||||
break
|
||||
case 'remove':
|
||||
JSP.handleEventRemove()
|
||||
break
|
||||
case 'screen':
|
||||
JSP.handleEventScreen({ item, is })
|
||||
break
|
||||
case 'download':
|
||||
Vue.prototype.$confirm(`${i18n.$t('Please confirm whether the workflow has been saved before downloading')}`, `${i18n.$t('Download')}`, {
|
||||
confirmButtonText: `${i18n.$t('Confirm')}`,
|
||||
cancelButtonText: `${i18n.$t('Cancel')}`,
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
DownChart.download({
|
||||
dagThis: self.dag
|
||||
})
|
||||
}).catch(() => {
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Echo data display
|
||||
*/
|
||||
Dag.prototype.backfill = function (arg) {
|
||||
const that = this
|
||||
if (arg) {
|
||||
const marginX = 100
|
||||
const g = new dagre.graphlib.Graph()
|
||||
g.setGraph({})
|
||||
g.setDefaultEdgeLabel(function () { return {} })
|
||||
|
||||
for (const i in store.state.dag.locations) {
|
||||
const location = store.state.dag.locations[i]
|
||||
g.setNode(i, { label: i, width: Math.min(location.name.length * 7, 170), height: 150 })
|
||||
}
|
||||
|
||||
for (const i in store.state.dag.connects) {
|
||||
const connect = store.state.dag.connects[i]
|
||||
g.setEdge(connect.endPointSourceId, connect.endPointTargetId)
|
||||
}
|
||||
dagre.layout(g)
|
||||
|
||||
const dataObject = {}
|
||||
g.nodes().forEach(function (v) {
|
||||
const node = g.node(v)
|
||||
const location = store.state.dag.locations[node.label]
|
||||
const obj = {}
|
||||
obj.name = location.name
|
||||
obj.x = node.x + marginX
|
||||
obj.y = node.y
|
||||
obj.targetarr = location.targetarr
|
||||
dataObject[node.label] = obj
|
||||
})
|
||||
jsPlumb.ready(() => {
|
||||
JSP.init({
|
||||
dag: this.dag,
|
||||
instance: this.instance,
|
||||
options: {
|
||||
onRemoveNodes ($id) {
|
||||
that.dag.removeEventModelById($id)
|
||||
}
|
||||
}
|
||||
})
|
||||
// Backfill
|
||||
JSP.jspBackfill({
|
||||
// connects
|
||||
connects: _.cloneDeep(store.state.dag.connects),
|
||||
// Node location information
|
||||
locations: _.cloneDeep(dataObject),
|
||||
// Node data
|
||||
largeJson: _.cloneDeep(store.state.dag.tasks)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
const plumbIns = jsPlumb.getInstance()
|
||||
plumbIns.reset()
|
||||
plumbIns.ready(() => {
|
||||
JSP.init({
|
||||
dag: this.dag,
|
||||
instance: this.instance,
|
||||
options: {
|
||||
onRemoveNodes ($id) {
|
||||
that.dag.removeEventModelById($id)
|
||||
}
|
||||
}
|
||||
})
|
||||
// Backfill
|
||||
JSP.jspBackfill({
|
||||
// connects
|
||||
connects: _.cloneDeep(store.state.dag.connects),
|
||||
// Node location information
|
||||
locations: _.cloneDeep(store.state.dag.locations),
|
||||
// Node data
|
||||
largeJson: _.cloneDeep(store.state.dag.tasks)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dag storage format data
|
||||
*/
|
||||
Dag.prototype.saveStore = function () {
|
||||
return JSP.saveStore()
|
||||
}
|
||||
|
||||
export default new Dag()
|
563
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss
Executable file → Normal file
@ -14,558 +14,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.dag-model {
|
||||
background: url("../img/dag_bg.png");
|
||||
height: calc(100vh - 100px);
|
||||
::selection {
|
||||
background:transparent;
|
||||
}
|
||||
::-moz-selection {
|
||||
background:transparent;
|
||||
}
|
||||
::-webkit-selection {
|
||||
background:transparent;
|
||||
}
|
||||
.jsplumb-connector {
|
||||
z-index: 1;
|
||||
}
|
||||
.endpoint-tasks {
|
||||
margin-top:22px;
|
||||
}
|
||||
.draggable {
|
||||
> span {
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-top: -4px;
|
||||
padding: 0 4px;
|
||||
width: 200px;
|
||||
margin-left: -81px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -12px;
|
||||
}
|
||||
.fa {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
top: -8px;
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
}
|
||||
.icos {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
&.active-tasks {
|
||||
span {
|
||||
color: #0296DF;
|
||||
}
|
||||
}
|
||||
}
|
||||
.icos {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 2px;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
z-index: 9;
|
||||
}
|
||||
.icos-SHELL {
|
||||
background: url("../img/toolbar_SHELL.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-WATERDROP {
|
||||
background: url("../img/toolbar_WATERDROP.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-SUB_PROCESS {
|
||||
background: url("../img/toolbar_SUB_PROCESS.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-PROCEDURE {
|
||||
background: url("../img/toolbar_PROCEDURE.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-SQL {
|
||||
background: url("../img/toolbar_SQL.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-SPARK {
|
||||
background: url("../img/toolbar_SPARK.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-FLINK {
|
||||
background: url("../img/toolbar_FLINK.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-MR {
|
||||
background: url("../img/toolbar_MR.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-PYTHON {
|
||||
background: url("../img/toolbar_PYTHON.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-DEPENDENT {
|
||||
background: url("../img/toolbar_DEPENDENT.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-HTTP {
|
||||
background: url("../img/toolbar_HTTP.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-DATAX {
|
||||
background: url("../img/toolbar_DATAX.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-SQOOP {
|
||||
background: url("../img/toolbar_SQOOP.png") no-repeat 50% 50%;
|
||||
}
|
||||
.icos-CONDITIONS {
|
||||
background: url("../img/toolbar_CONDITIONS.png") no-repeat 50% 50%;
|
||||
}
|
||||
.toolbar {
|
||||
width: 60px;
|
||||
height: 100%;
|
||||
background: #F2F3F7;
|
||||
float: left;
|
||||
border-radius: 0 0 0 3px;
|
||||
.title {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
background: #40434C;
|
||||
text-align: center;
|
||||
border-radius: 3px 0 0 0;
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.toolbar-btn {
|
||||
overflow: hidden;
|
||||
padding: 8px 11px 0 11px;
|
||||
.bar-box {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
float: left;
|
||||
margin-bottom: 3px;
|
||||
border-radius: 3px;
|
||||
.disabled {
|
||||
.icos {
|
||||
opacity: .6;
|
||||
-webkit-filter: grayscale(100%);
|
||||
-moz-filter: grayscale(100%);
|
||||
-ms-filter: grayscale(100%);
|
||||
-o-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
filter: gray;
|
||||
}
|
||||
}
|
||||
&:nth-child(odd) {
|
||||
margin-right: 6px;
|
||||
}
|
||||
&.active {
|
||||
background: #e1e2e3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.dag-contect {
|
||||
float: left;
|
||||
width: calc(100% - 60px);
|
||||
height: 100%;
|
||||
.dag-toolbar {
|
||||
height: 40px;
|
||||
background: #F2F3F7;
|
||||
position: relative;
|
||||
border-radius: 0 3px 0 0;
|
||||
.ans-btn-text {
|
||||
color: #337ab7;
|
||||
.ans-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
.assist-btn {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 7px;
|
||||
>.name {
|
||||
padding-left: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
>.copy-name {
|
||||
cursor: pointer;
|
||||
padding-left: 4px;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
&:hover {
|
||||
i {
|
||||
color: #47c3ff;
|
||||
}
|
||||
}
|
||||
i {
|
||||
color: #333;
|
||||
font-size: 18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
.save-btn {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 6px;
|
||||
.operation {
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
a {
|
||||
float: left;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
text-align: center;
|
||||
line-height: 28px;
|
||||
margin-left: 6px;
|
||||
border-radius: 3px;
|
||||
vertical-align: middle;
|
||||
i {
|
||||
color: #333;
|
||||
}
|
||||
&.active {
|
||||
// background: #e1e2e3;
|
||||
i {
|
||||
color: #2d8cf0;
|
||||
}
|
||||
}
|
||||
&.disable {
|
||||
i {
|
||||
color: #bbb;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.dag-container {
|
||||
height: calc(100% - 40px);
|
||||
overflow-x: auto;
|
||||
&::-webkit-scrollbar{
|
||||
width: 9px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tools-model {
|
||||
height: 60px;
|
||||
background: #F4F5F4;
|
||||
border-radius: 3px 3px 0px 0px;
|
||||
}
|
||||
}
|
||||
#screen {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.v-modal-custom-log {
|
||||
z-index: 101;
|
||||
}
|
||||
|
||||
svg path:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#chart-container .ui-selecting {
|
||||
span {
|
||||
color: #0296DF;
|
||||
}
|
||||
}
|
||||
#chart-container .ui-selected {
|
||||
span {
|
||||
color: #0296DF;
|
||||
}
|
||||
}
|
||||
|
||||
.contextmenu {
|
||||
position: fixed;
|
||||
width: 90px;
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 2px 4px 1px rgba(0, 0, 0, 0.1);
|
||||
padding: 4px 4px;
|
||||
visibility:hidden;
|
||||
z-index: 10000;
|
||||
a {
|
||||
height: 30px;
|
||||
line-height: 28px;
|
||||
display: block;
|
||||
i {
|
||||
font-size: 16px;
|
||||
vertical-align: middle;
|
||||
margin-left: 10px;
|
||||
}
|
||||
span {
|
||||
vertical-align: middle;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
padding-left: 2px;
|
||||
}
|
||||
&:hover {
|
||||
background: #f6faff;
|
||||
}
|
||||
&#startRunning {
|
||||
i {
|
||||
color: #35cd75;
|
||||
}
|
||||
}
|
||||
&#editNodes {
|
||||
i {
|
||||
color: #0097e0;
|
||||
}
|
||||
}
|
||||
&#removeNodes {
|
||||
i {
|
||||
color: #f04d4e;
|
||||
}
|
||||
}
|
||||
&#copyNodes {
|
||||
i {
|
||||
color: #FABC05;
|
||||
}
|
||||
}
|
||||
&.disbled {
|
||||
i,span {
|
||||
color: #aaa !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.jtk-demo {
|
||||
//min-width: calc(100% - 220px);
|
||||
width: 8000px;
|
||||
height: 5000px;
|
||||
svg:not(:root){
|
||||
z-index: 11;
|
||||
}
|
||||
}
|
||||
|
||||
.jtk-demo-canvas {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.jtk-bootstrap {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.jtk-bootstrap .jtk-page-container {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.jtk-bootstrap .jtk-container {
|
||||
width: 60%;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.jtk-bootstrap-wide .jtk-container {
|
||||
width: 80%;
|
||||
max-width: 1187px;
|
||||
}
|
||||
|
||||
.jtk-demo-main {
|
||||
position: relative;
|
||||
margin-top: 98px;
|
||||
}
|
||||
|
||||
.jtk-demo-main .description {
|
||||
font-size: 13px;
|
||||
margin-top: 25px;
|
||||
padding: 13px;
|
||||
margin-bottom: 22px;
|
||||
background-color: #f4f5ef;
|
||||
}
|
||||
|
||||
.jtk-demo-main .description li {
|
||||
list-style-type: disc !important;
|
||||
}
|
||||
|
||||
.canvas-wide {
|
||||
padding-top: 10px;
|
||||
margin-left: 0;
|
||||
-ms-transition: all .1s ease-out;
|
||||
-moz-transition: all .1s ease-out;
|
||||
-webkit-transition: all .1s ease-out;
|
||||
-o-transition: all .1s ease-out;
|
||||
}
|
||||
|
||||
.jtk-demo-dataset {
|
||||
text-align: left;
|
||||
max-height: 600px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.demo-title {
|
||||
float: left;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.controls {
|
||||
top: 25px;
|
||||
color: #FFF;
|
||||
margin-right: 10px;
|
||||
position: absolute;
|
||||
left: 25px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.controls i {
|
||||
background-color: #3E7E9C;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-right: 0;
|
||||
padding: 4px;
|
||||
}
|
||||
.w {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
font-size: 11px;
|
||||
-webkit-transition: background-color 0.25s ease-in;
|
||||
-moz-transition: background-color 0.25s ease-in;
|
||||
transition: background-color 0.25s ease-in;
|
||||
border: 7px solid transparent;
|
||||
border-bottom: 30px solid transparent;
|
||||
.icos {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
box-shadow: 2px 2px 19px #e0e0e0;
|
||||
-o-box-shadow: 2px 2px 19px #e0e0e0;
|
||||
-webkit-box-shadow: 2px 2px 19px #e0e0e0;
|
||||
-moz-box-shadow: 2px 2px 19px #e0e0e0;
|
||||
-moz-border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
opacity: 0.8;
|
||||
cursor: move;
|
||||
background-color: #fff;
|
||||
}
|
||||
.name-p {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 58px;
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
margin-left: -100px;
|
||||
word-break:break-all;
|
||||
}
|
||||
.ban-p {
|
||||
position: absolute;
|
||||
left: -4px;
|
||||
top: 36px;
|
||||
z-index: 21;
|
||||
i {
|
||||
font-size: 18px;
|
||||
color: #ff0000;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.state-p {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: 18px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
b {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.aLabel {
|
||||
-webkit-transition: background-color 0.25s ease-in;
|
||||
-moz-transition: background-color 0.25s ease-in;
|
||||
transition: background-color 0.25s ease-in;
|
||||
background-color: white;
|
||||
opacity: 0.8;
|
||||
padding: 0.3em;
|
||||
border-radius: 0.5em;
|
||||
border: 1px solid #346789;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.aLabel.jtk-hover,
|
||||
.jtk-source-hover,
|
||||
.jtk-target-hover {
|
||||
.icos {
|
||||
background-color: #333;
|
||||
color: #333;
|
||||
-ms-transition: all 0.6s ease-out;
|
||||
-moz-transition: all 0.6s ease-out;
|
||||
-webkit-transition: all 0.6s ease-out;
|
||||
-o-transition: all 0.6s ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
.jtk-tasks-active {
|
||||
.icos {
|
||||
background-color: #2db7f5;
|
||||
color: #0097e0;
|
||||
-ms-transition: all 0.6s ease-out;
|
||||
-moz-transition: all 0.6s ease-out;
|
||||
-webkit-transition: all 0.6s ease-out;
|
||||
-o-transition: all 0.6s ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.jtk-ep {
|
||||
.ep {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.ep {
|
||||
position: absolute;
|
||||
top: -4%;
|
||||
right: -1px;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
z-index: 12;
|
||||
background-color: orange;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 2px black;
|
||||
-webkit-transition: -webkit-box-shadow 0.25s ease-in;
|
||||
-moz-transition: -moz-box-shadow 0.25s ease-in;
|
||||
transition: box-shadow 0.25s ease-in;
|
||||
border-radius:100%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ep:hover {
|
||||
box-shadow: 0 0 6px black;
|
||||
}
|
||||
|
||||
.statemachine-demo .jtk-endpoint {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
.dot-style {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.form-mirror {
|
||||
|
||||
.dag-chart {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
.CodeMirror {
|
||||
height:auto;
|
||||
min-height: 72px;
|
||||
}
|
||||
height: calc(100vh - 100px);
|
||||
padding: 10px;
|
||||
background: #f2f3f7;
|
||||
|
||||
.CodeMirror-scroll {
|
||||
height:auto;
|
||||
min-height: 72px;
|
||||
overflow-y: hidden;
|
||||
overflow-x: auto;
|
||||
&.full-screen {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
|
||||
.ans-modal-box.ans-drawer.ans-drawer-right.dagMask.mask {
|
||||
width: 628px;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
|
||||
|
1297
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue
Executable file → Normal file
@ -50,8 +50,8 @@
|
||||
<div slot="text">{{$t('Run flag')}}</div>
|
||||
<div slot="content">
|
||||
<el-radio-group v-model="runFlag" size="small">
|
||||
<el-radio :label="'NORMAL'" :disabled="isDetails">{{$t('Normal')}}</el-radio>
|
||||
<el-radio :label="'FORBIDDEN'" :disabled="isDetails">{{$t('Prohibition execution')}}</el-radio>
|
||||
<el-radio :label="'YES'" :disabled="isDetails">{{$t('Normal')}}</el-radio>
|
||||
<el-radio :label="'NO'" :disabled="isDetails">{{$t('Prohibition execution')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</m-list-box>
|
||||
@ -259,11 +259,12 @@
|
||||
:pre-node="nodeData.preNode">
|
||||
</m-conditions>
|
||||
<!-- Pre-tasks in workflow -->
|
||||
<m-pre-tasks
|
||||
<!-- TODO -->
|
||||
<!-- <m-pre-tasks
|
||||
v-if="['SHELL', 'SUB_PROCESS'].indexOf(nodeData.taskType) > -1"
|
||||
@on-pre-tasks="_onPreTasks"
|
||||
ref="PRE_TASK"
|
||||
:backfill-item="backfillItem"></m-pre-tasks>
|
||||
:backfill-item="backfillItem"></m-pre-tasks> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom-box">
|
||||
@ -276,7 +277,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import _ from 'lodash'
|
||||
import { mapActions } from 'vuex'
|
||||
import { mapActions, mapState } from 'vuex'
|
||||
import mLog from './log'
|
||||
import mMr from './tasks/mr'
|
||||
import mSql from './tasks/sql'
|
||||
@ -287,7 +288,6 @@
|
||||
import mSpark from './tasks/spark'
|
||||
import mFlink from './tasks/flink'
|
||||
import mPython from './tasks/python'
|
||||
import JSP from './../plugIn/jsPlumbHandle'
|
||||
import mProcedure from './tasks/procedure'
|
||||
import mDependent from './tasks/dependent'
|
||||
import mHttp from './tasks/http'
|
||||
@ -299,10 +299,9 @@
|
||||
import mTimeoutAlarm from './_source/timeoutAlarm'
|
||||
import mDependentTimeout from './_source/dependentTimeout'
|
||||
import mWorkerGroups from './_source/workerGroups'
|
||||
import mPreTasks from './tasks/pre_tasks'
|
||||
// import mPreTasks from './tasks/pre_tasks'
|
||||
import clickoutside from '@/module/util/clickoutside'
|
||||
import disabledState from '@/module/mixin/disabledState'
|
||||
import { isNameExDag, rtBantpl } from './../plugIn/util'
|
||||
import mPriority from '@/module/components/priority/priority'
|
||||
|
||||
export default {
|
||||
@ -337,7 +336,7 @@
|
||||
// Current node params data
|
||||
params: {},
|
||||
// Running sign
|
||||
runFlag: 'NORMAL',
|
||||
runFlag: 'YES',
|
||||
// The second echo problem caused by the node data is specifically which node hook caused the unfinished special treatment
|
||||
isContentBox: false,
|
||||
// Number of failed retries
|
||||
@ -380,6 +379,31 @@
|
||||
},
|
||||
methods: {
|
||||
...mapActions('dag', ['getTaskInstanceList']),
|
||||
taskToBackfillItem (task) {
|
||||
return {
|
||||
code: task.code,
|
||||
conditionResult: task.taskParams.conditionResult,
|
||||
delayTime: task.delayTime,
|
||||
dependence: task.taskParams.dependence,
|
||||
desc: task.description,
|
||||
id: task.id,
|
||||
maxRetryTimes: task.failRetryTimes,
|
||||
name: task.name,
|
||||
params: _.omit(task.taskParams, ['conditionResult', 'dependence']),
|
||||
preTasks: [],
|
||||
retryInterval: task.failRetryInterval,
|
||||
runFlag: task.flag,
|
||||
taskInstancePriority: task.taskPriority,
|
||||
timeout: {
|
||||
interval: task.timeout,
|
||||
strategy: task.timeoutNotifyStrategy,
|
||||
enable: task.timeoutFlag === 'OPEN'
|
||||
},
|
||||
type: task.taskType,
|
||||
waitStartTimeout: task.waitStartTimeout,
|
||||
workerGroup: task.workerGroup
|
||||
}
|
||||
},
|
||||
/**
|
||||
* depend
|
||||
*/
|
||||
@ -449,8 +473,10 @@
|
||||
this.$message.error(e.msg || '')
|
||||
})
|
||||
} else {
|
||||
const processDefinitionId = this.backfillItem.params.processDefinitionId
|
||||
const process = this.processListS.find(process => process.processDefinition.id === processDefinitionId)
|
||||
this.$emit('onSubProcess', {
|
||||
subProcessId: this.backfillItem.params.processDefinitionId,
|
||||
subProcessCode: process.processDefinition.code,
|
||||
fromThis: this
|
||||
})
|
||||
}
|
||||
@ -461,39 +487,7 @@
|
||||
_onParams (o) {
|
||||
this.params = Object.assign({}, o)
|
||||
},
|
||||
|
||||
_onCacheParams (o) {
|
||||
this.params = Object.assign(this.params, {}, o)
|
||||
this._cacheItem()
|
||||
},
|
||||
|
||||
_cacheItem () {
|
||||
this.conditionResult.successNode[0] = this.successBranch
|
||||
this.conditionResult.failedNode[0] = this.failedBranch
|
||||
this.$emit('cacheTaskInfo', {
|
||||
item: {
|
||||
type: this.nodeData.taskType,
|
||||
id: this.nodeData.id,
|
||||
name: this.name,
|
||||
code: this.code,
|
||||
params: this.params,
|
||||
desc: this.desc,
|
||||
runFlag: this.runFlag,
|
||||
conditionResult: this.conditionResult,
|
||||
dependence: this.cacheDependence,
|
||||
maxRetryTimes: this.maxRetryTimes,
|
||||
retryInterval: this.retryInterval,
|
||||
delayTime: this.delayTime,
|
||||
timeout: this.timeout,
|
||||
waitStartTimeout: this.waitStartTimeout,
|
||||
taskInstancePriority: this.taskInstancePriority,
|
||||
workerGroup: this.workerGroup,
|
||||
status: this.status,
|
||||
branch: this.branch
|
||||
},
|
||||
fromThis: this
|
||||
})
|
||||
},
|
||||
_onCacheParams (o) {},
|
||||
/**
|
||||
* verification name
|
||||
*/
|
||||
@ -510,7 +504,9 @@
|
||||
return true
|
||||
}
|
||||
// Name repeat depends on dom backfill dependent store
|
||||
if (isNameExDag(this.name, _.isEmpty(this.backfillItem) ? 'dom' : 'backfill')) {
|
||||
const tasks = this.store.state.dag.tasks
|
||||
const task = tasks.find(t => t.name === 'this.name')
|
||||
if (task) {
|
||||
this.$message.warning(`${i18n.$t('Name already exists')}`)
|
||||
return false
|
||||
}
|
||||
@ -558,66 +554,35 @@
|
||||
if (!this.$refs.PRE_TASK._verification()) {
|
||||
return
|
||||
} else {
|
||||
// Sync data-targetarr
|
||||
$(`#${this.nodeData.id}`).attr(
|
||||
'data-targetarr', this.preTaskIdsInWorkflow ? this.preTaskIdsInWorkflow.join(',') : '')
|
||||
// TODO sync preTasks to graph
|
||||
|
||||
// Update JSP connections
|
||||
let plumbIns = JSP.JspInstance
|
||||
let targetId = this.nodeData.id
|
||||
|
||||
// Update new connections
|
||||
this.preTasksToAdd.map(sourceId => {
|
||||
plumbIns.connect({
|
||||
source: sourceId,
|
||||
target: targetId,
|
||||
type: 'basic',
|
||||
paintStyle: { strokeWidth: 2, stroke: '#2d8cf0' },
|
||||
HoverPaintStyle: { stroke: '#ccc', strokeWidth: 3 }
|
||||
})
|
||||
})
|
||||
|
||||
// Update remove connections
|
||||
let currentConnects = plumbIns.getAllConnections()
|
||||
let len = currentConnects.length
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (this.preTasksToDelete.indexOf(currentConnects[i].sourceId) > -1 && currentConnects[i].targetId === targetId) {
|
||||
plumbIns.deleteConnection(currentConnects[i])
|
||||
i -= 1
|
||||
len -= 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(`#${this.nodeData.id}`).find('span').text(this.name)
|
||||
this.conditionResult.successNode[0] = this.successBranch
|
||||
this.conditionResult.failedNode[0] = this.failedBranch
|
||||
// Store the corresponding node data structure
|
||||
this.$emit('addTaskInfo', {
|
||||
item: {
|
||||
type: this.nodeData.taskType,
|
||||
id: this.nodeData.id,
|
||||
code: this.nodeData.id,
|
||||
name: this.name,
|
||||
code: this.code,
|
||||
params: this.params,
|
||||
desc: this.desc,
|
||||
runFlag: this.runFlag,
|
||||
conditionResult: this.conditionResult,
|
||||
dependence: this.dependence,
|
||||
maxRetryTimes: this.maxRetryTimes,
|
||||
retryInterval: this.retryInterval,
|
||||
delayTime: this.delayTime,
|
||||
timeout: this.timeout,
|
||||
waitStartTimeout: this.waitStartTimeout,
|
||||
taskInstancePriority: this.taskInstancePriority,
|
||||
description: this.desc,
|
||||
taskType: this.nodeData.taskType,
|
||||
taskParams: {
|
||||
...this.params,
|
||||
dependence: this.cacheDependence,
|
||||
conditionResult: this.conditionResult
|
||||
},
|
||||
flag: this.runFlag,
|
||||
taskPriority: this.taskInstancePriority,
|
||||
workerGroup: this.workerGroup,
|
||||
status: this.status,
|
||||
branch: this.branch
|
||||
failRetryTimes: this.maxRetryTimes,
|
||||
failRetryInterval: this.retryInterval,
|
||||
timeoutFlag: this.timeout.enable ? 'OPEN' : 'CLOSE',
|
||||
timeoutNotifyStrategy: this.timeout.strategy,
|
||||
timeout: this.timeout.interval || 0,
|
||||
delayTime: this.delayTime
|
||||
},
|
||||
fromThis: this
|
||||
})
|
||||
|
||||
// set run flag
|
||||
this._setRunFlag()
|
||||
},
|
||||
@ -629,13 +594,10 @@
|
||||
},
|
||||
/**
|
||||
* set run flag
|
||||
* TODO
|
||||
*/
|
||||
_setRunFlag () {
|
||||
let dom = $(`#${this.nodeData.id}`).find('.ban-p')
|
||||
dom.html('')
|
||||
if (this.runFlag === 'FORBIDDEN') {
|
||||
dom.append(rtBantpl())
|
||||
}
|
||||
|
||||
},
|
||||
/**
|
||||
* Submit verification
|
||||
@ -661,42 +623,25 @@
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
/**
|
||||
* Watch the item change, cache the value it changes
|
||||
**/
|
||||
_item (val) {
|
||||
// this._cacheItem()
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// Unbind copy and paste events
|
||||
JSP.removePaste()
|
||||
// Backfill data
|
||||
let taskList = this.store.state.dag.tasks
|
||||
|
||||
// fillback use cacheTasks
|
||||
let cacheTasks = this.store.state.dag.cacheTasks
|
||||
let o = {}
|
||||
if (cacheTasks[this.nodeData.id]) {
|
||||
o = cacheTasks[this.nodeData.id]
|
||||
this.backfillItem = cacheTasks[this.nodeData.id]
|
||||
} else {
|
||||
if (taskList.length) {
|
||||
taskList.forEach(v => {
|
||||
if (v.id === this.nodeData.id) {
|
||||
o = v
|
||||
this.backfillItem = v
|
||||
}
|
||||
})
|
||||
}
|
||||
if (taskList.length) {
|
||||
taskList.forEach(task => {
|
||||
if (task.code === this.nodeData.id) {
|
||||
const backfillItem = this.taskToBackfillItem(task)
|
||||
o = backfillItem
|
||||
this.backfillItem = backfillItem
|
||||
}
|
||||
})
|
||||
}
|
||||
// Non-null objects represent backfill
|
||||
if (!_.isEmpty(o)) {
|
||||
this.code = o.code
|
||||
this.name = o.name
|
||||
this.taskInstancePriority = o.taskInstancePriority
|
||||
this.runFlag = o.runFlag || 'NORMAL'
|
||||
this.runFlag = o.runFlag || 'YES'
|
||||
this.desc = o.desc
|
||||
this.maxRetryTimes = o.maxRetryTimes
|
||||
this.retryInterval = o.retryInterval
|
||||
@ -755,33 +700,14 @@
|
||||
destroyed () {
|
||||
},
|
||||
computed: {
|
||||
...mapState('dag', [
|
||||
'processListS'
|
||||
]),
|
||||
/**
|
||||
* Child workflow entry show/hide
|
||||
*/
|
||||
_isGoSubProcess () {
|
||||
return this.nodeData.taskType === 'SUB_PROCESS' && this.name
|
||||
},
|
||||
|
||||
// Define the item model
|
||||
_item () {
|
||||
return {
|
||||
type: this.nodeData.taskType,
|
||||
id: this.nodeData.id,
|
||||
code: this.code,
|
||||
name: this.name,
|
||||
desc: this.desc,
|
||||
runFlag: this.runFlag,
|
||||
dependence: this.cacheDependence,
|
||||
maxRetryTimes: this.maxRetryTimes,
|
||||
retryInterval: this.retryInterval,
|
||||
delayTime: this.delayTime,
|
||||
timeout: this.timeout,
|
||||
waitStartTimeout: this.waitStartTimeout,
|
||||
taskInstancePriority: this.taskInstancePriority,
|
||||
workerGroup: this.workerGroup,
|
||||
successBranch: this.successBranch,
|
||||
failedBranch: this.failedBranch
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@ -805,8 +731,8 @@
|
||||
mTimeoutAlarm,
|
||||
mDependentTimeout,
|
||||
mPriority,
|
||||
mWorkerGroups,
|
||||
mPreTasks
|
||||
mWorkerGroups
|
||||
// mPreTasks
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -79,6 +79,7 @@
|
||||
store,
|
||||
router,
|
||||
isLog: false,
|
||||
// TODO
|
||||
stateId: $(`#${this.item.id}`).attr('data-state-id') || null,
|
||||
isScreen: false,
|
||||
loadingIndex: 0,
|
||||
|
@ -30,7 +30,7 @@
|
||||
v-for="city in processDefinitionList"
|
||||
:key="city.code"
|
||||
:value="city.id"
|
||||
:label="city.code">
|
||||
:label="city.name">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
@ -74,14 +74,14 @@
|
||||
/**
|
||||
* The selected process defines the upper component name padding
|
||||
*/
|
||||
_handleWdiChanged (o) {
|
||||
this.$emit('on-set-process-name', this._handleName(o))
|
||||
_handleWdiChanged (id) {
|
||||
this.$emit('on-set-process-name', this._handleName(id))
|
||||
},
|
||||
/**
|
||||
* Return the name according to the process definition id
|
||||
*/
|
||||
_handleName (id) {
|
||||
return _.filter(this.processDefinitionList, v => id === v.id)[0].code
|
||||
return _.filter(this.processDefinitionList, v => id === v.id)[0].name
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -93,22 +93,20 @@
|
||||
},
|
||||
created () {
|
||||
let processListS = _.cloneDeep(this.store.state.dag.processListS)
|
||||
let id = null
|
||||
let code = null
|
||||
if (this.router.history.current.name === 'projects-instance-details') {
|
||||
id = this.router.history.current.query.id || null
|
||||
code = this.router.history.current.query.code || null
|
||||
} else {
|
||||
id = this.router.history.current.params.id || null
|
||||
code = this.router.history.current.params.code || null
|
||||
}
|
||||
this.processDefinitionList = (() => {
|
||||
let a = _.map(processListS, v => {
|
||||
return {
|
||||
id: v.id,
|
||||
code: v.name,
|
||||
disabled: false
|
||||
}
|
||||
})
|
||||
return _.filter(a, v => +v.id !== +id)
|
||||
})()
|
||||
this.processDefinitionList = processListS.map(v => {
|
||||
return {
|
||||
id: v.processDefinition.id,
|
||||
code: v.processDefinition.code,
|
||||
name: v.processDefinition.name,
|
||||
disabled: false
|
||||
}
|
||||
}).filter(a => (a.code + '') !== code)
|
||||
|
||||
let o = this.backfillItem
|
||||
// Non-null objects represent backfill
|
||||
|
After Width: | Height: | Size: 463 B |
After Width: | Height: | Size: 652 B |
After Width: | Height: | Size: 575 B |
After Width: | Height: | Size: 575 B |
BIN
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/images/graph-format.png
Executable file
After Width: | Height: | Size: 458 B |
After Width: | Height: | Size: 461 B |
BIN
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/images/startup-params.png
Executable file
After Width: | Height: | Size: 903 B |
After Width: | Height: | Size: 903 B |
After Width: | Height: | Size: 812 B |
After Width: | Height: | Size: 736 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 743 B |
After Width: | Height: | Size: 745 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
BIN
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/images/task-icos/http.png
Executable file
After Width: | Height: | Size: 707 B |
After Width: | Height: | Size: 709 B |
BIN
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/images/task-icos/mr.png
Executable file
After Width: | Height: | Size: 930 B |
After Width: | Height: | Size: 862 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 747 B |
After Width: | Height: | Size: 745 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.0 KiB |
BIN
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/images/task-icos/sql.png
Executable file
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 896 B |
After Width: | Height: | Size: 897 B |
After Width: | Height: | Size: 692 B |
After Width: | Height: | Size: 693 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.0 KiB |
BIN
dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/images/view-variables.png
Executable file
After Width: | Height: | Size: 858 B |
After Width: | Height: | Size: 858 B |
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash'
|
||||
import canvg from 'canvg'
|
||||
import { tasksAll } from './util'
|
||||
import html2canvas from 'html2canvas'
|
||||
import { findComponentDownward } from '@/module/util/'
|
||||
|
||||
const DownChart = function () {
|
||||
this.dag = {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get interception location information
|
||||
*/
|
||||
DownChart.prototype.maxVal = function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
// All nodes
|
||||
const tasksAllList = tasksAll()
|
||||
const dom = $('.dag-container')
|
||||
const y = parseInt(_.maxBy(tasksAllList, 'y').y + 60)
|
||||
const x = parseInt(_.maxBy(tasksAllList, 'x').x + 100)
|
||||
|
||||
resolve({
|
||||
width: (x > 600 ? x : dom.width()) + 100,
|
||||
height: (y > 500 ? y : dom.height()) + 100
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Download to image
|
||||
*/
|
||||
DownChart.prototype.download = function ({ dagThis }) {
|
||||
this.dag = dagThis
|
||||
|
||||
this.maxVal().then(({ width, height }) => {
|
||||
// Dom to save
|
||||
const copyDom = $('#canvas')
|
||||
// gain
|
||||
const scale = 1
|
||||
// divReport is the id of the dom that needs to be intercepted into a picture
|
||||
const svgElem = copyDom.find('svg')
|
||||
svgElem.each((index, node) => {
|
||||
// svg handle
|
||||
const nodesToRecover = []
|
||||
const nodesToRemove = []
|
||||
const parentNode = node.parentNode
|
||||
const svg = node.outerHTML.trim()
|
||||
const canvas = document.createElement('canvas')
|
||||
canvg(canvas, svg)
|
||||
if (node.style.position) {
|
||||
canvas.style.position += node.style.position
|
||||
canvas.style.left += node.style.left
|
||||
canvas.style.top += node.style.top
|
||||
}
|
||||
nodesToRecover.push({
|
||||
parent: parentNode,
|
||||
child: node
|
||||
})
|
||||
parentNode.removeChild(node)
|
||||
nodesToRemove.push({
|
||||
parent: parentNode,
|
||||
child: canvas
|
||||
})
|
||||
parentNode.appendChild(canvas)
|
||||
})
|
||||
|
||||
const canvas = document.createElement('canvas')
|
||||
// canvas width
|
||||
canvas.width = width * scale
|
||||
// canvas height
|
||||
canvas.height = height * scale
|
||||
|
||||
const content = canvas.getContext('2d')
|
||||
content.scale(scale, scale)
|
||||
// Get the offset of the element relative to the inspection
|
||||
const rect = copyDom.get(0).getBoundingClientRect()
|
||||
// Set the context position, the value is a negative value relative to the window offset, let the picture reset
|
||||
content.translate(-rect.left, -rect.top)
|
||||
|
||||
html2canvas(copyDom[0], {
|
||||
dpi: window.devicePixelRatio * 2,
|
||||
scale: scale,
|
||||
width: width,
|
||||
canvas: canvas,
|
||||
heigth: height,
|
||||
useCORS: true // Enable cross-domain configuration
|
||||
}).then((canvas) => {
|
||||
const name = `${this.dag.name}.png`
|
||||
const url = canvas.toDataURL('image/png', 1)
|
||||
setTimeout(() => {
|
||||
const triggerDownload = $('<a>').attr('href', url).attr('download', name).appendTo('body')
|
||||
triggerDownload[0].click()
|
||||
triggerDownload.remove()
|
||||
}, 100)
|
||||
|
||||
// To refresh the dag instance, otherwise you can't re-plot
|
||||
setTimeout(() => {
|
||||
// Refresh current dag
|
||||
findComponentDownward(this.dag.$root, `${this.dag.type}-details`).init()
|
||||
}, 500)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default new DownChart()
|
@ -1,814 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import 'jquery-ui/ui/widgets/draggable'
|
||||
import 'jquery-ui/ui/widgets/droppable'
|
||||
import 'jquery-ui/ui/widgets/resizable'
|
||||
import _ from 'lodash'
|
||||
import i18n from '@/module/i18n'
|
||||
import { jsPlumb } from 'jsplumb'
|
||||
import DragZoom from './dragZoom'
|
||||
import store from '@/conf/home/store'
|
||||
import router from '@/conf/home/router'
|
||||
import { uuid, findComponentDownward } from '@/module/util/'
|
||||
|
||||
import {
|
||||
tasksAll,
|
||||
rtTasksTpl,
|
||||
setSvgColor,
|
||||
saveTargetarr,
|
||||
rtTargetarrArr,
|
||||
computeScale
|
||||
} from './util'
|
||||
import multiDrag from './multiDrag'
|
||||
|
||||
const JSP = function () {
|
||||
this.dag = {}
|
||||
this.selectedElement = {}
|
||||
|
||||
this.config = {
|
||||
// Whether to drag
|
||||
isDrag: true,
|
||||
// Whether to allow connection
|
||||
isAttachment: false,
|
||||
// Whether to drag a new node
|
||||
isNewNodes: true,
|
||||
// Whether to support double-click node events
|
||||
isDblclick: true,
|
||||
// Whether to support right-click menu events
|
||||
isContextmenu: true,
|
||||
// Whether to allow click events
|
||||
isClick: false
|
||||
}
|
||||
}
|
||||
/**
|
||||
* dag init
|
||||
*/
|
||||
JSP.prototype.init = function ({ dag, instance, options }) {
|
||||
// Get the dag component instance
|
||||
this.dag = dag
|
||||
// Get jsplumb instance
|
||||
this.JspInstance = instance
|
||||
// Get JSP options
|
||||
this.options = options || {}
|
||||
// Register jsplumb connection type and configuration
|
||||
this.JspInstance.registerConnectionType('basic', {
|
||||
anchor: 'Continuous',
|
||||
connector: 'Bezier' // Line type
|
||||
})
|
||||
|
||||
// Initial configuration
|
||||
this.setConfig({
|
||||
isDrag: !store.state.dag.isDetails,
|
||||
isAttachment: false,
|
||||
isNewNodes: !store.state.dag.isDetails, // Permissions.getAuth() === false ? false : !store.state.dag.isDetails,
|
||||
isDblclick: true,
|
||||
isContextmenu: true,
|
||||
isClick: false
|
||||
})
|
||||
|
||||
// Monitor line click
|
||||
this.JspInstance.bind('click', e => {
|
||||
// Untie event
|
||||
if (this.config.isClick) {
|
||||
this.connectClick(e)
|
||||
} else {
|
||||
findComponentDownward(this.dag.$root, 'dag-chart')._createLineLabel({ id: e._jsPlumb.overlays.label.canvas.id, sourceId: e.sourceId, targetId: e.targetId })
|
||||
}
|
||||
})
|
||||
|
||||
// Drag and drop
|
||||
if (this.config.isNewNodes) {
|
||||
DragZoom.init()
|
||||
}
|
||||
|
||||
// support multi drag
|
||||
multiDrag()
|
||||
}
|
||||
|
||||
/**
|
||||
* set config attribute
|
||||
*/
|
||||
JSP.prototype.setConfig = function (o) {
|
||||
this.config = Object.assign(this.config, {}, o)
|
||||
}
|
||||
|
||||
/**
|
||||
* Node binding event
|
||||
*/
|
||||
JSP.prototype.tasksEvent = function (selfId) {
|
||||
const tasks = $(`#${selfId}`)
|
||||
// Bind right event
|
||||
tasks.on('contextmenu', e => {
|
||||
this.tasksContextmenu(e)
|
||||
return false
|
||||
})
|
||||
|
||||
// Binding double click event
|
||||
tasks.find('.icos').bind('dblclick', e => {
|
||||
this.tasksDblclick(e)
|
||||
})
|
||||
|
||||
// Binding click event
|
||||
tasks.on('click', e => {
|
||||
this.tasksClick(e)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Dag node drag and drop processing
|
||||
*/
|
||||
JSP.prototype.draggable = function () {
|
||||
if (this.config.isNewNodes) {
|
||||
let selfId
|
||||
const self = this
|
||||
$('.toolbar-btn .roundedRect').draggable({
|
||||
scope: 'plant',
|
||||
helper: 'clone',
|
||||
containment: $('.dag-model'),
|
||||
stop: function (e, ui) {
|
||||
},
|
||||
drag: function () {
|
||||
$('body').find('.tooltip.fade.top.in').remove()
|
||||
}
|
||||
})
|
||||
|
||||
$('#canvas').droppable({
|
||||
scope: 'plant',
|
||||
drop: function (ev, ui) {
|
||||
let id = 'tasks-' + Math.ceil(Math.random() * 100000) // eslint-disable-line
|
||||
|
||||
let scale = computeScale($(this))
|
||||
scale = scale || 1
|
||||
|
||||
// Get mouse coordinates and after scale coordinate
|
||||
const left = parseInt(ui.offset.left - $(this).offset().left) / scale
|
||||
const top = parseInt(ui.offset.top - $(this).offset().top) / scale
|
||||
// Generate template node
|
||||
$('#canvas').append(rtTasksTpl({
|
||||
id: id,
|
||||
name: id,
|
||||
x: left,
|
||||
y: top,
|
||||
isAttachment: self.config.isAttachment,
|
||||
taskType: findComponentDownward(self.dag.$root, 'dag-chart').dagBarId
|
||||
}))
|
||||
|
||||
// Get the generated node
|
||||
const thisDom = jsPlumb.getSelector('.statemachine-demo .w')
|
||||
|
||||
// Generating a connection node
|
||||
self.JspInstance.batch(() => {
|
||||
self.initNode(thisDom[thisDom.length - 1])
|
||||
})
|
||||
selfId = id
|
||||
|
||||
self.tasksEvent(selfId)
|
||||
|
||||
// Dom structure is not generated without pop-up form form
|
||||
if ($(`#${selfId}`).html()) {
|
||||
// dag event
|
||||
findComponentDownward(self.dag.$root, 'dag-chart')._createNodes({
|
||||
id: selfId
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Echo json processing and old data structure processing
|
||||
*/
|
||||
JSP.prototype.jsonHandle = function ({ largeJson, locations }) {
|
||||
_.map(largeJson, v => {
|
||||
// Generate template
|
||||
$('#canvas').append(rtTasksTpl({
|
||||
id: v.id,
|
||||
name: v.name,
|
||||
x: locations[v.id].x,
|
||||
y: locations[v.id].y,
|
||||
targetarr: locations[v.id].targetarr,
|
||||
isAttachment: this.config.isAttachment,
|
||||
taskType: v.type,
|
||||
runFlag: v.runFlag,
|
||||
nodenumber: locations[v.id].nodenumber,
|
||||
successNode: v.conditionResult === undefined ? '' : v.conditionResult.successNode[0],
|
||||
failedNode: v.conditionResult === undefined ? '' : v.conditionResult.failedNode[0]
|
||||
}))
|
||||
|
||||
// contextmenu event
|
||||
$(`#${v.id}`).on('contextmenu', e => {
|
||||
this.tasksContextmenu(e)
|
||||
return false
|
||||
})
|
||||
|
||||
// dblclick event
|
||||
$(`#${v.id}`).find('.icos').bind('dblclick', e => {
|
||||
this.tasksDblclick(e)
|
||||
})
|
||||
|
||||
// click event
|
||||
$(`#${v.id}`).bind('click', e => {
|
||||
this.tasksClick(e)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a single node
|
||||
*/
|
||||
JSP.prototype.initNode = function (el) {
|
||||
// Whether to drag
|
||||
if (this.config.isDrag) {
|
||||
this.JspInstance.draggable(el, {
|
||||
containment: 'dag-container'
|
||||
})
|
||||
}
|
||||
|
||||
// Node attribute configuration
|
||||
this.JspInstance.makeSource(el, {
|
||||
filter: '.ep',
|
||||
anchor: 'Continuous',
|
||||
connectorStyle: {
|
||||
stroke: '#2d8cf0',
|
||||
strokeWidth: 2,
|
||||
outlineStroke: 'transparent',
|
||||
outlineWidth: 4
|
||||
},
|
||||
// This place is leaking
|
||||
// connectionType: "basic",
|
||||
extract: {
|
||||
action: 'the-action'
|
||||
},
|
||||
maxConnections: -1
|
||||
})
|
||||
|
||||
// Node connection property configuration
|
||||
this.JspInstance.makeTarget(el, {
|
||||
dropOptions: { hoverClass: 'dragHover' },
|
||||
anchor: 'Continuous',
|
||||
allowLoopback: false // Forbid yourself to connect yourself
|
||||
})
|
||||
this.JspInstance.fire('jsPlumbDemoNodeAdded', el)
|
||||
}
|
||||
|
||||
/**
|
||||
* Node right click menu
|
||||
*/
|
||||
JSP.prototype.tasksContextmenu = function (event) {
|
||||
if (this.config.isContextmenu) {
|
||||
const routerName = router.history.current.name
|
||||
// state
|
||||
const isOne = routerName === 'projects-definition-details' && this.dag.releaseState !== 'NOT_RELEASE'
|
||||
// hide
|
||||
const isTwo = store.state.dag.isDetails
|
||||
|
||||
const html = [
|
||||
`<a href="javascript:" id="startRunning" class="${isOne ? '' : 'disbled'}"><em class="el-icon-video-play"></em><span>${i18n.$t('Start')}</span></a>`,
|
||||
`<a href="javascript:" id="editNodes" class="${isTwo ? 'disbled' : ''}"><em class="el-icon-edit-outline"></em><span>${i18n.$t('Edit')}</span></a>`,
|
||||
`<a href="javascript:" id="copyNodes" class="${isTwo ? 'disbled' : ''}"><em class="el-icon-copy-document"></em><span>${i18n.$t('Copy')}</span></a>`,
|
||||
`<a href="javascript:" id="removeNodes" class="${isTwo ? 'disbled' : ''}"><em class="el-icon-delete"></em><span>${i18n.$t('Delete')}</span></a>`
|
||||
]
|
||||
|
||||
const operationHtml = () => {
|
||||
return html.splice(',')
|
||||
}
|
||||
|
||||
const e = event
|
||||
const $id = e.currentTarget.id
|
||||
const $contextmenu = $('#contextmenu')
|
||||
const $name = $(`#${$id}`).find('.name-p').text()
|
||||
const $left = e.pageX + document.body.scrollLeft - 5
|
||||
const $top = e.pageY + document.body.scrollTop - 5
|
||||
$contextmenu.css({
|
||||
left: $left,
|
||||
top: $top,
|
||||
visibility: 'visible'
|
||||
})
|
||||
// Action bar
|
||||
$contextmenu.html('').append(operationHtml)
|
||||
|
||||
if (isOne) {
|
||||
// start run
|
||||
$('#startRunning').on('click', () => {
|
||||
const name = store.state.dag.name
|
||||
const id = router.history.current.params.id
|
||||
store.dispatch('dag/getStartCheck', { processDefinitionId: id }).then(res => {
|
||||
this.dag.startRunning({ id: id, name: name }, $name, 'contextmenu')
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!isTwo) {
|
||||
// edit node
|
||||
$('#editNodes').click(ev => {
|
||||
findComponentDownward(this.dag.$root, 'dag-chart')._createNodes({
|
||||
id: $id,
|
||||
type: $(`#${$id}`).attr('data-tasks-type')
|
||||
})
|
||||
})
|
||||
// delete node
|
||||
$('#removeNodes').click(ev => {
|
||||
this.removeNodes($id)
|
||||
})
|
||||
|
||||
// copy node
|
||||
$('#copyNodes').click(res => {
|
||||
this.copyNodes($id)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node double click event
|
||||
*/
|
||||
JSP.prototype.tasksDblclick = function (e) {
|
||||
// Untie event
|
||||
if (this.config.isDblclick) {
|
||||
const id = $(e.currentTarget.offsetParent).attr('id')
|
||||
findComponentDownward(this.dag.$root, 'dag-chart')._createNodes({
|
||||
id: id,
|
||||
type: $(`#${id}`).attr('data-tasks-type')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Node click event
|
||||
*/
|
||||
JSP.prototype.tasksClick = function (e) {
|
||||
let $id
|
||||
const self = this
|
||||
const $body = $('body')
|
||||
if (this.config.isClick) {
|
||||
const $connect = this.selectedElement.connect
|
||||
$('.w').removeClass('jtk-tasks-active')
|
||||
$(e.currentTarget).addClass('jtk-tasks-active')
|
||||
if ($connect) {
|
||||
setSvgColor($connect, '#2d8cf0')
|
||||
this.selectedElement.connect = null
|
||||
}
|
||||
this.selectedElement.id = $(e.currentTarget).attr('id')
|
||||
|
||||
// Unbind copy and paste events
|
||||
$body.unbind('copy').unbind('paste')
|
||||
// Copy binding id
|
||||
$id = self.selectedElement.id
|
||||
|
||||
$body.bind({
|
||||
copy: function () {
|
||||
$id = self.selectedElement.id
|
||||
},
|
||||
paste: function () {
|
||||
$id && self.copyNodes($id)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove binding events
|
||||
* paste
|
||||
*/
|
||||
JSP.prototype.removePaste = function () {
|
||||
const $body = $('body')
|
||||
// Unbind copy and paste events
|
||||
$body.unbind('copy').unbind('paste')
|
||||
// Remove selected node parameters
|
||||
this.selectedElement.id = null
|
||||
// Remove node selection effect
|
||||
$('.w').removeClass('jtk-tasks-active')
|
||||
}
|
||||
|
||||
/**
|
||||
* Line click event
|
||||
*/
|
||||
JSP.prototype.connectClick = function (e) {
|
||||
// Set svg color
|
||||
setSvgColor(e, '#0097e0')
|
||||
const $id = this.selectedElement.id
|
||||
if ($id) {
|
||||
$(`#${$id}`).removeClass('jtk-tasks-active')
|
||||
this.selectedElement.id = null
|
||||
}
|
||||
this.selectedElement.connect = e
|
||||
}
|
||||
|
||||
/**
|
||||
* toolbarEvent
|
||||
* @param {Pointer}
|
||||
*/
|
||||
JSP.prototype.handleEventPointer = function (is) {
|
||||
this.setConfig({
|
||||
isClick: is,
|
||||
isAttachment: false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* toolbarEvent
|
||||
* @param {Line}
|
||||
*/
|
||||
JSP.prototype.handleEventLine = function (is) {
|
||||
const wDom = $('.w')
|
||||
this.setConfig({
|
||||
isAttachment: is
|
||||
})
|
||||
is ? wDom.addClass('jtk-ep') : wDom.removeClass('jtk-ep')
|
||||
}
|
||||
|
||||
/**
|
||||
* toolbarEvent
|
||||
* @param {Remove}
|
||||
*/
|
||||
JSP.prototype.handleEventRemove = function () {
|
||||
const $id = this.selectedElement.id || null
|
||||
const $connect = this.selectedElement.connect || null
|
||||
if ($id) {
|
||||
this.removeNodes(this.selectedElement.id)
|
||||
} else {
|
||||
this.removeConnect($connect)
|
||||
}
|
||||
|
||||
// Monitor whether to edit DAG
|
||||
store.commit('dag/setIsEditDag', true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete node
|
||||
*/
|
||||
JSP.prototype.removeNodes = function ($id) {
|
||||
// Delete node processing(data-targetarr)
|
||||
_.map(tasksAll(), v => {
|
||||
const targetarr = v.targetarr.split(',')
|
||||
if (targetarr.length) {
|
||||
const newArr = _.filter(targetarr, v1 => v1 !== $id)
|
||||
$(`#${v.id}`).attr('data-targetarr', newArr.toString())
|
||||
}
|
||||
})
|
||||
// delete node
|
||||
this.JspInstance.remove($id)
|
||||
|
||||
// delete dom
|
||||
$(`#${$id}`).remove()
|
||||
|
||||
// callback onRemoveNodes event
|
||||
this.options && this.options.onRemoveNodes && this.options.onRemoveNodes($id)
|
||||
const connects = []
|
||||
_.map(this.JspInstance.getConnections(), v => {
|
||||
connects.push({
|
||||
endPointSourceId: v.sourceId,
|
||||
endPointTargetId: v.targetId,
|
||||
label: v._jsPlumb.overlays.label.canvas.innerText
|
||||
})
|
||||
})
|
||||
// Storage line dependence
|
||||
store.commit('dag/setConnects', connects)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete connection
|
||||
*/
|
||||
JSP.prototype.removeConnect = function ($connect) {
|
||||
if (!$connect) {
|
||||
return
|
||||
}
|
||||
// Remove connections and remove node and node dependencies
|
||||
const targetId = $connect.targetId
|
||||
const sourceId = $connect.sourceId
|
||||
let targetarr = rtTargetarrArr(targetId)
|
||||
if (targetarr.length) {
|
||||
targetarr = _.filter(targetarr, v => v !== sourceId)
|
||||
$(`#${targetId}`).attr('data-targetarr', targetarr.toString())
|
||||
}
|
||||
if ($(`#${sourceId}`).attr('data-tasks-type') === 'CONDITIONS') {
|
||||
$(`#${sourceId}`).attr('data-nodenumber', Number($(`#${sourceId}`).attr('data-nodenumber')) - 1)
|
||||
}
|
||||
this.JspInstance.deleteConnection($connect)
|
||||
|
||||
this.selectedElement = {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy node
|
||||
*/
|
||||
JSP.prototype.copyNodes = function ($id) {
|
||||
let newNodeInfo = _.cloneDeep(_.find(store.state.dag.tasks, v => v.id === $id))
|
||||
const newNodePors = store.state.dag.locations[$id]
|
||||
// Unstored nodes do not allow replication
|
||||
if (!newNodePors) {
|
||||
return
|
||||
}
|
||||
// Generate random id
|
||||
const newUuId = `${uuid() + uuid()}`
|
||||
const id = newNodeInfo.id.length > 8 ? newNodeInfo.id.substr(0, 7) : newNodeInfo.id
|
||||
const name = newNodeInfo.name.length > 8 ? newNodeInfo.name.substr(0, 7) : newNodeInfo.name
|
||||
|
||||
// new id
|
||||
const newId = `${id || ''}-${newUuId}`
|
||||
// new name
|
||||
const newName = `${name || ''}-${newUuId}`
|
||||
// coordinate x
|
||||
const newX = newNodePors.x + 100
|
||||
// coordinate y
|
||||
const newY = newNodePors.y + 40
|
||||
|
||||
// Generate template node
|
||||
$('#canvas').append(rtTasksTpl({
|
||||
id: newId,
|
||||
name: newName,
|
||||
x: newX,
|
||||
y: newY,
|
||||
isAttachment: this.config.isAttachment,
|
||||
taskType: newNodeInfo.type
|
||||
}))
|
||||
|
||||
// Get the generated node
|
||||
const thisDom = jsPlumb.getSelector('.statemachine-demo .w')
|
||||
|
||||
// Copy node information
|
||||
newNodeInfo = Object.assign(newNodeInfo, {
|
||||
id: newId,
|
||||
name: newName
|
||||
})
|
||||
|
||||
// Add new node
|
||||
store.commit('dag/addTasks', newNodeInfo)
|
||||
// Add node location information
|
||||
store.commit('dag/addLocations', {
|
||||
[newId]: {
|
||||
name: newName,
|
||||
targetarr: '',
|
||||
nodenumber: 0,
|
||||
x: newX,
|
||||
y: newY
|
||||
}
|
||||
})
|
||||
|
||||
// Generating a connection node
|
||||
this.JspInstance.batch(() => {
|
||||
this.initNode(thisDom[thisDom.length - 1])
|
||||
// Add events to nodes
|
||||
this.tasksEvent(newId)
|
||||
})
|
||||
}
|
||||
/**
|
||||
* toolbarEvent
|
||||
* @param {Screen}
|
||||
*/
|
||||
JSP.prototype.handleEventScreen = function ({ item, is }) {
|
||||
let screenOpen = true
|
||||
if (is) {
|
||||
item.icon = 'el-icon-aim'
|
||||
screenOpen = true
|
||||
} else {
|
||||
item.icon = 'el-icon-full-screen'
|
||||
screenOpen = false
|
||||
}
|
||||
const $mainLayoutModel = $('.main-layout-model')
|
||||
if (screenOpen) {
|
||||
$mainLayoutModel.addClass('dag-screen')
|
||||
} else {
|
||||
$mainLayoutModel.removeClass('dag-screen')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* save task
|
||||
* @param tasks
|
||||
* @param locations
|
||||
* @param connects
|
||||
*/
|
||||
JSP.prototype.saveStore = function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
const connects = []
|
||||
const locations = {}
|
||||
const tasks = []
|
||||
|
||||
const is = (id) => {
|
||||
return !!_.filter(tasksAll(), v => v.id === id).length
|
||||
}
|
||||
|
||||
// task
|
||||
_.map(_.cloneDeep(store.state.dag.tasks), v => {
|
||||
if (is(v.id)) {
|
||||
const preTasks = []
|
||||
const id = $(`#${v.id}`)
|
||||
const tar = id.attr('data-targetarr')
|
||||
const idDep = tar ? id.attr('data-targetarr').split(',') : []
|
||||
if (idDep.length) {
|
||||
_.map(idDep, v1 => {
|
||||
preTasks.push($(`#${v1}`).find('.name-p').text())
|
||||
})
|
||||
}
|
||||
|
||||
let tasksParam = _.assign(v, {
|
||||
preTasks: preTasks,
|
||||
depList: null
|
||||
})
|
||||
|
||||
// Sub-workflow has no retries and interval
|
||||
if (v.type === 'SUB_PROCESS') {
|
||||
tasksParam = _.omit(tasksParam, ['maxRetryTimes', 'retryInterval'])
|
||||
}
|
||||
|
||||
tasks.push(tasksParam)
|
||||
}
|
||||
})
|
||||
|
||||
if (store.state.dag.connects.length === this.JspInstance.getConnections().length) {
|
||||
_.map(store.state.dag.connects, u => {
|
||||
connects.push({
|
||||
endPointSourceId: u.endPointSourceId,
|
||||
endPointTargetId: u.endPointTargetId,
|
||||
label: u.label
|
||||
})
|
||||
})
|
||||
} else if (store.state.dag.connects.length > 0 && store.state.dag.connects.length < this.JspInstance.getConnections().length) {
|
||||
_.map(this.JspInstance.getConnections(), v => {
|
||||
connects.push({
|
||||
endPointSourceId: v.sourceId,
|
||||
endPointTargetId: v.targetId,
|
||||
label: v._jsPlumb.overlays.label.canvas.innerText
|
||||
})
|
||||
})
|
||||
_.map(store.state.dag.connects, u => {
|
||||
_.map(connects, v => {
|
||||
if (u.label && u.endPointSourceId === v.endPointSourceId && u.endPointTargetId === v.endPointTargetId) {
|
||||
v.label = u.label
|
||||
}
|
||||
})
|
||||
})
|
||||
} else if (store.state.dag.connects.length === 0) {
|
||||
_.map(this.JspInstance.getConnections(), v => {
|
||||
connects.push({
|
||||
endPointSourceId: v.sourceId,
|
||||
endPointTargetId: v.targetId,
|
||||
label: v._jsPlumb.overlays.label.canvas.innerText
|
||||
})
|
||||
})
|
||||
} else if (store.state.dag.connects.length > this.JspInstance.getConnections().length) {
|
||||
_.map(this.JspInstance.getConnections(), v => {
|
||||
connects.push({
|
||||
endPointSourceId: v.sourceId,
|
||||
endPointTargetId: v.targetId,
|
||||
label: v._jsPlumb.overlays.label.canvas.innerText
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
_.map(tasksAll(), v => {
|
||||
locations[v.id] = {
|
||||
name: v.name,
|
||||
targetarr: v.targetarr,
|
||||
nodenumber: v.nodenumber,
|
||||
x: v.x,
|
||||
y: v.y
|
||||
}
|
||||
})
|
||||
|
||||
// Storage node
|
||||
store.commit('dag/setTasks', tasks)
|
||||
// Store coordinate information
|
||||
store.commit('dag/setLocations', locations)
|
||||
// Storage line dependence
|
||||
store.commit('dag/setConnects', connects)
|
||||
|
||||
resolve({
|
||||
connects: connects,
|
||||
tasks: tasks,
|
||||
locations: locations
|
||||
})
|
||||
})
|
||||
}
|
||||
/**
|
||||
* Event processing
|
||||
*/
|
||||
|
||||
JSP.prototype.handleEvent = function () {
|
||||
this.JspInstance.bind('beforeDrop', function (info) {
|
||||
const sourceId = info.sourceId// 出
|
||||
const targetId = info.targetId// 入
|
||||
/**
|
||||
* Recursive search for nodes
|
||||
*/
|
||||
let recursiveVal
|
||||
const recursiveTargetarr = (arr, targetId) => {
|
||||
for (const i in arr) {
|
||||
if (arr[i] === targetId) {
|
||||
recursiveVal = targetId
|
||||
} else {
|
||||
recursiveTargetarr(rtTargetarrArr(arr[i]), targetId)
|
||||
}
|
||||
}
|
||||
return recursiveVal
|
||||
}
|
||||
|
||||
// Connection to connected nodes is not allowed
|
||||
if (_.findIndex(rtTargetarrArr(targetId), v => v === sourceId) !== -1) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Recursive form to find if the target Targetarr has a sourceId
|
||||
if (recursiveTargetarr(rtTargetarrArr(sourceId), targetId)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if ($(`#${sourceId}`).attr('data-tasks-type') === 'CONDITIONS' && $(`#${sourceId}`).attr('data-nodenumber') === 2) {
|
||||
return false
|
||||
} else {
|
||||
$(`#${sourceId}`).attr('data-nodenumber', Number($(`#${sourceId}`).attr('data-nodenumber')) + 1)
|
||||
}
|
||||
|
||||
// Storage node dependency information
|
||||
saveTargetarr(sourceId, targetId)
|
||||
|
||||
// Monitor whether to edit DAG
|
||||
store.commit('dag/setIsEditDag', true)
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
/**
|
||||
* Backfill data processing
|
||||
*/
|
||||
JSP.prototype.jspBackfill = function ({ connects, locations, largeJson }) {
|
||||
// Backfill nodes
|
||||
this.jsonHandle({
|
||||
largeJson: largeJson,
|
||||
locations: locations
|
||||
})
|
||||
|
||||
const wNodes = jsPlumb.getSelector('.statemachine-demo .w')
|
||||
|
||||
// Backfill line
|
||||
this.JspInstance.batch(() => {
|
||||
for (let i = 0; i < wNodes.length; i++) {
|
||||
this.initNode(wNodes[i])
|
||||
}
|
||||
_.map(connects, v => {
|
||||
let sourceId = v.endPointSourceId.split('-')
|
||||
let targetId = v.endPointTargetId.split('-')
|
||||
const labels = v.label
|
||||
if (sourceId.length === 4 && targetId.length === 4) {
|
||||
sourceId = `${sourceId[0]}-${sourceId[1]}-${sourceId[2]}`
|
||||
targetId = `${targetId[0]}-${targetId[1]}-${targetId[2]}`
|
||||
} else {
|
||||
sourceId = v.endPointSourceId
|
||||
targetId = v.endPointTargetId
|
||||
}
|
||||
|
||||
if ($(`#${sourceId}`).attr('data-tasks-type') === 'CONDITIONS' && $(`#${sourceId}`).attr('data-successnode') === $(`#${targetId}`).find('.name-p').text()) {
|
||||
this.JspInstance.connect({
|
||||
source: sourceId,
|
||||
target: targetId,
|
||||
type: 'basic',
|
||||
paintStyle: { strokeWidth: 2, stroke: '#4caf50' },
|
||||
HoverPaintStyle: { stroke: '#ccc', strokeWidth: 3 },
|
||||
overlays: [['Label', { label: labels }]]
|
||||
})
|
||||
} else if ($(`#${sourceId}`).attr('data-tasks-type') === 'CONDITIONS' && $(`#${sourceId}`).attr('data-failednode') === $(`#${targetId}`).find('.name-p').text()) {
|
||||
this.JspInstance.connect({
|
||||
source: sourceId,
|
||||
target: targetId,
|
||||
type: 'basic',
|
||||
paintStyle: { strokeWidth: 2, stroke: '#252d39' },
|
||||
HoverPaintStyle: { stroke: '#ccc', strokeWidth: 3 },
|
||||
overlays: [['Label', { label: labels }]]
|
||||
})
|
||||
} else {
|
||||
this.JspInstance.connect({
|
||||
source: sourceId,
|
||||
target: targetId,
|
||||
type: 'basic',
|
||||
paintStyle: { strokeWidth: 2, stroke: '#2d8cf0' },
|
||||
HoverPaintStyle: { stroke: '#ccc', strokeWidth: 3 },
|
||||
overlays: [['Label', { label: labels }]]
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
jsPlumb.fire('jsPlumbDemoLoaded', this.JspInstance)
|
||||
|
||||
// Connection monitoring
|
||||
this.handleEvent()
|
||||
|
||||
// Drag and drop new nodes
|
||||
this.draggable()
|
||||
}
|
||||
|
||||
export default new JSP()
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import JSP from './jsPlumbHandle'
|
||||
/**
|
||||
* when and only ctrl or meta key pressing, we can select one or more dags to drag
|
||||
*/
|
||||
export default function () {
|
||||
// init
|
||||
let selectableObjects = []
|
||||
JSP.JspInstance.clearDragSelection()
|
||||
let ctrlPress = false
|
||||
|
||||
let nodes = null
|
||||
const $window = $(window)
|
||||
|
||||
$window.bind('keydown', function (event) {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
if (nodes) {
|
||||
nodes.unbind('mousedown', select)
|
||||
}
|
||||
nodes = $('.jtk-draggable')
|
||||
nodes.bind('mousedown', select)
|
||||
ctrlPress = true
|
||||
}
|
||||
})
|
||||
$window.bind('keyup', function (event) {
|
||||
clear()
|
||||
})
|
||||
|
||||
function select (event) {
|
||||
if (ctrlPress && event.button === 0) {
|
||||
let index = null
|
||||
if ((index = selectableObjects.indexOf(this)) !== -1) {
|
||||
selectableObjects.splice(index, 1)
|
||||
JSP.JspInstance.removeFromDragSelection(this)
|
||||
$(this).css('border-color', '')
|
||||
} else {
|
||||
selectableObjects.push(this)
|
||||
JSP.JspInstance.addToDragSelection(this)
|
||||
$(this).css('border-color', '#4af')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clear () {
|
||||
ctrlPress = false
|
||||
selectableObjects.map(item => {
|
||||
$(item).css('border-color', '')
|
||||
})
|
||||
selectableObjects = []
|
||||
JSP.JspInstance.clearDragSelection()
|
||||
}
|
||||
}
|
@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import _ from 'lodash'
|
||||
import i18n from '@/module/i18n'
|
||||
import store from '@/conf/home/store'
|
||||
|
||||
/**
|
||||
* Node, to array
|
||||
*/
|
||||
const rtTargetarrArr = (id) => {
|
||||
const ids = $(`#${id}`).attr('data-targetarr')
|
||||
return ids ? ids.split(',') : []
|
||||
}
|
||||
|
||||
/**
|
||||
* Store node id to targetarr
|
||||
*/
|
||||
const saveTargetarr = (valId, domId) => {
|
||||
const $target = $(`#${domId}`)
|
||||
const targetStr = $target.attr('data-targetarr') ? $target.attr('data-targetarr') + `,${valId}` : `${valId}`
|
||||
$target.attr('data-targetarr', targetStr)
|
||||
}
|
||||
|
||||
const rtBantpl = () => {
|
||||
return `<em class="ri-indeterminate-circle-line" data-toggle="tooltip" data-html="true" data-container="body" data-placement="left" title="${i18n.$t('Prohibition execution')}"></em>`
|
||||
}
|
||||
|
||||
/**
|
||||
* return node html
|
||||
*/
|
||||
const rtTasksTpl = ({ id, name, x, y, targetarr, isAttachment, taskType, runFlag, nodenumber, successNode, failedNode }) => {
|
||||
let tpl = ''
|
||||
tpl += `<div class="w jtk-draggable jtk-droppable jtk-endpoint-anchor jtk-connected ${isAttachment ? 'jtk-ep' : ''}" data-targetarr="${targetarr || ''}" data-successNode="${successNode || ''}" data-failedNode="${failedNode || ''}" data-nodenumber="${nodenumber || 0}" data-tasks-type="${taskType}" id="${id}" style="left: ${x}px; top: ${y}px;">`
|
||||
tpl += '<div>'
|
||||
tpl += '<div class="state-p"></div>'
|
||||
tpl += `<div class="icos icos-${taskType}"></div>`
|
||||
tpl += `<span class="name-p">${name}</span>`
|
||||
tpl += '</div>'
|
||||
tpl += '<div class="ep"></div>'
|
||||
tpl += '<div class="ban-p">'
|
||||
if (runFlag === 'FORBIDDEN') {
|
||||
tpl += rtBantpl()
|
||||
}
|
||||
tpl += '</div>'
|
||||
tpl += '</div>'
|
||||
|
||||
return tpl
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all tasks nodes
|
||||
*/
|
||||
const tasksAll = () => {
|
||||
const a = []
|
||||
$('#canvas .w').each(function (idx, elem) {
|
||||
const e = $(elem)
|
||||
a.push({
|
||||
id: e.attr('id'),
|
||||
name: e.find('.name-p').text(),
|
||||
targetarr: e.attr('data-targetarr') || '',
|
||||
nodenumber: e.attr('data-nodenumber'),
|
||||
x: parseInt(e.css('left'), 10),
|
||||
y: parseInt(e.css('top'), 10)
|
||||
})
|
||||
})
|
||||
return a
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if name is in the current dag map
|
||||
* rely dom / backfill
|
||||
*/
|
||||
const isNameExDag = (name, rely) => {
|
||||
if (rely === 'dom') {
|
||||
return _.findIndex(tasksAll(), v => v.name === name) !== -1
|
||||
} else {
|
||||
return _.findIndex(store.state.dag.tasks, v => v.name === name) !== -1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change svg line color
|
||||
*/
|
||||
const setSvgColor = (e, color) => {
|
||||
// Traverse clear all colors
|
||||
$('.jtk-connector').each((i, o) => {
|
||||
_.map($(o)[0].childNodes, v => {
|
||||
if ($(v).attr('fill') === '#ccc') {
|
||||
$(v).attr('fill', '#2d8cf0')
|
||||
}
|
||||
if ($(v).attr('fill') === '#4caf50') {
|
||||
$(v).attr('fill', '#4caf50').attr('stroke', '#4caf50').attr('stroke-width', 2)
|
||||
$(v).prev().attr('stroke', '#4caf50').attr('stroke-width', 2)
|
||||
} else if ($(v).attr('fill') === '#252d39') {
|
||||
$(v).attr('stroke', '#252d39').attr('stroke-width', 2)
|
||||
$(v).prev().attr('stroke', '#252d39').attr('stroke-width', 2)
|
||||
} else {
|
||||
$(v).attr('stroke', '#2d8cf0').attr('stroke-width', 2)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Add color to the selection
|
||||
_.map($(e.canvas)[0].childNodes, (v, i) => {
|
||||
if ($(v).attr('fill') === '#2d8cf0') {
|
||||
$(v).attr('fill', '#ccc')
|
||||
}
|
||||
$(v).attr('stroke', '#ccc')
|
||||
if ($(v).attr('class')) {
|
||||
$(v).attr('stroke-width', 2)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all node ids
|
||||
*/
|
||||
const allNodesId = () => {
|
||||
const idArr = []
|
||||
$('.w').each((i, o) => {
|
||||
const $obj = $(o)
|
||||
const $span = $obj.find('.name-p').text()
|
||||
if ($span) {
|
||||
idArr.push({
|
||||
id: $obj.attr('id'),
|
||||
name: $span
|
||||
})
|
||||
}
|
||||
})
|
||||
return idArr
|
||||
}
|
||||
/**
|
||||
* compute scale,because it cant get from jquery directly
|
||||
* @param el element
|
||||
* @returns {boolean|number}
|
||||
*/
|
||||
const computeScale = function (el) {
|
||||
const matrix = el.css('transform')
|
||||
if (!matrix || matrix === 'none') {
|
||||
return false
|
||||
}
|
||||
const values = matrix.split('(')[1].split(')')[0].split(',')
|
||||
return Math.sqrt(values[0] * values[0] + values[1] * values[1])
|
||||
}
|
||||
|
||||
export {
|
||||
rtTargetarrArr,
|
||||
saveTargetarr,
|
||||
rtTasksTpl,
|
||||
tasksAll,
|
||||
isNameExDag,
|
||||
setSvgColor,
|
||||
allNodesId,
|
||||
rtBantpl,
|
||||
computeScale
|
||||
}
|
@ -61,8 +61,11 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
_onChange (o) {
|
||||
this.$emit('tenantSelectEvent', o)
|
||||
_onChange (id) {
|
||||
const tenant = this.itemList.find(item => item.id === id)
|
||||
if (tenant) {
|
||||
this.$emit('tenantSelectEvent', tenant.tenantCode)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||
<div class="title" style="padding-top: 6px;">
|
||||
<span class="text-b">{{$t('select tenant')}}</span>
|
||||
<form-tenant v-model="tenantId"></form-tenant>
|
||||
<form-tenant v-model="tenantCode"></form-tenant>
|
||||
</div>
|
||||
<div class="title" style="padding-top: 6px;">
|
||||
<span class="text-b">{{$t('warning of timeout')}}</span>
|
||||
@ -117,8 +117,8 @@
|
||||
syncDefine: true,
|
||||
// Timeout alarm
|
||||
timeout: 0,
|
||||
|
||||
tenantId: -1,
|
||||
// tenant code
|
||||
tenantCode: 'default',
|
||||
// checked Timeout alarm
|
||||
checkedTimeout: true
|
||||
}
|
||||
@ -150,7 +150,7 @@
|
||||
|
||||
this.store.commit('dag/setName', _.cloneDeep(this.name))
|
||||
this.store.commit('dag/setTimeout', _.cloneDeep(this.timeout))
|
||||
this.store.commit('dag/setTenantId', _.cloneDeep(this.tenantId))
|
||||
this.store.commit('dag/setTenantCode', _.cloneDeep(this.tenantCode))
|
||||
this.store.commit('dag/setDesc', _.cloneDeep(this.description))
|
||||
this.store.commit('dag/setSyncDefine', this.syncDefine)
|
||||
this.store.commit('dag/setReleaseState', this.releaseState)
|
||||
@ -257,10 +257,10 @@
|
||||
this.timeout = dag.timeout || 0
|
||||
this.checkedTimeout = this.timeout !== 0
|
||||
this.$nextTick(() => {
|
||||
if (dag.tenantId > -1) {
|
||||
this.tenantId = dag.tenantId
|
||||
} else if (this.store.state.user.userInfo.tenantId) {
|
||||
this.tenantId = this.store.state.user.userInfo.tenantId
|
||||
if (dag.tenantCode) {
|
||||
this.tenantCode = dag.tenantCode
|
||||
} else {
|
||||
this.tenantCode = this.store.state.user.userInfo.tenantCode || 'default'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -53,7 +53,7 @@
|
||||
// Promise Get node needs data
|
||||
Promise.all([
|
||||
// Node details
|
||||
this.getProcessDetails(this.$route.params.id),
|
||||
this.getProcessDetails(this.$route.params.code),
|
||||
// get process definition
|
||||
this.getProcessList(),
|
||||
// get project
|
||||
@ -69,8 +69,8 @@
|
||||
this.getTenantList()
|
||||
]).then((data) => {
|
||||
let item = data[0]
|
||||
this.setIsDetails(item.releaseState === 'ONLINE')
|
||||
this.releaseState = item.releaseState
|
||||
this.setIsDetails(item.processDefinition.releaseState === 'ONLINE')
|
||||
this.releaseState = item.processDefinition.releaseState
|
||||
this.isLoading = false
|
||||
// Whether to pop up the box?
|
||||
Affirm.init(this.$root)
|
||||
@ -82,7 +82,7 @@
|
||||
* Redraw (refresh operation)
|
||||
*/
|
||||
_reset () {
|
||||
this.getProcessDetails(this.$route.params.id).then(res => {
|
||||
this.getProcessDetails(this.$route.params.code).then(res => {
|
||||
let item = res
|
||||
this.setIsDetails(item.releaseState === 'ONLINE')
|
||||
this.releaseState = item.releaseState
|
||||
|
@ -25,7 +25,7 @@
|
||||
<el-popover trigger="hover" placement="top">
|
||||
<p>{{ scope.row.name }}</p>
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<router-link :to="{ path: `/projects/${projectId}/definition/list/${scope.row.id}` }" tag="a" class="links">
|
||||
<router-link :to="{ path: `/projects/${projectCode}/definition/list/${scope.row.code}` }" tag="a" class="links">
|
||||
<span class="ellipsis">{{scope.row.name}}</span>
|
||||
</router-link>
|
||||
</div>
|
||||
@ -256,7 +256,7 @@
|
||||
}
|
||||
// remove one
|
||||
this.deleteDefinition({
|
||||
processDefinitionId: item.id
|
||||
code: item.code
|
||||
}).then(res => {
|
||||
this._onUpdate()
|
||||
this.$message.success(res.msg)
|
||||
@ -268,14 +268,14 @@
|
||||
* edit
|
||||
*/
|
||||
_edit (item) {
|
||||
this.$router.push({ path: `/projects/${this.projectId}/definition/list/${item.id}` })
|
||||
this.$router.push({ path: `/projects/${this.projectCode}/definition/list/${item.code}` })
|
||||
},
|
||||
/**
|
||||
* Offline
|
||||
*/
|
||||
_downline (item) {
|
||||
this._upProcessState({
|
||||
processId: item.id,
|
||||
...item,
|
||||
releaseState: 'OFFLINE'
|
||||
})
|
||||
},
|
||||
@ -284,7 +284,7 @@
|
||||
*/
|
||||
_poponline (item) {
|
||||
this._upProcessState({
|
||||
processId: item.id,
|
||||
...item,
|
||||
releaseState: 'ONLINE'
|
||||
})
|
||||
},
|
||||
@ -520,7 +520,7 @@
|
||||
mounted () {
|
||||
},
|
||||
computed: {
|
||||
...mapState('dag', ['projectId'])
|
||||
...mapState('dag', ['projectId', 'projectCode'])
|
||||
},
|
||||
components: { mVersions, mStart, mTiming, mRelatedItems }
|
||||
}
|
||||
|
@ -265,7 +265,7 @@
|
||||
}
|
||||
}
|
||||
let param = {
|
||||
processDefinitionId: this.startData.id,
|
||||
processDefinitionCode: this.startData.code,
|
||||
scheduleTime: this.scheduleTime.length && this.scheduleTime.join(',') || '',
|
||||
failureStrategy: this.failureStrategy,
|
||||
warningType: this.warningType,
|
||||
@ -319,7 +319,7 @@
|
||||
}
|
||||
},
|
||||
_getGlobalParams () {
|
||||
this.store.dispatch('dag/getProcessDetails', this.startData.id).then(res => {
|
||||
this.store.dispatch('dag/getProcessDetails', this.startData.code).then(res => {
|
||||
this.definitionGlobalParams = _.cloneDeep(this.store.state.dag.globalParams)
|
||||
this.udpList = _.cloneDeep(this.store.state.dag.globalParams)
|
||||
})
|
||||
|
@ -92,7 +92,7 @@ const router = new Router({
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/kinship',
|
||||
path: '/projects/:projectCode/kinship',
|
||||
name: 'projects-kinship',
|
||||
component: resolve => require(['../pages/projects/pages/kinship/index'], resolve),
|
||||
meta: {
|
||||
@ -101,7 +101,7 @@ const router = new Router({
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/definition',
|
||||
path: '/projects/:projectCode/definition',
|
||||
name: 'definition',
|
||||
component: resolve => require(['../pages/projects/pages/definition/index'], resolve),
|
||||
meta: {
|
||||
@ -113,7 +113,7 @@ const router = new Router({
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '/projects/:projectId/definition/list',
|
||||
path: '/projects/:projectCode/definition/list',
|
||||
name: 'projects-definition-list',
|
||||
component: resolve => require(['../pages/projects/pages/definition/pages/list/index'], resolve),
|
||||
meta: {
|
||||
@ -122,7 +122,7 @@ const router = new Router({
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/definition/list/:id',
|
||||
path: '/projects/:projectCode/definition/list/:code',
|
||||
name: 'projects-definition-details',
|
||||
component: resolve => require(['../pages/projects/pages/definition/pages/details/index'], resolve),
|
||||
meta: {
|
||||
@ -131,7 +131,7 @@ const router = new Router({
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/definition/create',
|
||||
path: '/projects/:projectCode/definition/create',
|
||||
name: 'definition-create',
|
||||
component: resolve => require(['../pages/projects/pages/definition/pages/create/index'], resolve),
|
||||
meta: {
|
||||
@ -139,7 +139,7 @@ const router = new Router({
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/definition/tree/:id',
|
||||
path: '/projects/:projectCode/definition/tree/:id',
|
||||
name: 'definition-tree-view-index',
|
||||
component: resolve => require(['../pages/projects/pages/definition/pages/tree/index'], resolve),
|
||||
meta: {
|
||||
@ -148,7 +148,7 @@ const router = new Router({
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/definition/list/timing/:code',
|
||||
path: '/projects/:projectCode/definition/list/timing/:code',
|
||||
name: 'definition-timing-details',
|
||||
component: resolve => require(['../pages/projects/pages/definition/timing/index'], resolve),
|
||||
meta: {
|
||||
@ -159,7 +159,7 @@ const router = new Router({
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/instance',
|
||||
path: '/projects/:projectCode/instance',
|
||||
name: 'instance',
|
||||
component: resolve => require(['../pages/projects/pages/instance/index'], resolve),
|
||||
meta: {
|
||||
@ -170,7 +170,7 @@ const router = new Router({
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '/projects/:projectId/instance/list',
|
||||
path: '/projects/:projectCode/instance/list',
|
||||
name: 'projects-instance-list',
|
||||
component: resolve => require(['../pages/projects/pages/instance/pages/list/index'], resolve),
|
||||
meta: {
|
||||
@ -179,7 +179,7 @@ const router = new Router({
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/instance/list/:id',
|
||||
path: '/projects/:projectCode/instance/list/:id',
|
||||
name: 'projects-instance-details',
|
||||
component: resolve => require(['../pages/projects/pages/instance/pages/details/index'], resolve),
|
||||
meta: {
|
||||
@ -188,7 +188,7 @@ const router = new Router({
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/instance/gantt/:id',
|
||||
path: '/projects/:projectCode/instance/gantt/:id',
|
||||
name: 'instance-gantt-index',
|
||||
component: resolve => require(['../pages/projects/pages/instance/pages/gantt/index'], resolve),
|
||||
meta: {
|
||||
@ -199,7 +199,7 @@ const router = new Router({
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/task-instance',
|
||||
path: '/projects/:projectCode/task-instance',
|
||||
name: 'task-instance',
|
||||
component: resolve => require(['../pages/projects/pages/taskInstance'], resolve),
|
||||
meta: {
|
||||
@ -209,7 +209,7 @@ const router = new Router({
|
||||
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/task-record',
|
||||
path: '/projects/:projectCode/task-record',
|
||||
name: 'task-record',
|
||||
component: resolve => require(['../pages/projects/pages/taskRecord'], resolve),
|
||||
meta: {
|
||||
@ -218,7 +218,7 @@ const router = new Router({
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projects/:projectId/history-task-record',
|
||||
path: '/projects/:projectCode/history-task-record',
|
||||
name: 'history-task-record',
|
||||
component: resolve => require(['../pages/projects/pages/historyTaskRecord'], resolve),
|
||||
meta: {
|
||||
|
@ -19,32 +19,13 @@ import _ from 'lodash'
|
||||
import io from '@/module/io'
|
||||
import { tasksState } from '@/conf/home/pages/dag/_source/config'
|
||||
|
||||
// delete 'definitionList' from tasks
|
||||
const deleteDefinitionList = (tasks) => {
|
||||
const newTasks = []
|
||||
tasks.forEach(item => {
|
||||
const newItem = Object.assign({}, item)
|
||||
if (newItem.dependence && newItem.dependence.dependTaskList) {
|
||||
newItem.dependence.dependTaskList.forEach(dependTaskItem => {
|
||||
if (dependTaskItem.dependItemList) {
|
||||
dependTaskItem.dependItemList.forEach(dependItem => {
|
||||
Reflect.deleteProperty(dependItem, 'definitionList')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
newTasks.push(newItem)
|
||||
})
|
||||
return newTasks
|
||||
}
|
||||
|
||||
export default {
|
||||
/**
|
||||
* Task status acquisition
|
||||
*/
|
||||
getTaskState ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/instance/task-list-by-process-id`, {
|
||||
io.get(`projects/${state.projectCode}/instance/task-list-by-process-id`, {
|
||||
processInstanceId: payload
|
||||
}, res => {
|
||||
const arr = _.map(res.data.taskList, v => {
|
||||
@ -69,8 +50,9 @@ export default {
|
||||
*/
|
||||
editProcessState ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.post(`projects/${state.projectName}/process/release`, {
|
||||
processId: payload.processId,
|
||||
io.post(`projects/${state.projectCode}/process/release`, {
|
||||
code: payload.code,
|
||||
name: payload.name,
|
||||
releaseState: payload.releaseState
|
||||
}, res => {
|
||||
resolve(res)
|
||||
@ -85,7 +67,7 @@ export default {
|
||||
*/
|
||||
getProcessDefinitionVersionsPage ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/versions`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/versions`, payload, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -98,7 +80,7 @@ export default {
|
||||
*/
|
||||
switchProcessDefinitionVersion ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/version/switch`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/version/switch`, payload, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -111,7 +93,7 @@ export default {
|
||||
*/
|
||||
deleteProcessDefinitionVersion ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/version/delete`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/version/delete`, payload, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -139,7 +121,7 @@ export default {
|
||||
*/
|
||||
verifDAGName ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/verify-name`, {
|
||||
io.get(`projects/${state.projectCode}/process/verify-name`, {
|
||||
name: payload
|
||||
}, res => {
|
||||
state.name = payload
|
||||
@ -155,36 +137,45 @@ export default {
|
||||
*/
|
||||
getProcessDetails ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/select-by-id`, {
|
||||
processId: payload
|
||||
io.get(`projects/${state.projectCode}/process/select-by-code`, {
|
||||
code: payload
|
||||
}, res => {
|
||||
// process definition code
|
||||
state.code = res.data.code
|
||||
state.code = res.data.processDefinition.code
|
||||
// version
|
||||
state.version = res.data.version
|
||||
state.version = res.data.processDefinition.version
|
||||
// name
|
||||
state.name = res.data.name
|
||||
state.name = res.data.processDefinition.name
|
||||
// description
|
||||
state.description = res.data.description
|
||||
// connects
|
||||
state.connects = JSON.parse(res.data.connects)
|
||||
state.description = res.data.processDefinition.description
|
||||
// taskRelationJson
|
||||
state.connects = res.data.processTaskRelationList
|
||||
// locations
|
||||
state.locations = JSON.parse(res.data.locations)
|
||||
// Process definition
|
||||
const processDefinitionJson = JSON.parse(res.data.processDefinitionJson)
|
||||
// tasks info
|
||||
state.tasks = processDefinitionJson.tasks
|
||||
// tasks cache
|
||||
state.cacheTasks = {}
|
||||
processDefinitionJson.tasks.forEach(v => {
|
||||
state.cacheTasks[v.id] = v
|
||||
})
|
||||
state.locations = JSON.parse(res.data.processDefinition.locations)
|
||||
// global params
|
||||
state.globalParams = processDefinitionJson.globalParams
|
||||
state.globalParams = res.data.processDefinition.globalParamList
|
||||
// timeout
|
||||
state.timeout = processDefinitionJson.timeout
|
||||
|
||||
state.tenantId = processDefinitionJson.tenantId
|
||||
state.timeout = res.data.processDefinition.timeout
|
||||
// tenantId
|
||||
state.tenantCode = res.data.processDefinition.tenantCode
|
||||
// tasks info
|
||||
state.tasks = res.data.taskDefinitionList.map(task => _.pick(task, [
|
||||
'code',
|
||||
'name',
|
||||
'version',
|
||||
'description',
|
||||
'delayTime',
|
||||
'taskType',
|
||||
'taskParams',
|
||||
'flag',
|
||||
'taskPriority',
|
||||
'workerGroup',
|
||||
'failRetryTimes',
|
||||
'failRetryInterval',
|
||||
'timeoutFlag',
|
||||
'timeoutNotifyStrategy',
|
||||
'timeout'
|
||||
]))
|
||||
resolve(res.data)
|
||||
}).catch(res => {
|
||||
reject(res)
|
||||
@ -197,7 +188,7 @@ export default {
|
||||
*/
|
||||
copyProcess ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.post(`projects/${state.projectName}/process/copy`, {
|
||||
io.post(`projects/${state.projectCode}/process/copy`, {
|
||||
processDefinitionIds: payload.processDefinitionIds,
|
||||
targetProjectId: payload.targetProjectId
|
||||
}, res => {
|
||||
@ -213,7 +204,7 @@ export default {
|
||||
*/
|
||||
moveProcess ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.post(`projects/${state.projectName}/process/move`, {
|
||||
io.post(`projects/${state.project}/process/move`, {
|
||||
processDefinitionIds: payload.processDefinitionIds,
|
||||
targetProjectId: payload.targetProjectId
|
||||
}, res => {
|
||||
@ -242,37 +233,46 @@ export default {
|
||||
*/
|
||||
getInstancedetail ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/instance/select-by-id`, {
|
||||
io.get(`projects/${state.projectCode}/instance/select-by-id`, {
|
||||
processInstanceId: payload
|
||||
}, res => {
|
||||
const { processDefinition, processTaskRelationList, taskDefinitionList } = res.data.dagData
|
||||
// code
|
||||
state.code = res.data.processDefinitionCode
|
||||
state.code = processDefinition.code
|
||||
// version
|
||||
state.version = res.data.processDefinitionVersion
|
||||
state.version = processDefinition.version
|
||||
// name
|
||||
state.name = res.data.name
|
||||
// desc
|
||||
state.description = res.data.description
|
||||
state.description = processDefinition.description
|
||||
// connects
|
||||
state.connects = JSON.parse(res.data.connects)
|
||||
state.connects = processTaskRelationList
|
||||
// locations
|
||||
state.locations = JSON.parse(res.data.locations)
|
||||
// process instance
|
||||
const processInstanceJson = JSON.parse(res.data.processInstanceJson)
|
||||
// tasks info
|
||||
state.tasks = processInstanceJson.tasks
|
||||
// tasks cache
|
||||
state.cacheTasks = {}
|
||||
processInstanceJson.tasks.forEach(v => {
|
||||
state.cacheTasks[v.id] = v
|
||||
})
|
||||
state.locations = JSON.parse(processDefinition.locations)
|
||||
// global params
|
||||
state.globalParams = processInstanceJson.globalParams
|
||||
state.globalParams = processDefinition.globalParamList
|
||||
// timeout
|
||||
state.timeout = processInstanceJson.timeout
|
||||
|
||||
state.tenantId = processInstanceJson.tenantId
|
||||
|
||||
state.timeout = processDefinition.timeout
|
||||
// tenantCode
|
||||
state.tenantCode = res.data.tenantCode
|
||||
// tasks info
|
||||
state.tasks = taskDefinitionList.map(task => _.pick(task, [
|
||||
'code',
|
||||
'name',
|
||||
'version',
|
||||
'description',
|
||||
'delayTime',
|
||||
'taskType',
|
||||
'taskParams',
|
||||
'flag',
|
||||
'taskPriority',
|
||||
'workerGroup',
|
||||
'failRetryTimes',
|
||||
'failRetryInterval',
|
||||
'timeoutFlag',
|
||||
'timeoutNotifyStrategy',
|
||||
'timeout'
|
||||
]))
|
||||
// startup parameters
|
||||
state.startup = _.assign(state.startup, _.pick(res.data, ['commandType', 'failureStrategy', 'processInstancePriority', 'workerGroup', 'warningType', 'warningGroupId', 'receivers', 'receiversCc']))
|
||||
state.startup.commandParam = JSON.parse(res.data.commandParam)
|
||||
@ -288,18 +288,15 @@ export default {
|
||||
*/
|
||||
saveDAGchart ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const data = {
|
||||
globalParams: state.globalParams,
|
||||
tasks: deleteDefinitionList(state.tasks),
|
||||
tenantId: state.tenantId,
|
||||
timeout: state.timeout
|
||||
}
|
||||
io.post(`projects/${state.projectName}/process/save`, {
|
||||
processDefinitionJson: JSON.stringify(data),
|
||||
name: _.trim(state.name),
|
||||
description: _.trim(state.description),
|
||||
io.post(`projects/${state.projectCode}/process/save`, {
|
||||
locations: JSON.stringify(state.locations),
|
||||
connects: JSON.stringify(state.connects)
|
||||
name: _.trim(state.name),
|
||||
taskDefinitionJson: JSON.stringify(state.tasks),
|
||||
taskRelationJson: JSON.stringify(state.connects),
|
||||
tenantCode: state.tenantCode,
|
||||
description: _.trim(state.description),
|
||||
globalParams: JSON.stringify(state.globalParams),
|
||||
timeout: state.timeout
|
||||
}, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
@ -312,20 +309,17 @@ export default {
|
||||
*/
|
||||
updateDefinition ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const data = {
|
||||
globalParams: state.globalParams,
|
||||
tasks: deleteDefinitionList(state.tasks),
|
||||
tenantId: state.tenantId,
|
||||
timeout: state.timeout
|
||||
}
|
||||
io.post(`projects/${state.projectName}/process/update`, {
|
||||
processDefinitionJson: JSON.stringify(data),
|
||||
io.post(`projects/${state.projectCode}/process/update`, {
|
||||
locations: JSON.stringify(state.locations),
|
||||
connects: JSON.stringify(state.connects),
|
||||
name: _.trim(state.name),
|
||||
taskDefinitionJson: JSON.stringify(state.tasks),
|
||||
taskRelationJson: JSON.stringify(state.connects),
|
||||
tenantCode: state.tenantCode,
|
||||
description: _.trim(state.description),
|
||||
id: payload,
|
||||
releaseState: state.releaseState
|
||||
globalParams: JSON.stringify(state.globalParams),
|
||||
timeout: state.timeout,
|
||||
releaseState: state.releaseState,
|
||||
code: payload
|
||||
}, res => {
|
||||
resolve(res)
|
||||
state.isEditDag = false
|
||||
@ -345,7 +339,7 @@ export default {
|
||||
tenantId: state.tenantId,
|
||||
timeout: state.timeout
|
||||
}
|
||||
io.post(`projects/${state.projectName}/instance/update`, {
|
||||
io.post(`projects/${state.projectCode}/instance/update`, {
|
||||
processInstanceJson: JSON.stringify(data),
|
||||
locations: JSON.stringify(state.locations),
|
||||
connects: JSON.stringify(state.connects),
|
||||
@ -368,7 +362,7 @@ export default {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
io.get(`projects/${state.projectName}/process/list`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/list`, payload, res => {
|
||||
state.processListS = res.data
|
||||
resolve(res.data)
|
||||
}).catch(res => {
|
||||
@ -381,7 +375,7 @@ export default {
|
||||
*/
|
||||
getProcessListP ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/list-paging`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/list-paging`, payload, res => {
|
||||
resolve(res.data)
|
||||
}).catch(res => {
|
||||
reject(res)
|
||||
@ -410,7 +404,7 @@ export default {
|
||||
*/
|
||||
getProcessByProjectId ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/queryProcessDefinitionAllByProjectId`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/queryProcessDefinitionAllByProjectId`, payload, res => {
|
||||
resolve(res.data)
|
||||
}).catch(res => {
|
||||
reject(res)
|
||||
@ -474,7 +468,7 @@ export default {
|
||||
*/
|
||||
getProcessInstance ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/instance/list-paging`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/instance/list-paging`, payload, res => {
|
||||
state.instanceListS = res.data.totalList
|
||||
resolve(res.data)
|
||||
}).catch(res => {
|
||||
@ -531,7 +525,7 @@ export default {
|
||||
*/
|
||||
getSubProcessId ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/instance/select-sub-process`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/instance/select-sub-process`, payload, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -628,7 +622,7 @@ export default {
|
||||
*/
|
||||
deleteInstance ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/instance/delete`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/instance/delete`, payload, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -640,7 +634,7 @@ export default {
|
||||
*/
|
||||
batchDeleteInstance ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/instance/batch-delete`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/instance/batch-delete`, payload, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -652,7 +646,7 @@ export default {
|
||||
*/
|
||||
deleteDefinition ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/delete`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/delete`, payload, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -664,7 +658,7 @@ export default {
|
||||
*/
|
||||
batchDeleteDefinition ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/batch-delete`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/batch-delete`, payload, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -696,7 +690,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
io.get(`projects/${state.projectName}/process/export`, { processDefinitionIds: payload.processDefinitionIds }, res => {
|
||||
io.get(`projects/${state.projectCode}/process/export`, { processDefinitionIds: payload.processDefinitionIds }, res => {
|
||||
downloadBlob(res, payload.fileName)
|
||||
}, e => {
|
||||
|
||||
@ -710,7 +704,7 @@ export default {
|
||||
*/
|
||||
getViewvariables ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/instance/view-variables`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/instance/view-variables`, payload, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -734,7 +728,7 @@ export default {
|
||||
*/
|
||||
getTaskInstanceList ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/task-instance/list-paging`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/task-instance/list-paging`, payload, res => {
|
||||
resolve(res.data)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -746,7 +740,7 @@ export default {
|
||||
*/
|
||||
forceTaskSuccess ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.post(`projects/${state.projectName}/task-instance/force-success`, payload, res => {
|
||||
io.post(`projects/${state.projectCode}/task-instance/force-success`, payload, res => {
|
||||
resolve(res)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -782,7 +776,7 @@ export default {
|
||||
*/
|
||||
getViewTree ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/view-tree`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/view-tree`, payload, res => {
|
||||
resolve(res.data)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -794,7 +788,7 @@ export default {
|
||||
*/
|
||||
getViewGantt ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/instance/view-gantt`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/instance/view-gantt`, payload, res => {
|
||||
resolve(res.data)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -806,7 +800,7 @@ export default {
|
||||
*/
|
||||
getProcessTasksList ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/gen-task-list`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/gen-task-list`, payload, res => {
|
||||
resolve(res.data)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -815,7 +809,7 @@ export default {
|
||||
},
|
||||
getTaskListDefIdAll ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectName}/process/get-task-list`, payload, res => {
|
||||
io.get(`projects/${state.projectCode}/process/get-task-list`, payload, res => {
|
||||
resolve(res.data)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
@ -842,5 +836,14 @@ export default {
|
||||
reject(e)
|
||||
})
|
||||
})
|
||||
},
|
||||
genTaskCodeList ({ state }, payload) {
|
||||
return new Promise((resolve, reject) => {
|
||||
io.get(`projects/${state.projectCode}/task/gen-task-code-list`, payload, res => {
|
||||
resolve(res.data)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -64,10 +64,10 @@ export default {
|
||||
state.timeout = payload
|
||||
},
|
||||
/**
|
||||
* set tenantId
|
||||
* set tenantCode
|
||||
*/
|
||||
setTenantId (state, payload) {
|
||||
state.tenantId = payload
|
||||
setTenantCode (state, payload) {
|
||||
state.tenantCode = payload
|
||||
},
|
||||
/**
|
||||
* set global params
|
||||
@ -108,13 +108,12 @@ export default {
|
||||
* reset params
|
||||
*/
|
||||
resetParams (state, payload) {
|
||||
$('#canvas').html('')
|
||||
state.globalParams = (payload && payload.globalParams) || []
|
||||
state.tasks = (payload && payload.tasks) || []
|
||||
state.name = (payload && payload.name) || ''
|
||||
state.description = (payload && payload.description) || ''
|
||||
state.timeout = (payload && payload.timeout) || 0
|
||||
state.tenantId = (payload && payload.tenantId) || -1
|
||||
state.tenantCode = (payload && payload.tenantCode) || ''
|
||||
state.processListS = (payload && payload.processListS) || []
|
||||
state.resourcesListS = (payload && payload.resourcesListS) || []
|
||||
state.resourcesListJar = (payload && payload.resourcesListJar) || []
|
||||
@ -126,48 +125,23 @@ export default {
|
||||
},
|
||||
/**
|
||||
* add task
|
||||
* object {}
|
||||
* @param {Task} task
|
||||
*/
|
||||
addTasks (state, payload) {
|
||||
const i = _.findIndex(state.tasks, v => v.id === payload.id)
|
||||
addTask (state, task) {
|
||||
const i = _.findIndex(state.tasks, v => v.code === task.code)
|
||||
if (i !== -1) {
|
||||
state.tasks[i] = Object.assign(state.tasks[i], {}, payload)
|
||||
state.tasks[i] = Object.assign(state.tasks[i], {}, task)
|
||||
} else {
|
||||
state.tasks.push(payload)
|
||||
state.tasks.push(task)
|
||||
}
|
||||
if (state.cacheTasks[payload.id]) {
|
||||
state.cacheTasks[payload.id] = Object.assign(state.cacheTasks[payload.id], {}, payload)
|
||||
} else {
|
||||
state.cacheTasks[payload.id] = payload
|
||||
}
|
||||
const dom = $(`#${payload.id}`)
|
||||
state.locations[payload.id] = _.assign(state.locations[payload.id], {
|
||||
name: dom.find('.name-p').text(),
|
||||
targetarr: dom.attr('data-targetarr'),
|
||||
nodenumber: dom.attr('data-nodenumber'),
|
||||
x: parseInt(dom.css('left'), 10),
|
||||
y: parseInt(dom.css('top'), 10)
|
||||
})
|
||||
},
|
||||
addConnects (state, payload) {
|
||||
state.connects = _.map(state.connects, v => {
|
||||
if (v.endPointSourceId === payload.sourceId && v.endPointTargetId === payload.targetId) {
|
||||
v.label = payload.labelName
|
||||
}
|
||||
return v
|
||||
})
|
||||
},
|
||||
/**
|
||||
* Cache the input
|
||||
* @param state
|
||||
* @param payload
|
||||
* remove task
|
||||
* @param {object} state
|
||||
* @param {string} code
|
||||
*/
|
||||
cacheTasks (state, payload) {
|
||||
if (state.cacheTasks[payload.id]) {
|
||||
state.cacheTasks[payload.id] = Object.assign(state.cacheTasks[payload.id], {}, payload)
|
||||
} else {
|
||||
state.cacheTasks[payload.id] = payload
|
||||
}
|
||||
removeTask (state, code) {
|
||||
state.tasks = state.tasks.filter(task => task.code !== code)
|
||||
},
|
||||
resetLocalParam (state, payload) {
|
||||
const tasks = state.tasks
|
||||
|
@ -39,11 +39,11 @@ export default {
|
||||
cacheTasks: {},
|
||||
// Timeout alarm
|
||||
timeout: 0,
|
||||
// tenant id
|
||||
tenantId: -1,
|
||||
// tenant code
|
||||
tenantCode: '',
|
||||
// Node location information
|
||||
locations: {},
|
||||
// Node-to-node connection
|
||||
// Node relations
|
||||
connects: [],
|
||||
// Running sign
|
||||
runFlag: '',
|
||||
|