|
|
@@ -16,11 +16,11 @@
|
|
|
</el-select>
|
|
|
</div>
|
|
|
<div class="toolbar-right">
|
|
|
- <el-input
|
|
|
- v-model="form.workflowDesc"
|
|
|
- placeholder="工作流描述"
|
|
|
- size="small"
|
|
|
- style="width: 200px; margin-right: 10px"
|
|
|
+ <el-input
|
|
|
+ v-model="form.workflowDesc"
|
|
|
+ placeholder="工作流描述"
|
|
|
+ size="small"
|
|
|
+ style="width: 200px; margin-right: 10px"
|
|
|
/>
|
|
|
<el-divider direction="vertical" />
|
|
|
<el-button icon="el-icon-zoom-in" size="small" @click="zoomIn">放大</el-button>
|
|
|
@@ -57,7 +57,7 @@
|
|
|
<div
|
|
|
class="canvas-container"
|
|
|
ref="canvasContainer"
|
|
|
- tabindex="0"
|
|
|
+ tabindex="0"
|
|
|
@drop="onDrop"
|
|
|
@dragover.prevent
|
|
|
@click="onCanvasClick"
|
|
|
@@ -74,7 +74,7 @@
|
|
|
</pattern>
|
|
|
</defs>
|
|
|
<rect :width="canvasSize.width" :height="canvasSize.height" fill="url(#grid)" />
|
|
|
-
|
|
|
+
|
|
|
<!-- 连线 -->
|
|
|
<g class="edges-layer" :transform="`translate(${canvasOffset.x}, ${canvasOffset.y}) scale(${scale})`">
|
|
|
<g
|
|
|
@@ -159,16 +159,19 @@
|
|
|
{{ selectedNode ? '节点属性' : '连线属性' }}
|
|
|
<i class="el-icon-close" @click="clearSelection"></i>
|
|
|
</div>
|
|
|
-
|
|
|
+
|
|
|
<!-- 节点属性 -->
|
|
|
<el-form v-if="selectedNode" label-width="80px" size="small">
|
|
|
<el-form-item label="节点内容">
|
|
|
- <el-input
|
|
|
- v-model="selectedNode.nodeName"
|
|
|
+ <el-input
|
|
|
+ v-model="selectedNode.nodeName"
|
|
|
type="textarea"
|
|
|
:autosize="{ minRows: 1, maxRows: 6 }"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
+ <div v-if="selectedNode.nodeType == 'http'">
|
|
|
+ <el-input v-model="selectedNode.nodeConfig.url" />
|
|
|
+ </div>
|
|
|
<el-form-item label="节点类型">
|
|
|
<el-input :value="getNodeTypeName(selectedNode.nodeType)" disabled />
|
|
|
</el-form-item>
|
|
|
@@ -276,7 +279,7 @@ export default {
|
|
|
this.$nextTick(() => {
|
|
|
this.$refs.canvasContainer.focus() // 这里应该是 canvasContainer 不是 container
|
|
|
})
|
|
|
-
|
|
|
+
|
|
|
// 添加全局键盘事件监听
|
|
|
// window.addEventListener('keydown', this.handleGlobalKeydown)
|
|
|
document.addEventListener('mousemove', this.onMouseMove)
|
|
|
@@ -292,33 +295,34 @@ export default {
|
|
|
focusCanvasContainer() {
|
|
|
this.$refs.canvasContainer.focus()
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
// 点击画布时聚焦
|
|
|
onCanvasClick() {
|
|
|
this.clearSelection()
|
|
|
this.focusCanvasContainer()
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
// 点击节点时聚焦
|
|
|
selectNode(node) {
|
|
|
this.selectedNode = node
|
|
|
+ this.selectedNode.nodeConfig = JSON.parse(node.nodeConfig)
|
|
|
this.selectedEdge = null
|
|
|
this.focusCanvasContainer()
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
// 点击连线时聚焦
|
|
|
selectEdge(edge) {
|
|
|
this.selectedEdge = edge
|
|
|
this.selectedNode = null
|
|
|
this.focusCanvasContainer()
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
// 局部键盘事件
|
|
|
handleDelete(event) {
|
|
|
event.preventDefault() // 阻止默认行为(如浏览器后退)
|
|
|
this.deleteSelected()
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
// 全局键盘事件
|
|
|
// handleGlobalKeydown(event) {
|
|
|
// // 检查是否按下了退格键或删除键
|
|
|
@@ -327,7 +331,7 @@ export default {
|
|
|
// this.deleteSelected()
|
|
|
// }
|
|
|
// },
|
|
|
-
|
|
|
+
|
|
|
// 删除选中项的逻辑
|
|
|
deleteSelected() {
|
|
|
if (this.selectedNode) {
|
|
|
@@ -336,7 +340,7 @@ export default {
|
|
|
this.deleteSelectedEdge()
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
// 删除选中节点
|
|
|
deleteSelectedNode() {
|
|
|
if (!this.selectedNode) return
|
|
|
@@ -349,16 +353,16 @@ export default {
|
|
|
const key = this.selectedNode.nodeKey
|
|
|
this.nodes = this.nodes.filter(n => n.nodeKey !== key)
|
|
|
// 同时删除与该节点相关的连线
|
|
|
- this.edges = this.edges.filter(e =>
|
|
|
+ this.edges = this.edges.filter(e =>
|
|
|
e.sourceNodeKey !== key && e.targetNodeKey !== key)
|
|
|
this.selectedNode = null
|
|
|
}).catch(() => {})
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
// 删除选中连线
|
|
|
deleteSelectedEdge() {
|
|
|
if (!this.selectedEdge) return
|
|
|
-
|
|
|
+
|
|
|
this.$confirm('是否确认删除该连线?', '警告', {
|
|
|
confirmButtonText: '确定',
|
|
|
cancelButtonText: '取消',
|
|
|
@@ -368,7 +372,7 @@ export default {
|
|
|
this.selectedEdge = null
|
|
|
}).catch(() => {})
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
// 检查是否有输入框获得焦点
|
|
|
isInputFocused() {
|
|
|
const activeElement = document.activeElement
|
|
|
@@ -378,7 +382,7 @@ export default {
|
|
|
const isNodeInput = activeElement.classList && activeElement.classList.contains('node-name-input')
|
|
|
return isEditable || isNodeInput
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
/** 加载节点类型 */
|
|
|
loadNodeTypes() {
|
|
|
getNodeTypes().then(res => {
|
|
|
@@ -405,6 +409,7 @@ export default {
|
|
|
basic: { key: 'basic', name: '基础节点', types: [] },
|
|
|
logic: { key: 'logic', name: '逻辑节点', types: [] },
|
|
|
ai: { key: 'ai', name: 'AI节点', types: [] },
|
|
|
+ ai: { key: 'ai-cell', name: '外呼几点', types: [] },
|
|
|
integration: { key: 'integration', name: '集成节点', types: [] }
|
|
|
}
|
|
|
this.nodeTypes.forEach(t => {
|
|
|
@@ -461,7 +466,7 @@ export default {
|
|
|
const rect = this.$refs.canvasContainer.getBoundingClientRect()
|
|
|
const x = (e.clientX - rect.left - this.canvasOffset.x) / this.scale
|
|
|
const y = (e.clientY - rect.top - this.canvasOffset.y) / this.scale
|
|
|
-
|
|
|
+
|
|
|
const newNode = {
|
|
|
nodeKey: this.generateKey(),
|
|
|
nodeName: nodeType.typeName,
|
|
|
@@ -479,7 +484,7 @@ export default {
|
|
|
// 检测并扩展画布
|
|
|
this.checkAndExpandCanvas(newNode)
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
/** 画布鼠标按下 */
|
|
|
onCanvasMouseDown(e) {
|
|
|
// 只响应左键且点击在空白区域
|
|
|
@@ -495,7 +500,7 @@ export default {
|
|
|
e.preventDefault()
|
|
|
}
|
|
|
},
|
|
|
-
|
|
|
+
|
|
|
/** 清除选中 */
|
|
|
clearSelection() {
|
|
|
this.selectedNode = null
|
|
|
@@ -553,10 +558,10 @@ export default {
|
|
|
const nodeHeight = node.height || 36
|
|
|
const padding = 200 // 边缘预留空间
|
|
|
const expandStep = 500 // 每次扩展的大小
|
|
|
-
|
|
|
+
|
|
|
const nodeRight = node.posX + this.nodeWidth
|
|
|
const nodeBottom = node.posY + nodeHeight
|
|
|
-
|
|
|
+
|
|
|
// 检测右边缘
|
|
|
if (nodeRight + padding > this.canvasSize.width) {
|
|
|
this.canvasSize.width += expandStep
|
|
|
@@ -626,10 +631,10 @@ export default {
|
|
|
},
|
|
|
/** 创建连线 */
|
|
|
createEdge(sourceKey, targetKey, sourceAnchor, targetAnchor) {
|
|
|
- const exists = this.edges.find(e =>
|
|
|
+ const exists = this.edges.find(e =>
|
|
|
e.sourceNodeKey === sourceKey && e.targetNodeKey === targetKey)
|
|
|
if (exists) return
|
|
|
-
|
|
|
+
|
|
|
this.edges.push({
|
|
|
edgeKey: 'edge_' + Date.now(),
|
|
|
sourceNodeKey: sourceKey,
|
|
|
@@ -645,7 +650,7 @@ export default {
|
|
|
const sourceNode = this.nodes.find(n => n.nodeKey === edge.sourceNodeKey)
|
|
|
const targetNode = this.nodes.find(n => n.nodeKey === edge.targetNodeKey)
|
|
|
if (!sourceNode || !targetNode) return ''
|
|
|
-
|
|
|
+
|
|
|
const start = this.getAnchorPos(sourceNode, edge.sourceAnchor || 'bottom')
|
|
|
const end = this.getAnchorPos(targetNode, edge.targetAnchor || 'top')
|
|
|
return this.calcPath(start.x, start.y, end.x, end.y)
|
|
|
@@ -689,16 +694,21 @@ export default {
|
|
|
this.msgWarning('请输入工作流名称')
|
|
|
return
|
|
|
}
|
|
|
+ const nodes = JSON.parse(JSON.stringify(this.nodes))
|
|
|
+ nodes.filter(node => typeof node.nodeConfig == 'object').forEach(node => {
|
|
|
+ console.log(typeof node.nodeConfig)
|
|
|
+ node.nodeConfig = JSON.stringify(node.nodeConfig);
|
|
|
+ })
|
|
|
const data = {
|
|
|
workflowId: this.workflowId,
|
|
|
workflowName: this.form.workflowName,
|
|
|
workflowDesc: this.form.workflowDesc,
|
|
|
workflowType: this.form.workflowType,
|
|
|
canvasData: JSON.stringify({ scale: this.scale, offset: this.canvasOffset }),
|
|
|
- nodes: this.nodes,
|
|
|
+ nodes: nodes,
|
|
|
edges: this.edges
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (this.workflowId) {
|
|
|
updateWorkflow(data).then(() => {
|
|
|
this.msgSuccess('保存成功')
|
|
|
@@ -717,4 +727,4 @@ export default {
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
@import './design.scss';
|
|
|
-</style>
|
|
|
+</style>
|