feat: 仿真策划导入
This commit is contained in:
@@ -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);
|
||||
};
|
||||
/**
|
||||
* 查询项目工位的报告列表
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user