feat: 谱系

This commit is contained in:
JiangSheng
2026-01-16 11:36:58 +08:00
parent 0cff272b01
commit c39795ce2b
3 changed files with 142 additions and 69 deletions

View File

@@ -13,16 +13,15 @@
/>
</div>
<div v-else-if="currentNode === 'simParams'" class="detail-content sim-params-content">
<div class="flow-section">
<RunFlowPage
ref="runFlowRef"
:runInfo="runInfo"
@change="flowNodeChangeFun"
@update="flowUpdateFun"
/>
<div v-else-if="currentNode === 'simParams'" class="detail-content">
<div class="sim-params-tabs">
<el-radio-group v-model="currentFlowNodeId" @change="flowNodeRadioChangeFun">
<el-radio-button v-for="item in flowNodeList" :key="item.uuid" :value="item.uuid">
{{ item.nodeName }}
</el-radio-button>
</el-radio-group>
</div>
<div class="param-section">
<div class="sim-params-content">
<FlowNodeParamTable
ref="paramTableRef"
:nodeParams="currentNodeParams"
@@ -138,24 +137,28 @@ import BaseTable from '@/components/common/table/baseTable.vue';
import { getSimulationTaskFileApi } from '@/api/data/dataAnalysis';
import { getRunPerformanceApi } from '@/api/task/taskpool';
import { FILE_TYPE } from '@/utils/enum/file';
import RunFlowPage from '@/views/task/execution/components/runDetailPage/runPagecomponent/flow/runFlowPage.vue';
import FlowNodeParamTable from '@/components/flow/flowNodeParamTable.vue';
import { listSimulationFlowNodeApi } from '@/api/project/run';
import { getRunListByRunIdListApi } from '@/api/project/node';
import { queryFlowTemplateDetailApi } from '@/api/capability/flow';
import { useDict } from '@/utils/useDict';
import FilePreview from '@/components/common/filePreview/index.vue';
import csvFileReview from '@/views/data/analysis/components/csvFileReview.vue';
import { downloadFileById } from '@/utils/file';
import { cloneDeep } from 'lodash-es';
interface Props {
currentNode?: string;
runId?: string;
rowData?: Record<string, any>;
defaultKeyResultType?: '1' | '2' | '3';
}
const props = withDefaults(defineProps<Props>(), {
currentNode: 'inputModel',
runId: '',
rowData: () => ({}),
defaultKeyResultType: '1',
});
const { PERFORMANCE_UNIT } = useDict('PERFORMANCE_UNIT');
@@ -182,9 +185,7 @@ const modelActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const calcFileActionList = [
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const calcFileActionList = [{ title: '下载', type: 'primary', click: downloadFileFun }];
const cloudImageActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
@@ -200,23 +201,61 @@ const reportActionList = [
const keyResultType = ref('1');
const runFlowRef = ref();
const flowNodeList = ref<any[]>([]);
const currentFlowNodeId = ref<string>('');
const runInfo = ref<any>({});
const paramTableRef = ref();
const currentFlowNode = ref<any>(null);
const currentPageInfo = ref<any>({});
const nodeConfigList = ref<any>({});
const userDetailParams = ref<any>({});
const nodeDatas = ref<any>([]);
const runInfo = ref<any>({});
const fetchRunInfoFun = async () => {
const fetchFlowNodesFun = async () => {
if (!props.runId) {
flowNodeList.value = [];
runInfo.value = {};
nodeConfigList.value = {};
return;
}
const res: any = await getRunListByRunIdListApi({ runIdList: [props.runId] });
if (res?.code === 200 && res.data?.length > 0) {
runInfo.value = res.data[0];
const [nodesRes, runInfoRes]: any = await Promise.all([
listSimulationFlowNodeApi({ runId: props.runId }),
getRunListByRunIdListApi({ runIdList: [props.runId] }),
]);
if (runInfoRes?.code === 200 && runInfoRes.data?.length > 0) {
runInfo.value = runInfoRes.data[0];
if (runInfo.value.flowTemplate) {
const templateRes: any = await queryFlowTemplateDetailApi({
uuid: runInfo.value.flowTemplate,
status: 1,
});
if (templateRes?.code === 200 && templateRes.data?.viewContent) {
try {
const viewData = JSON.parse(templateRes.data.viewContent);
const nodes = viewData.cells?.filter((item: any) => item.type) || [];
const configMap: any = {};
nodes.forEach((node: any) => {
if (node.data?.label && node.data?.pageConfigList) {
configMap[node.data.label] = node.data.pageConfigList;
}
});
nodeConfigList.value = configMap;
} catch {
nodeConfigList.value = {};
}
}
}
}
if (nodesRes?.code === 200 && nodesRes.data?.flowNodeDtoList) {
const allNodes = nodesRes.data.flowNodeDtoList || [];
flowNodeList.value = allNodes.filter((node: any) => {
const nodeType = node.nodeDetailInfo?.type;
return nodeType !== 'StartEvent' && nodeType !== 'EndEvent';
});
if (flowNodeList.value.length > 0 && !currentFlowNodeId.value) {
currentFlowNodeId.value = flowNodeList.value[0].uuid;
flowNodeRadioChangeFun(flowNodeList.value[0].uuid);
}
} else {
flowNodeList.value = [];
}
};
@@ -236,13 +275,21 @@ const fetchPerformanceListFun = async () => {
const currentNodeParams = ref<any>([]);
const updateCurrentNodeParamsFun = () => {
if (!currentFlowNode.value) {
currentNodeParams.value = [];
return;
const mergeUserParamsFun = (list: any[], userParams: any): any[] => {
const result = cloneDeep(list);
for (const item of result) {
if (item.englishLabel && userParams?.[item.englishLabel] !== undefined) {
item.defaultValue = userParams[item.englishLabel];
}
if (item.children?.length) {
const childParams =
item.tagType === 'view' && item.tagIcon === 'row'
? userParams?.[item.vModel] || {}
: userParams;
item.children = mergeUserParamsFun(item.children, childParams);
}
}
const nodeName = currentFlowNode.value?.store?.data?.data?.label || '';
currentNodeParams.value = nodeConfigList.value[nodeName] || [];
return result;
};
const getFileListApiFun = async (params: any) => {
@@ -259,40 +306,44 @@ const keyResultTypeChangeFun = () => {
}
};
const flowNodeChangeFun = (data: any) => {
currentFlowNode.value = data.node;
const nodeData = data.data || {};
currentPageInfo.value = {
userParams: nodeData.userParams || {},
inputDirId: nodeData.inputDirId || '',
};
updateCurrentNodeParamsFun();
};
const flowUpdateFun = (data: any) => {
nodeConfigList.value = data.list || {};
userDetailParams.value = data.param || {};
nodeDatas.value = data.nodeDatas || [];
updateCurrentNodeParamsFun();
const flowNodeRadioChangeFun = (uuid: string) => {
const selectedNode = flowNodeList.value.find((node: any) => node.uuid === uuid);
if (selectedNode) {
currentFlowNode.value = selectedNode;
const userParams = selectedNode.userParams || {};
currentPageInfo.value = {
userParams,
inputDirId: selectedNode.inputDirId || '',
};
const nodeName = selectedNode.nodeName || '';
const templateConfig = nodeConfigList.value[nodeName] || [];
currentNodeParams.value = mergeUserParamsFun(templateConfig, userParams);
}
};
watch(
() => props.currentNode,
(newVal) => {
if (newVal === 'keyResult') {
keyResultType.value = '1';
}
if (newVal === 'simParams') {
fetchRunInfoFun();
currentFlowNodeId.value = '';
fetchFlowNodesFun();
}
}
);
watch(
() => props.defaultKeyResultType,
(newVal) => {
keyResultType.value = newVal;
}
);
watch(
() => props.runId,
(newVal) => {
if (newVal && props.currentNode === 'simParams') {
fetchRunInfoFun();
currentFlowNodeId.value = '';
fetchFlowNodesFun();
}
},
{ immediate: true }
@@ -309,25 +360,17 @@ watch(
height: 100%;
}
.sim-params-content {
.sim-params-tabs {
width: 100%;
height: 50px;
display: flex;
gap: 16px;
align-items: center;
padding: 0 10px;
}
.flow-section {
width: 50%;
height: 100%;
border: 1px solid #ebeef5;
border-radius: 4px;
overflow: hidden;
}
.param-section {
width: 50%;
height: 100%;
border: 1px solid #ebeef5;
border-radius: 4px;
overflow: hidden;
}
.sim-params-content {
width: 100%;
height: calc(100% - 50px);
}
.empty-tip {

View File

@@ -17,7 +17,12 @@
<span class="title-text">{{ currentNodeLabel }}</span>
</div>
<div class="detail-wrapper">
<PedigreeDetail :currentNode="currentNodeId" :runId="runId" :rowData="rowData" />
<PedigreeDetail
:currentNode="currentNodeId"
:runId="runId"
:rowData="rowData"
:defaultKeyResultType="defaultKeyResultType"
/>
</div>
</div>
</div>
@@ -36,7 +41,7 @@ const { t } = useI18n();
interface Props {
modelValue?: boolean;
rowData?: Record<string, any>;
dataType?: string;
dataType?: '模型文件' | '仿真报告' | '计算文件' | '结果曲线' | '结果云图' | '';
}
const props = withDefaults(defineProps<Props>(), {
@@ -67,6 +72,27 @@ const nodeLabelsKey: Record<string, string> = {
const currentNodeLabel = computed(() => t(nodeLabelsKey[currentNodeId.value]) || '');
const dataTypeToNodeIdMap: Record<string, string> = {
模型文件: 'inputModel',
仿真报告: 'simReport',
计算文件: 'calcModel',
结果曲线: 'keyResult',
结果云图: 'keyResult',
};
const dataTypeToKeyResultTypeMap: Record<string, string> = {
结果云图: '1',
结果曲线: '2',
};
const getDefaultNodeIdFun = () => {
return dataTypeToNodeIdMap[props.dataType] || 'inputModel';
};
const defaultKeyResultType = computed(() => {
return dataTypeToKeyResultTypeMap[props.dataType] || '1';
});
const runId = computed(() => {
return props.rowData?.ownRunId;
});
@@ -79,9 +105,10 @@ watch(
() => props.modelValue,
(newVal) => {
if (newVal) {
currentNodeId.value = 'inputModel';
const defaultNodeId = getDefaultNodeIdFun();
currentNodeId.value = defaultNodeId;
nextTick(() => {
flowRef.value?.setSelectedNodeFun('inputModel');
flowRef.value?.setSelectedNodeFun(defaultNodeId);
});
}
}

View File

@@ -564,6 +564,9 @@ const modeChangeFun = () => {
currentPedigreeRow.value = row;
pedigreeVisible.value = true;
},
hide: (row: any) => {
return !row.ownRunId;
},
},
{
id: 3,