feat: 仿真策划导入

This commit is contained in:
JiangSheng
2026-03-23 15:43:52 +08:00
parent 6a689b0d73
commit 32f97d5ec7
4 changed files with 300 additions and 4 deletions

View File

@@ -1,4 +1,4 @@
import { download, post, get } from '@/api/request';
import { download, post, get, upload } from '@/api/request';
const env = import.meta.env;
const PREFIX = env.VITE_API_PREFIX_PROJECT;
@@ -36,6 +36,10 @@ export const getTaskTreeListApi = (params: any) => {
export const queryDesignVersionsApi = (params: any) => {
return get(`${PREFIX}project/queryDesignVersions`, params);
};
export const importSimulationExternalFormApi = (params: any) => {
return upload(`${PREFIX}project/importSimulationExternalForm`, params);
};
/**
* 查询项目工位的报告列表
*/

View File

@@ -195,6 +195,27 @@
v-model="row.payAttentionMemberIds"
></userSelect>
</template>
<!-- 3D负责人 -->
<template #tMemberIds="{ row, icon }">
<TreeEditItem
v-if="[NODE_TYPE.TASK].includes(row.nodeType)"
:data="row.tMemberIds"
:editMode="editMode"
:icon="icon"
hideTitle
>
<span :title="disposeMemberList(row['tMemberList'], 'tMemberList')">
{{ disposeMemberList(row['tMemberList'], 'tMemberList') }}
</span>
</TreeEditItem>
</template>
<template #tMemberIds-edit="{ row }">
<userSelect
@change="(data) => changeUserFun(row, data, 'tMemberList', 'tMemberIds')"
:multiple="true"
v-model="row.tMemberIds"
></userSelect>
</template>
<!-- 计划开始时间 -->
<template #beginTime="{ row, icon }">
<TreeEditItem

View File

@@ -96,6 +96,9 @@ export const disposeTaskMembers = (disposeKey: string, row: any) => {
if (row.key === 'payAttentionMemberIds' || row.key === 'payAttentionMemberList') {
obj.payAttentionMemberListArr = row.val;
}
if (row.key === 'tMemberIds' || row.key === 'tMemberList') {
obj.tMemberListArr = row.val;
}
return obj;
}
if (disposeKey === 'getListAndIds') {
@@ -109,6 +112,9 @@ export const disposeTaskMembers = (disposeKey: string, row: any) => {
payAttentionMemberList: row.payAttentionMemberListArr,
// EP的关注人
payAttentionMemberIds: getMemberListIds(row.payAttentionMemberListArr),
// 3D负责人
tMemberList: row.tMemberListArr,
tMemberIds: getMemberListIds(row.tMemberListArr),
};
} else {
return {
@@ -128,6 +134,7 @@ export const disposeTaskMembers = (disposeKey: string, row: any) => {
eMemberList: getMemberListIds(row.eMemberList),
pMemberList: getMemberListIds(row.pMemberList),
payAttentionMemberList: getMemberListIds(row.payAttentionMemberList),
tMemberList: getMemberListIds(row.tMemberList),
};
}
if (disposeKey === 'setListToArr') {
@@ -135,6 +142,7 @@ export const disposeTaskMembers = (disposeKey: string, row: any) => {
eMemberListArr: row.eMemberList,
pMemberListArr: row.pMemberList,
payAttentionMemberListArr: row.payAttentionMemberList,
tMemberListArr: row.tMemberList,
};
}
if (disposeKey === 'setArrToList') {
@@ -142,6 +150,7 @@ export const disposeTaskMembers = (disposeKey: string, row: any) => {
eMemberList: row.eMemberListArr,
pMemberList: row.pMemberListArr,
payAttentionMemberList: row.payAttentionMemberListArr,
tMemberList: row.tMemberListArr,
};
}
if (disposeKey === 'setListToIds') {
@@ -157,6 +166,10 @@ export const disposeTaskMembers = (disposeKey: string, row: any) => {
if (row.payAttentionMemberList?.length > 0) {
row.payAttentionMemberIds = getMemberListIds(row.payAttentionMemberList);
}
row.tMemberIds = '';
if (row.tMemberList?.length > 0) {
row.tMemberIds = getMemberListIds(row.tMemberList);
}
}
if (disposeKey === 'setListToIdsNoTranslate') {
row.pMemberIds = '';
@@ -171,6 +184,10 @@ export const disposeTaskMembers = (disposeKey: string, row: any) => {
if (row.payAttentionMemberList?.length > 0) {
row.payAttentionMemberIds = row.payAttentionMemberList;
}
row.tMemberIds = '';
if (row.tMemberList?.length > 0) {
row.tMemberIds = row.tMemberList;
}
}
};

View File

@@ -264,9 +264,21 @@
needTagKey
>
<template #otherLeftOptions>
<el-button class="other-button" @click="showBatchUpdateTaskDialogFun"
>批量修改</el-button
<el-upload
ref="importSimulationExternalFormUploadRef"
:show-file-list="false"
:auto-upload="false"
:limit="1"
accept=".xls,.xlsx"
:on-change="importSimulationExternalFormFun"
>
<el-button class="other-button" :loading="importSimulationExternalFormLoading">
导入
</el-button>
</el-upload>
<el-button class="other-button" @click="showBatchUpdateTaskDialogFun">
批量修改
</el-button>
</template>
</loadCaseTable>
<!-- <loadcase-pro-table
@@ -340,6 +352,7 @@ import {
import { ElMessage, ElMessageBox } from 'element-plus';
import { cloneDeep } from 'lodash-es';
import { v4 as uuidv4 } from 'uuid';
import { diff } from '@/utils/diff';
import {
getAllTaskPoolApi,
getTaskPoolApi,
@@ -363,7 +376,7 @@ import { TABLE_NAME } from '@/utils/enum/tableName';
import TableForm from '@/components/common/table/tableForm.vue';
import { CommonStore } from '@/stores/common';
import AddApprove from '@/views/competenceCenter/condition/components/addApprove.vue';
import { queryDesignVersionsApi } from '@/api/project/project';
import { queryDesignVersionsApi, importSimulationExternalFormApi } from '@/api/project/project';
import { getSeeDisciplines } from '@/tenants/lyric/views/task/lyricTask';
import { enableConfigByTenant, TENANT_ENUM } from '@/tenants/tenant';
@@ -1201,6 +1214,8 @@ const leftExcelTableData = ref();
const leftExcelLoading = ref(false);
const leftExcelTableRef = ref();
const importSimulationExternalFormUploadRef = ref();
const importSimulationExternalFormLoading = ref(false);
const getFilterColumnsFun = async () => {
const res: any = await getFormConfigureApi({ formName: 'TASK_POOL' });
@@ -1253,6 +1268,245 @@ const uploadExcelFileFun = async (file: any) => {
}
};
const getImportExcelHeadersFun = async () => {
const res: any = await getFormConfigureApi({
formName: 'PROJECT_TASK_PLANNING',
});
if (res.code === 200 && res.data?.formConfig) {
const config = JSON.parse(res.data.formConfig);
return config
.filter((column: any) => column.isShow)
.map((column: any) => {
const header: any = {
key: column.key,
title: column.title,
type: column.type,
};
if (
['select', 'multipleSelect', 'radio', 'checkbox'].includes(column.inputMode) &&
commonStore.getDictData(column.formOptions)
) {
header.dictCode = column.formOptions;
header.dictData = commonStore.getDictData(column.formOptions).O;
}
return header;
});
}
return [];
};
const flattenRowRefsFun = (nodes: any[] = []) => {
const rows: any[] = [];
const walk = (list: any[]) => {
(list || []).forEach((item: any) => {
rows.push(item);
if (Array.isArray(item.children) && item.children.length > 0) {
walk(item.children);
}
});
};
walk(nodes);
return rows;
};
const getCurrentRightTreeDataFun = () => {
const table = getRightVxeRef()?.getTableData?.();
if (table && Array.isArray(table.fullData)) {
return cloneDeep(table.fullData);
}
return cloneDeep(rightTableData.value || []);
};
const syncDisposeTaskMembersFun = (row: any) => {
if (!row || typeof row !== 'object') {
return;
}
disposeTaskMembers('setListToIds', row);
const memberFieldMap: Array<[string, string]> = [
['pMemberList', 'pMemberIds'],
['eMemberList', 'eMemberIds'],
['payAttentionMemberList', 'payAttentionMemberIds'],
['tMemberList', 'tMemberIds'],
];
memberFieldMap.forEach(([listKey, idKey]) => {
if (typeof row[listKey] === 'string' && row[listKey]) {
row[idKey] = row[listKey];
}
});
};
const getRightRowByFakeIdFun = (fakeId?: string) => {
const vxeRef = getRightVxeRef();
if (!vxeRef || !fakeId) {
return null;
}
const { fullData } = vxeRef.getTableData();
return flattenRowRefsFun(fullData || []).find((row: any) => row.fakeId === fakeId) || null;
};
const syncRowInTreeFun = (list: any[], rowInfo: any): boolean => {
for (const item of list || []) {
if (item.fakeId === rowInfo.fakeId) {
Object.assign(item, rowInfo, {
children: item.children,
});
return true;
}
if (Array.isArray(item.children) && item.children.length > 0) {
const found = syncRowInTreeFun(item.children, rowInfo);
if (found) {
return true;
}
}
}
return false;
};
const applyImportDiffToRightTableFun = async (importedTree: any[]) => {
const vxeRef = getRightVxeRef();
if (!vxeRef) {
rightTableData.value = cloneDeep(importedTree || []);
return {
insertCount: Array.isArray(importedTree) ? importedTree.length : 0,
updateCount: 0,
};
}
const { insertRecords, updateRecords } = diff(
getCurrentRightTreeDataFun() as any,
(Array.isArray(importedTree) ? importedTree : []) as any
);
const updatedFakeIds = new Set<string>();
let updateCount = 0;
for (const item of updateRecords || []) {
const fakeId = String(item?.fakeId || '');
if (!fakeId || updatedFakeIds.has(fakeId)) {
continue;
}
const row = getRightRowByFakeIdFun(fakeId);
if (!row) {
continue;
}
updatedFakeIds.add(fakeId);
const rowInfo = {
...cloneDeep(row),
...cloneDeep(item),
fakeId: row.fakeId,
parentId: row.parentId,
children: row.children,
};
syncDisposeTaskMembersFun(rowInfo);
vxeRef.setRow(row, rowInfo);
const { fullData } = vxeRef.getTableData();
syncRowInTreeFun(fullData || [], rowInfo);
updateCount++;
}
let insertCount = 0;
for (const item of insertRecords || []) {
const insertRow: any = {
...cloneDeep(item),
children: [],
uuid: undefined,
};
if (!insertRow.parentId) {
insertRow.parentId = '0';
}
if (insertRow.parentId === '0') {
insertRow.pid = nodeLevel2Uuid.value;
} else {
const parentRow = getRightRowByFakeIdFun(String(insertRow.parentId));
insertRow.pid = parentRow?.uuid;
}
if (insertRow.nodeType === NODE_TYPE.TASK) {
// if (!insertRow.beginTime) {
// if (nodeLevel2SelectRef.value?.nodeInfo?.beginTime) {
// insertRow.beginTime = nodeLevel2SelectRef.value?.nodeInfo.beginTime;
// } else if (props.projectBeginTime) {
// insertRow.beginTime = props.projectBeginTime;
// } else {
// insertRow.beginTime = dayjs().format('YYYY-MM-DD');
// }
// }
// if (!insertRow.endTime) {
// if (nodeLevel2SelectRef.value?.nodeInfo?.endTime) {
// insertRow.endTime = nodeLevel2SelectRef.value?.nodeInfo.endTime;
// } else if (props.projectEndTime) {
// insertRow.endTime = props.projectEndTime;
// } else {
// insertRow.endTime = dayjs().format('YYYY-MM-DD');
// }
// }
if (!insertRow.exeStatus) {
insertRow.exeStatus = TASK_PROCESS_STATUS.NO_STARTED;
}
if (!insertRow.achieveStatus) {
insertRow.achieveStatus = TASK_CALCULATE_STATUS.NO_CALCULATE;
}
}
if (insertRow.nodeType !== NODE_TYPE.PERFORMANCE) {
const parentRow =
insertRow.parentId && insertRow.parentId !== '0'
? getRightRowByFakeIdFun(String(insertRow.parentId))
: null;
const pTagKeyList = parentRow?.tagKeyList || [];
disposeTagKey(insertRow, pTagKeyList, tagKeyMap.value);
insertRow.tagKeyList = Array.isArray(insertRow.tagKeyList) ? insertRow.tagKeyList : [];
}
syncDisposeTaskMembersFun(insertRow);
await vxeRef.insertAt(insertRow, -1);
insertCount++;
}
nextTick(() => {
expandTree(rightTableRef.value);
});
return { insertCount, updateCount };
};
const importSimulationExternalFormFun = async (file: any) => {
if (!file?.raw) {
ElMessage.warning('请选择Excel文件');
return;
}
if (!props.nodeLevel1Info?.nodeCode) {
ElMessage.warning('当前项目编号为空,无法导入');
importSimulationExternalFormUploadRef.value?.clearFiles?.();
return;
}
importSimulationExternalFormLoading.value = true;
try {
const excelHeaders = await getImportExcelHeadersFun();
const req = {
file: file.raw,
columns: JSON.stringify({
excelHeaders,
params: {
projectCode: props.nodeLevel1Info?.nodeCode,
},
}),
};
const res: any = await importSimulationExternalFormApi(req);
if (res?.code === 200) {
const importedNodes = Array.isArray(res.data?.nodes) ? res.data.nodes : [];
await applyImportDiffToRightTableFun(importedNodes);
ElMessage.success(res.message);
}
} finally {
importSimulationExternalFormLoading.value = false;
importSimulationExternalFormUploadRef.value?.clearFiles?.();
}
};
const batchUpdateTaskDialogVisible = ref(false);
const showBatchUpdateTaskDialogFun = () => {
const selectTasks = getRightVxeRef().getCheckboxRecords();