|
|
<template>
|
|
|
<div class="project-budget-container">
|
|
|
<!-- 审批按钮组件 -->
|
|
|
<approvalButton
|
|
|
@submitForm="handleSave"
|
|
|
@approvalVerifyOpen="approvalVerifyOpen"
|
|
|
@handleApprovalRecord="handleApprovalRecord"
|
|
|
:buttonLoading="buttonLoading"
|
|
|
:id="searchForm.budgetId"
|
|
|
:status="searchForm.flowStatus"
|
|
|
:pageType="routeParams.type"
|
|
|
:mode="false"
|
|
|
/>
|
|
|
<!-- 顶部表单区域 -->
|
|
|
<el-card class="mb-6">
|
|
|
<el-form :model="searchForm" label-width="80px">
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="6">
|
|
|
<el-form-item label="项目号">
|
|
|
<el-input v-model="searchForm.projectCode" placeholder="请选择项目" readonly @click="showProjectSelectDialog" suffix-icon="Search">
|
|
|
</el-input>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="6">
|
|
|
<el-form-item label="项目名称">
|
|
|
<el-input v-model="searchForm.projectName" placeholder="请选择项目后自动填充" disabled />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<!-- <el-col :span="12" class="text-right">-->
|
|
|
<!-- <el-button type="primary" @click="exportBudget" size="default">-->
|
|
|
<!-- <el-icon><Download /></el-icon>-->
|
|
|
<!-- 导出-->
|
|
|
<!-- </el-button>-->
|
|
|
<!-- </el-col>-->
|
|
|
</el-row>
|
|
|
</el-form>
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 中间标签页区域 -->
|
|
|
<!-- 研发项目预算 -->
|
|
|
<el-card class="mb-6" v-if="searchForm.projectCategory === PROJECT_CATEGORY.RD || searchForm.projectCategory === PROJECT_CATEGORY.PRE_PRODUCTION">
|
|
|
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
|
|
<el-tab-pane label="预算表" name="budgetTable">
|
|
|
<RdBudgetTable
|
|
|
ref="rdBudgetTableRef"
|
|
|
:projectId="searchForm.projectId"
|
|
|
:costData="costData"
|
|
|
:projectInfo="projectInfo"
|
|
|
:userList="userList"
|
|
|
/>
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="设备费" name="equipmentCost">
|
|
|
<RdEquipmentCost ref="rdEquipmentCostRef" :projectId="searchForm.projectId" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="材料费" name="materialCost">
|
|
|
<RdMaterialCost ref="rdMaterialCostRef" :projectId="searchForm.projectId" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="会议差旅交流" name="travelMeetingExchange">
|
|
|
<RdTravelMeetingExchange ref="rdTravelMeetingExchangeRef" :projectId="searchForm.projectId" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="人工劳务咨询" name="laborService">
|
|
|
<RdLaborService ref="rdLaborServiceRef" :projectId="searchForm.projectId" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="资料文献费" name="literatureCost">
|
|
|
<RdLiteratureCost ref="rdLiteratureCostRef" :projectId="searchForm.projectId" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="测试化验费" name="testingCost">
|
|
|
<RdTestingCost ref="rdTestingCostRef" :projectId="searchForm.projectId" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="其他" name="otherCost">
|
|
|
<RdOtherCost ref="rdOtherCostRef" :projectId="searchForm.projectId" />
|
|
|
</el-tab-pane>
|
|
|
</el-tabs>
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 市场项目预算 -->
|
|
|
<el-card
|
|
|
class="mb-6"
|
|
|
shadow="never"
|
|
|
v-if="searchForm.projectCategory === PROJECT_CATEGORY.MARKET || searchForm.projectCategory === PROJECT_CATEGORY.MARKET_PART"
|
|
|
>
|
|
|
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
|
|
<el-tab-pane label="预算表" name="budget">
|
|
|
<BudgetTable ref="budgetTableRef" :projectInfo="projectInfo" :userList="userList" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="材料费" name="material">
|
|
|
<MaterialCost ref="materialCostRef" :budgetId="budgetId" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="人工费" name="labor">
|
|
|
<LaborCost ref="laborCostRef" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="安装费" name="installation">
|
|
|
<InstallationCost ref="installationCostRef" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="差旅费" name="travel">
|
|
|
<TravelCost ref="travelCostRef" />
|
|
|
</el-tab-pane>
|
|
|
<el-tab-pane label="其他" name="other">
|
|
|
<OtherCost ref="otherCostRef" />
|
|
|
</el-tab-pane>
|
|
|
</el-tabs>
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 项目选择弹窗 -->
|
|
|
<el-dialog v-model="projectSelectDialogVisible" title="选择项目" width="880px">
|
|
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
|
|
<div class="mb-[10px]">
|
|
|
<el-card shadow="hover">
|
|
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="80px">
|
|
|
<el-form-item label="项目号" prop="projectCode">
|
|
|
<el-input v-model="queryParams.projectCode" placeholder="请输入项目编号" clearable @keyup.enter="handleQuery" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="项目名称" prop="projectName">
|
|
|
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable @keyup.enter="handleQuery" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="项目状态" prop="projectStatus">
|
|
|
<el-select v-model="queryParams.projectStatus" placeholder="请选择项目状态" clearable>
|
|
|
<el-option v-for="dict in project_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item>
|
|
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
</el-card>
|
|
|
</div>
|
|
|
</transition>
|
|
|
|
|
|
<el-table :data="projectList" border @row-click="selectProject" style="width: 100%" v-loading="projectLoading" highlight-current-row>
|
|
|
<el-table-column prop="projectCode" label="项目号" width="150" />
|
|
|
<el-table-column prop="projectName" label="项目名称" min-width="180" />
|
|
|
<el-table-column prop="businessDirection" label="业务方向" width="120">
|
|
|
<template #default="scope">
|
|
|
<dict-tag :options="business_direction" :value="scope.row.businessDirection" />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="projectCategory" label="项目类别" width="160">
|
|
|
<template #default="scope">
|
|
|
<dict-tag :options="project_category" :value="scope.row.projectCategory" />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="projectStatus" label="项目状态" width="100">
|
|
|
<template #default="scope">
|
|
|
<dict-tag :options="project_status" :value="scope.row.projectStatus" />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
|
|
|
<div class="mt-4 flex justify-between items-center">
|
|
|
<pagination
|
|
|
v-show="projectTotal > 0"
|
|
|
:total="projectTotal"
|
|
|
v-model:page="queryParams.pageNum"
|
|
|
v-model:limit="queryParams.pageSize"
|
|
|
@pagination="getProjectList"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
<template #footer>
|
|
|
<span class="dialog-footer">
|
|
|
<el-button @click="projectSelectDialogVisible = false">取消</el-button>
|
|
|
<el-button type="primary" @click="confirmProjectSelection">确定</el-button>
|
|
|
</span>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
|
|
|
<!-- 提交审批组件 -->
|
|
|
<submitVerify ref="submitVerifyRef" @submit-callback="submitCallback" />
|
|
|
<!-- 审批记录 -->
|
|
|
<approvalRecord ref="approvalRecordRef" />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<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 { ProjectInfoVO, ProjectInfoQuery } from '@/api/oa/erp/projectInfo/types';
|
|
|
import { getUserList } from '@/api/system/user';
|
|
|
|
|
|
import { deepEqualArrays } from '@/utils/objHandle';
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
const { business_direction, project_status, project_category } = toRefs<any>(
|
|
|
proxy?.useDict('business_direction', 'project_status', 'project_category')
|
|
|
);
|
|
|
|
|
|
//研发项目tab
|
|
|
import RdBudgetTable from './rd/BudgetTable.vue';
|
|
|
import RdEquipmentCost from './rd/EquipmentCost.vue';
|
|
|
import RdMaterialCost from './rd/MaterialCost.vue';
|
|
|
import RdTravelMeetingExchange from './rd/TravelMeetingExchange.vue';
|
|
|
import RdLaborService from './rd/LaborService.vue';
|
|
|
import RdLiteratureCost from './rd/LiteratureCost.vue';
|
|
|
import RdTestingCost from './rd/TestingCost.vue';
|
|
|
import RdOtherCost from './rd/OtherCost.vue';
|
|
|
|
|
|
//市场项目tab
|
|
|
import BudgetTable from './market/BudgetTable.vue';
|
|
|
import MaterialCost from './market/MaterialCost.vue';
|
|
|
import LaborCost from './market/LaborCost.vue';
|
|
|
import InstallationCost from './market/InstallationCost.vue';
|
|
|
import TravelCost from './market/TravelCost.vue';
|
|
|
import OtherCost from './market/OtherCost.vue';
|
|
|
|
|
|
// 定义成本数据类型
|
|
|
interface CostData {
|
|
|
equipmentCost: number;
|
|
|
materialCost: number;
|
|
|
travelCost: number;
|
|
|
meetingCost: number;
|
|
|
internationalExchangeCost: number;
|
|
|
consultingDevelopmentCost: number;
|
|
|
laborCost: number;
|
|
|
serviceCost: number;
|
|
|
literatureCost: number;
|
|
|
testingCost: number;
|
|
|
otherCost: number;
|
|
|
}
|
|
|
|
|
|
// 研发项目预算tab组件引用
|
|
|
const rdBudgetTableRef = ref();
|
|
|
const rdEquipmentCostRef = ref();
|
|
|
const rdMaterialCostRef = ref();
|
|
|
const rdTravelMeetingExchangeRef = ref();
|
|
|
const rdLaborServiceRef = ref();
|
|
|
const rdLiteratureCostRef = ref();
|
|
|
const rdTestingCostRef = ref();
|
|
|
const rdOtherCostRef = ref();
|
|
|
|
|
|
// 市场项目预算tab组件引用
|
|
|
const budgetTableRef = ref();
|
|
|
const materialCostRef = ref();
|
|
|
const laborCostRef = ref();
|
|
|
const installationCostRef = ref();
|
|
|
const travelCostRef = ref();
|
|
|
const otherCostRef = ref();
|
|
|
|
|
|
const oriBudgetMaterialCostList = ref<budgetMaterialCostVO[]>([]);
|
|
|
const oriBudgetLaborCostList = ref<budgetLaborCostVO[]>([]);
|
|
|
const oriBudgetInstallCostList = ref<budgetInstallCostVO[]>([]);
|
|
|
const oriBudgetTravelCostList = ref<budgetTravelCostVO[]>([]);
|
|
|
const oriBudgetOtherCostList = ref<budgetOtherCostVO[]>([]);
|
|
|
|
|
|
const oriRdBudgetEquipmentCostList = ref<rdBudgetEquipmentCostVO[]>([]);
|
|
|
const oriRdBudgetMaterialCostList = ref<rdBudgetMaterialCostVO[]>([]);
|
|
|
const oriRdBudgetTravelCostList = ref<rdBudgetTravelCostVO[]>([]);
|
|
|
const oriRdBudgetMeetingCostList = ref<rdBudgetMeetingCostVO[]>([]);
|
|
|
const oriRdBudgetExchangeCostList = ref<rdBudgetExchangeCostVO[]>([]);
|
|
|
const oriRdBudgetTechConsultCostList = ref<rdBudgetTechCostVO[]>([]); //技术咨询
|
|
|
const oriRdBudgetExpertMeetingCostList = ref<rdBudgetTechCostVO[]>([]); //专家咨询会议形式
|
|
|
const oriRdBudgetExpertCommCostList = ref<rdBudgetTechCostVO[]>([]); //专家咨询通讯形式
|
|
|
const oriRdBudgetLaborCostList = ref<rdBudgetLaborCostVO[]>([]); //人工费
|
|
|
const oriRdBudgetServiceCostList = ref<rdBudgetLaborCostVO[]>([]); //劳务费
|
|
|
const oriRdBudgetLiteratureMaterialCostList = ref<rdBudgetLiteratureCostVO[]>([]); //资料费
|
|
|
const oriRdBudgetLiteratureSofwareCostList = ref<rdBudgetLiteratureCostVO[]>([]); //专用软件购买费
|
|
|
const oriRdBudgetTestingCostList = ref<rdBudgetTestingCostVO[]>([]);
|
|
|
const oriRdBudgetOtherCostList = ref<rdBudgetOtherCostVO[]>([]);
|
|
|
|
|
|
const PROJECT_CATEGORY = reactive({
|
|
|
MARKET: '1', //销售(实施、物流)
|
|
|
MARKET_PART: '2', //销售(备件)
|
|
|
RD: '3', //研发
|
|
|
PRE_PRODUCTION: '4' //预投
|
|
|
});
|
|
|
|
|
|
const BUSINESS_STATUS = reactive({
|
|
|
DRAFT: '1', //暂存
|
|
|
WAITING: '2', //审批中
|
|
|
AVAILABLE: '3' //可用
|
|
|
});
|
|
|
|
|
|
const MATERIAL_TYPE = {
|
|
|
MAIN: '1', //主要材料费
|
|
|
OTHER: '2' //其他材料费
|
|
|
};
|
|
|
|
|
|
const TECH_TYPE = reactive({
|
|
|
TECH_CONSULT: '1', //技术咨询开发
|
|
|
EXPERT_MEETING: '2', //专家咨询-会议形式
|
|
|
EXPERT_COMM: '3' //专家咨询-通讯形式
|
|
|
});
|
|
|
|
|
|
const LABOR_TYPE = reactive({
|
|
|
LABOR: '1', //人工费
|
|
|
SERVICE: '2' //劳务费
|
|
|
});
|
|
|
|
|
|
const LITERATURE_TYPE = {
|
|
|
MATERIAL: '1', //资料费
|
|
|
DOCUMENT: '2', //文件检索费
|
|
|
SOFTWARE: '3' //专用软件购买费
|
|
|
};
|
|
|
|
|
|
// 响应式数据
|
|
|
// 将activeTab从computed改为ref,使其可变
|
|
|
const activeTab = ref('budget');
|
|
|
const buttonLoading = ref(false);
|
|
|
|
|
|
const searchForm = reactive({
|
|
|
budgetId: undefined,
|
|
|
projectId: '',
|
|
|
projectName: '',
|
|
|
projectCode: '',
|
|
|
projectCategory: '',
|
|
|
flowStatus: ''
|
|
|
});
|
|
|
|
|
|
// 监听项目类别变化,更新默认标签页
|
|
|
watch(
|
|
|
() => searchForm.projectCategory,
|
|
|
(newCategory) => {
|
|
|
if (newCategory === PROJECT_CATEGORY.RD || newCategory === PROJECT_CATEGORY.PRE_PRODUCTION) {
|
|
|
activeTab.value = 'budgetTable';
|
|
|
} else if (newCategory === PROJECT_CATEGORY.MARKET || newCategory === PROJECT_CATEGORY.MARKET_PART) {
|
|
|
activeTab.value = 'budget';
|
|
|
}
|
|
|
}
|
|
|
);
|
|
|
|
|
|
// 项目信息
|
|
|
const projectInfo = reactive<ProjectInfoVO>({
|
|
|
projectName: '',
|
|
|
projectCode: '',
|
|
|
projectCategory: ''
|
|
|
});
|
|
|
|
|
|
// 研发预算成本数据
|
|
|
const costData = reactive<CostData>({
|
|
|
equipmentCost: 0,
|
|
|
materialCost: 0,
|
|
|
travelCost: 0,
|
|
|
meetingCost: 0,
|
|
|
internationalExchangeCost: 0,
|
|
|
consultingDevelopmentCost: 0,
|
|
|
laborCost: 0,
|
|
|
serviceCost: 0,
|
|
|
literatureCost: 0,
|
|
|
testingCost: 0,
|
|
|
otherCost: 0
|
|
|
});
|
|
|
|
|
|
const userList = ref<UserVO[]>([]);
|
|
|
/** 查询用户列表 */
|
|
|
const getUsers = async () => {
|
|
|
const res = await getUserList({});
|
|
|
userList.value = res.data;
|
|
|
};
|
|
|
|
|
|
// 项目选择弹窗相关
|
|
|
const projectSelectDialogVisible = ref(false);
|
|
|
const selectedProject = ref<ProjectInfoVO | null>(null);
|
|
|
const projectList = ref<ProjectInfoVO[]>([]);
|
|
|
const projectTotal = ref(0);
|
|
|
const projectLoading = ref(true);
|
|
|
const data = reactive<{ queryParams: ProjectInfoQuery }>({
|
|
|
queryParams: {
|
|
|
pageNum: 1,
|
|
|
pageSize: 10,
|
|
|
contractFlag: undefined,
|
|
|
projectCode: undefined,
|
|
|
projectName: undefined,
|
|
|
businessDirection: undefined,
|
|
|
projectCategory: undefined,
|
|
|
spareFlag: undefined,
|
|
|
projectTypeId: undefined,
|
|
|
paymentMethod: undefined,
|
|
|
deptId: undefined,
|
|
|
managerId: undefined,
|
|
|
chargeId: undefined,
|
|
|
deputyId: undefined,
|
|
|
peopleId: undefined,
|
|
|
amount: undefined,
|
|
|
projectStatus: undefined,
|
|
|
flowStatus: undefined,
|
|
|
sortOrder: undefined,
|
|
|
contractId: undefined,
|
|
|
activeFlag: undefined,
|
|
|
params: {}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
const { queryParams } = toRefs(data);
|
|
|
|
|
|
const queryFormRef = ref<ElFormInstance>();
|
|
|
|
|
|
/** 搜索按钮操作 */
|
|
|
const handleQuery = () => {
|
|
|
queryParams.value.pageNum = 1;
|
|
|
getProjectList();
|
|
|
};
|
|
|
|
|
|
/** 重置按钮操作 */
|
|
|
const resetQuery = () => {
|
|
|
queryFormRef.value?.resetFields();
|
|
|
handleQuery();
|
|
|
};
|
|
|
|
|
|
/** 查询项目信息列表 */
|
|
|
const getProjectList = async () => {
|
|
|
projectLoading.value = true;
|
|
|
const res = await listProjectInfo(queryParams.value);
|
|
|
console.log(searchForm);
|
|
|
projectList.value = res.rows;
|
|
|
projectTotal.value = res.total;
|
|
|
projectLoading.value = false;
|
|
|
};
|
|
|
|
|
|
// 标签页切换处理
|
|
|
const handleTabClick = (tab: any) => {
|
|
|
activeTab.value = tab.paneName;
|
|
|
if ((budgetId.value && routeParams.value.type === 'update') || !budgetId.value) {
|
|
|
if (searchForm.projectCategory === PROJECT_CATEGORY.RD || searchForm.projectCategory === PROJECT_CATEGORY.PRE_PRODUCTION) {
|
|
|
updateRdBudgetTable();
|
|
|
} else if (searchForm.projectCategory === PROJECT_CATEGORY.MARKET || searchForm.projectCategory === PROJECT_CATEGORY.MARKET_PART) {
|
|
|
updateBudgetTable();
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 显示项目选择弹窗
|
|
|
const showProjectSelectDialog = () => {
|
|
|
projectSelectDialogVisible.value = true;
|
|
|
selectedProject.value = undefined;
|
|
|
getProjectList();
|
|
|
};
|
|
|
|
|
|
// 选择项目
|
|
|
const selectProject = (row: ProjectInfoVO) => {
|
|
|
selectedProject.value = row;
|
|
|
};
|
|
|
|
|
|
// 确认项目选择
|
|
|
const confirmProjectSelection = () => {
|
|
|
if (!selectedProject.value) {
|
|
|
ElMessage.warning('请选择一个项目');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 更新项目信息
|
|
|
searchForm.projectId = selectedProject.value.projectId;
|
|
|
searchForm.projectName = selectedProject.value.projectName;
|
|
|
searchForm.projectCode = selectedProject.value.projectCode;
|
|
|
searchForm.projectCategory = selectedProject.value.projectCategory;
|
|
|
|
|
|
projectInfo.projectId = selectedProject.value.projectId;
|
|
|
projectInfo.projectName = selectedProject.value.projectName;
|
|
|
projectInfo.projectCode = selectedProject.value.projectCode;
|
|
|
projectInfo.projectCategory = selectedProject.value.projectCategory;
|
|
|
|
|
|
projectSelectDialogVisible.value = false;
|
|
|
// ElMessage.success('项目选择成功');
|
|
|
|
|
|
// 重置所有成本数据
|
|
|
Object.keys(costData).forEach((key) => {
|
|
|
costData[key as keyof CostData] = 0;
|
|
|
});
|
|
|
};
|
|
|
|
|
|
// 设备费更新处理
|
|
|
const handleEquipmentCostUpdate = (data: { equipmentCost: number }) => {
|
|
|
costData.equipmentCost = data.equipmentCost;
|
|
|
if (rdBudgetTableRef.value) {
|
|
|
rdBudgetTableRef.value.updateCostData(costData);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 材料费更新处理
|
|
|
const handleMaterialCostUpdate = (data: { mainMaterialCost: number; otherMaterialCost: number; totalAmount: number }) => {
|
|
|
costData.materialCost = data.materialCost;
|
|
|
if (rdBudgetTableRef.value) {
|
|
|
rdBudgetTableRef.value.updateCostData(costData);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 会议差旅交流更新处理
|
|
|
const handleTravelMeetingExchangeUpdate = (data: { travelCost: number; meetingCost: number; internationalExchangeCost: number }) => {
|
|
|
costData.travelCost = data.travelCost;
|
|
|
costData.meetingCost = data.meetingCost;
|
|
|
costData.internationalExchangeCost = data.internationalExchangeCost;
|
|
|
if (rdBudgetTableRef.value) {
|
|
|
rdBudgetTableRef.value.updateCostData(costData);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 人工劳务咨询更新处理
|
|
|
const handleLaborServiceUpdate = (data: { techConsultTotal: number; laborTotal: number; serviceTotal: number }) => {
|
|
|
costData.consultingDevelopmentCost = data.techConsultTotal;
|
|
|
costData.laborCost = data.laborTotal;
|
|
|
costData.serviceCost = data.serviceTotal;
|
|
|
if (rdBudgetTableRef.value) {
|
|
|
rdBudgetTableRef.value.updateCostData(costData);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 资料文献费更新处理
|
|
|
const handleLiteratureCostUpdate = (data: { literatureCost: number }) => {
|
|
|
costData.literatureCost = data.literatureCost;
|
|
|
if (rdBudgetTableRef.value) {
|
|
|
rdBudgetTableRef.value.updateCostData(costData);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 测试化验费更新处理
|
|
|
const handleTestingCostUpdate = (data: { totalAmount: number }) => {
|
|
|
costData.testingCost = data.totalAmount;
|
|
|
if (rdBudgetTableRef.value) {
|
|
|
rdBudgetTableRef.value.updateCostData(costData);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 其他费用更新处理
|
|
|
const handleOtherCostUpdate = (data: { totalAmount: number }) => {
|
|
|
costData.otherCost = data.totalAmount;
|
|
|
if (rdBudgetTableRef.value) {
|
|
|
rdBudgetTableRef.value.updateCostData(costData);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 更新市场项目预算预算表数据
|
|
|
const updateBudgetTable = async () => {
|
|
|
if (!budgetTableRef.value) return;
|
|
|
|
|
|
// 获取各tab页的合计数据
|
|
|
const materialTotal = materialCostRef.value?.getTotalAmount() || { budgetAmount: 0, reducedAmount: 0 };
|
|
|
const laborTotal = laborCostRef.value?.getTotalAmount() || { budgetAmount: 0, reducedAmount: 0 };
|
|
|
const installationTotal = installationCostRef.value?.getTotalAmount() || { budgetAmount: 0, reducedAmount: 0 };
|
|
|
const travelTotal = travelCostRef.value?.getTotalAmount() || { budgetAmount: 0, reducedAmount: 0 };
|
|
|
const otherTotal = otherCostRef.value?.getTotalAmount() || { budgetAmount: 0, reducedAmount: 0 };
|
|
|
|
|
|
// 更新预算表,目前是按单位是万元传值,后续如果根据单位是元,则在此判断更新传的值
|
|
|
budgetTableRef.value.updateBudgetDetailData('材料费', materialTotal.budgetAmount / 10000, materialTotal.reducedAmount / 10000);
|
|
|
budgetTableRef.value.updateBudgetDetailData('人工费', laborTotal.budgetAmount / 10000, laborTotal.reducedAmount / 10000);
|
|
|
budgetTableRef.value.updateBudgetDetailData('安装费', installationTotal.budgetAmount / 10000, installationTotal.reducedAmount / 10000);
|
|
|
budgetTableRef.value.updateBudgetDetailData('差旅费', travelTotal.budgetAmount / 10000, travelTotal.reducedAmount / 10000);
|
|
|
budgetTableRef.value.updateBudgetDetailData('其他费用', otherTotal.budgetAmount / 10000, otherTotal.reducedAmount / 10000);
|
|
|
};
|
|
|
|
|
|
// 更新研发项目预算预算表数据
|
|
|
const updateRdBudgetTable = async () => {
|
|
|
// 获取各tab页的合计数据
|
|
|
const equipmentAmount = rdEquipmentCostRef.value?.getTotalAmount();
|
|
|
const equipmentTotal = equipmentAmount.equipmentTotal || 0;
|
|
|
const materialTotal = rdMaterialCostRef.value?.getTotalAmount() || 0;
|
|
|
const travelMeetingExchangeAmount = rdTravelMeetingExchangeRef.value?.getTravelMeetingExchangeAmount();
|
|
|
const travelTotal = travelMeetingExchangeAmount.travelSubtotalTotal || 0;
|
|
|
const meetingFeeTotal = travelMeetingExchangeAmount.meetingFeeTotal || 0;
|
|
|
const internationalSubtotalTotal = travelMeetingExchangeAmount.internationalSubtotalTotal || 0;
|
|
|
const laborAmount = rdLaborServiceRef.value?.getLaborAmount();
|
|
|
const techConsultTotal = laborAmount.techConsultTotal || 0;
|
|
|
const laborTotal = laborAmount.laborTotal || 0;
|
|
|
const serviceTotal = laborAmount.serviceTotal || 0;
|
|
|
const literatureCost = rdLiteratureCostRef.value?.getLiteratureCost() || 0;
|
|
|
const literatureTotal = literatureCost.literatureTotal || 0;
|
|
|
const testingCost = rdTestingCostRef.value?.getTestingAmount() || 0;
|
|
|
const testingTotal = testingCost.testingTotal || 0;
|
|
|
const otherCost = rdOtherCostRef.value?.getOtherCost() || 0;
|
|
|
const otherTotal = otherCost.otherTotal || 0;
|
|
|
|
|
|
// 更新预算表,目前是按单位是万元传值,后续如果根据单位是元,则在此判断更新传的值
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('设备费', equipmentTotal / 10000);
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('材料费', materialTotal / 10000);
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('差旅费', travelTotal / 10000);
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('会议费', meetingFeeTotal / 10000);
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('国际合作与交流费', internationalSubtotalTotal / 10000);
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('咨询开发费', techConsultTotal / 10000);
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('人工费', laborTotal / 10000);
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('劳务费', serviceTotal / 10000);
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('资料/文献费', literatureTotal / 10000);
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('测试化验费', testingTotal / 10000);
|
|
|
rdBudgetTableRef.value.updateRdBudgetDetailData('其他费用', otherTotal / 10000);
|
|
|
};
|
|
|
|
|
|
// 新增一个方法用于在tab切换时更新预算数据
|
|
|
const updateBudgetDataOnTabChange = () => {
|
|
|
nextTick(() => {
|
|
|
if (searchForm.projectCategory === PROJECT_CATEGORY.RD) {
|
|
|
// 确保调用更新方法时传递正确的参数
|
|
|
if (rdEquipmentCostRef.value?.getTotalAmount) {
|
|
|
handleEquipmentCostUpdate({ equipmentCost: rdEquipmentCostRef.value.getTotalAmount() });
|
|
|
}
|
|
|
if (rdMaterialCostRef.value?.getTotalAmount) {
|
|
|
const materialTotal = rdMaterialCostRef.value.getTotalAmount();
|
|
|
handleMaterialCostUpdate({
|
|
|
mainMaterialCost: materialTotal.mainMaterialCost || 0,
|
|
|
otherMaterialCost: materialTotal.otherMaterialCost || 0,
|
|
|
materialCost: (materialTotal.mainMaterialCost || 0) + (materialTotal.otherMaterialCost || 0)
|
|
|
});
|
|
|
}
|
|
|
// 其他方法类似处理...
|
|
|
} else if (searchForm.projectCategory === PROJECT_CATEGORY.MARKET) {
|
|
|
updateBudgetTable();
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
|
|
|
// 监听tab切换,更新预算表数据
|
|
|
// watch(activeTab, () => {
|
|
|
// updateBudgetDataOnTabChange();
|
|
|
// });
|
|
|
// 导出预算
|
|
|
const exportBudget = () => {
|
|
|
if (!searchForm.projectId) {
|
|
|
ElMessage.warning('请先选择项目');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
ElMessage.success('导出预算成功');
|
|
|
};
|
|
|
|
|
|
// 提取用户查找逻辑
|
|
|
const findUserName = (userList: any[], userId: number): string => {
|
|
|
const user = userList?.find((item) => item.userId === userId);
|
|
|
return user?.nickName || '';
|
|
|
};
|
|
|
|
|
|
// 提取数据比较和赋值逻辑
|
|
|
const assignIfChanged = (targetArray: any[], sourceArray: any[], originalArray: any[]): any[] => {
|
|
|
return !deepEqualArrays(originalArray, sourceArray) ? sourceArray || [] : [];
|
|
|
};
|
|
|
|
|
|
const handleSave = async (status: string, mode: boolean) => {
|
|
|
if (!searchForm.projectId) {
|
|
|
ElMessage.warning('请先选择项目');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
buttonLoading.value = true;
|
|
|
|
|
|
const isRdProject = [PROJECT_CATEGORY.RD, PROJECT_CATEGORY.PRE_PRODUCTION].includes(searchForm.projectCategory);
|
|
|
const isMarketProject = [PROJECT_CATEGORY.MARKET, PROJECT_CATEGORY.MARKET_PART].includes(searchForm.projectCategory);
|
|
|
|
|
|
let budgetForm: budgetInfoForm = {};
|
|
|
|
|
|
if (isRdProject) {
|
|
|
budgetForm = await processRdBudgetForm(status);
|
|
|
} else if (isMarketProject) {
|
|
|
budgetForm = await processMarketBudgetForm(status);
|
|
|
} else {
|
|
|
ElMessage.warning('不支持的预算类型');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 统一保存逻辑
|
|
|
const saveOperation = budgetForm.budgetId ? () => updateErpBudgetInfo(budgetForm) : () => addErpBudgetInfo(budgetForm);
|
|
|
|
|
|
await saveOperation();
|
|
|
|
|
|
ElMessage.success('操作成功');
|
|
|
handleSaveSuccess();
|
|
|
} catch (error) {
|
|
|
console.error('保存失败:', error);
|
|
|
ElMessage.error('保存失败');
|
|
|
} finally {
|
|
|
buttonLoading.value = false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 处理研发预算表单
|
|
|
const processRdBudgetForm = async (status: string): Promise<budgetInfoForm> => {
|
|
|
await updateRdBudgetTable();
|
|
|
|
|
|
const budgetDetailData = rdBudgetTableRef.value?.budgetDetailData || [];
|
|
|
const rdBudgetInfoForm = rdBudgetTableRef.value?.rdBudgetInfoForm || {};
|
|
|
const footerForm = rdBudgetTableRef.value?.footerForm || {};
|
|
|
|
|
|
// 合并表单数据
|
|
|
const budgetForm = {
|
|
|
...rdBudgetInfoForm,
|
|
|
// 设置状态
|
|
|
budgetStatus: getBudgetStatus(status),
|
|
|
flowStatus: getFlowStatus(status),
|
|
|
// 设置负责人信息
|
|
|
managerId: footerForm.managerId,
|
|
|
managerName: findUserName(userList.value, footerForm.managerId),
|
|
|
approveUserId: footerForm.approveUserId,
|
|
|
approveUserName: findUserName(userList.value, footerForm.approveUserId),
|
|
|
// 预算详情
|
|
|
erpBudgetDetailList: budgetDetailData,
|
|
|
// 初始化所有成本列表
|
|
|
...initializeRdCostLists()
|
|
|
};
|
|
|
|
|
|
console.log(budgetForm);
|
|
|
|
|
|
// 处理各项成本数据
|
|
|
processRdCostData(budgetForm);
|
|
|
|
|
|
// 如果有预算ID,设置要删除的列表
|
|
|
if (budgetForm.budgetId) {
|
|
|
setRdToDeletedLists(budgetForm);
|
|
|
}
|
|
|
|
|
|
return budgetForm;
|
|
|
};
|
|
|
|
|
|
// 处理市场预算表单
|
|
|
const processMarketBudgetForm = async (status: string): Promise<budgetInfoForm> => {
|
|
|
await updateBudgetTable();
|
|
|
|
|
|
const budgetDetailData = budgetTableRef.value?.budgetDetailData || [];
|
|
|
const budgetFormData = budgetTableRef.value?.budgetForm || {};
|
|
|
|
|
|
const budgetForm = {
|
|
|
...budgetFormData,
|
|
|
budgetStatus: getBudgetStatus(status),
|
|
|
flowStatus: getFlowStatus(status),
|
|
|
managerName: findUserName(userList.value, budgetFormData.managerId),
|
|
|
productManagerName: findUserName(userList.value, budgetFormData.productManagerId),
|
|
|
erpBudgetDetailList: budgetDetailData,
|
|
|
// 初始化市场预算成本列表
|
|
|
...initializeMarketCostLists()
|
|
|
};
|
|
|
|
|
|
// 处理市场预算成本数据
|
|
|
processMarketCostData(budgetForm);
|
|
|
|
|
|
// 如果有预算ID,设置要删除的列表
|
|
|
if (budgetForm.budgetId) {
|
|
|
setMarketToDeletedLists(budgetForm);
|
|
|
}
|
|
|
|
|
|
return budgetForm;
|
|
|
};
|
|
|
|
|
|
// 辅助函数
|
|
|
const getBudgetStatus = (status: string): string => {
|
|
|
return status === 'draft' ? BUSINESS_STATUS.DRAFT : BUSINESS_STATUS.WAITING;
|
|
|
};
|
|
|
|
|
|
const getFlowStatus = (status: string): string => {
|
|
|
return status === 'draft' ? 'draft' : 'waiting';
|
|
|
};
|
|
|
|
|
|
const initializeRdCostLists = () => ({
|
|
|
erpRdBudgetEquipmentCostList: [],
|
|
|
erpRdBudgetMaterialCostList: [],
|
|
|
erpRdBudgetTravelCostList: [],
|
|
|
erpRdBudgetMeetingCostList: [],
|
|
|
erpRdBudgetExchangeCostList: [],
|
|
|
erpRdBudgetTechCostList: [],
|
|
|
erpRdBudgetLaborCostList: [],
|
|
|
erpRdBudgetLiteratureCostList: [],
|
|
|
erpRdBudgetTestingCostList: [],
|
|
|
erpRdBudgetOtherCostList: []
|
|
|
});
|
|
|
|
|
|
const initializeMarketCostLists = () => ({
|
|
|
erpBudgetMaterialCostList: [],
|
|
|
erpBudgetLaborCostList: [],
|
|
|
erpBudgetInstallCostList: [],
|
|
|
erpBudgetTravelCostList: [],
|
|
|
erpBudgetOtherCostList: []
|
|
|
});
|
|
|
|
|
|
// 处理研发成本数据
|
|
|
const processRdCostData = (budgetForm: budgetInfoForm) => {
|
|
|
// 设备成本
|
|
|
if (assignIfChanged([], rdEquipmentCostRef.value?.equipmentData, oriRdBudgetEquipmentCostList.value).length) {
|
|
|
budgetForm.erpRdBudgetEquipmentCostList = rdEquipmentCostRef.value?.equipmentData || [];
|
|
|
}
|
|
|
|
|
|
// 材料成本
|
|
|
if (assignIfChanged([], rdMaterialCostRef.value?.allMaterialData, oriRdBudgetMaterialCostList.value).length) {
|
|
|
budgetForm.erpRdBudgetMaterialCostList = rdMaterialCostRef.value?.allMaterialData || [];
|
|
|
}
|
|
|
|
|
|
// 差旅、会议、交流成本
|
|
|
const travelMeetingExchangeRef = rdTravelMeetingExchangeRef.value;
|
|
|
if (assignIfChanged([], travelMeetingExchangeRef?.travelList, oriRdBudgetTravelCostList.value).length) {
|
|
|
budgetForm.erpRdBudgetTravelCostList = travelMeetingExchangeRef?.travelList || [];
|
|
|
}
|
|
|
if (assignIfChanged([], travelMeetingExchangeRef?.meetingList, oriRdBudgetMeetingCostList.value).length) {
|
|
|
budgetForm.erpRdBudgetMeetingCostList = travelMeetingExchangeRef?.meetingList || [];
|
|
|
}
|
|
|
if (assignIfChanged([], travelMeetingExchangeRef?.exchangeList, oriRdBudgetExchangeCostList.value).length) {
|
|
|
budgetForm.erpRdBudgetExchangeCostList = travelMeetingExchangeRef?.exchangeList || [];
|
|
|
}
|
|
|
|
|
|
// 技术成本
|
|
|
const laborServiceRef = rdLaborServiceRef.value;
|
|
|
budgetForm.erpRdBudgetTechCostList = [
|
|
|
...assignIfChanged([], laborServiceRef?.techConsultList, oriRdBudgetTechConsultCostList.value),
|
|
|
...assignIfChanged([], laborServiceRef?.expertMeetingList, oriRdBudgetExpertMeetingCostList.value),
|
|
|
...assignIfChanged([], laborServiceRef?.expertCommList, oriRdBudgetExpertCommCostList.value)
|
|
|
];
|
|
|
|
|
|
// 劳务成本
|
|
|
budgetForm.erpRdBudgetLaborCostList = [
|
|
|
...assignIfChanged([], laborServiceRef?.laborList, oriRdBudgetLaborCostList.value),
|
|
|
...assignIfChanged([], laborServiceRef?.serviceList, oriRdBudgetServiceCostList.value)
|
|
|
];
|
|
|
|
|
|
// 文献成本
|
|
|
const literatureCostRef = rdLiteratureCostRef.value;
|
|
|
budgetForm.erpRdBudgetLiteratureCostList = [
|
|
|
...assignIfChanged([], literatureCostRef?.materialsList, oriRdBudgetLiteratureMaterialCostList.value),
|
|
|
...assignIfChanged([], literatureCostRef?.softwareList, oriRdBudgetLiteratureSofwareCostList.value),
|
|
|
literatureCostRef?.literatureRetrieval || {}
|
|
|
].filter((item) => Object.keys(item).length > 0);
|
|
|
|
|
|
// 测试成本
|
|
|
if (assignIfChanged([], rdTestingCostRef.value?.testData, oriRdBudgetTestingCostList.value).length) {
|
|
|
budgetForm.erpRdBudgetTestingCostList = rdTestingCostRef.value?.testData || [];
|
|
|
}
|
|
|
|
|
|
// 其他成本
|
|
|
if (assignIfChanged([], rdOtherCostRef.value?.otherCostList, oriRdBudgetOtherCostList.value).length) {
|
|
|
budgetForm.erpRdBudgetOtherCostList = rdOtherCostRef.value?.otherCostList || [];
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 设置研发删除列表
|
|
|
const setRdToDeletedLists = (budgetForm: budgetInfoForm) => {
|
|
|
const refs = {
|
|
|
equipment: rdEquipmentCostRef.value,
|
|
|
material: rdMaterialCostRef.value,
|
|
|
travelMeetingExchange: rdTravelMeetingExchangeRef.value,
|
|
|
laborService: rdLaborServiceRef.value,
|
|
|
literature: rdLiteratureCostRef.value,
|
|
|
testing: rdTestingCostRef.value,
|
|
|
other: rdOtherCostRef.value
|
|
|
};
|
|
|
|
|
|
budgetForm.toDeletedRdEquipmentCostIdList = refs.equipment?.toDeletedEquipmentCostIdList;
|
|
|
budgetForm.toDeletedRdMaterialCostIdList = refs.material?.toDeletedMaterialCostIdList;
|
|
|
budgetForm.toDeletedRdTravelCostIdList = refs.travelMeetingExchange?.toDeletedTravelCostIdList;
|
|
|
budgetForm.toDeletedRdMeetingCostIdList = refs.travelMeetingExchange?.toDeletedMeetingCostIdList;
|
|
|
budgetForm.toDeletedRdExchangeCostIdList = refs.travelMeetingExchange?.toDeletedExchangeCostIdList;
|
|
|
budgetForm.toDeletedRdTechCostIdList = refs.laborService?.toDeletedTechCostIdList;
|
|
|
budgetForm.toDeletedRdLaborCostIdList = refs.laborService?.toDeletedLaborCostIdList;
|
|
|
budgetForm.toDeletedRdLiteratureCostIdList = refs.literature?.toDeletedLiteratureCostIdList;
|
|
|
budgetForm.toDeletedRdTestingCostIdList = refs.testing?.toDeletedTestCostIdList;
|
|
|
budgetForm.toDeletedRdOtherCostIdList = refs.other?.toDeletedOtherCostIdList;
|
|
|
};
|
|
|
|
|
|
// 处理市场成本数据
|
|
|
const processMarketCostData = (budgetForm: budgetInfoForm) => {
|
|
|
const assignCostData = (targetKey: keyof budgetInfoForm, sourceData: any[], originalData: any[]) => {
|
|
|
if (!deepEqualArrays(originalData, sourceData)) {
|
|
|
budgetForm[targetKey] = sourceData || [];
|
|
|
}
|
|
|
};
|
|
|
|
|
|
assignCostData('erpBudgetMaterialCostList', materialCostRef.value?.budgetMaterialCostList, oriBudgetMaterialCostList.value);
|
|
|
assignCostData('erpBudgetLaborCostList', laborCostRef.value?.budgetLaborCostList, oriBudgetLaborCostList.value);
|
|
|
assignCostData('erpBudgetInstallCostList', installationCostRef.value?.installCostList, oriBudgetInstallCostList.value);
|
|
|
assignCostData('erpBudgetTravelCostList', travelCostRef.value?.travelCostList, oriBudgetTravelCostList.value);
|
|
|
assignCostData('erpBudgetOtherCostList', otherCostRef.value?.otherCostList, oriBudgetOtherCostList.value);
|
|
|
};
|
|
|
|
|
|
// 设置市场删除列表
|
|
|
const setMarketToDeletedLists = (budgetForm: budgetInfoForm) => {
|
|
|
budgetForm.toDeletedMaterialCostIdList = materialCostRef.value?.toDeletedMaterialCostIdList;
|
|
|
budgetForm.toDeletedLaborCostIdList = laborCostRef.value?.toDeletedLaborCostIdList;
|
|
|
budgetForm.toDeletedInstallCostIdList = installationCostRef.value?.toDeletedInstallCostIdList;
|
|
|
budgetForm.toDeletedTravelCostIdList = travelCostRef.value?.toDeletedTravelCostIdList;
|
|
|
budgetForm.toDeletedOtherCostIdList = otherCostRef.value?.toDeletedOtherCostIdList;
|
|
|
};
|
|
|
|
|
|
// 保存成功处理
|
|
|
const handleSaveSuccess = () => {
|
|
|
const obj = {
|
|
|
path: '/budget/erp/budgetInfo',
|
|
|
query: {
|
|
|
t: Date.now(),
|
|
|
pageNum: routeParams.value.pageNum
|
|
|
}
|
|
|
};
|
|
|
proxy?.$tab.closeOpenPage(obj);
|
|
|
};
|
|
|
|
|
|
// 关闭页面
|
|
|
const handleClose = () => {
|
|
|
// 可以添加确认对话框
|
|
|
// 这里简单实现返回上一页
|
|
|
window.history.back();
|
|
|
};
|
|
|
|
|
|
const route = useRoute();
|
|
|
const budgetId = ref();
|
|
|
// 初始化
|
|
|
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;
|
|
|
});
|
|
|
});
|
|
|
|
|
|
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
|
|
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
|
|
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
|
|
import { getContractInfo } from '@/api/oa/erp/contractInfo';
|
|
|
import { budgetMaterialCostVO } from '@/api/oa/erp/budgetInfo/market/budgetMaterialCost/types';
|
|
|
import { budgetLaborCostVO } from '@/api/oa/erp/budgetInfo/market/budgetLaborCost/types';
|
|
|
import { budgetInstallCostVO } from '@/api/oa/erp/budgetInfo/market/budgetInstallCost/types';
|
|
|
import { budgetTravelCostVO } from '@/api/oa/erp/budgetInfo/market/budgetTravelCost/types';
|
|
|
import { budgetOtherCostVO } from '@/api/oa/erp/budgetInfo/market/budgetOtherCost/types';
|
|
|
import { budgetInfoForm } from '@/api/oa/erp/budgetInfo/types';
|
|
|
import { rdBudgetEquipmentCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetEquipmentCost/types';
|
|
|
import { rdBudgetMaterialCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetMaterialCost/types';
|
|
|
import { rdBudgetTravelCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetTravelCost/types';
|
|
|
import { rdBudgetMeetingCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetMeetingCost/types';
|
|
|
import { rdBudgetExchangeCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetExchangeCost/types';
|
|
|
import { rdBudgetTechCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetTechCost/types';
|
|
|
import { rdBudgetLaborCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetLaborCost/types';
|
|
|
import { rdBudgetLiteratureCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetLiteratureCost/types';
|
|
|
import { rdBudgetTestingCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetTestingCost/types';
|
|
|
import { rdBudgetOtherCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetOtherCost/types';
|
|
|
import { UserVO } from '@/api/system/user/types';
|
|
|
// 路由参数
|
|
|
const routeParams = ref<Record<string, any>>({});
|
|
|
// 审批相关组件引用
|
|
|
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
|
|
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
|
|
// 审批
|
|
|
const approvalVerifyOpen = async () => {
|
|
|
await submitVerifyRef.value.openDialog(routeParams.value.taskId);
|
|
|
};
|
|
|
|
|
|
// 审批记录
|
|
|
const handleApprovalRecord = () => {
|
|
|
approvalRecordRef.value.init(searchForm.budgetId);
|
|
|
};
|
|
|
|
|
|
// 提交回调
|
|
|
const submitCallback = async () => {
|
|
|
await proxy.$tab.closePage(proxy.$route);
|
|
|
router.go(-1);
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
.project-budget-container {
|
|
|
padding: 20px;
|
|
|
}
|
|
|
|
|
|
.dialog-footer {
|
|
|
display: flex;
|
|
|
justify-content: flex-end;
|
|
|
gap: 12px;
|
|
|
}
|
|
|
|
|
|
.justify-end {
|
|
|
justify-content: flex-end;
|
|
|
}
|
|
|
|
|
|
.gap-2 {
|
|
|
gap: 8px;
|
|
|
}
|
|
|
|
|
|
.gap-4 {
|
|
|
gap: 16px;
|
|
|
}
|
|
|
|
|
|
.mb-6 {
|
|
|
margin-top: 12px;
|
|
|
margin-bottom: 6px;
|
|
|
}
|
|
|
</style>
|