优化工作流组件,增强节点数据处理的可选性和安全性,修复潜在的空值引用问题。
This commit is contained in:
@@ -55,9 +55,9 @@ import { ref, computed } from 'vue';
|
|||||||
import type { Node } from '@vue-flow/core';
|
import type { Node } from '@vue-flow/core';
|
||||||
|
|
||||||
interface NodeData {
|
interface NodeData {
|
||||||
label: string;
|
label?: string;
|
||||||
nodeCode: string;
|
nodeCode?: string;
|
||||||
inputSource: Array<{ nodeId: string; field: string[]; quoteOutput?: boolean }> | null;
|
inputSource?: Array<{ nodeId: string; field: string[]; quoteOutput?: boolean }> | null;
|
||||||
formConfig?: any[];
|
formConfig?: any[];
|
||||||
modelConfig?: any;
|
modelConfig?: any;
|
||||||
skillName?: string;
|
skillName?: string;
|
||||||
@@ -74,8 +74,8 @@ interface ParamOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
selectedNode: Node<NodeData> | null;
|
selectedNode: Node<NodeData, any, string> | null;
|
||||||
nodes: Node<NodeData>[];
|
nodes: Node<NodeData, any, string>[];
|
||||||
edges: any[];
|
edges: any[];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
@@ -89,19 +89,19 @@ const selectedParam = ref('');
|
|||||||
|
|
||||||
// 当前节点的 inputSource
|
// 当前节点的 inputSource
|
||||||
const currentInputSource = computed(() => {
|
const currentInputSource = computed(() => {
|
||||||
if (!props.selectedNode?.data.inputSource) return [];
|
if (!props.selectedNode?.data?.inputSource) return [];
|
||||||
return props.selectedNode.data.inputSource.filter((item) => item.field && item.field.length > 0);
|
return props.selectedNode.data.inputSource.filter((item) => item.field && item.field.length > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取节点名称
|
// 获取节点名称
|
||||||
const getNodeName = (nodeId: string) => {
|
const getNodeName = (nodeId: string) => {
|
||||||
const node = props.nodes.find((n) => n.id === nodeId);
|
const node = props.nodes.find((n) => n.id === nodeId);
|
||||||
return node?.data.label || nodeId;
|
return node?.data?.label || nodeId;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取所有上级节点(用于显示输出引用选项)
|
// 获取所有上级节点(用于显示输出引用选项)
|
||||||
const availableParentNodes = computed(() => {
|
const availableParentNodes = computed(() => {
|
||||||
if (!props.selectedNode) return [];
|
if (!props.selectedNode?.data) return [];
|
||||||
|
|
||||||
// 获取已经引用了字段的节点ID列表
|
// 获取已经引用了字段的节点ID列表
|
||||||
const inputSource = props.selectedNode.data.inputSource;
|
const inputSource = props.selectedNode.data.inputSource;
|
||||||
@@ -134,7 +134,7 @@ const availableParentNodes = computed(() => {
|
|||||||
const parentNodes = allParentIds
|
const parentNodes = allParentIds
|
||||||
.map((parentId) => {
|
.map((parentId) => {
|
||||||
const parentNode = props.nodes.find((n) => n.id === parentId);
|
const parentNode = props.nodes.find((n) => n.id === parentId);
|
||||||
if (!parentNode) return null;
|
if (!parentNode?.data) return null;
|
||||||
|
|
||||||
const nodeCode = String(parentNode.data.nodeCode || '').toLowerCase();
|
const nodeCode = String(parentNode.data.nodeCode || '').toLowerCase();
|
||||||
const isJudge = ['判断', 'judge', 'condition', 'if', 'branch', 'gateway'].some((k) => nodeCode.includes(k));
|
const isJudge = ['判断', 'judge', 'condition', 'if', 'branch', 'gateway'].some((k) => nodeCode.includes(k));
|
||||||
@@ -144,7 +144,7 @@ const availableParentNodes = computed(() => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
id: parentId,
|
id: parentId,
|
||||||
name: parentNode.data.label,
|
name: parentNode.data.label || parentId,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
@@ -154,7 +154,7 @@ const availableParentNodes = computed(() => {
|
|||||||
|
|
||||||
// 检查节点输出是否被引用
|
// 检查节点输出是否被引用
|
||||||
const isNodeOutputQuoted = (nodeId: string): boolean => {
|
const isNodeOutputQuoted = (nodeId: string): boolean => {
|
||||||
if (!props.selectedNode) return false;
|
if (!props.selectedNode?.data) return false;
|
||||||
const inputSource = props.selectedNode.data.inputSource;
|
const inputSource = props.selectedNode.data.inputSource;
|
||||||
if (!Array.isArray(inputSource)) return false;
|
if (!Array.isArray(inputSource)) return false;
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ const availableParams = computed(() => {
|
|||||||
.filter((e) => e.target === nodeId)
|
.filter((e) => e.target === nodeId)
|
||||||
.forEach((edge) => {
|
.forEach((edge) => {
|
||||||
const parent = props.nodes.find((n) => n.id === edge.source);
|
const parent = props.nodes.find((n) => n.id === edge.source);
|
||||||
if (parent && parent.data.nodeCode !== '__start__' && parent.data.nodeCode !== 'judge') {
|
if (parent?.data && parent.data.nodeCode !== '__start__' && parent.data.nodeCode !== 'judge') {
|
||||||
params.push({
|
params.push({
|
||||||
label: `${parent.data.label}.output`,
|
label: `${parent.data.label}.output`,
|
||||||
value: `\${${parent.id}.output}`,
|
value: `\${${parent.id}.output}`,
|
||||||
|
|||||||
@@ -4,16 +4,16 @@
|
|||||||
<div v-if="selectedNode">
|
<div v-if="selectedNode">
|
||||||
<el-form label-position="top">
|
<el-form label-position="top">
|
||||||
<el-form-item label="节点名称">
|
<el-form-item label="节点名称">
|
||||||
<el-input :model-value="selectedNode.data.label" @update:model-value="updateNodeLabel" />
|
<el-input :model-value="selectedNode.data?.label" @update:model-value="updateNodeLabel" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="节点类型">
|
<el-form-item label="节点类型">
|
||||||
<el-tag>{{ selectedNode.data.nodeCode }}</el-tag>
|
<el-tag>{{ selectedNode.data?.nodeCode }}</el-tag>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 模型选择 -->
|
<!-- 模型选择 -->
|
||||||
<el-form-item v-if="nodeConfig?.modelConfig && nodeConfig.modelConfig.length > 0" label="选择模型">
|
<el-form-item v-if="nodeConfig?.modelConfig && nodeConfig.modelConfig.length > 0" label="选择模型">
|
||||||
<el-button type="primary" @click="emit('openModelSelector')" style="width: 100%">选择模型</el-button>
|
<el-button type="primary" @click="emit('openModelSelector')" style="width: 100%">选择模型</el-button>
|
||||||
<div v-if="selectedNode.data.modelConfig?.modelName" class="selected-tag">
|
<div v-if="selectedNode.data?.modelConfig?.modelName" class="selected-tag">
|
||||||
<el-tag type="success" size="large" closable @close="emit('removeModel')">
|
<el-tag type="success" size="large" closable @close="emit('removeModel')">
|
||||||
{{ selectedNode.data.modelConfig.modelName }}
|
{{ selectedNode.data.modelConfig.modelName }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<!-- 技能选择 -->
|
<!-- 技能选择 -->
|
||||||
<el-form-item v-if="nodeConfig?.skillOption" label="选择技能">
|
<el-form-item v-if="nodeConfig?.skillOption" label="选择技能">
|
||||||
<el-button type="primary" @click="emit('openSkillSelector')" style="width: 100%">选择技能</el-button>
|
<el-button type="primary" @click="emit('openSkillSelector')" style="width: 100%">选择技能</el-button>
|
||||||
<div v-if="selectedNode.data.skillName" class="selected-tag">
|
<div v-if="selectedNode.data?.skillName" class="selected-tag">
|
||||||
<el-tag type="success" size="large" closable @close="emit('removeSkill')">
|
<el-tag type="success" size="large" closable @close="emit('removeSkill')">
|
||||||
{{ selectedNode.data.skillName }}
|
{{ selectedNode.data.skillName }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
|
|
||||||
<!-- 上级参数管理 -->
|
<!-- 上级参数管理 -->
|
||||||
<InputSourceManager
|
<InputSourceManager
|
||||||
v-if="selectedNode.data.nodeCode !== '__start__'"
|
v-if="selectedNode.data?.nodeCode !== '__start__'"
|
||||||
:selected-node="selectedNode"
|
:selected-node="selectedNode"
|
||||||
:nodes="allNodes"
|
:nodes="allNodes"
|
||||||
:edges="allEdges"
|
:edges="allEdges"
|
||||||
@@ -98,9 +98,9 @@ import type { Node } from '@vue-flow/core';
|
|||||||
import InputSourceManager from './InputSourceManager.vue';
|
import InputSourceManager from './InputSourceManager.vue';
|
||||||
|
|
||||||
interface NodeData {
|
interface NodeData {
|
||||||
label: string;
|
label?: string;
|
||||||
nodeCode: string;
|
nodeCode?: string;
|
||||||
inputSource: Array<{ nodeId: string; field: string[]; quoteOutput?: boolean }> | null;
|
inputSource?: Array<{ nodeId: string; field: string[]; quoteOutput?: boolean }> | null;
|
||||||
formConfig?: any[];
|
formConfig?: any[];
|
||||||
modelConfig?: any;
|
modelConfig?: any;
|
||||||
skillName?: string;
|
skillName?: string;
|
||||||
@@ -118,15 +118,15 @@ interface NodeConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
selectedNode: Node<NodeData> | null;
|
selectedNode: Node<NodeData, any, string> | null;
|
||||||
availableParams: ParamRef[];
|
availableParams: ParamRef[];
|
||||||
nodeConfig: NodeConfig | null;
|
nodeConfig: NodeConfig | null;
|
||||||
allNodes: Node<NodeData>[];
|
allNodes: Node<NodeData, any, string>[];
|
||||||
allEdges: any[];
|
allEdges: any[];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:selectedNode', node: Node<NodeData>): void;
|
(e: 'update:selectedNode', node: Node<NodeData, any, string>): void;
|
||||||
(e: 'addParam', param: ParamRef): void;
|
(e: 'addParam', param: ParamRef): void;
|
||||||
(e: 'openModelSelector'): void;
|
(e: 'openModelSelector'): void;
|
||||||
(e: 'removeModel'): void;
|
(e: 'removeModel'): void;
|
||||||
@@ -138,7 +138,7 @@ const emit = defineEmits<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const updateNodeLabel = (newLabel: string) => {
|
const updateNodeLabel = (newLabel: string) => {
|
||||||
if (!props.selectedNode) return;
|
if (!props.selectedNode?.data) return;
|
||||||
const updatedNode = {
|
const updatedNode = {
|
||||||
...props.selectedNode,
|
...props.selectedNode,
|
||||||
data: {
|
data: {
|
||||||
@@ -150,13 +150,13 @@ const updateNodeLabel = (newLabel: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getFieldValue = (fieldName: string) => {
|
const getFieldValue = (fieldName: string) => {
|
||||||
if (!props.selectedNode?.data.formConfig) return '';
|
if (!props.selectedNode?.data?.formConfig) return '';
|
||||||
const field = props.selectedNode.data.formConfig.find((f: any) => f.field === fieldName);
|
const field = props.selectedNode.data.formConfig.find((f: any) => f.field === fieldName);
|
||||||
return field?.value ?? '';
|
return field?.value ?? '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateFieldValue = (fieldName: string, value: any) => {
|
const updateFieldValue = (fieldName: string, value: any) => {
|
||||||
if (!props.selectedNode) return;
|
if (!props.selectedNode?.data) return;
|
||||||
|
|
||||||
const formConfig = props.selectedNode.data.formConfig || [];
|
const formConfig = props.selectedNode.data.formConfig || [];
|
||||||
const existingIndex = formConfig.findIndex((f: any) => f.field === fieldName);
|
const existingIndex = formConfig.findIndex((f: any) => f.field === fieldName);
|
||||||
|
|||||||
@@ -35,7 +35,12 @@
|
|||||||
|
|
||||||
<!-- 中间:VueFlow 画布(节点库在画布内) -->
|
<!-- 中间:VueFlow 画布(节点库在画布内) -->
|
||||||
<div class="flow-wrapper">
|
<div class="flow-wrapper">
|
||||||
<NodeLibraryPanel :node-library-groups="filteredNodeLibraryGroups" :collapsed="nodeLibraryCollapsed" @update:collapsed="nodeLibraryCollapsed = $event" @add-node="addNodeFromLibrary" />
|
<NodeLibraryPanel
|
||||||
|
:node-library-groups="filteredNodeLibraryGroups"
|
||||||
|
:collapsed="nodeLibraryCollapsed"
|
||||||
|
@update:collapsed="nodeLibraryCollapsed = $event"
|
||||||
|
@add-node="addNodeFromLibrary"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- VueFlow 画布 -->
|
<!-- VueFlow 画布 -->
|
||||||
<VueFlow
|
<VueFlow
|
||||||
@@ -55,18 +60,24 @@
|
|||||||
|
|
||||||
<!-- 右侧:工作流列表 -->
|
<!-- 右侧:工作流列表 -->
|
||||||
<WorkflowListPanel
|
<WorkflowListPanel
|
||||||
:user-workflow-list="userWorkflowList"
|
:user-workflow-list="userWorkflowList"
|
||||||
:template-workflow-list="templateWorkflowList"
|
:template-workflow-list="templateWorkflowList"
|
||||||
:current-editing-id="currentEditingWorkflowId"
|
:current-editing-id="currentEditingWorkflowId"
|
||||||
:loading="workflowListLoading"
|
:loading="workflowListLoading"
|
||||||
@edit="editWorkflow"
|
@edit="editWorkflow"
|
||||||
@delete="deleteWorkflowAction"
|
@delete="deleteWorkflowAction"
|
||||||
@create="createNewWorkflow"
|
@create="createNewWorkflow"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 保存工作流对话框 -->
|
<!-- 保存工作流对话框 -->
|
||||||
<SaveWorkflowDialog v-model="saveDialogVisible" :save-form="saveForm" :current-editing-workflow-id="currentEditingWorkflowId" :saving="saving" @confirm="confirmSaveWorkflow" />
|
<SaveWorkflowDialog
|
||||||
|
v-model="saveDialogVisible"
|
||||||
|
:save-form="saveForm"
|
||||||
|
:current-editing-workflow-id="currentEditingWorkflowId"
|
||||||
|
:saving="saving"
|
||||||
|
@confirm="confirmSaveWorkflow"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 模型选择器 -->
|
<!-- 模型选择器 -->
|
||||||
<ModelSelector v-model="showModelSelector" :default-model="selectedModelData" :model-type="currentNodeModelType" @confirm="handleModelConfirm" />
|
<ModelSelector v-model="showModelSelector" :default-model="selectedModelData" :model-type="currentNodeModelType" @confirm="handleModelConfirm" />
|
||||||
@@ -102,9 +113,9 @@ import ModelSelector from '/@/components/model/ModelSelector.vue';
|
|||||||
import SkillSelector from '/@/components/skill/SkillSelector.vue';
|
import SkillSelector from '/@/components/skill/SkillSelector.vue';
|
||||||
|
|
||||||
interface NodeData {
|
interface NodeData {
|
||||||
label: string;
|
label?: string;
|
||||||
nodeCode: string;
|
nodeCode?: string;
|
||||||
inputSource: Array<{ nodeId: string; field: string[]; quoteOutput?: boolean }> | null;
|
inputSource?: Array<{ nodeId: string; field: string[]; quoteOutput?: boolean }> | null;
|
||||||
formConfig?: any[];
|
formConfig?: any[];
|
||||||
modelConfig?: any;
|
modelConfig?: any;
|
||||||
skillName?: string;
|
skillName?: string;
|
||||||
@@ -146,7 +157,7 @@ const nodeConfigMap = computed(() => {
|
|||||||
|
|
||||||
// 当前选中节点的配置
|
// 当前选中节点的配置
|
||||||
const currentNodeConfig = computed(() => {
|
const currentNodeConfig = computed(() => {
|
||||||
if (!selectedNode.value) return null;
|
if (!selectedNode.value?.data?.nodeCode) return null;
|
||||||
return nodeConfigMap.value.get(selectedNode.value.data.nodeCode) || null;
|
return nodeConfigMap.value.get(selectedNode.value.data.nodeCode) || null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -164,9 +175,9 @@ const saveForm = ref({
|
|||||||
description: '',
|
description: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const nodes = ref<Node<NodeData>[]>([]);
|
const nodes = ref<Node<NodeData, any, string>[]>([]);
|
||||||
const edges = ref<Edge[]>([]);
|
const edges = ref<Edge[]>([]);
|
||||||
const selectedNode = ref<Node<NodeData> | null>(null);
|
const selectedNode = ref<Node<NodeData, any, string> | null>(null);
|
||||||
let nodeId = 0;
|
let nodeId = 0;
|
||||||
|
|
||||||
// 模型选择器相关状态
|
// 模型选择器相关状态
|
||||||
@@ -186,7 +197,7 @@ const showSkillSelector = ref(false);
|
|||||||
const selectedSkillData = ref<any>(null);
|
const selectedSkillData = ref<any>(null);
|
||||||
|
|
||||||
const deleteSelectedNode = async () => {
|
const deleteSelectedNode = async () => {
|
||||||
if (!selectedNode.value) return;
|
if (!selectedNode.value?.data) return;
|
||||||
|
|
||||||
if (selectedNode.value.data.nodeCode === '__start__') {
|
if (selectedNode.value.data.nodeCode === '__start__') {
|
||||||
ElMessage.warning('开始节点不能删除');
|
ElMessage.warning('开始节点不能删除');
|
||||||
@@ -212,7 +223,7 @@ const onConnect = (connection: Connection) => {
|
|||||||
const source = findNode(connection.source);
|
const source = findNode(connection.source);
|
||||||
const target = findNode(connection.target);
|
const target = findNode(connection.target);
|
||||||
|
|
||||||
if (!source || !target) return;
|
if (!source?.data || !target?.data) return;
|
||||||
|
|
||||||
if (target.data.nodeCode === '__start__') {
|
if (target.data.nodeCode === '__start__') {
|
||||||
ElMessage.warning('开始节点不能被连接');
|
ElMessage.warning('开始节点不能被连接');
|
||||||
@@ -237,11 +248,11 @@ const onConnect = (connection: Connection) => {
|
|||||||
ElMessage.success('连接成功');
|
ElMessage.success('连接成功');
|
||||||
};
|
};
|
||||||
|
|
||||||
const onNodeClick = (event: { node: Node<NodeData> }) => {
|
const onNodeClick = (event: { node: Node<NodeData, any, string> }) => {
|
||||||
selectedNode.value = event.node;
|
selectedNode.value = event.node;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateSelectedNode = (updatedNode: Node<NodeData>) => {
|
const updateSelectedNode = (updatedNode: Node<NodeData, any, string>) => {
|
||||||
selectedNode.value = updatedNode;
|
selectedNode.value = updatedNode;
|
||||||
// 同步更新到 nodes 数组
|
// 同步更新到 nodes 数组
|
||||||
const index = nodes.value.findIndex((n) => n.id === updatedNode.id);
|
const index = nodes.value.findIndex((n) => n.id === updatedNode.id);
|
||||||
@@ -260,7 +271,7 @@ const availableParams = computed(() => {
|
|||||||
.filter((e) => e.target === nodeId)
|
.filter((e) => e.target === nodeId)
|
||||||
.forEach((edge) => {
|
.forEach((edge) => {
|
||||||
const parent = findNode(edge.source);
|
const parent = findNode(edge.source);
|
||||||
if (parent && parent.data.nodeCode !== '__start__' && parent.data.nodeCode !== 'judge') {
|
if (parent?.data && parent.data.nodeCode !== '__start__' && parent.data.nodeCode !== 'judge') {
|
||||||
parents.push({ id: parent.id, label: `${parent.data.label}.output` });
|
parents.push({ id: parent.id, label: `${parent.data.label}.output` });
|
||||||
}
|
}
|
||||||
findParents(edge.source, visited);
|
findParents(edge.source, visited);
|
||||||
@@ -271,15 +282,15 @@ const availableParams = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const addParam = (param: ParamRef) => {
|
const addParam = (param: ParamRef) => {
|
||||||
if (!selectedNode.value) return;
|
if (!selectedNode.value?.data) return;
|
||||||
|
|
||||||
if (!selectedNode.value.data.inputSource) {
|
if (!selectedNode.value.data.inputSource) {
|
||||||
selectedNode.value.data.inputSource = [];
|
selectedNode.value.data.inputSource = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找是否已存在该节点的引用
|
// 查找是否已存在该节点的引用
|
||||||
const existingIndex = selectedNode.value.data.inputSource.findIndex((item) => item.nodeId === param.id);
|
const existingIndex = selectedNode.value.data.inputSource.findIndex((item) => item.nodeId === param.id);
|
||||||
|
|
||||||
if (existingIndex >= 0) {
|
if (existingIndex >= 0) {
|
||||||
// 已存在,添加 output 到 field 数组
|
// 已存在,添加 output 到 field 数组
|
||||||
const existing = selectedNode.value.data.inputSource[existingIndex];
|
const existing = selectedNode.value.data.inputSource[existingIndex];
|
||||||
@@ -302,9 +313,9 @@ const addParam = (param: ParamRef) => {
|
|||||||
|
|
||||||
// 模型选择确认
|
// 模型选择确认
|
||||||
const handleModelConfirm = (model: any) => {
|
const handleModelConfirm = (model: any) => {
|
||||||
if (!selectedNode.value) return;
|
if (!selectedNode.value?.data) return;
|
||||||
|
|
||||||
const updatedNode = {
|
const updatedNode: Node<NodeData> = {
|
||||||
...selectedNode.value,
|
...selectedNode.value,
|
||||||
data: {
|
data: {
|
||||||
...selectedNode.value.data,
|
...selectedNode.value.data,
|
||||||
@@ -330,9 +341,9 @@ const handleModelConfirm = (model: any) => {
|
|||||||
|
|
||||||
// 移除模型
|
// 移除模型
|
||||||
const handleRemoveModel = () => {
|
const handleRemoveModel = () => {
|
||||||
if (!selectedNode.value) return;
|
if (!selectedNode.value?.data) return;
|
||||||
|
|
||||||
const updatedNode = {
|
const updatedNode: Node<NodeData> = {
|
||||||
...selectedNode.value,
|
...selectedNode.value,
|
||||||
data: {
|
data: {
|
||||||
...selectedNode.value.data,
|
...selectedNode.value.data,
|
||||||
@@ -353,9 +364,9 @@ const handleRemoveModel = () => {
|
|||||||
|
|
||||||
// 技能选择确认
|
// 技能选择确认
|
||||||
const handleSkillConfirm = (skill: any) => {
|
const handleSkillConfirm = (skill: any) => {
|
||||||
if (!selectedNode.value) return;
|
if (!selectedNode.value?.data) return;
|
||||||
|
|
||||||
const updatedNode = {
|
const updatedNode: Node<NodeData> = {
|
||||||
...selectedNode.value,
|
...selectedNode.value,
|
||||||
data: {
|
data: {
|
||||||
...selectedNode.value.data,
|
...selectedNode.value.data,
|
||||||
@@ -376,9 +387,9 @@ const handleSkillConfirm = (skill: any) => {
|
|||||||
|
|
||||||
// 移除技能
|
// 移除技能
|
||||||
const handleRemoveSkill = () => {
|
const handleRemoveSkill = () => {
|
||||||
if (!selectedNode.value) return;
|
if (!selectedNode.value?.data) return;
|
||||||
|
|
||||||
const updatedNode = {
|
const updatedNode: Node<NodeData> = {
|
||||||
...selectedNode.value,
|
...selectedNode.value,
|
||||||
data: {
|
data: {
|
||||||
...selectedNode.value.data,
|
...selectedNode.value.data,
|
||||||
@@ -399,7 +410,7 @@ const handleRemoveSkill = () => {
|
|||||||
|
|
||||||
// 删除上级参数字段
|
// 删除上级参数字段
|
||||||
const handleRemoveField = (nodeId: string, fieldName: string) => {
|
const handleRemoveField = (nodeId: string, fieldName: string) => {
|
||||||
if (!selectedNode.value) return;
|
if (!selectedNode.value?.data) return;
|
||||||
|
|
||||||
const inputSource = selectedNode.value.data.inputSource || [];
|
const inputSource = selectedNode.value.data.inputSource || [];
|
||||||
const nodeIndex = inputSource.findIndex((item) => item.nodeId === nodeId);
|
const nodeIndex = inputSource.findIndex((item) => item.nodeId === nodeId);
|
||||||
@@ -416,7 +427,7 @@ const handleRemoveField = (nodeId: string, fieldName: string) => {
|
|||||||
updatedInputSource = inputSource.filter((_, idx) => idx !== nodeIndex);
|
updatedInputSource = inputSource.filter((_, idx) => idx !== nodeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedNode = {
|
const updatedNode: Node<NodeData> = {
|
||||||
...selectedNode.value,
|
...selectedNode.value,
|
||||||
data: {
|
data: {
|
||||||
...selectedNode.value.data,
|
...selectedNode.value.data,
|
||||||
@@ -435,7 +446,7 @@ const handleRemoveField = (nodeId: string, fieldName: string) => {
|
|||||||
|
|
||||||
// 切换节点输出引用
|
// 切换节点输出引用
|
||||||
const handleToggleOutput = (nodeId: string, enabled: boolean) => {
|
const handleToggleOutput = (nodeId: string, enabled: boolean) => {
|
||||||
if (!selectedNode.value) return;
|
if (!selectedNode.value?.data) return;
|
||||||
|
|
||||||
const inputSource = selectedNode.value.data.inputSource || [];
|
const inputSource = selectedNode.value.data.inputSource || [];
|
||||||
const nodeIndex = inputSource.findIndex((item) => item.nodeId === nodeId);
|
const nodeIndex = inputSource.findIndex((item) => item.nodeId === nodeId);
|
||||||
@@ -458,7 +469,7 @@ const handleToggleOutput = (nodeId: string, enabled: boolean) => {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedNode = {
|
const updatedNode: Node<NodeData> = {
|
||||||
...selectedNode.value,
|
...selectedNode.value,
|
||||||
data: {
|
data: {
|
||||||
...selectedNode.value.data,
|
...selectedNode.value.data,
|
||||||
@@ -473,13 +484,13 @@ const handleToggleOutput = (nodeId: string, enabled: boolean) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const parentNode = nodes.value.find((n) => n.id === nodeId);
|
const parentNode = nodes.value.find((n) => n.id === nodeId);
|
||||||
const nodeName = parentNode?.data.label || '节点';
|
const nodeName = parentNode?.data?.label || '节点';
|
||||||
ElMessage.success(enabled ? `已开启引入 ${nodeName} 的输出` : `已关闭引入 ${nodeName} 的输出`);
|
ElMessage.success(enabled ? `已开启引入 ${nodeName} 的输出` : `已关闭引入 ${nodeName} 的输出`);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 通过参数值添加上级参数
|
// 通过参数值添加上级参数
|
||||||
const handleAddParamByValue = (paramValue: string) => {
|
const handleAddParamByValue = (paramValue: string) => {
|
||||||
if (!selectedNode.value) return;
|
if (!selectedNode.value?.data) return;
|
||||||
|
|
||||||
const match = paramValue.match(/\$\{([^.]+)\.(.+)\}/);
|
const match = paramValue.match(/\$\{([^.]+)\.(.+)\}/);
|
||||||
if (!match) return;
|
if (!match) return;
|
||||||
@@ -514,7 +525,7 @@ const handleAddParamByValue = (paramValue: string) => {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedNode = {
|
const updatedNode: Node<NodeData> = {
|
||||||
...selectedNode.value,
|
...selectedNode.value,
|
||||||
data: {
|
data: {
|
||||||
...selectedNode.value.data,
|
...selectedNode.value.data,
|
||||||
@@ -532,14 +543,14 @@ const handleAddParamByValue = (paramValue: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 辅助函数:判断是否为开始节点
|
// 辅助函数:判断是否为开始节点
|
||||||
const isStartNode = (node: Node<NodeData>) => {
|
const isStartNode = (node: Node<NodeData, any, string>) => {
|
||||||
return node.data.nodeCode === START_NODE_CODE;
|
return node.data?.nodeCode === START_NODE_CODE;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 辅助函数:判断是否为判断节点
|
// 辅助函数:判断是否为判断节点
|
||||||
const isJudgeNode = (node: Node<NodeData>) => {
|
const isJudgeNode = (node: Node<NodeData, any, string>) => {
|
||||||
const nodeCode = (node.data.nodeCode || '').toLowerCase();
|
const nodeCode = (node.data?.nodeCode || '').toLowerCase();
|
||||||
const nodeName = (node.data.label || '').toLowerCase();
|
const nodeName = (node.data?.label || '').toLowerCase();
|
||||||
return JUDGE_KEYWORDS.some((k) => nodeCode.includes(k) || nodeName.includes(k));
|
return JUDGE_KEYWORDS.some((k) => nodeCode.includes(k) || nodeName.includes(k));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -659,10 +670,10 @@ const createNewWorkflow = () => {
|
|||||||
edges.value = [];
|
edges.value = [];
|
||||||
selectedNode.value = null;
|
selectedNode.value = null;
|
||||||
nodeId = 0;
|
nodeId = 0;
|
||||||
|
|
||||||
// 添加默认开始节点
|
// 添加默认开始节点
|
||||||
addDefaultStartNode();
|
addDefaultStartNode();
|
||||||
|
|
||||||
ElMessage.success('已清空画布,可以开始创建新工作流');
|
ElMessage.success('已清空画布,可以开始创建新工作流');
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -690,7 +701,7 @@ const loadWorkflowFromDsl = (dsl: any) => {
|
|||||||
const loadedNodes = (dsl.nodes || []).map((n: any) => {
|
const loadedNodes = (dsl.nodes || []).map((n: any) => {
|
||||||
// 确保 inputSource 使用新结构
|
// 确保 inputSource 使用新结构
|
||||||
let normalizedInputSource: Array<{ nodeId: string; field: string[]; quoteOutput?: boolean }> | null = null;
|
let normalizedInputSource: Array<{ nodeId: string; field: string[]; quoteOutput?: boolean }> | null = null;
|
||||||
|
|
||||||
if (n.inputSource) {
|
if (n.inputSource) {
|
||||||
if (Array.isArray(n.inputSource)) {
|
if (Array.isArray(n.inputSource)) {
|
||||||
// 检查是否为新结构(对象数组)
|
// 检查是否为新结构(对象数组)
|
||||||
@@ -775,18 +786,18 @@ const confirmSaveWorkflow = async () => {
|
|||||||
startNodeId: nodes.value[0]?.id || '',
|
startNodeId: nodes.value[0]?.id || '',
|
||||||
nodes: nodes.value.map((n) => ({
|
nodes: nodes.value.map((n) => ({
|
||||||
id: n.id,
|
id: n.id,
|
||||||
nodeCode: n.data.nodeCode || 'unknown',
|
nodeCode: n.data?.nodeCode || 'unknown',
|
||||||
name: n.data.label || '',
|
name: n.data?.label || '',
|
||||||
type: n.type || 'default',
|
type: n.type || 'default',
|
||||||
skillName: n.data.skillName || null,
|
skillName: n.data?.skillName || null,
|
||||||
config: {
|
config: {
|
||||||
nodeCode: n.data.nodeCode || 'unknown',
|
nodeCode: n.data?.nodeCode || 'unknown',
|
||||||
x: n.position?.x || 0,
|
x: n.position?.x || 0,
|
||||||
y: n.position?.y || 0,
|
y: n.position?.y || 0,
|
||||||
},
|
},
|
||||||
inputSource: n.data.inputSource || null,
|
inputSource: n.data?.inputSource || null,
|
||||||
formConfig: n.data.formConfig || null,
|
formConfig: n.data?.formConfig || null,
|
||||||
modelConfig: n.data.modelConfig || null,
|
modelConfig: n.data?.modelConfig || null,
|
||||||
outputResult: null,
|
outputResult: null,
|
||||||
})),
|
})),
|
||||||
edges: edges.value.map((e) => ({
|
edges: edges.value.map((e) => ({
|
||||||
|
|||||||
Reference in New Issue
Block a user