Files
SPDM/src/views/data/analysis/components/pedigree/pedigreeDetail.vue
2026-03-25 16:52:45 +08:00

505 lines
15 KiB
Vue

<template>
<div class="pedigree-detail">
<div v-if="currentNode === 'inputModel'" class="detail-content">
<BaseTable
ref="inputModelTableRef"
tableName="DATA_SEARCH"
:api="getFileListApiFun"
:params="modelParams"
showIndex
:fullHeight="true"
hideSearch
:actionList="modelActionList"
/>
</div>
<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="sim-params-content">
<FlowNodeParamTable
ref="paramTableRef"
:nodeParams="currentNodeParams"
:pageInfo="currentPageInfo"
:currentNode="currentFlowNode"
:runInfo="runInfo"
:hideButtons="true"
:readonly="true"
/>
</div>
</div>
<div v-else-if="currentNode === 'calcModel'" class="detail-content">
<BaseTable
ref="calcModelTableRef"
tableName="DATA_SEARCH"
:api="getFileListApiFun"
:params="calcFileParams"
showIndex
:fullHeight="true"
hideSearch
:actionList="calcFileActionList"
/>
</div>
<div v-else-if="currentNode === 'calcResult'" class="detail-content">
<BaseTable
ref="calcResultTableRef"
tableName="DATA_SEARCH"
:api="getFileListApiFun"
:params="calcResultParams"
showIndex
:fullHeight="true"
hideSearch
:actionList="calcFileActionList"
/>
</div>
<div v-else-if="currentNode === 'keyResult'" class="detail-content">
<div class="key-result-tabs">
<el-radio-group v-model="keyResultType" @change="refreshKeyResultTableFun">
<el-radio-button value="1">{{ $t('数据谱系.云图结果') }}</el-radio-button>
<el-radio-button value="2">{{ $t('数据谱系.曲线结果') }}</el-radio-button>
<el-radio-button value="3">{{ $t('数据谱系.数值指标') }}</el-radio-button>
<el-radio-button value="4">{{ $t('数据谱系.视频文件') }}</el-radio-button>
</el-radio-group>
</div>
<div class="key-result-content">
<BaseTable
v-if="keyResultType === '1'"
ref="cloudImageTableRef"
tableName="DATA_SEARCH"
:api="getFileListApiFun"
:params="cloudImageParams"
showIndex
:fullHeight="true"
hideSearch
:actionList="cloudImageActionList"
/>
<BaseTable
v-else-if="keyResultType === '2'"
ref="curveTableRef"
tableName="DATA_SEARCH"
:api="getFileListApiFun"
:params="curveParams"
showIndex
:fullHeight="true"
hideSearch
:actionList="curveActionList"
/>
<TaskPerformance
v-else-if="keyResultType === '3'"
:paramType="pedigreeType === 'task' ? 'task' : 'run'"
:taskInfo="pedigreeType === 'task' ? { uuid: taskId } : undefined"
:runInfo="pedigreeType === 'run' ? { uuid: runId } : undefined"
:fullHeight="true"
:showLeftOptions="false"
:showSaveButton="false"
:showSetting="false"
:canUpdate="false"
:showCheckbox="false"
/>
<BaseTable
v-else-if="keyResultType === '4'"
ref="videoTableRef"
tableName="DATA_SEARCH"
:api="getFileListApiFun"
:params="videoParams"
showIndex
:fullHeight="true"
hideSearch
:actionList="videoActionList"
/>
</div>
</div>
<div v-else-if="currentNode === 'simReport'" class="detail-content">
<BaseTable
ref="reportTableRef"
tableName="DATA_SEARCH"
:api="getFileListApiFun"
:params="reportParams"
showIndex
:fullHeight="true"
hideSearch
:actionList="reportActionList"
/>
</div>
<div v-else-if="currentNode === 'testData'" class="detail-content">
<BaseTable
ref="testDataTableRef"
tableName="DATA_SEARCH"
:api="getFileListApiFun"
:params="testDataParams"
showIndex
:fullHeight="true"
hideSearch
:actionList="testDataActionList"
/>
</div>
<div
v-else-if="currentNode === 'reviewReport' && enableConfigByTenant([TENANT_ENUM.LYRIC])"
class="detail-content"
>
<BaseTable
ref="reviewReportTableRef"
tableName="DATA_SEARCH"
:api="getFileListApiFun"
:params="reviewFileParams"
showIndex
:fullHeight="true"
hideSearch
:actionList="reviewReportActionList"
/>
</div>
<FilePreview v-model="previewVisible" :fileId="currentRow?.id" />
</div>
</template>
<script setup lang="ts">
import { ref, watch, computed } from 'vue';
import BaseTable from '@/components/common/table/baseTable.vue';
import { getSimulationTaskFileApi } from '@/api/data/dataAnalysis';
import { FILE_TYPE } from '@/utils/enum/file';
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 FilePreview from '@/components/common/filePreview/index.vue';
import TaskPerformance from '@/components/taskDetail/taskPerformance.vue';
import { downloadFileById } from '@/utils/file';
import { cloneDeep } from 'lodash-es';
import { enableConfigByTenant, TENANT_ENUM } from '@/tenants/tenant';
const FILE_DICT_CLASS = 'ALL_FILE_TYPE';
const DICT_TAGS = ['fileTypeDictClass', 'fileTypeDictValue'];
interface Props {
currentNode?: string;
runId?: string;
taskId?: string;
rowData?: Record<string, any>;
pedigreeType?: 'task' | 'run';
defaultKeyResultType?: '1' | '2' | '3' | string;
}
const props = withDefaults(defineProps<Props>(), {
currentNode: 'inputModel',
runId: '',
taskId: '',
rowData: () => ({}),
pedigreeType: 'run',
defaultKeyResultType: '1',
});
const previewVisible = ref(false);
const currentRow = ref<any>(null);
const previewFileFun = (row: any) => {
currentRow.value = row;
previewVisible.value = true;
};
const downloadFileFun = (row: any) => {
downloadFileById(row.id);
};
const modelActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const calcFileActionList = [{ title: '下载', type: 'primary', click: downloadFileFun }];
const cloudImageActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const curveActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const reportActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const testDataActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const reviewReportActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const videoActionList = [
{ title: '预览', type: 'primary', click: previewFileFun },
{ title: '下载', type: 'primary', click: downloadFileFun },
];
const keyResultType = ref('1');
const flowNodeList = ref<any[]>([]);
const currentFlowNodeId = ref<string>('');
const runInfo = ref<any>({});
const currentFlowNode = ref<any>(null);
const currentPageInfo = ref<any>({});
const nodeConfigList = ref<any>({});
const currentCalcResultNodeId = ref<string>('');
const currentCalcResultNode = ref<any>(null);
const fetchFlowNodesFun = async () => {
if (!props.runId) {
flowNodeList.value = [];
runInfo.value = {};
nodeConfigList.value = {};
return;
}
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);
}
if (flowNodeList.value.length > 0 && !currentCalcResultNodeId.value) {
currentCalcResultNodeId.value = flowNodeList.value[0].uuid;
flowNodeRadioChangeFun(flowNodeList.value[0].uuid);
}
} else {
flowNodeList.value = [];
}
};
const currentNodeParams = ref<any>([]);
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);
}
}
return result;
};
const getFileListApiFun = async (params: any) => {
if (props.pedigreeType === 'task') {
const res: any = await getSimulationTaskFileApi({
...params,
runId: props.runId,
});
return res;
} else {
const res: any = await getSimulationTaskFileApi({
...params,
runId: props.runId,
});
return res;
}
};
const buildParamsFun = (fileType: number) => {
if (props.pedigreeType === 'task') {
return {
uuid: props.taskId,
fileTypeDictValue: String(fileType),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
level: 'task',
tagReq: {
...props?.rowData?.tagReq,
},
};
} else {
return {
uuid: props.runId,
fileTypeDictValue: String(fileType),
fileTypeDictClass: FILE_DICT_CLASS,
dictTags: DICT_TAGS,
tagReq: {
...props?.rowData?.tagReq,
},
};
}
};
const modelParams = computed(() => buildParamsFun(FILE_TYPE.MODEL_3D_FILE));
const calcFileParams = computed(() => buildParamsFun(FILE_TYPE.CALCULATION_FILE));
const calcResultParams = computed(() => buildParamsFun(FILE_TYPE.CALCULATION_RESULT));
const reportParams = computed(() => buildParamsFun(FILE_TYPE.REPORT_FILE));
const testDataParams = computed(() => buildParamsFun(FILE_TYPE.TEST_DOCUMENT_FILE));
const reviewFileParams = computed(() => buildParamsFun(FILE_TYPE.REVIEW_FILE));
const cloudImageParams = computed(() => buildParamsFun(FILE_TYPE.PNG_FILE));
const curveParams = computed(() => buildParamsFun(FILE_TYPE.CANVAS_FILE));
const videoParams = computed(() => buildParamsFun(FILE_TYPE.VIDEO_FILE));
const cloudImageTableRef = ref();
const curveTableRef = ref();
const videoTableRef = ref();
const refreshKeyResultTableFun = () => {
const tableRefMap: Record<string, any> = {
'1': cloudImageTableRef,
'2': curveTableRef,
'4': videoTableRef,
};
tableRefMap[keyResultType.value]?.value?.resetFun(true);
};
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);
currentCalcResultNode.value = selectedNode;
}
};
watch(
() => props.currentNode,
(newVal) => {
if (newVal === 'simParams') {
currentFlowNodeId.value = '';
fetchFlowNodesFun();
} else if (newVal === 'calcResult') {
currentCalcResultNodeId.value = '';
fetchFlowNodesFun();
} else if (newVal === 'keyResult' && props.defaultKeyResultType) {
keyResultType.value = props.defaultKeyResultType;
refreshKeyResultTableFun();
}
}
);
watch(
() => props.defaultKeyResultType,
(newVal) => {
if (props.currentNode === 'keyResult' && newVal) {
keyResultType.value = newVal;
refreshKeyResultTableFun();
}
},
{ immediate: true }
);
watch(
() => props.runId,
(newVal, oldVal) => {
if (newVal && newVal !== oldVal && props.currentNode === 'keyResult') {
keyResultType.value = props.defaultKeyResultType || '1';
refreshKeyResultTableFun();
}
}
);
watch(
() => props.runId,
(newVal) => {
if (newVal && props.currentNode === 'simParams') {
currentFlowNodeId.value = '';
fetchFlowNodesFun();
}
},
{ immediate: true }
);
</script>
<style lang="scss" scoped>
.pedigree-detail {
width: 100%;
height: 100%;
.detail-content {
width: 100%;
height: 100%;
}
.sim-params-tabs {
width: 100%;
height: 50px;
display: flex;
align-items: center;
padding: 0 10px;
}
.sim-params-content {
width: 100%;
height: calc(100% - 50px);
}
.empty-tip {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.key-result-tabs {
width: 100%;
height: 50px;
display: flex;
align-items: center;
padding: 0 10px;
}
.key-result-content {
width: 100%;
height: calc(100% - 50px);
}
}
</style>