Files
SPDM/src/views/competenceCenter/condition/components/taskPool.vue
2025-11-13 14:33:24 +08:00

1108 lines
34 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="loadcase">
<div class="contain" v-if="loadcaseOrPerformanceSwitch || pageType === 'loadcase'">
<div
class="flex-end"
:style="{
right: loadcaseOrPerformanceSwitch ? '375px' : '165px',
top: loadcaseOrPerformanceSwitch ? '12px' : '1px',
}"
>
<el-space>
<template v-if="pageType === 'loadcase' || loadcaseOrPerformanceSwitch">
<el-button @click="addPoolFun">
<el-icon class="mr5">
<Plus />
</el-icon>
{{ $t("工况库.创建清单库") }}
</el-button>
<el-button @click="openImportPoolFun">
<el-icon class="mr5">
<Upload />
</el-icon>
{{ $t("工况库.导入Excel") }}
</el-button>
<el-button @click="onExportPoolFun" :loading="exportLoading">
<el-icon class="mr5">
<Download />
</el-icon>
{{ $t("工况库.导出Excel") }}
</el-button>
</template>
<el-button type="primary" @click="openAddApproveUserFun">
<el-icon class="mr5">
<Finished />
</el-icon>
{{ $t("工况库.提交评审") }}
</el-button>
<el-button type="danger" @click="openDelPoolFun">
<el-icon class="mr5">
<Finished />
</el-icon>
{{ $t("工况库.删除库") }}
</el-button>
<div class="pool-select select-form">
<el-form :inline="true">
<el-form-item :label="$t('工况库.工况清单库')" :label-width="100">
<el-select
:teleported="false"
v-model="currentPoolBrief"
:props="{ label: 'poolName', value: 'value' }"
value-key="poolName"
:fit-input-width="true"
@change="onPoolChangeFun"
>
<el-option
v-for="item in poolList"
:key="item.value"
:label="item.poolName"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('工况库.版本')" :label-width="40">
<el-select
:teleported="false"
v-model="currentPoolBriefVersion"
:props="{ label: 'poolVersion', value: 'value' }"
value-key="poolVersion"
:fit-input-width="true"
@change="onVersionChangeFun"
>
<el-option
v-for="item in versionList"
:key="item.value"
:label="item.poolVersion"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('工况库.显示配置')" :label-width="80">
<el-select
v-model="currentTableType"
:fit-input-width="true"
:options="tableTypeOptions"
>
</el-select>
</el-form-item>
</el-form>
</div>
</el-space>
</div>
<loadCaseTable
v-show="currentTableType==='tree'"
ref="treeTableRef"
tableName="TASK_POOL"
:modalTableNameList="['TASK_POOL_CATEGORY','TASK_POOL_TASK','TASK_POOL_PERFORMANCE']"
:data="tableData"
:loading="loading"
:editMode="true"
> </loadCaseTable>
<loadCaseTable
v-show="currentTableType==='list'"
ref="listTableRef"
border="full"
:hasOperationColumn="false"
readonly
tableName="TASK_POOL_LIST"
:data="extractTableData"
:loading="loading"
:editMode="false"
>
</loadCaseTable>
<loadcase-pro-table
v-if="false"
ref="treeTableRef2"
:columns="tableColumns"
:data-source="tableData"
:checkStrictly="true"
:loading="loading"
:leftVisible="true"
:toolbarConfig="{
enabled: true,
custom: true,
}"
:key="tableKey"
:showHeader="false"
:isAdaptTableHeight="true"
@refresh="refreshData"
:readonly="true"
>
<template #toolbar_tools_extra>
<span v-if="pageType === 'performance'">
显示配置
<el-radio-group
v-model="loadcaseOrPerformanceSwitch"
@change="changeLoadcaseOrPerformanceType"
>
<el-radio :value="true" size="large">树结构</el-radio>
<el-radio :value="false" size="large">表结构</el-radio>
</el-radio-group>
</span>
</template>
</loadcase-pro-table>
</div>
<div class="contain" v-if="!loadcaseOrPerformanceSwitch && pageType !== 'loadcase'">
<div class="pool-select">
<el-form :inline="true">
<el-form-item :label="$t('工况库.工况清单库')" :label-width="100">
<el-select
:teleported="false"
v-model="currentPoolBrief"
:props="{ label: 'poolName', value: 'value' }"
value-key="poolName"
:fit-input-width="true"
@change="onPoolChangeFun"
>
<el-option
v-for="item in poolList"
:key="item.value"
:label="item.poolName"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('工况库.版本')" :label-width="40">
<el-select
:teleported="false"
v-model="currentPoolBriefVersion"
:props="{ label: 'poolVersion', value: 'value' }"
value-key="poolVersion"
:fit-input-width="true"
@change="onVersionChangeFun"
>
<el-option
v-for="item in versionList"
:key="item.value"
:label="item.poolVersion"
:value="item"
/>
</el-select>
</el-form-item>
</el-form>
</div>
<loadCaseTable
:editMode="false"
ref="treeTableRef"
:loading="performanceLoading"
readonly
:loadCaseTable="false"
tableName="PERFORMANCE_POOL"
:data="performanceData"
:hasOperationColumn="false"
> </loadCaseTable>
<loadcase-pro-table
v-if="false"
ref="treeTableRef"
:toolbarConfig="{
enabled: false,
custom: true,
}"
:loading="performanceLoading"
:columns="tableColumns"
:data-source="performanceData"
:isTreeTable="false"
:excludeOperation="[]"
:expandVisible="loadcaseOrPerformanceSwitch"
:key="tableKey"
:showHeader="false"
:isAdaptTableHeight="true"
readonly
>
<template #toolbar_tools_extra>
<span v-if="pageType === 'performance'">
显示配置
<el-radio-group v-model="loadcaseOrPerformanceSwitch">
<el-radio :value="true" size="large">树结构</el-radio>
<el-radio :value="false" size="large">表结构</el-radio>
</el-radio-group>
</span>
</template>
<template #loadcase_name="{ row, column }">
<!-- <img
width="15"
class="mr5"
style="vertical-align: text-bottom"
src="@/components/loadCaseTable/img/systemConfig/loadcase.png"
alt=""
/> -->
{{ row[column.field] }}
</template>
</loadcase-pro-table>
</div>
</div>
<addApproveUser
v-model="dialogApproveUserVisible"
:isInitial="isEmptyPool"
@ok="onConfirmFun"
></addApproveUser>
<add-pool-modal
v-model="addPoolModalVisible"
mode="add"
:poolList="poolList"
detail="{}"
@ok="onAddPoolOkFun"
/>
<del-pool-modal v-model="delPoolModalVisible" @ok="onDelPoolOkFun" />
<import-pool-modal
v-model="importPoolModalVisible"
:poolList="poolList"
@ok="onImportPoolOkFun"
/>
</template>
<script lang="ts" setup>
import { computed, nextTick, onMounted, ref, type Ref } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
import { clone, cloneDeep, groupBy, isEqual, uniqBy } from 'lodash-es';
import { onBeforeRouteLeave, useRouter } from 'vue-router';
import loadcaseProTable from '@/components/loadCaseTable/commonTable/loadcaseProTable.vue';
import loadCaseTable from '@/components/common/treeCaseTable/loadCaseTable.vue';
import {
getLoadcaseLibColumn,
getPerformanceLibColumn,
taskPoolDictOptions,
} from '@/components/loadCaseTable/utils/project.ts';
import addApproveUser from './addApproveUsers.vue';
import {
transformPoolNodesToTree,
transformTreeToPoolNodes,
getNodeExtras,
canAddChild,
extractLeafNodesWithParentTypes,
} from '@/utils/node';
import { poolNodeExtraPropPickMap } from '@/utils/enum/node';
import {
createTaskPoolApi,
updateTaskPoolApi,
getTaskPoolApi,
getTaskPoolPerformanceApi,
getTaskPoolVersionsApi,
getAllTaskPoolApi,
importTaskPoolApi,
exportTaskPoolApi,
} from '@/api/task/taskpool';
import { NODE_TYPE } from '@/utils/enum/node';
import addPoolModal from './addPoolModal.vue';
import delPoolModal from './delPoolModal.vue';
import importPoolModal from './importPoolModal.vue';
import type { Pool, Extra } from './types';
import type { TreeNode } from '@/utils/enum/node';
import { getUserTenantId } from '@/utils/user';
const props = defineProps(['pageType']);
const tenantId = getUserTenantId();
const loading = ref(false);
const loadcaseLibColumn = ref<any>([]);
const getColumnsFun = async () => {
if (props.pageType === 'loadcase') {
loadcaseLibColumn.value = await getLoadcaseLibColumn();
} else if (props.pageType === 'performance') {
loadcaseLibColumn.value = await getPerformanceLibColumn([], false);
}
};
const tableColumns = computed(() => {
let data: any = cloneDeep(loadcaseLibColumn.value);
if (props.pageType === 'performance' && !loadcaseOrPerformanceSwitch.value) {
data = data.filter((item: any) => {
return ![
'operation',
'nodeType',
'days',
'flowTemplateName',
'analysisSoftware',
'confidence',
'difficult',
'analyseTarget',
].includes(item.field);
});
data.forEach((item: any) => {
if (item.field === 'nodeName') {
item.title = '指标名';
item.treeNode = false;
}
});
data.splice(1, 0, {
title: '分析项名',
dataIndex: 'taskName',
field: 'taskName',
key: 'taskName',
ellipsis: true,
resizable: true,
minWidth: 150,
custom: true,
align: 'left',
slots: { default: 'loadcase_name', header: 'content_filter' },
});
}
return data;
});
const tableData = ref<any>([]);
const isHaveNotSave = () => {
try {
const { insertRecords, removeRecords, updateRecords } = getRecordSetFun();
return (
insertRecords.length > 0 || removeRecords.length > 0 || updateRecords.length > 0
);
} catch (e) {
console.error('e', e);
return false;
}
};
const saveType = ref<string>('');
const refreshData = async (callback?: any) => {
if (callback) {
callback();
}
// 指标库
if (props.pageType === 'performance') {
}
saveType.value = '';
};
const treeTableRef = ref();
const listTableRef = ref();
const getVxeRef = () => {
return treeTableRef?.value?.loadcaseTableRef?.TreeTableRef?.treeTableRef;
};
const getRecordSetFun = () => {
return treeTableRef?.value?.loadcaseTableRef?.TreeTableRef?.getRecordSetFun();
};
// 任务模板库、仿真指标库切换
const loadcaseOrPerformanceSwitch = ref<boolean>(false); // 指标数据
// 获取指标库
const performanceLoading = ref<boolean>(false);
const performanceData = ref<any>([]);
const dialogApproveUserVisible = ref(false);
// 打开选中评审人弹窗
const openAddApproveUserFun = () => {
const { visibleData } = getVxeRef()?.getTableData();
if (!visibleData.length) {
ElMessage.warning('不能提交空数据');
return;
}
if (!isEmptyPool.value ) {
if (!isHaveNotSave()) {
ElMessage.warning('没有修改的数据需要提交审批');
return;
}
}
dialogApproveUserVisible.value = true;
};
const isEmptyPool = ref(true);
const currentPoolBrief = ref();
const currentPoolBriefVersion = ref();
const currentTableType = ref('tree');
const tableTypeOptions = ref([
{ label: '树结构', value: 'tree' },
{ label: '一维表格', value: 'list' },
]);
const onConfirmFun = async (formData: any) => {
dialogApproveUserVisible.value = false;
if (isEmptyPool.value) {
await createTaskPoolFun(formData);
} else {
await updateTaskPoolFun(formData);
}
if (pendingRoute.value) {
const to = pendingRoute.value;
pendingRoute.value = null;
suppressConfirm.value = true;
router.push(to.fullPath || to.path).catch(() => {
suppressConfirm.value = false;
});
}
};
const createTaskPoolFun = async (formData: any) => {
const { fullData } = getVxeRef()?.getTableData();
const columns = getVxeRef()?.getColumns();
const nodes = cloneDeep(fullData);
const pickedNodes = transformTreeToPoolNodes(nodes);
const req = {
poolBrief: {
poolName: currentPoolBrief.value.poolName,
tenantId: currentPoolBrief.value.tenantId,
},
nodes: pickedNodes,
bApprove: formData.bApprove,
approveTemplateId: formData.approveTemplateId,
approveTemplateName: formData.approveTemplateName,
fullTableColumns: cloneDeep(columns),
fullTableData: cloneDeep(fullData),
};
const res: any = await createTaskPoolApi(req);
if (res.code === 200) {
refreshPoolFun();
}
};
const updateTaskPoolFun = async (formData: any) => {
const { insertRecords, removeRecords, updateRecords } =
getRecordSetFun();
const { fullData } = getVxeRef()?.getTableData();
const columns = getVxeRef()?.getColumns();
const req = {
bApprove: formData.bApprove,
approveTemplateId: formData.approveTemplateId,
approveTemplateName: formData.approveTemplateName,
bNewVersion: formData.bNewVersion,
versionType: formData.versionType,
poolBrief: {
...currentPoolBriefVersion.value,
},
addNodes: [],
addNodeArray: [],
addNodeExtras: [],
addTasks: [],
addTaskArray: [],
addTaskExtras: [],
addPerformances: [],
addPerformanceExtras: [],
updateNodes: [],
updateNodeExtras: [],
updateTasks: [],
updateTaskExtras: [],
updatePerformances: [],
updatePerformanceExtras: [],
deleteNodes: [],
deleteNodeExtras: [],
deleteTasks: [],
deleteTaskExtras: [],
deletePerformances: [],
deletePerformanceExtras: [],
fullTableColumns: cloneDeep(columns),
fullTableData: cloneDeep(fullData),
};
if (insertRecords.length > 0) {
const addObj = formatAddFun(cloneDeep(insertRecords), cloneDeep(updateRecords));
Object.assign(req, addObj);
}
if (updateRecords.length > 0) {
const updateObj = formatUpdateFun(cloneDeep(updateRecords));
Object.assign(req, updateObj);
}
if (removeRecords.length > 0) {
const delObj = formatDelFun(cloneDeep(removeRecords));
Object.assign(req, delObj);
}
const res: any = await updateTaskPoolApi(req);
if (res.code === 200) {
ElMessage.success(res.message);
refreshVersionFun();
}
};
const dedupeTreeFun = (nodes: any[]) => {
const flattenAll = (arr: any[]) => {
const out: any[] = [];
const walk = (list: any[]) => {
(list || []).forEach((it: any) => {
if (!it) return;
out.push(it);
if (it.children && it.children.length) {
walk(it.children);
}
});
};
walk(arr);
return out;
};
const flatInsert = flattenAll(nodes);
const uniqueFlatInsert = uniqBy(flatInsert, 'fakeId');
const map: Record<string, any> = {};
uniqueFlatInsert.forEach((node: any) => {
map[node.fakeId] = { ...cloneDeep(node), children: [] };
});
const roots: any[] = [];
uniqueFlatInsert.forEach((node: any) => {
const cur = map[node.fakeId];
if (cur.parentId && map[cur.parentId]) {
map[cur.parentId].children.push(cur);
} else {
roots.push(cur);
}
});
return roots;
};
const formatAddFun = (insertRecords: TreeNode[], updateRecords: TreeNode[]) => {
const { visibleData } = getVxeRef()?.getTableData();
let nodes: any[] = [];
const nodeExtras: any[] = [];
let tasks: any[] = [];
const taskExtras: any[] = [];
let performances: any[] = [];
const performanceExtras: any[] = [];
const formatAdd = (arr: any) => {
arr.forEach((item: any) => {
const parentRow = visibleData.find((row: any) => {
return row.fakeId === item.parentId;
});
if (item.nodeType === NODE_TYPE.TASK) {
if (parentRow && parentRow.uuid) {
item.parentId = parentRow.uuid;
tasks.push(item);
} else {
item.isTemp = true;
}
} else if (item.nodeType === NODE_TYPE.PERFORMANCE) {
if (parentRow && parentRow.uuid) {
item.parentId = parentRow.uuid;
performances.push(item);
} else {
item.isTemp = true;
}
} else {
if (parentRow && parentRow.uuid) {
item.parentId = parentRow.uuid;
} else {
if (canAddChild({ nodeType: NODE_TYPE.ROOT }, item.nodeType)) {
item.parentId = '';
} else {
item.isTemp = true;
}
}
nodes.push(item);
}
});
};
formatAdd(dedupeTreeFun(insertRecords));
nodes = nodes.filter((item) => !item.isTemp);
tasks = tasks.filter((item) => !item.isTemp);
performances = performances.filter((item) => !item.isTemp);
const nodesGroup = groupBy(nodes, 'parentId');
const addNodes = Object.keys(nodesGroup).map((key) => {
return {
parentId: key === 'undefined' ? '' : key,
nodes: transformTreeToPoolNodes(nodesGroup[key]),
};
});
const tasksGroup = groupBy(tasks, 'parentId');
const addTasks = Object.keys(tasksGroup).map((key) => {
return {
nodeId: key === 'undefined' ? '' : key,
tasks: transformTreeToPoolNodes(tasksGroup[key]),
};
});
const performancesGroup = groupBy(performances, 'parentId');
const addPerformances = Object.keys(performancesGroup).map((key) => {
return {
nodeId: key === 'undefined' ? '' : key,
taskId: key === 'undefined' ? '' : key,
performances: transformTreeToPoolNodes(performancesGroup[key]),
};
});
const formatUpdate = (arr: any) => {
arr.forEach((item: any) => {
item.extras = getNodeExtras(item, poolNodeExtraPropPickMap);
if (Array.isArray(item.extras) && item.extras.length > 0) {
item.extras.forEach((extra: any) => {
if (!extra.uuid) {
if (item.nodeType === NODE_TYPE.TASK) {
taskExtras.push(extra);
} else if (item.nodeType === NODE_TYPE.PERFORMANCE) {
performanceExtras.push(extra);
} else {
nodeExtras.push(extra);
}
}
});
}
});
};
formatUpdate(updateRecords);
return {
addNodeArray: addNodes,
addNodeExtras: nodeExtras,
addTaskArray: addTasks,
addTaskExtras: taskExtras,
addPerformances,
addPerformanceExtras: performanceExtras,
};
};
const formatUpdateFun = (updateRecords: TreeNode[]) => {
const updateNodes: any[] = [];
const updateNodeExtras: any[] = [];
const updateTasks: any[] = [];
const updateTaskExtras: any[] = [];
const updatePerformances: any[] = [];
const updatePerformanceExtras: any[] = [];
const formatUpdate = (arr: TreeNode[]) => {
arr.forEach((item) => {
if (item.nodeType === NODE_TYPE.TASK) {
updateTasks.push(item);
} else if (item.nodeType === NODE_TYPE.PERFORMANCE) {
updatePerformances.push(item);
} else {
updateNodes.push(item);
}
item.extras = getNodeExtras(item, poolNodeExtraPropPickMap);
if (Array.isArray(item.extras) && item.extras.length > 0) {
item.extras.forEach((extra) => {
if (extra.uuid) {
if (item.nodeType === NODE_TYPE.TASK) {
updateTaskExtras.push(extra);
} else if (item.nodeType === NODE_TYPE.PERFORMANCE) {
updatePerformanceExtras.push(extra);
} else {
updateNodeExtras.push(extra);
}
}
});
}
});
};
formatUpdate(updateRecords);
return {
updateNodes: transformTreeToPoolNodes(updateNodes),
updateNodeExtras,
updateTasks: transformTreeToPoolNodes(updateTasks),
updateTaskExtras,
updatePerformances: transformTreeToPoolNodes(updatePerformances),
updatePerformanceExtras,
};
};
const formatDelFun = (removeRecords: TreeNode[]) => {
const deleteNodes: any[] = [];
const deleteNodeExtras: any[] = [];
const deleteTasks: any[] = [];
const deleteTaskExtras: any[] = [];
const deletePerformances: any[] = [];
const deletePerformanceExtras: any[] = [];
removeRecords.forEach((item: TreeNode) => {
if (item.nodeType === NODE_TYPE.TASK) {
deleteTasks.push(item.uuid);
if (Array.isArray(item.extras) && item.extras.length > 0) {
item.extras.forEach((extra: Extra) => {
deleteTaskExtras.push(extra.uuid);
});
}
} else if (item.nodeType === NODE_TYPE.PERFORMANCE) {
deletePerformances.push(item.uuid);
if (Array.isArray(item.extras) && item.extras.length > 0) {
item.extras.forEach((extra: Extra) => {
deletePerformanceExtras.push(extra.uuid);
});
}
} else {
deleteNodes.push(item.uuid);
if (Array.isArray(item.extras) && item.extras.length > 0) {
item.extras.forEach((extra: Extra) => {
deleteNodeExtras.push(extra.uuid);
});
}
}
});
return {
deleteNodes,
deleteNodeExtras,
deleteTasks,
deleteTaskExtras,
deletePerformances,
deletePerformanceExtras,
};
};
const tableKey = ref<any>(new Date().getTime());
const changeLoadcaseOrPerformanceType = () => {
tableKey.value = new Date().getTime();
};
const router = useRouter();
const pendingRoute: any = ref(null);
const suppressConfirm = ref(false);
onBeforeRouteLeave((to, from, next) => {
if (suppressConfirm.value) {
suppressConfirm.value = false;
next();
return;
}
if (!isHaveNotSave()) {
next();
return;
}
ElMessageBox.confirm('当前有修改未保存!是否将修改提交评审后离开!', '提示', {
confirmButtonText: '是',
cancelButtonText: '否',
type: 'warning',
})
.then(() => {
pendingRoute.value = to;
dialogApproveUserVisible.value = true;
next(false);
})
.catch(() => {
next();
});
});
const poolList: Ref<Pool[]> = ref([]);
const queryPoolListFun = async () => {
const res: any = await getAllTaskPoolApi();
if (res.code === 200 && Array.isArray(res.data)) {
poolList.value = res.data.reverse();
} else {
poolList.value = [];
}
if (poolList.value.length > 0) {
currentPoolBrief.value = poolList.value[0];
queryVersionsFun();
}
};
const versionList = ref();
const onPoolChangeFun = (pool: any) => {
if (isHaveNotSave()) {
ElMessageBox.confirm('当前有修改未保存!是否先提交评审?', '提示', {
confirmButtonText: '是',
cancelButtonText: '否',
type: 'warning',
})
.then(() => {
dialogApproveUserVisible.value = true;
})
.catch(() => {
currentPoolBrief.value = pool;
queryVersionsFun();
});
return;
} else {
currentPoolBrief.value = pool;
queryVersionsFun();
}
};
const onVersionChangeFun = () => {
if (!isHaveNotSave()) {
refreshTreeFun();
return;
}
ElMessageBox.confirm('当前有修改未保存!是否先提交评审?', '提示', {
confirmButtonText: '是',
cancelButtonText: '否',
type: 'warning',
})
.then(() => {
dialogApproveUserVisible.value = true;
})
.catch(() => {
refreshTreeFun();
});
};
const extractTableData:any = ref([]);
const queryTaskPoolFun = async () => {
if (!currentPoolBriefVersion.value) {
return;
}
const req = {
poolName: currentPoolBriefVersion.value.poolName,
version: currentPoolBriefVersion.value.poolVersion,
};
loading.value = true;
const res: any = await getTaskPoolApi(req);
loading.value = false;
let tree = [];
if (res.code === 200 && res.data.poolBrief && res.data && res.data.nodes) {
tree = transformPoolNodesToTree(res.data.nodes);
tableData.value = tree;
isEmptyPool.value = false;
extractTableData.value = extractLeafNodesWithParentTypes(res.data.nodes);
const vxeInstance = listTableRef?.value?.loadcaseTableRef?.TreeTableRef?.treeTableRef;
const mergeCells = calcMergeCellsFun(cloneDeep(extractTableData.value));
console.log('extractTableData.value', extractTableData.value);
console.log('mergeCells', mergeCells);
nextTick(() => {
vxeInstance.setMergeCells(mergeCells);
// treeTableRef.value?.changeLevel('全部展开');
});
} else {
tableData.value = [];
isEmptyPool.value = true;
}
};
const calcMergeCellsFun = (tableData: any) => {
const mergeCells: any[] = [];
if (!Array.isArray(tableData) || tableData.length === 0) return mergeCells;
const excludeFields = ['performanceName', 'operation', '_X_ROW_KEY', '_X_ROW_CHILD'];
const isEmpty = (v: any) => v === null || v === undefined || v === '';
const vxeInstance = listTableRef?.value?.loadcaseTableRef?.TreeTableRef?.treeTableRef;
let columnOrder: string[] = [];
try {
if (vxeInstance && typeof vxeInstance.getColumns === 'function') {
const cols = vxeInstance.getColumns() || [];
columnOrder = cols
.filter((c: any) => {
const t = c.type || c.colType || '';
return !['checkbox', 'seq', 'expand', 'radio'].includes(t);
})
.map((c: any) => c.property || c.field || c.dataIndex || c.key || '')
.filter(Boolean);
}
} catch (e) {
throw new Error('获取表格列顺序失败');
}
const compCols =
Array.isArray(tableColumns?.value) && tableColumns.value.length > 0
? tableColumns.value.map((c: any) => c.field || c.dataIndex || c.key).filter(Boolean)
: [];
const rowKeys = Object.keys(tableData[0] || {});
const fullOrder = columnOrder.length > 0 ? columnOrder : compCols.length > 0 ? compCols : rowKeys;
const fields = fullOrder.filter((f) => !!f && !excludeFields.includes(f));
const norm = (v: any) => {
if (isEmpty(v)) return null;
if (typeof v === 'object') return v;
return String(v).trim();
};
const valuesEqual = (a: any, b: any) => {
if (a === null || b === null) return false;
if (typeof a === 'object' || typeof b === 'object') return isEqual(a, b);
return a === b;
};
fields.forEach((field) => {
const colIdx = fullOrder.findIndex((f) => f === field);
if (colIdx === -1) return;
const n = tableData.length;
let start = 0;
while (start < n && norm(tableData[start]?.[field]) === null) start++;
if (start >= n) return;
let startVal = norm(tableData[start][field]);
for (let i = start + 1; i <= n; i++) {
const currVal = i < n ? norm(tableData[i]?.[field]) : null;
const equal = i < n && valuesEqual(startVal, currVal);
if (!equal) {
const rowspan = i - start;
if (rowspan > 1 && startVal !== null) {
mergeCells.push({
row: start,
col: colIdx + 1,
rowspan,
colspan: 1,
});
}
start = i;
while (start < n && norm(tableData[start]?.[field]) === null) start++;
startVal = start < n ? norm(tableData[start][field]) : null;
}
}
});
return mergeCells;
};
const queryTaskPoolPerformanceFun = async () => {
performanceLoading.value = true;
const req = {
poolName: currentPoolBriefVersion.value.poolName,
};
const res: any = await getTaskPoolPerformanceApi(req);
performanceLoading.value = false;
if (res.code === 200 && Array.isArray(res.data)) {
performanceData.value = transformPoolNodesToTree(res.data);
}
};
const refreshTreeFun = async () => {
if (props.pageType === 'loadcase') {
await queryTaskPoolFun();
}
if (props.pageType === 'performance') {
await queryTaskPoolPerformanceFun();
}
};
const refreshPoolFun = async () => {
await queryPoolListFun();
};
const refreshVersionFun = async () => {
await queryVersionsFun();
};
const queryVersionsFun = async () => {
const req = {
poolName: currentPoolBrief.value.poolName,
};
const res: any = await getTaskPoolVersionsApi(req);
if (res.code === 200 && res.data && Array.isArray(res.data) && res.data.length > 0) {
versionList.value = res.data;
if (versionList.value.length > 0) {
currentPoolBriefVersion.value = versionList.value[0];
}
} else {
versionList.value = [];
currentPoolBriefVersion.value = null;
tableData.value = [];
}
await refreshTreeFun();
};
const addPoolModalVisible = ref(false);
const addPoolFun = () => {
addPoolModalVisible.value = true;
};
const onAddPoolOkFun = (formData: any) => {
const newPool = {
tenantId,
poolName: formData.name,
};
currentPoolBrief.value = newPool;
currentPoolBriefVersion.value = null;
poolList.value.unshift(newPool);
versionList.value = [];
addPoolModalVisible.value = false;
tableData.value = [];
isEmptyPool.value = true;
};
const delPoolModalVisible = ref(false);
const openDelPoolFun = () => {
delPoolModalVisible.value = true;
};
const onDelPoolOkFun = () => {
refreshPoolFun();
};
const importPoolModalVisible = ref(false);
const openImportPoolFun = () => {
importPoolModalVisible.value = true;
};
// const compareTree = (originArr:TreeNode[], insertArr:TreeNode[]) => {
// const insertData: any = [];
// const findInsert = (originArr: any, insertArr: any, originNode: any = null) => {
// insertArr.forEach((insertNode: any) => {
// let found = false;
// // 在第一个树中查找是否存在相同的节点
// originArr.some((originNode: any) => {
// if (insertNode.nodeName === originNode.nodeName && insertNode.nodeType === originNode.nodeType) {
// found = true;
// for (const key in insertNode) {
// if (!['children', 'fakeId', 'parentId', 'highValue', 'oldValue'].includes(key)) {
// originNode[key] = insertNode[key];
// }
// }
// // 如果存在相同节点且有子节点,则递归比较子节点
// if (insertNode.children && originNode.children) {
// findInsert(originNode.children, insertNode.children, originNode);
// }
// return true; // 停止遍历
// }
// return false;
// });
// // 如果在第一个树中未找到相同的节点,则插入
// if (!found) {
// if (originNode?.fakeId) {
// insertNode.parentId = originNode?.fakeId;
// insertNode.fakeId = insertNode.fakeId + random(0, 1, true);
// }
// insertNode._X_ROW_CHILD = [];
// insertNode._X_ROW_KEY = null;
// insertData.push(insertNode);
// }
// });
// };
// findInsert(originArr, insertArr);
// return insertData;
// };
const dict = computed(() => ({
bCapacity: taskPoolDictOptions.value.capacityOptions,
unit: taskPoolDictOptions.value.performanceUnitOptions,
department: taskPoolDictOptions.value.departmentListOptions,
section: taskPoolDictOptions.value.sectionListOptions,
group: taskPoolDictOptions.value.groupListOptions,
}));
const onImportPoolOkFun = async (formData: any) => {
importPoolModalVisible.value = false;
const req = {
poolName: formData.poolName,
file: formData.file.raw,
dicts: JSON.stringify(dict.value),
};
const res: any = await importTaskPoolApi(req);
if (res.code === 200) {
const newPool = {
tenantId,
poolName: formData.poolName,
};
currentPoolBrief.value = newPool;
currentPoolBriefVersion.value = null;
poolList.value.unshift(newPool);
versionList.value = [];
isEmptyPool.value = true;
const tree = transformPoolNodesToTree(res.data.nodes);
tableData.value = tree;
extractTableData.value = extractLeafNodesWithParentTypes(res.data.nodes);
const vxeInstance = listTableRef?.value?.loadcaseTableRef?.TreeTableRef?.treeTableRef;
const mergeCells = calcMergeCellsFun(cloneDeep(extractTableData.value));
nextTick(() => {
vxeInstance.setMergeCells(mergeCells);
// treeTableRef.value?.changeLevel('全部展开');
});
}
// let excelJson = [];
// if (res.code === 200) {
// excelJson = res.data;
// } else {
// ElMessage.error(res.message || '导入失败');
// }
// if (excelJson.length > 0) {
// if (formData.importExcelType === 'add') {
// const newPool = {
// tenantId,
// poolName: formData.poolName,
// };
// currentPoolBrief.value = newPool;
// currentPoolBriefVersion.value = null;
// poolList.value.unshift(newPool);
// versionList.value = [];
// tableData.value = transformPoolNodesToTree(excelJson);
// isEmptyPool.value = true;
// } else if (formData.importExcelType === 'cover') {
// const insertData = compareTree(tableData.value, transformPoolNodesToTree(excelJson));
// const insertDataFlat = flatNode(insertData);
// console.log('insertDataFlat', insertDataFlat);
// treeTableRef.value?.loadcaseTableRef.proTreeRef.vxeGridRef?.insertAt(insertDataFlat);
// }
// nextTick(() => {
// treeTableRef.value?.changeLevel('全部展开');
// });
// };
};
const exportLoading = ref(false);
const onExportPoolFun = async () => {
exportLoading.value = true;
if (!currentPoolBriefVersion.value) {
exportLoading.value = false;
return ElMessage.warning('请选择工况库及版本');
}
const req = {
poolName: currentPoolBriefVersion.value.poolName,
poolVersion: currentPoolBriefVersion.value.poolVersion,
dicts: JSON.stringify(dict.value),
};
await exportTaskPoolApi(req);
exportLoading.value = false;
};
onMounted(async () => {
await getColumnsFun();
await queryPoolListFun();
});
</script>
<style src="./taskPool.scss" lang="scss" scoped />