|
|
|
|
@ -175,11 +175,12 @@
|
|
|
|
|
<script setup lang="ts" name="BudgetInfoEdit">
|
|
|
|
|
import { ref, reactive } from 'vue';
|
|
|
|
|
import { ElMessage } from 'element-plus';
|
|
|
|
|
import { listProjectInfo, addErpBudgetInfo, updateErpBudgetInfo, getErpBudgetInfo } from '@/api/oa/erp/budgetInfo';
|
|
|
|
|
import { listProjectInfo, addErpBudgetInfo, updateErpBudgetInfo, changeErpBudgetInfo, getErpBudgetInfo } from '@/api/oa/erp/budgetInfo';
|
|
|
|
|
import { ProjectInfoVO, ProjectInfoQuery } from '@/api/oa/erp/projectInfo/types';
|
|
|
|
|
import { getUserList } from '@/api/system/user';
|
|
|
|
|
|
|
|
|
|
import { deepEqualArrays } from '@/utils/objHandle';
|
|
|
|
|
import { cloneDeep } from 'lodash-es';
|
|
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
|
|
@ -644,11 +645,20 @@ const handleSave = async (status: string, mode: boolean) => {
|
|
|
|
|
ElMessage.warning('不支持的预算类型');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
console.log('----');
|
|
|
|
|
console.log(budgetForm);
|
|
|
|
|
|
|
|
|
|
// 统一保存逻辑
|
|
|
|
|
const saveOperation = budgetForm.budgetId ? () => updateErpBudgetInfo(budgetForm) : () => addErpBudgetInfo(budgetForm);
|
|
|
|
|
|
|
|
|
|
await saveOperation();
|
|
|
|
|
if (budgetForm.budgetId) {
|
|
|
|
|
await updateErpBudgetInfo(budgetForm);
|
|
|
|
|
} else {
|
|
|
|
|
if (routeParams.value.changeFlag === '1') {
|
|
|
|
|
await changeErpBudgetInfo(budgetForm);
|
|
|
|
|
} else {
|
|
|
|
|
budgetForm.budgetVersion = 1;
|
|
|
|
|
await addErpBudgetInfo(budgetForm);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ElMessage.success('操作成功');
|
|
|
|
|
handleSaveSuccess();
|
|
|
|
|
@ -685,8 +695,6 @@ const processRdBudgetForm = async (status: string): Promise<budgetInfoForm> => {
|
|
|
|
|
...initializeRdCostLists()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
console.log(budgetForm);
|
|
|
|
|
|
|
|
|
|
// 处理各项成本数据
|
|
|
|
|
processRdCostData(budgetForm);
|
|
|
|
|
|
|
|
|
|
@ -760,6 +768,8 @@ const initializeMarketCostLists = () => ({
|
|
|
|
|
// 处理研发成本数据
|
|
|
|
|
const processRdCostData = (budgetForm: budgetInfoForm) => {
|
|
|
|
|
// 设备成本
|
|
|
|
|
console.log(rdMaterialCostRef.value?.allMaterialData);
|
|
|
|
|
console.log(oriRdBudgetMaterialCostList.value);
|
|
|
|
|
if (assignIfChanged([], rdEquipmentCostRef.value?.equipmentData, oriRdBudgetEquipmentCostList.value).length) {
|
|
|
|
|
budgetForm.erpRdBudgetEquipmentCostList = rdEquipmentCostRef.value?.equipmentData || [];
|
|
|
|
|
}
|
|
|
|
|
@ -883,153 +893,437 @@ const handleClose = () => {
|
|
|
|
|
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const budgetId = ref();
|
|
|
|
|
|
|
|
|
|
// 初始化
|
|
|
|
|
// 定义不同类型的主键字段映射
|
|
|
|
|
const PRIMARY_KEY_MAP = {
|
|
|
|
|
// 研发预算相关
|
|
|
|
|
erpRdBudgetEquipmentCostList: 'equipmentCostId',
|
|
|
|
|
erpRdBudgetMaterialCostList: 'materialCostId',
|
|
|
|
|
erpRdBudgetTravelCostList: 'travelCostId',
|
|
|
|
|
erpRdBudgetMeetingCostList: 'meetingCostId',
|
|
|
|
|
erpRdBudgetExchangeCostList: 'exchangeCostId',
|
|
|
|
|
erpRdBudgetTechCostList: 'techCostId',
|
|
|
|
|
erpRdBudgetLaborCostList: 'laborCostId',
|
|
|
|
|
erpRdBudgetLiteratureCostList: 'literatureCostId',
|
|
|
|
|
erpRdBudgetTestingCostList: 'testingCostId',
|
|
|
|
|
erpRdBudgetOtherCostList: 'otherCostId',
|
|
|
|
|
|
|
|
|
|
// 市场预算相关
|
|
|
|
|
erpBudgetMaterialCostList: 'materialCostId',
|
|
|
|
|
erpBudgetLaborCostList: 'laborCostId',
|
|
|
|
|
erpBudgetInstallCostList: 'installCostId',
|
|
|
|
|
erpBudgetTravelCostList: 'travelCostId',
|
|
|
|
|
erpBudgetOtherCostList: 'otherCostId',
|
|
|
|
|
|
|
|
|
|
// 预算明细
|
|
|
|
|
erpBudgetDetailList: 'budgetDetailId',
|
|
|
|
|
erpBudgetInfo: 'budgetId',
|
|
|
|
|
|
|
|
|
|
// 默认主键
|
|
|
|
|
default: 'id'
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
// 定义需要删除的通用字段
|
|
|
|
|
const COMMON_FIELDS_TO_REMOVE = ['budgetId', 'createDept', 'createBy', 'createTime', 'updateBy', 'updateTime', 'delFlag'];
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
nextTick(async () => {
|
|
|
|
|
// 获取路由参数
|
|
|
|
|
routeParams.value = route.query;
|
|
|
|
|
budgetId.value = routeParams.value.id as string | number;
|
|
|
|
|
if (budgetId.value && (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval')) {
|
|
|
|
|
proxy?.$modal.loading('正在加载数据,请稍后...');
|
|
|
|
|
|
|
|
|
|
const res = await getErpBudgetInfo(budgetId.value);
|
|
|
|
|
Object.assign(searchForm, res.data);
|
|
|
|
|
console.log(res.data);
|
|
|
|
|
await getUsers();
|
|
|
|
|
if (searchForm.projectCategory === PROJECT_CATEGORY.RD || searchForm.projectCategory === PROJECT_CATEGORY.PRE_PRODUCTION) {
|
|
|
|
|
oriRdBudgetEquipmentCostList.value = JSON.parse(JSON.stringify(res.data.erpRdBudgetEquipmentCostList));
|
|
|
|
|
|
|
|
|
|
const erpRdBudgetMaterialCostList = res.data.erpRdBudgetMaterialCostList;
|
|
|
|
|
const groupedRdBudgetMaterialCostListByMaterialType = erpRdBudgetMaterialCostList.reduce((acc, item) => {
|
|
|
|
|
const materialType = item.materialType;
|
|
|
|
|
if (!acc[materialType]) {
|
|
|
|
|
acc[materialType] = [];
|
|
|
|
|
}
|
|
|
|
|
acc[materialType].push(item);
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
const rdBudgetMainMaterialCostList = groupedRdBudgetMaterialCostListByMaterialType[MATERIAL_TYPE.MAIN] || [];
|
|
|
|
|
const rdBudgetOtherMaterialCostList = groupedRdBudgetMaterialCostListByMaterialType[MATERIAL_TYPE.OTHER] || [];
|
|
|
|
|
oriRdBudgetMaterialCostList.value = JSON.parse(JSON.stringify(erpRdBudgetMaterialCostList));
|
|
|
|
|
|
|
|
|
|
oriRdBudgetTravelCostList.value = JSON.parse(JSON.stringify(res.data.erpRdBudgetTravelCostList));
|
|
|
|
|
oriRdBudgetMeetingCostList.value = JSON.parse(JSON.stringify(res.data.erpRdBudgetMeetingCostList));
|
|
|
|
|
oriRdBudgetExchangeCostList.value = JSON.parse(JSON.stringify(res.data.erpRdBudgetExchangeCostList));
|
|
|
|
|
|
|
|
|
|
const erpRdBudgetTechCostList = res.data.erpRdBudgetTechCostList;
|
|
|
|
|
const groupedRdBudgetTechCostListByTechType = erpRdBudgetTechCostList.reduce((acc, item) => {
|
|
|
|
|
const techType = item.techType;
|
|
|
|
|
if (!acc[techType]) {
|
|
|
|
|
acc[techType] = [];
|
|
|
|
|
}
|
|
|
|
|
acc[techType].push(item);
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
const rdBudgetTechConsultCostList = groupedRdBudgetTechCostListByTechType[TECH_TYPE.TECH_CONSULT] || [];
|
|
|
|
|
const rdBudgetExpertMeetingCostList = groupedRdBudgetTechCostListByTechType[TECH_TYPE.EXPERT_MEETING] || [];
|
|
|
|
|
const rdBudgetExpertCommCostList = groupedRdBudgetTechCostListByTechType[TECH_TYPE.EXPERT_COMM] || [];
|
|
|
|
|
oriRdBudgetTechConsultCostList.value = JSON.parse(JSON.stringify(rdBudgetTechConsultCostList)); //技术咨询
|
|
|
|
|
oriRdBudgetExpertMeetingCostList.value = JSON.parse(JSON.stringify(rdBudgetExpertMeetingCostList)); //专家咨询会议形式
|
|
|
|
|
oriRdBudgetExpertCommCostList.value = JSON.parse(JSON.stringify(rdBudgetExpertCommCostList)); //专家咨询通讯形式
|
|
|
|
|
|
|
|
|
|
const erpRdBudgetLaborCostList = res.data.erpRdBudgetLaborCostList;
|
|
|
|
|
const groupedRdBudgetLaborCostListByLaborType = erpRdBudgetLaborCostList.reduce((acc, item) => {
|
|
|
|
|
const laborType = item.laborType;
|
|
|
|
|
if (!acc[laborType]) {
|
|
|
|
|
acc[laborType] = [];
|
|
|
|
|
}
|
|
|
|
|
acc[laborType].push(item);
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
const rdBudgetLaborCostList = groupedRdBudgetLaborCostListByLaborType[LABOR_TYPE.LABOR] || [];
|
|
|
|
|
const rdBudgetServiceCostList = groupedRdBudgetLaborCostListByLaborType[LABOR_TYPE.SERVICE] || [];
|
|
|
|
|
oriRdBudgetLaborCostList.value = JSON.parse(JSON.stringify(rdBudgetLaborCostList)); //人工费
|
|
|
|
|
oriRdBudgetServiceCostList.value = JSON.parse(JSON.stringify(rdBudgetServiceCostList)); //劳务费
|
|
|
|
|
|
|
|
|
|
const erpRdBudgetLiteratureCostList = res.data.erpRdBudgetLiteratureCostList;
|
|
|
|
|
const groupedRdBudgetLiteratureCostListByLiteratureType = erpRdBudgetLiteratureCostList.reduce((acc, item) => {
|
|
|
|
|
const literatureType = item.literatureType;
|
|
|
|
|
if (!acc[literatureType]) {
|
|
|
|
|
acc[literatureType] = [];
|
|
|
|
|
}
|
|
|
|
|
acc[literatureType].push(item);
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
const rdBudgetLiteratureMaterialCostList = groupedRdBudgetLiteratureCostListByLiteratureType[LITERATURE_TYPE.MATERIAL] || [];
|
|
|
|
|
const rdBudgetLiteratureSoftwareCostList = groupedRdBudgetLiteratureCostListByLiteratureType[LITERATURE_TYPE.SOFTWARE] || [];
|
|
|
|
|
oriRdBudgetLiteratureMaterialCostList.value = JSON.parse(JSON.stringify(rdBudgetLiteratureMaterialCostList)); //资料费
|
|
|
|
|
oriRdBudgetLiteratureSofwareCostList.value = JSON.parse(JSON.stringify(rdBudgetLiteratureSoftwareCostList)); //专用软件购买费
|
|
|
|
|
|
|
|
|
|
const rdBudgetLiteratureRetrievalCostList = groupedRdBudgetLiteratureCostListByLiteratureType[LITERATURE_TYPE.DOCUMENT] || []; //文献检索费
|
|
|
|
|
|
|
|
|
|
oriRdBudgetTestingCostList.value = JSON.parse(JSON.stringify(res.data.erpRdBudgetTestingCostList));
|
|
|
|
|
oriRdBudgetOtherCostList.value = JSON.parse(JSON.stringify(res.data.erpRdBudgetOtherCostList));
|
|
|
|
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
console.log(rdBudgetTableRef.value?.budgetForm);
|
|
|
|
|
Object.assign(rdBudgetTableRef.value?.rdBudgetInfoForm, res.data);
|
|
|
|
|
Object.assign(rdBudgetTableRef.value?.footerForm, res.data);
|
|
|
|
|
Object.assign(rdBudgetTableRef.value?.budgetDetailData || [], res.data.erpBudgetDetailList);
|
|
|
|
|
Object.assign(rdEquipmentCostRef.value?.equipmentData || [], res.data.erpRdBudgetEquipmentCostList);
|
|
|
|
|
Object.assign(rdMaterialCostRef.value?.materialData || [], rdBudgetMainMaterialCostList);
|
|
|
|
|
Object.assign(rdMaterialCostRef.value?.otherMaterial || [], rdBudgetOtherMaterialCostList[0]);
|
|
|
|
|
Object.assign(rdTravelMeetingExchangeRef.value?.travelList || [], res.data.erpRdBudgetTravelCostList);
|
|
|
|
|
Object.assign(rdTravelMeetingExchangeRef.value?.meetingList || [], res.data.erpRdBudgetMeetingCostList);
|
|
|
|
|
Object.assign(rdTravelMeetingExchangeRef.value?.exchangeList || [], res.data.erpRdBudgetExchangeCostList);
|
|
|
|
|
Object.assign(rdLaborServiceRef.value?.techConsultList || [], rdBudgetTechConsultCostList);
|
|
|
|
|
Object.assign(rdLaborServiceRef.value?.expertMeetingList || [], rdBudgetExpertMeetingCostList);
|
|
|
|
|
Object.assign(rdLaborServiceRef.value?.expertCommList || [], rdBudgetExpertCommCostList);
|
|
|
|
|
Object.assign(rdLaborServiceRef.value?.laborList || [], rdBudgetLaborCostList);
|
|
|
|
|
Object.assign(rdLaborServiceRef.value?.serviceList || [], rdBudgetServiceCostList);
|
|
|
|
|
|
|
|
|
|
Object.assign(rdLiteratureCostRef.value?.materialsList || [], rdBudgetLiteratureMaterialCostList);
|
|
|
|
|
Object.assign(rdLiteratureCostRef.value?.softwareList || [], rdBudgetLiteratureSoftwareCostList);
|
|
|
|
|
Object.assign(
|
|
|
|
|
rdLiteratureCostRef.value?.literatureRetrieval || [],
|
|
|
|
|
rdBudgetLiteratureRetrievalCostList.length > 0 ? rdBudgetLiteratureRetrievalCostList[0] : {}
|
|
|
|
|
);
|
|
|
|
|
Object.assign(rdTestingCostRef.value?.testData || [], res.data.erpRdBudgetTestingCostList);
|
|
|
|
|
Object.assign(rdOtherCostRef.value?.otherCostList || [], res.data.erpRdBudgetOtherCostList);
|
|
|
|
|
});
|
|
|
|
|
} else if (searchForm.projectCategory === PROJECT_CATEGORY.MARKET || searchForm.projectCategory === PROJECT_CATEGORY.MARKET_PART) {
|
|
|
|
|
// 创建初始状态的深拷贝(确保完全独立)
|
|
|
|
|
oriBudgetMaterialCostList.value = JSON.parse(JSON.stringify(res.data.erpBudgetMaterialCostList));
|
|
|
|
|
oriBudgetLaborCostList.value = JSON.parse(JSON.stringify(res.data.erpBudgetLaborCostList));
|
|
|
|
|
oriBudgetInstallCostList.value = JSON.parse(JSON.stringify(res.data.erpBudgetInstallCostList));
|
|
|
|
|
oriBudgetTravelCostList.value = JSON.parse(JSON.stringify(res.data.erpBudgetTravelCostList));
|
|
|
|
|
oriBudgetOtherCostList.value = JSON.parse(JSON.stringify(res.data.erpBudgetOtherCostList));
|
|
|
|
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
console.log(budgetTableRef.value?.budgetForm);
|
|
|
|
|
Object.assign(budgetTableRef.value?.budgetForm, res.data);
|
|
|
|
|
Object.assign(budgetTableRef.value?.budgetDetailData, res.data.erpBudgetDetailList);
|
|
|
|
|
Object.assign(materialCostRef.value?.budgetMaterialCostList, res.data.erpBudgetMaterialCostList);
|
|
|
|
|
Object.assign(laborCostRef.value?.budgetLaborCostList, res.data.erpBudgetLaborCostList);
|
|
|
|
|
Object.assign(installationCostRef.value?.installCostList, res.data.erpBudgetInstallCostList);
|
|
|
|
|
Object.assign(travelCostRef.value?.travelCostList, res.data.erpBudgetTravelCostList);
|
|
|
|
|
Object.assign(otherCostRef.value?.otherCostList, res.data.erpBudgetOtherCostList);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proxy?.$modal.closeLoading();
|
|
|
|
|
} else {
|
|
|
|
|
searchForm.projectCategory = routeParams.value.projectCategory;
|
|
|
|
|
// 新增模式:如果已有合同编号,禁用生成按钮
|
|
|
|
|
// if (form.value.contractCode) {
|
|
|
|
|
// isCodeGenerated.value = true;
|
|
|
|
|
// } else if (form.value.contractFlag === '1') {
|
|
|
|
|
// // 如果有合同但没有编号,允许生成
|
|
|
|
|
// isCodeGenerated.value = false;
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
queryParams.value.projectCategory = searchForm.projectCategory;
|
|
|
|
|
await loadBudgetData();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
async function loadBudgetData() {
|
|
|
|
|
routeParams.value = route.query;
|
|
|
|
|
budgetId.value = routeParams.value.id as string | number;
|
|
|
|
|
|
|
|
|
|
if (!budgetId.value || !['update', 'view', 'approval'].includes(routeParams.value.type as string)) {
|
|
|
|
|
handleAddMode();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await handleLoadMode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleAddMode() {
|
|
|
|
|
searchForm.projectCategory = routeParams.value.projectCategory;
|
|
|
|
|
queryParams.value.projectCategory = searchForm.projectCategory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleLoadMode() {
|
|
|
|
|
proxy?.$modal.loading('正在加载数据,请稍后...');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const res = await getErpBudgetInfo(budgetId.value);
|
|
|
|
|
Object.assign(searchForm, res.data);
|
|
|
|
|
if (routeParams.value.changeFlag === '1') {
|
|
|
|
|
searchForm.flowStatus = 'draft';
|
|
|
|
|
}
|
|
|
|
|
await getUsers();
|
|
|
|
|
|
|
|
|
|
if (isRdOrPreProductionCategory()) {
|
|
|
|
|
await handleRdOrPreProductionData(res.data);
|
|
|
|
|
} else if (isMarketCategory()) {
|
|
|
|
|
await handleMarketCategoryData(res.data);
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
proxy?.$modal.closeLoading();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isRdOrPreProductionCategory(): boolean {
|
|
|
|
|
return searchForm.projectCategory === PROJECT_CATEGORY.RD || searchForm.projectCategory === PROJECT_CATEGORY.PRE_PRODUCTION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isMarketCategory(): boolean {
|
|
|
|
|
return searchForm.projectCategory === PROJECT_CATEGORY.MARKET || searchForm.projectCategory === PROJECT_CATEGORY.MARKET_PART;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleRdOrPreProductionData(data: any) {
|
|
|
|
|
const isChangeType = routeParams.value.changeFlag === '1';
|
|
|
|
|
|
|
|
|
|
// 只有在非变更类型时才初始化原始数据
|
|
|
|
|
if (!isChangeType) {
|
|
|
|
|
initOriginalRdData(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 分组数据
|
|
|
|
|
const groupedMaterialData = groupByField(data.erpRdBudgetMaterialCostList, 'materialType');
|
|
|
|
|
const groupedTechData = groupByField(data.erpRdBudgetTechCostList, 'techType');
|
|
|
|
|
const groupedLaborData = groupByField(data.erpRdBudgetLaborCostList, 'laborType');
|
|
|
|
|
const groupedLiteratureData = groupByField(data.erpRdBudgetLiteratureCostList, 'literatureType');
|
|
|
|
|
|
|
|
|
|
// 获取并处理分类数据
|
|
|
|
|
const categorizedData = {
|
|
|
|
|
rdBudgetMainMaterialCostList: handleChangeTypeIds(groupedMaterialData[MATERIAL_TYPE.MAIN] || [], 'erpRdBudgetMaterialCostList', isChangeType),
|
|
|
|
|
rdBudgetOtherMaterialCostList: handleChangeTypeIds(groupedMaterialData[MATERIAL_TYPE.OTHER] || [], 'erpRdBudgetMaterialCostList', isChangeType),
|
|
|
|
|
rdBudgetTechConsultCostList: handleChangeTypeIds(groupedTechData[TECH_TYPE.TECH_CONSULT] || [], 'erpRdBudgetTechCostList', isChangeType),
|
|
|
|
|
rdBudgetExpertMeetingCostList: handleChangeTypeIds(groupedTechData[TECH_TYPE.EXPERT_MEETING] || [], 'erpRdBudgetTechCostList', isChangeType),
|
|
|
|
|
rdBudgetExpertCommCostList: handleChangeTypeIds(groupedTechData[TECH_TYPE.EXPERT_COMM] || [], 'erpRdBudgetTechCostList', isChangeType),
|
|
|
|
|
rdBudgetLaborCostList: handleChangeTypeIds(groupedLaborData[LABOR_TYPE.LABOR] || [], 'erpRdBudgetLaborCostList', isChangeType),
|
|
|
|
|
rdBudgetServiceCostList: handleChangeTypeIds(groupedLaborData[LABOR_TYPE.SERVICE] || [], 'erpRdBudgetLaborCostList', isChangeType),
|
|
|
|
|
rdBudgetLiteratureMaterialCostList: handleChangeTypeIds(
|
|
|
|
|
groupedLiteratureData[LITERATURE_TYPE.MATERIAL] || [],
|
|
|
|
|
'erpRdBudgetLiteratureCostList',
|
|
|
|
|
isChangeType
|
|
|
|
|
),
|
|
|
|
|
rdBudgetLiteratureSoftwareCostList: handleChangeTypeIds(
|
|
|
|
|
groupedLiteratureData[LITERATURE_TYPE.SOFTWARE] || [],
|
|
|
|
|
'erpRdBudgetLiteratureCostList',
|
|
|
|
|
isChangeType
|
|
|
|
|
),
|
|
|
|
|
rdBudgetLiteratureRetrievalCostList: handleChangeTypeIds(
|
|
|
|
|
groupedLiteratureData[LITERATURE_TYPE.DOCUMENT] || [],
|
|
|
|
|
'erpRdBudgetLiteratureCostList',
|
|
|
|
|
isChangeType
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
await nextTick();
|
|
|
|
|
|
|
|
|
|
assignRdDataToComponents(data, categorizedData, isChangeType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleMarketCategoryData(data: any) {
|
|
|
|
|
const isChangeType = routeParams.value.changeFlag === '1';
|
|
|
|
|
|
|
|
|
|
// 只有在非变更类型时才初始化原始数据
|
|
|
|
|
if (!isChangeType) {
|
|
|
|
|
initOriginalMarketData(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理所有列表数据
|
|
|
|
|
const processedLists = {
|
|
|
|
|
materialCostList: handleChangeTypeIds(data.erpBudgetMaterialCostList, 'erpBudgetMaterialCostList', isChangeType),
|
|
|
|
|
laborCostList: handleChangeTypeIds(data.erpBudgetLaborCostList, 'erpBudgetLaborCostList', isChangeType),
|
|
|
|
|
installCostList: handleChangeTypeIds(data.erpBudgetInstallCostList, 'erpBudgetInstallCostList', isChangeType),
|
|
|
|
|
travelCostList: handleChangeTypeIds(data.erpBudgetTravelCostList, 'erpBudgetTravelCostList', isChangeType),
|
|
|
|
|
otherCostList: handleChangeTypeIds(data.erpBudgetOtherCostList, 'erpBudgetOtherCostList', isChangeType),
|
|
|
|
|
detailList: handleChangeTypeIds(data.erpBudgetDetailList, 'erpBudgetDetailList', isChangeType)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
await nextTick();
|
|
|
|
|
|
|
|
|
|
assignMarketDataToComponents(data, processedLists, isChangeType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据字段名获取主键字段
|
|
|
|
|
function getPrimaryKeyField(listName: string): string {
|
|
|
|
|
return PRIMARY_KEY_MAP[listName] || PRIMARY_KEY_MAP.default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理变更类型的数据:清空主键ID和相关字段
|
|
|
|
|
function handleChangeTypeIds(data: any[], listName: string, isChangeType: boolean): any[] {
|
|
|
|
|
if (!isChangeType || !data || data.length === 0) {
|
|
|
|
|
return data || [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const primaryKey = getPrimaryKeyField(listName);
|
|
|
|
|
|
|
|
|
|
return data.map((item) => {
|
|
|
|
|
return processFormDataForChange(item, primaryKey);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理表单数据的变更逻辑
|
|
|
|
|
function processFormDataForChange(data: any, primaryKey: string): any {
|
|
|
|
|
const processedData = { ...data };
|
|
|
|
|
|
|
|
|
|
// 删除主键字段
|
|
|
|
|
if (primaryKey in processedData) {
|
|
|
|
|
delete processedData[primaryKey];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 删除通用字段
|
|
|
|
|
COMMON_FIELDS_TO_REMOVE.forEach((field) => {
|
|
|
|
|
if (field in processedData) {
|
|
|
|
|
delete processedData[field];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 删除所有以"Id"结尾的字段(通常是外键)
|
|
|
|
|
// Object.keys(newItem).forEach((key) => {
|
|
|
|
|
// if (key.endsWith('Id') && key !== primaryKey) {
|
|
|
|
|
// delete newItem[key];
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
return processedData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function groupByField(array: any[], field: string): Record<string, any[]> {
|
|
|
|
|
if (!array) return {};
|
|
|
|
|
|
|
|
|
|
return array.reduce((acc, item) => {
|
|
|
|
|
const key = item[field];
|
|
|
|
|
if (!acc[key]) {
|
|
|
|
|
acc[key] = [];
|
|
|
|
|
}
|
|
|
|
|
acc[key].push(item);
|
|
|
|
|
return acc;
|
|
|
|
|
}, {});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function initOriginalRdData(data: any) {
|
|
|
|
|
// 只保存原始数据,不处理变更逻辑
|
|
|
|
|
oriRdBudgetEquipmentCostList.value = deepClone(data.erpRdBudgetEquipmentCostList);
|
|
|
|
|
oriRdBudgetMaterialCostList.value = deepClone(data.erpRdBudgetMaterialCostList);
|
|
|
|
|
oriRdBudgetTravelCostList.value = deepClone(data.erpRdBudgetTravelCostList);
|
|
|
|
|
oriRdBudgetMeetingCostList.value = deepClone(data.erpRdBudgetMeetingCostList);
|
|
|
|
|
oriRdBudgetExchangeCostList.value = deepClone(data.erpRdBudgetExchangeCostList);
|
|
|
|
|
oriRdBudgetTestingCostList.value = deepClone(data.erpRdBudgetTestingCostList);
|
|
|
|
|
oriRdBudgetOtherCostList.value = deepClone(data.erpRdBudgetOtherCostList);
|
|
|
|
|
|
|
|
|
|
// 处理分组后的数据
|
|
|
|
|
if (data.erpRdBudgetTechCostList) {
|
|
|
|
|
const groupedTechData = groupByField(data.erpRdBudgetTechCostList, 'techType');
|
|
|
|
|
oriRdBudgetTechConsultCostList.value = deepClone(groupedTechData[TECH_TYPE.TECH_CONSULT] || []);
|
|
|
|
|
oriRdBudgetExpertMeetingCostList.value = deepClone(groupedTechData[TECH_TYPE.EXPERT_MEETING] || []);
|
|
|
|
|
oriRdBudgetExpertCommCostList.value = deepClone(groupedTechData[TECH_TYPE.EXPERT_COMM] || []);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data.erpRdBudgetLaborCostList) {
|
|
|
|
|
const groupedLaborData = groupByField(data.erpRdBudgetLaborCostList, 'laborType');
|
|
|
|
|
oriRdBudgetLaborCostList.value = deepClone(groupedLaborData[LABOR_TYPE.LABOR] || []);
|
|
|
|
|
oriRdBudgetServiceCostList.value = deepClone(groupedLaborData[LABOR_TYPE.SERVICE] || []);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data.erpRdBudgetLiteratureCostList) {
|
|
|
|
|
const groupedLiteratureData = groupByField(data.erpRdBudgetLiteratureCostList, 'literatureType');
|
|
|
|
|
oriRdBudgetLiteratureMaterialCostList.value = deepClone(groupedLiteratureData[LITERATURE_TYPE.MATERIAL] || []);
|
|
|
|
|
oriRdBudgetLiteratureSofwareCostList.value = deepClone(groupedLiteratureData[LITERATURE_TYPE.SOFTWARE] || []);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 修改 initOriginalMarketData 函数,移除 isChangeType 参数
|
|
|
|
|
function initOriginalMarketData(data: any) {
|
|
|
|
|
// 只保存原始数据,不处理变更逻辑
|
|
|
|
|
oriBudgetMaterialCostList.value = deepClone(data.erpBudgetMaterialCostList);
|
|
|
|
|
oriBudgetLaborCostList.value = deepClone(data.erpBudgetLaborCostList);
|
|
|
|
|
oriBudgetInstallCostList.value = deepClone(data.erpBudgetInstallCostList);
|
|
|
|
|
oriBudgetTravelCostList.value = deepClone(data.erpBudgetTravelCostList);
|
|
|
|
|
oriBudgetOtherCostList.value = deepClone(data.erpBudgetOtherCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 研发数据赋值到组件(保持不变)
|
|
|
|
|
function assignRdDataToComponents(data: any, categorizedData: any, isChangeType: boolean) {
|
|
|
|
|
if (!rdBudgetTableRef.value) return;
|
|
|
|
|
|
|
|
|
|
// 处理基础表单数据 - 如果是变更类型,清空预算ID
|
|
|
|
|
const formData = isChangeType ? processFormDataForChange(data, 'budgetId') : data;
|
|
|
|
|
Object.assign(rdBudgetTableRef.value.rdBudgetInfoForm, formData);
|
|
|
|
|
Object.assign(rdBudgetTableRef.value.footerForm, formData);
|
|
|
|
|
|
|
|
|
|
// 处理预算明细数据
|
|
|
|
|
const budgetDetailList = isChangeType
|
|
|
|
|
? handleChangeTypeIds(data.erpBudgetDetailList, 'erpBudgetDetailList', true)
|
|
|
|
|
: deepClone(data.erpBudgetDetailList || []);
|
|
|
|
|
|
|
|
|
|
// 预算明细数据
|
|
|
|
|
if (rdBudgetTableRef.value.budgetDetailData) {
|
|
|
|
|
rdBudgetTableRef.value.budgetDetailData = budgetDetailList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设备费数据 - 如果是变更类型,直接从 categorizedData 获取;否则从 ori 获取
|
|
|
|
|
const equipmentData = isChangeType
|
|
|
|
|
? handleChangeTypeIds(data.erpRdBudgetEquipmentCostList, 'erpRdBudgetEquipmentCostList', true)
|
|
|
|
|
: oriRdBudgetEquipmentCostList.value;
|
|
|
|
|
|
|
|
|
|
if (rdEquipmentCostRef.value?.equipmentData) {
|
|
|
|
|
rdEquipmentCostRef.value.equipmentData = deepClone(equipmentData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 材料费数据
|
|
|
|
|
if (rdMaterialCostRef.value) {
|
|
|
|
|
// 主要材料
|
|
|
|
|
if (rdMaterialCostRef.value.materialData) {
|
|
|
|
|
rdMaterialCostRef.value.materialData = deepClone(categorizedData.rdBudgetMainMaterialCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 其他材料(单个对象)
|
|
|
|
|
if (categorizedData.rdBudgetOtherMaterialCostList.length > 0) {
|
|
|
|
|
rdMaterialCostRef.value.otherMaterial = deepClone(categorizedData.rdBudgetOtherMaterialCostList[0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 差旅/会议/交流费数据
|
|
|
|
|
if (rdTravelMeetingExchangeRef.value) {
|
|
|
|
|
// 差旅费
|
|
|
|
|
const travelData = isChangeType
|
|
|
|
|
? handleChangeTypeIds(data.erpRdBudgetTravelCostList, 'erpRdBudgetTravelCostList', true)
|
|
|
|
|
: oriRdBudgetTravelCostList.value;
|
|
|
|
|
|
|
|
|
|
if (rdTravelMeetingExchangeRef.value.travelList) {
|
|
|
|
|
rdTravelMeetingExchangeRef.value.travelList = deepClone(travelData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 会议费
|
|
|
|
|
const meetingData = isChangeType
|
|
|
|
|
? handleChangeTypeIds(data.erpRdBudgetMeetingCostList, 'erpRdBudgetMeetingCostList', true)
|
|
|
|
|
: oriRdBudgetMeetingCostList.value;
|
|
|
|
|
|
|
|
|
|
if (rdTravelMeetingExchangeRef.value.meetingList) {
|
|
|
|
|
rdTravelMeetingExchangeRef.value.meetingList = deepClone(meetingData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 交流费
|
|
|
|
|
const exchangeData = isChangeType
|
|
|
|
|
? handleChangeTypeIds(data.erpRdBudgetExchangeCostList, 'erpRdBudgetExchangeCostList', true)
|
|
|
|
|
: oriRdBudgetExchangeCostList.value;
|
|
|
|
|
|
|
|
|
|
if (rdTravelMeetingExchangeRef.value.exchangeList) {
|
|
|
|
|
rdTravelMeetingExchangeRef.value.exchangeList = deepClone(exchangeData);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 劳务/服务费数据
|
|
|
|
|
if (rdLaborServiceRef.value) {
|
|
|
|
|
// 技术咨询费
|
|
|
|
|
if (rdLaborServiceRef.value.techConsultList) {
|
|
|
|
|
rdLaborServiceRef.value.techConsultList = deepClone(categorizedData.rdBudgetTechConsultCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 专家咨询会议形式
|
|
|
|
|
if (rdLaborServiceRef.value.expertMeetingList) {
|
|
|
|
|
rdLaborServiceRef.value.expertMeetingList = deepClone(categorizedData.rdBudgetExpertMeetingCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 专家咨询通讯形式
|
|
|
|
|
if (rdLaborServiceRef.value.expertCommList) {
|
|
|
|
|
rdLaborServiceRef.value.expertCommList = deepClone(categorizedData.rdBudgetExpertCommCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 人工费
|
|
|
|
|
if (rdLaborServiceRef.value.laborList) {
|
|
|
|
|
rdLaborServiceRef.value.laborList = deepClone(categorizedData.rdBudgetLaborCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 劳务费
|
|
|
|
|
if (rdLaborServiceRef.value.serviceList) {
|
|
|
|
|
rdLaborServiceRef.value.serviceList = deepClone(categorizedData.rdBudgetServiceCostList);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 资料/软件/文献检索费数据
|
|
|
|
|
if (rdLiteratureCostRef.value) {
|
|
|
|
|
// 资料费
|
|
|
|
|
if (rdLiteratureCostRef.value.materialsList) {
|
|
|
|
|
rdLiteratureCostRef.value.materialsList = deepClone(categorizedData.rdBudgetLiteratureMaterialCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 专用软件购买费
|
|
|
|
|
if (rdLiteratureCostRef.value.softwareList) {
|
|
|
|
|
rdLiteratureCostRef.value.softwareList = deepClone(categorizedData.rdBudgetLiteratureSoftwareCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 文献检索费(单个对象)
|
|
|
|
|
if (rdLiteratureCostRef.value.literatureRetrieval && categorizedData.rdBudgetLiteratureRetrievalCostList.length > 0) {
|
|
|
|
|
rdLiteratureCostRef.value.literatureRetrieval = deepClone(categorizedData.rdBudgetLiteratureRetrievalCostList[0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 测试/化验/加工费数据
|
|
|
|
|
const testingData = isChangeType
|
|
|
|
|
? handleChangeTypeIds(data.erpRdBudgetTestingCostList, 'erpRdBudgetTestingCostList', true)
|
|
|
|
|
: oriRdBudgetTestingCostList.value;
|
|
|
|
|
|
|
|
|
|
if (rdTestingCostRef.value?.testData) {
|
|
|
|
|
rdTestingCostRef.value.testData = deepClone(testingData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 其他费用数据
|
|
|
|
|
const otherData = isChangeType
|
|
|
|
|
? handleChangeTypeIds(data.erpRdBudgetOtherCostList, 'erpRdBudgetOtherCostList', true)
|
|
|
|
|
: oriRdBudgetOtherCostList.value;
|
|
|
|
|
|
|
|
|
|
if (rdOtherCostRef.value?.otherCostList) {
|
|
|
|
|
rdOtherCostRef.value.otherCostList = deepClone(otherData);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 修改 assignMarketDataToComponents 函数,增加 isChangeType 参数
|
|
|
|
|
function assignMarketDataToComponents(data: any, processedLists: any, isChangeType: boolean) {
|
|
|
|
|
if (!budgetTableRef.value) return;
|
|
|
|
|
|
|
|
|
|
// 基础表单数据
|
|
|
|
|
const formData = isChangeType ? processFormDataForChange(data, 'budgetId') : data;
|
|
|
|
|
Object.assign(budgetTableRef.value.budgetForm, formData);
|
|
|
|
|
|
|
|
|
|
// 预算明细数据
|
|
|
|
|
if (budgetTableRef.value.budgetDetailData) {
|
|
|
|
|
budgetTableRef.value.budgetDetailData = deepClone(processedLists.detailList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 材料费数据
|
|
|
|
|
if (materialCostRef.value?.budgetMaterialCostList) {
|
|
|
|
|
materialCostRef.value.budgetMaterialCostList = deepClone(processedLists.materialCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 人工费数据
|
|
|
|
|
if (laborCostRef.value?.budgetLaborCostList) {
|
|
|
|
|
laborCostRef.value.budgetLaborCostList = deepClone(processedLists.laborCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 安装费数据
|
|
|
|
|
if (installationCostRef.value?.installCostList) {
|
|
|
|
|
installationCostRef.value.installCostList = deepClone(processedLists.installCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 差旅费数据
|
|
|
|
|
if (travelCostRef.value?.travelCostList) {
|
|
|
|
|
travelCostRef.value.travelCostList = deepClone(processedLists.travelCostList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 其他费用数据
|
|
|
|
|
if (otherCostRef.value?.otherCostList) {
|
|
|
|
|
otherCostRef.value.otherCostList = deepClone(processedLists.otherCostList);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function deepClone<T>(obj: T): T {
|
|
|
|
|
return cloneDeep(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
|
|
|
|
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
|
|
|
|
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
|
|
|
|
|