|
|
@@ -611,7 +611,7 @@ import {
|
|
|
import { getWorkflow, addWorkflow, updateWorkflow, getNodeTypes } from '@/api/company/companyWorkflow'
|
|
|
import {getDicts} from "@/api/system/dict/data";
|
|
|
import { getGatewayList, getLlmAccountList, getVoiceCodeList, getBusiGroupList } from '@/api/company/easyCall'
|
|
|
-import { listAll } from '@/api/company/wxDialog';
|
|
|
+// import { listAll } from '@/api/company/wxDialog';
|
|
|
export default {
|
|
|
name: 'WorkflowDesign',
|
|
|
data() {
|
|
|
@@ -711,11 +711,11 @@ export default {
|
|
|
if (this.workflowId) {
|
|
|
this.loadWorkflow()
|
|
|
}
|
|
|
- listAll().then(e => {
|
|
|
- this.wxDialogList = e.data;
|
|
|
- console.log("------")
|
|
|
- console.log(this.wxDialogList)
|
|
|
- })
|
|
|
+ // listAll().then(e => {
|
|
|
+ // this.wxDialogList = e.data;
|
|
|
+ // console.log("------")
|
|
|
+ // console.log(this.wxDialogList)
|
|
|
+ // })
|
|
|
},
|
|
|
mounted() {
|
|
|
// 确保容器可获取焦点
|
|
|
@@ -1117,6 +1117,14 @@ export default {
|
|
|
}
|
|
|
this.hideContextMenu()
|
|
|
},
|
|
|
+ /** 判断是否是开始节点 */
|
|
|
+ isStartNodeType(typeCode) {
|
|
|
+ return typeCode === 'START' || typeCode === 'start'
|
|
|
+ },
|
|
|
+ /** 判断是否是结束节点 */
|
|
|
+ isEndNodeType(typeCode) {
|
|
|
+ return typeCode === 'END' || typeCode === 'end'
|
|
|
+ },
|
|
|
/** 拖拽开始 */
|
|
|
onDragStart(e, nodeType) {
|
|
|
e.dataTransfer.setData('nodeType', JSON.stringify(nodeType))
|
|
|
@@ -1126,6 +1134,23 @@ export default {
|
|
|
const nodeTypeStr = e.dataTransfer.getData('nodeType')
|
|
|
if (!nodeTypeStr) return
|
|
|
const nodeType = JSON.parse(nodeTypeStr)
|
|
|
+
|
|
|
+ // 检查开始/结束节点是否已存在(限制只能有一个)
|
|
|
+ if (this.isStartNodeType(nodeType.typeCode)) {
|
|
|
+ const existingStart = this.nodes.find(n => this.isStartNodeType(n.nodeType))
|
|
|
+ if (existingStart) {
|
|
|
+ this.$message.warning('已存在开始节点,工作流只能有一个开始节点')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (this.isEndNodeType(nodeType.typeCode)) {
|
|
|
+ const existingEnd = this.nodes.find(n => this.isEndNodeType(n.nodeType))
|
|
|
+ if (existingEnd) {
|
|
|
+ this.$message.warning('已存在结束节点,工作流只能有一个结束节点')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
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
|
|
|
@@ -1446,9 +1471,76 @@ export default {
|
|
|
/** 保存工作流 */
|
|
|
handleSave() {
|
|
|
if (!this.form.workflowName) {
|
|
|
- this.msgWarning('请输入工作流名称')
|
|
|
+ this.$message.warning('请输入工作流名称')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 校验开始节点和结束节点
|
|
|
+ const startNodes = this.nodes.filter(node => this.isStartNodeType(node.nodeType))
|
|
|
+ const endNodes = this.nodes.filter(node => this.isEndNodeType(node.nodeType))
|
|
|
+
|
|
|
+ if (startNodes.length === 0) {
|
|
|
+ this.$message.warning('工作流必须包含一个开始节点')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (startNodes.length > 1) {
|
|
|
+ this.$message.warning('工作流只能包含一个开始节点')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (endNodes.length === 0) {
|
|
|
+ this.$message.warning('工作流必须包含一个结束节点')
|
|
|
return
|
|
|
}
|
|
|
+ if (endNodes.length > 1) {
|
|
|
+ this.$message.warning('工作流只能包含一个结束节点')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 校验所有节点都必须有连线
|
|
|
+ if (this.nodes.length > 0) {
|
|
|
+ const connectedNodeKeys = new Set()
|
|
|
+ this.edges.forEach(edge => {
|
|
|
+ connectedNodeKeys.add(edge.sourceNodeKey)
|
|
|
+ connectedNodeKeys.add(edge.targetNodeKey)
|
|
|
+ })
|
|
|
+ const isolatedNodes = this.nodes.filter(node => !connectedNodeKeys.has(node.nodeKey))
|
|
|
+ if (isolatedNodes.length > 0) {
|
|
|
+ const isolatedNames = isolatedNodes.map(n => n.nodeName).join('、')
|
|
|
+ this.$message.warning(`以下节点未连线:${isolatedNames},所有节点必须连线`)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 校验短信节点和外呼节点配置
|
|
|
+ for (const node of this.nodes) {
|
|
|
+ // 短信节点校验:短信模版必选
|
|
|
+ if (node.nodeType === 'AI_SEND_MSG_TASK') {
|
|
|
+ if (!node.nodeConfig || !node.nodeConfig.smsTempId) {
|
|
|
+ this.$message.warning(`节点「${node.nodeName}」未选择短信模版`)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 外呼节点校验
|
|
|
+ if (node.nodeType === 'AI_CALL_TASK') {
|
|
|
+ const callMode = node.nodeConfig ? node.nodeConfig.callMode : null
|
|
|
+ // callMode=2 为AI自动外呼,需要校验必选项
|
|
|
+ if (callMode === 2) {
|
|
|
+ if (!node.nodeConfig.gatewayId) {
|
|
|
+ this.$message.warning(`节点「${node.nodeName}」未选择外呼网关`)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!node.nodeConfig.llmAccountId) {
|
|
|
+ this.$message.warning(`节点「${node.nodeName}」未选择大模型`)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!node.nodeConfig.voiceCode) {
|
|
|
+ this.$message.warning(`节点「${node.nodeName}」未选择音色`)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const nodes = JSON.parse(JSON.stringify(this.nodes))
|
|
|
this.edges.forEach((edges) => {
|
|
|
edges.conditionExpr = JSON.stringify(edges.conditionExprObj);
|
|
|
@@ -1457,10 +1549,6 @@ export default {
|
|
|
node.nodeConfig = JSON.stringify(node.nodeConfig);
|
|
|
})
|
|
|
|
|
|
- // 查找开始节点和结束节点
|
|
|
- const startNode = this.nodes.find(node => node.nodeType === 'START')
|
|
|
- const endNode = this.nodes.find(node => node.nodeType === 'END')
|
|
|
-
|
|
|
const data = {
|
|
|
workflowId: this.workflowId,
|
|
|
workflowName: this.form.workflowName,
|
|
|
@@ -1469,17 +1557,17 @@ export default {
|
|
|
canvasData: JSON.stringify({ scale: this.scale, offset: this.canvasOffset }),
|
|
|
nodes: nodes,
|
|
|
edges: this.edges,
|
|
|
- startNodeKey: startNode ? startNode.nodeKey : null,
|
|
|
- endNodeKey: endNode ? endNode.nodeKey : null
|
|
|
+ startNodeKey: startNodes[0].nodeKey,
|
|
|
+ endNodeKey: endNodes[0].nodeKey
|
|
|
}
|
|
|
|
|
|
if (this.workflowId) {
|
|
|
updateWorkflow(data).then(() => {
|
|
|
- this.msgSuccess('保存成功')
|
|
|
+ this.$message.success('保存成功')
|
|
|
})
|
|
|
} else {
|
|
|
addWorkflow(data).then(res => {
|
|
|
- this.msgSuccess('保存成功')
|
|
|
+ this.$message.success('保存成功')
|
|
|
this.workflowId = res.data
|
|
|
this.$router.replace('/companyWx/companyWorkflow/design/' + this.workflowId)
|
|
|
})
|