1.0.45.1:

前端:
   feat(budget):完成研发项目预算保存和更新功能;
   fix(budget):预算更新时判断问题修复等
dev
xs 2 weeks ago
parent 6beea2392e
commit 31103f3c99

@ -1,3 +1,4 @@
/**
*
* @param {any} obj1
@ -13,6 +14,13 @@ export function isDeepEqual(obj1: any, obj2: any) {
return obj1 === obj2;
}
if (isNumeric(obj1) && isNumeric(obj2)) {
console.log("-----111111")
// 将两者都转为数字进行比较,处理 "4.00" == 4 的情况
return Number(obj1) === Number(obj2);
}
// 处理数组
if (Array.isArray(obj1) && Array.isArray(obj2)) {
if (obj1.length !== obj2.length) return false;
@ -45,3 +53,112 @@ export function isDeepEqual(obj1: any, obj2: any) {
return true;
}
/**
*
* @param {Array} arr1 -
* @param {Array} arr2 -
* @returns {boolean} - true
*/
export function deepEqualArrays(arr1, arr2) {
// 1. 快速检查:相同引用或都是 null/undefined
if (arr1 === arr2) return true;
// 2. 检查是否为数组
if (!Array.isArray(arr1) || !Array.isArray(arr2)) {
return false;
}
// 3. 检查数组长度
if (arr1.length !== arr2.length) return false;
// 4. 深度比较每个元素
for (let i = 0; i < arr1.length; i++) {
if (!deepEqualObjects(arr1[i], arr2[i])) {
return false;
}
}
return true;
}
/**
*
* @param {any} obj1 -
* @param {any} obj2 -
* @returns {boolean} - true
*/
function deepEqualObjects(obj1, obj2) {
// 1. 快速检查
if (obj1 === obj2) return true;
// 2. 处理 null 和 undefined
if (obj1 == null || obj2 == null) {
return obj1 === obj2;
}
// 3. 处理数字和数字字符串
if (isNumeric(obj1) && isNumeric(obj2)) {
const num1 = Number(obj1);
const num2 = Number(obj2);
// 处理浮点数精度问题
return Math.abs(num1 - num2) < 0.000001;
}
// 4. 处理数组
if (Array.isArray(obj1) && Array.isArray(obj2)) {
return deepEqualArrays(obj1, obj2);
}
// 5. 处理普通对象
if (typeof obj1 === 'object' && typeof obj2 === 'object') {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
// 检查所有键是否相同
const keySet = new Set([...keys1, ...keys2]);
if (keySet.size !== keys1.length) return false;
// 递归比较每个属性
for (const key of keys1) {
if (!deepEqualObjects(obj1[key], obj2[key])) {
return false;
}
}
return true;
}
// 6. 其他情况使用严格相等
return obj1 === obj2;
}
/**
*
* @param {any} value -
* @returns {boolean} - true
*/
function isNumeric(value) {
if (value === null || value === undefined || value === '') {
return false;
}
// 如果是数字类型
if (typeof value === 'number') {
return !isNaN(value) && isFinite(value);
}
// 如果是字符串
if (typeof value === 'string') {
const trimmed = value.trim();
if (trimmed === '') return false;
// 检查是否为有效的数字字符串
const num = Number(trimmed);
return !isNaN(num) && isFinite(num);
}
return false;
}

@ -16,21 +16,14 @@
<el-form :model="searchForm" label-width="80px">
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="项目名称">
<el-input v-model="searchForm.projectName" placeholder="请选择项目名称" readonly @click="showProjectSelectDialog">
<template #append>
<el-icon @click="showProjectSelectDialog">
<el-icon :size="16">
<Search />
</el-icon>
</el-icon>
</template>
<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.projectCode" placeholder="项目号" readonly />
<el-form-item label="项目名称">
<el-input v-model="searchForm.projectName" placeholder="请选择项目后自动填充" disabled />
</el-form-item>
</el-col>
<!-- <el-col :span="12" class="text-right">-->
@ -48,7 +41,13 @@
<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" />
<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" />
@ -82,7 +81,7 @@
>
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
<el-tab-pane label="预算表" name="budget">
<BudgetTable ref="budgetTableRef" :projectInfo="projectInfo" />
<BudgetTable ref="budgetTableRef" :projectInfo="projectInfo" :userList="userList" />
</el-tab-pane>
<el-tab-pane label="材料费" name="material">
<MaterialCost ref="materialCostRef" :budgetId="budgetId" />
@ -103,14 +102,30 @@
</el-card>
<!-- 项目选择弹窗 -->
<el-dialog v-model="projectSelectDialogVisible" title="选择项目" width="800px">
<div class="mb-4">
<el-input v-model="projectSearchForm.keyword" placeholder="请输入项目名称或项目号" clearable @input="handleProjectSearch">
<template #append>
<el-button @click="handleProjectSearch"></el-button>
</template>
</el-input>
</div>
<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" />
@ -136,8 +151,8 @@
<pagination
v-show="projectTotal > 0"
:total="projectTotal"
v-model:page="projectSearchForm.pageNum"
v-model:limit="projectSearchForm.pageSize"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getProjectList"
/>
</div>
@ -162,7 +177,9 @@ 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 { isDeepEqual } from '@/utils/objHandle';
import { getUserList } from '@/api/system/user';
import { deepEqualArrays } from '@/utils/objHandle';
const router = useRouter();
@ -311,18 +328,6 @@ const projectInfo = reactive<ProjectInfoVO>({
projectCategory: ''
});
//
const marketCostData = reactive<CostData>({
materialCost: 0,
laborCost: 0,
installCost: 0,
travelCost: 0,
serviceCost: 0,
literatureCost: 0,
testingCost: 0,
otherCost: 0
});
//
const costData = reactive<CostData>({
equipmentCost: 0,
@ -338,22 +343,66 @@ const costData = reactive<CostData>({
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 projectSearchForm = reactive({
projectCategory: '',
pageNum: 1,
pageSize: 10
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(projectSearchForm);
const res = await listProjectInfo(queryParams.value);
console.log(searchForm);
projectList.value = res.rows;
projectTotal.value = res.total;
@ -379,21 +428,6 @@ const showProjectSelectDialog = () => {
getProjectList();
};
//
const handleProjectSearch = () => {
projectSearchForm.pageNum = 1;
};
//
const handleProjectPageSizeChange = (size: number) => {
projectSearchForm.pageSize = size;
};
//
const handleProjectCurrentPageChange = (current: number) => {
projectSearchForm.pageNum = current;
};
//
const selectProject = (row: ProjectInfoVO) => {
selectedProject.value = row;
@ -487,7 +521,7 @@ const handleOtherCostUpdate = (data: { totalAmount: number }) => {
};
//
const updateBudgetTable = () => {
const updateBudgetTable = async () => {
if (!budgetTableRef.value) return;
// tab
@ -506,7 +540,7 @@ const updateBudgetTable = () => {
};
//
const updateRdBudgetTable = () => {
const updateRdBudgetTable = async () => {
// tab
const equipmentAmount = rdEquipmentCostRef.value?.getTotalAmount();
const equipmentTotal = equipmentAmount.equipmentTotal || 0;
@ -577,7 +611,17 @@ const exportBudget = () => {
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('请先选择项目');
@ -586,157 +630,250 @@ const handleSave = async (status: string, mode: boolean) => {
try {
buttonLoading.value = true;
const budgetForm = reactive<budgetInfoForm>({});
if (searchForm.projectCategory === PROJECT_CATEGORY.RD || searchForm.projectCategory === PROJECT_CATEGORY.PRE_PRODUCTION) {
updateRdBudgetTable();
const budgetDetailData = rdBudgetTableRef.value?.budgetDetailData;
const isRdProject = [PROJECT_CATEGORY.RD, PROJECT_CATEGORY.PRE_PRODUCTION].includes(searchForm.projectCategory);
const isMarketProject = [PROJECT_CATEGORY.MARKET, PROJECT_CATEGORY.MARKET_PART].includes(searchForm.projectCategory);
Object.assign(budgetForm,
rdBudgetTableRef.value?.rdBudgetInfoForm || {},
rdBudgetTableRef.value?.footerForm || {}
);
let budgetForm: budgetInfoForm = {};
budgetForm.budgetStatus = status === 'draft' ? BUSINESS_STATUS.DRAFT : BUSINESS_STATUS.WAITING;
budgetForm.flowStatus = status === 'draft' ? 'draft' : 'waiting';
budgetForm.erpRdBudgetEquipmentCostList = [];
budgetForm.erpRdBudgetMaterialCostList = [];
budgetForm.erpRdBudgetTravelCostList = [];
budgetForm.erpRdBudgetMeetingCostList = [];
budgetForm.erpRdBudgetExchangeCostList = [];
budgetForm.erpRdBudgetTechCostList = [];
budgetForm.erpRdBudgetLaborCostList = [];
budgetForm.erpRdBudgetLiteratureCostList = [];
budgetForm.erpRdBudgetTestingCostList = [];
budgetForm.erpRdBudgetOtherCostList = [];
// console.log(budgetForm);
budgetForm.erpBudgetDetailList = budgetDetailData;
if (!isDeepEqual(oriRdBudgetEquipmentCostList.value, rdEquipmentCostRef.value?.equipmentData)) {
budgetForm.erpRdBudgetEquipmentCostList = rdEquipmentCostRef.value?.equipmentData;
}
if (!isDeepEqual(oriRdBudgetMaterialCostList.value, rdMaterialCostRef.value?.allMaterialData)) {
budgetForm.erpRdBudgetMaterialCostList = rdMaterialCostRef.value?.allMaterialData;
}
if (!isDeepEqual(oriRdBudgetTravelCostList.value, rdTravelMeetingExchangeRef.value?.travelList)) {
budgetForm.erpRdBudgetTravelCostList = rdTravelMeetingExchangeRef.value?.travelList;
}
if (!isDeepEqual(oriRdBudgetMeetingCostList.value, rdTravelMeetingExchangeRef.value?.meetingList)) {
budgetForm.erpRdBudgetMeetingCostList = rdTravelMeetingExchangeRef.value?.meetingList;
}
if (!isDeepEqual(oriRdBudgetExchangeCostList.value, rdTravelMeetingExchangeRef.value?.exchangeList)) {
budgetForm.erpRdBudgetExchangeCostList = rdTravelMeetingExchangeRef.value?.exchangeList;
}
budgetForm.erpRdBudgetTechCostList = [
...(!isDeepEqual(oriRdBudgetTechConsultCostList.value, rdLaborServiceRef.value?.techConsultList)
? rdLaborServiceRef.value?.techConsultList || []
: []),
...(!isDeepEqual(oriRdBudgetExpertMeetingCostList.value, rdLaborServiceRef.value?.expertMeetingList)
? rdLaborServiceRef.value?.expertMeetingList || []
: []),
...(!isDeepEqual(oriRdBudgetExpertCommCostList.value, rdLaborServiceRef.value?.expertCommList)
? rdLaborServiceRef.value?.expertCommList || []
: [])
];
console.log('---');
console.log(budgetForm.erpRdBudgetTechCostList);
budgetForm.erpRdBudgetLaborCostList = [
...(!isDeepEqual(oriRdBudgetLaborCostList.value, rdLaborServiceRef.value?.laborList) ? rdLaborServiceRef.value?.laborList || [] : []),
...(!isDeepEqual(oriRdBudgetServiceCostList.value, rdLaborServiceRef.value?.serviceList) ? rdLaborServiceRef.value?.serviceList || [] : [])
];
budgetForm.erpRdBudgetLiteratureCostList = [
...(!isDeepEqual(oriRdBudgetLiteratureMaterialCostList.value, rdLiteratureCostRef.value?.materialsList)
? rdLiteratureCostRef.value?.materialsList || []
: []),
...(!isDeepEqual(oriRdBudgetLiteratureSofwareCostList.value, rdLiteratureCostRef.value?.softwareList)
? rdLiteratureCostRef.value?.softwareList || []
: [])
];
budgetForm.erpRdBudgetLiteratureCostList.push(rdLiteratureCostRef.value?.literatureRetrieval);
if (!isDeepEqual(oriRdBudgetTestingCostList.value, rdTestingCostRef.value?.testData)) {
budgetForm.erpRdBudgetTestingCostList = rdTestingCostRef.value?.testData;
}
if (!isDeepEqual(oriRdBudgetOtherCostList.value, rdOtherCostRef.value?.otherCostList)) {
budgetForm.erpRdBudgetOtherCostList = rdOtherCostRef.value?.otherCostList;
}
if (budgetForm.budgetId) {
budgetForm.toDeletedRdEquipmentCostIdList = rdEquipmentCostRef.value?.toDeletedEquipmentCostIdList;
budgetForm.toDeletedRdMaterialCostIdList = rdMaterialCostRef.value?.toDeletedMaterialCostIdList;
budgetForm.toDeletedRdTravelCostIdList = rdTravelMeetingExchangeRef.value?.toDeletedTravelCostIdList;
budgetForm.toDeletedRdMeetingCostIdList = rdTravelMeetingExchangeRef.value?.toDeletedMeetingCostIdList;
budgetForm.toDeletedRdExchangeCostIdList = rdTravelMeetingExchangeRef.value?.toDeletedExchangeCostIdList;
budgetForm.toDeletedRdTechCostIdList = rdLaborServiceRef.value?.toDeletedTechCostIdList;
budgetForm.toDeletedRdLaborCostIdList = rdLaborServiceRef.value?.toDeletedLaborCostIdList;
budgetForm.toDeletedRdLiteratureCostIdList = rdLiteratureCostRef.value?.toDeletedLiteratureCostIdList;
budgetForm.toDeletedRdTestingCostIdList = rdTestingCostRef.value?.toDeletedTestCostIdList;
budgetForm.toDeletedRdOtherCostIdList = rdOtherCostRef.value?.toDeletedOtherCostIdList;
}
} else if (searchForm.projectCategory === PROJECT_CATEGORY.MARKET || searchForm.projectCategory === PROJECT_CATEGORY.MARKET_PART) {
updateBudgetTable();
const budgetDetailData = budgetTableRef.value?.budgetDetailData;
Object.assign(budgetForm, budgetTableRef.value?.budgetForm);
budgetForm.budgetStatus = status === 'draft' ? BUSINESS_STATUS.DRAFT : BUSINESS_STATUS.WAITING;
budgetForm.flowStatus = status === 'draft' ? 'draft' : 'waiting';
budgetForm.erpBudgetMaterialCostList = [];
budgetForm.erpBudgetLaborCostList = [];
budgetForm.erpBudgetInstallCostList = [];
budgetForm.erpBudgetTravelCostList = [];
budgetForm.erpBudgetOtherCostList = [];
console.log(budgetForm);
budgetForm.erpBudgetDetailList = budgetDetailData;
if (!isDeepEqual(oriBudgetMaterialCostList.value, materialCostRef.value?.budgetMaterialCostList)) {
budgetForm.erpBudgetMaterialCostList = materialCostRef.value?.budgetMaterialCostList;
}
if (!isDeepEqual(oriBudgetLaborCostList.value, laborCostRef.value?.budgetLaborCostList)) {
budgetForm.erpBudgetLaborCostList = laborCostRef.value?.budgetLaborCostList;
}
if (!isDeepEqual(oriBudgetInstallCostList.value, installationCostRef.value?.installCostList)) {
budgetForm.erpBudgetInstallCostList = installationCostRef.value?.installCostList;
}
if (!isDeepEqual(oriBudgetTravelCostList.value, travelCostRef.value?.travelCostList)) {
budgetForm.erpBudgetTravelCostList = travelCostRef.value?.travelCostList;
}
if (!isDeepEqual(oriBudgetOtherCostList.value, otherCostRef.value?.otherCostList)) {
budgetForm.erpBudgetOtherCostList = otherCostRef.value?.otherCostList;
}
if (budgetForm.budgetId) {
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;
}
}
if (budgetForm.budgetId) {
await updateErpBudgetInfo(budgetForm).finally(() => (buttonLoading.value = false));
if (isRdProject) {
budgetForm = await processRdBudgetForm(status);
} else if (isMarketProject) {
budgetForm = await processMarketBudgetForm(status);
} else {
await addErpBudgetInfo(budgetForm).finally(() => (buttonLoading.value = false));
ElMessage.warning('不支持的预算类型');
return;
}
proxy?.$modal.msgSuccess('操作成功');
// tab
const obj = { path: '/budget/erp/budgetInfo', query: { t: Date.now(), pageNum: routeParams.value.pageNum } };
proxy?.$tab.closeOpenPage(obj);
// router.go(-1);
// handleClose();
//
const saveOperation = budgetForm.budgetId ? () => updateErpBudgetInfo(budgetForm) : () => addErpBudgetInfo(budgetForm);
await saveOperation();
ElMessage.success('操作成功');
handleSaveSuccess();
} catch (error) {
ElMessage.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 = () => {
//
@ -748,9 +885,6 @@ const route = useRoute();
const budgetId = ref();
//
onMounted(() => {
//
routeParams.value.type = 'add';
nextTick(async () => {
//
routeParams.value = route.query;
@ -760,7 +894,8 @@ onMounted(() => {
const res = await getErpBudgetInfo(budgetId.value);
Object.assign(searchForm, res.data);
console.log(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));
@ -891,7 +1026,7 @@ console.log(res.data)
// isCodeGenerated.value = false;
// }
}
projectSearchForm.projectCategory = searchForm.projectCategory;
queryParams.value.projectCategory = searchForm.projectCategory;
});
});
@ -915,6 +1050,7 @@ import { rdBudgetLaborCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetLaborCos
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>>({});
//

@ -20,10 +20,14 @@
</el-form-item>
<el-form-item label="项目经理" prop="managerId">
<el-select v-model="queryParams.managerId" filterable placeholder="请选择项目经理">
<el-option v-for="item in userList" :key="item.userId" :label="item.userName" :value="item.userId"></el-option>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId"></el-option>
</el-select>
</el-form-item>
<el-form-item label="预算状态" prop="budgetStatus">
<el-select v-model="queryParams.budgetStatus" placeholder="请选择预算状态" clearable>
<el-option v-for="dict in budget_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>
@ -42,19 +46,19 @@
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAddRd" v-hasPermi="['oa:erp/budgetInfo:add']"> </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['oa:erp/budgetInfo:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['oa:erp/budgetInfo:remove']"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['oa:erp/budgetInfo:export']"> </el-button>
</el-col>
<!-- <el-col :span="1.5">-->
<!-- <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['oa:erp/budgetInfo:edit']"-->
<!-- >修改-->
<!-- </el-button>-->
<!-- </el-col>-->
<!-- <el-col :span="1.5">-->
<!-- <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['oa:erp/budgetInfo:remove']"-->
<!-- >删除-->
<!-- </el-button>-->
<!-- </el-col>-->
<!-- <el-col :span="1.5">-->
<!-- <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['oa:erp/budgetInfo:export']"> </el-button>-->
<!-- </el-col>-->
<right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true" @queryTable="getList"></right-toolbar>
</el-row>
</template>
@ -62,31 +66,83 @@
<el-table v-loading="loading" border :data="budgetInfoList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="版本,新版本+1" align="center" prop="budgetVersion" v-if="columns[4].visible" />-->
<el-table-column label="项目类别" align="center" prop="projectCategory" v-if="columns[5].visible">
<el-table-column label="项目类别" align="center" prop="projectCategory" v-if="columns[5].visible" width="150">
<template #default="scope">
<dict-tag :options="project_category" :value="scope.row.projectCategory" />
</template>
</el-table-column>
<el-table-column label="项目号" align="center" prop="projectCode" v-if="columns[6].visible" />
<el-table-column label="项目名称" align="center" prop="projectName" v-if="columns[7].visible" />
<el-table-column label="项目经理" align="center" prop="managerId" v-if="columns[8].visible" />
<el-table-column label="产品经理关联sys_user" align="center" prop="productManagerId" v-if="columns[10].visible" />
<el-table-column label="合同额(元)" align="center" prop="contractAmount" v-if="columns[14].visible" />
<el-table-column label="合同净额(元)" align="center" prop="netContractAmount" v-if="columns[15].visible" />
<el-table-column label="预算成本(元)" align="center" prop="budgetCost" v-if="columns[16].visible" />
<el-table-column label="预算毛利率乘以100保存" align="center" prop="budgetRate" v-if="columns[17].visible" />
<el-table-column label="降成本后预算成本(元)" align="center" prop="reduceBudgetCost" v-if="columns[18].visible" />
<el-table-column label="降成本后预算毛利率" align="center" prop="reduceBudgetRate" v-if="columns[19].visible" />
<el-table-column label="项目经理" align="center" prop="managerName" v-if="columns[8].visible" width="100px;"/>
<el-table-column label="产品经理" align="center" prop="productManagerName" v-if="columns[10].visible" />
<el-table-column label="合同额(万元)" align="center" prop="contractAmount" v-if="columns[14].visible" />
<el-table-column label="合同净额(万元)" align="center" prop="netContractAmount" v-if="columns[15].visible" />
<el-table-column label="预算成本(万元)" align="center" prop="budgetCost" v-if="columns[16].visible" />
<el-table-column label="预算毛利率" align="center" prop="budgetRate" v-if="columns[17].visible">
<template #default="scope">
{{ formatRate(scope.row.reduceBudgetRate) }}
</template>
</el-table-column>
<el-table-column label="降成本后预算成本(万元)" align="center" prop="reduceBudgetCost" v-if="columns[18].visible" />
<el-table-column label="降成本后预算毛利率" align="center" prop="reduceBudgetRate" v-if="columns[19].visible">
<template #default="scope">
{{ formatRate(scope.row.reduceBudgetRate) }}
</template>
</el-table-column>
<el-table-column label="项目预算期间" align="center" prop="duringOperation" v-if="columns[20].visible" />
<el-table-column label="预算状态(1暂存 2审批中 3可用)" align="center" prop="budgetStatus" v-if="columns[24].visible" />
<el-table-column label="流程状态" align="center" prop="flowStatus" v-if="columns[25].visible" />
<el-table-column label="预算状态" align="center" prop="budgetStatus" v-if="columns[24].visible" width="100px;">
<template #default="scope">
<dict-tag :options="budget_status" :value="scope.row.budgetStatus" />
</template>
</el-table-column>
<el-table-column label="流程状态" align="center" prop="flowStatus" v-if="columns[25].visible" width="100px;">
<template #default="scope">
<dict-tag :options="wf_business_status" :value="scope.row.flowStatus" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="查看详情" placement="top" v-if="scope.row.budgetStatus !== BUDGET_STATUS.DRAFT">
<el-button type="primary" size="small" icon="View" @click="handleUpdate(scope.row,'view')" v-hasPermi="['oa:erp/budgetInfo:view']">&nbsp;</el-button>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['oa:erp/budgetInfo:edit']"></el-button>
<el-button
type="primary"
icon="Edit"
size="small"
@click="handleUpdate(scope.row,'update')"
v-if="scope.row.budgetStatus === BUDGET_STATUS.DRAFT"
v-hasPermi="['oa:erp/budgetInfo:edit']"
>修改&nbsp;</el-button>
</el-tooltip>
<el-tooltip content="导出" placement="top">
<el-button
type="primary"
icon="Download"
size="small"
@click="handleExport(scope.row)"
v-hasPermi="['oa:erp/budgetInfo:export']"
>导出&nbsp;</el-button>
</el-tooltip>
<el-tooltip content="变更" placement="top">
<el-button
size="small"
type="warning"
icon="Delete"
@click="handleUpdate(scope.row,'change')"
v-if="scope.row.budgetStatus === BUDGET_STATUS.DRAFT"
v-hasPermi="['oa:erp/budgetInfo:change']"
>变更&nbsp;</el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['oa:erp/budgetInfo:remove']"></el-button>
<el-button
size="small"
type="danger"
icon="Delete"
@click="handleDelete(scope.row)"
v-if="scope.row.budgetStatus === BUDGET_STATUS.DRAFT"
v-hasPermi="['oa:erp/budgetInfo:remove']"
>删除&nbsp;</el-button>
</el-tooltip>
</template>
</el-table-column>
@ -107,7 +163,9 @@ import { reactive } from 'vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { project_category } = toRefs<any>(proxy?.useDict('project_category'));
const { project_category, budget_status, wf_business_status } = toRefs<any>(
proxy?.useDict('project_category', 'budget_status', 'wf_business_status')
);
const budgetInfoList = ref<budgetInfoVO[]>([]);
const userList = ref<UserVO[]>([]);
@ -139,7 +197,7 @@ const columns = ref<FieldOption[]>([
{ key: 7, label: `项目名称`, visible: true },
{ key: 8, label: `项目经理`, visible: true },
{ key: 9, label: `项目经理姓名`, visible: true },
{ key: 10, label: `产品经理关联sys_user`, visible: true },
{ key: 10, label: `产品经理关联sys_user`, visible: false },
{ key: 11, label: `产品经理姓名`, visible: true },
{ key: 12, label: `审核(评审组长)ID关联sys_user`, visible: true },
{ key: 13, label: `审核(评审组长)姓名`, visible: true },
@ -245,6 +303,18 @@ const PROJECT_CATEGORY = reactive({
PRE_PRODUCTION: '4' //
});
const BUDGET_STATUS = reactive({
DRAFT: '1', //稿
AUDITING: '2', //
AVAILABLE: '3' //
});
//
const formatRate = (value: number) => {
if (!value) return '';
return value + '%';
};
/** 查询用户列表 */
const getUsers = async () => {
const res = await getUserList({});
@ -320,40 +390,50 @@ const handleAddRd = () => {
});
};
/** 修改按钮操作 */
const handleUpdate = async (row?: budgetInfoVO) => {
const params = { pageNum: queryParams.value.pageNum, type: 'update', id: row.budgetId };
proxy.$tab.openPage('/oa/erp/budgetInfo/edit', '项目预算申请', params);
};
/** 提交按钮 */
const submitForm = () => {
budgetInfoFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.budgetId) {
await updateErpBudgetInfo(form.value).finally(() => (buttonLoading.value = false));
} else {
await addErpBudgetInfo(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
/** 查询、修改和变更按钮操作 */
const handleUpdate = async (row?: budgetInfoVO, type?: string) => {
router.push({
path: '/budget/budget-add/index',
query: {
type: type,
id: row.budgetId,
pageNum: queryParams.value.pageNum,
projectCategory: row.projectCategory
}
});
// const params = { pageNum: queryParams.value.pageNum, type: 'update', id: row.budgetId };//router
// proxy.$tab.openPage('/oa/erp/budgetInfo/edit', '', params);
};
/** 修改按钮操作 */
const handleView = async (row?: budgetInfoVO) => {
router.push({
path: '/budget/budget-add/index',
query: {
type: 'view',
id: row.budgetId,
pageNum: queryParams.value.pageNum,
projectCategory: row.projectCategory
}
});
// const params = { pageNum: queryParams.value.pageNum, type: 'update', id: row.budgetId };//router
// proxy.$tab.openPage('/oa/erp/budgetInfo/edit', '', params);
};
/** 删除按钮操作 */
const handleDelete = async (row?: budgetInfoVO) => {
const _budgetIds = row?.budgetId || ids.value;
await proxy?.$modal.confirm('是否确认删除项目预算编号为"' + _budgetIds + '"的数据项?').finally(() => (loading.value = false));
const projectName = row.projectName;
await proxy?.$modal.confirm('是否确认删除项目名称为"' + projectName + '"的数据项?').finally(() => (loading.value = false));
await delErpBudgetInfo(_budgetIds);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
const handleExport = (row?: budgetInfoVO) => {
proxy?.download(
'oa/erp/budgetInfo/export',
{
@ -367,4 +447,8 @@ onMounted(() => {
getList();
getUsers();
});
onActivated(() => {
getList();
});
</script>

@ -8,12 +8,12 @@
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目名称">
<el-input v-model="budgetForm.projectName" readonly />
<el-input v-model="budgetForm.projectName" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目号">
<el-input v-model="budgetForm.projectCode" readonly />
<el-input v-model="budgetForm.projectCode" disabled />
</el-form-item>
</el-col>
</el-row>
@ -36,7 +36,7 @@
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="合同额">
<el-input-number v-model="budgetForm.contractAmount" @change="computedAmountAndRate" style="width:100%"/>
<el-input-number v-model="budgetForm.contractAmount" :min="0" :precision="2" @change="computedAmountAndRate" style="width:100%;text-align: left"/>
</el-form-item>
</el-col>
<el-col :span="12">
@ -289,28 +289,17 @@ const updateBudgetDetailData = (type: string, budgetCost: number, reduceBudgetCo
}
};
//
const updateBudgetCost = (row: any) => {
row.budgetCost = parseFloat(row.budgetCost) || 0;
};
//
const updateReduceBudgetCost = (row: any) => {
row.reduceBudgetCost = parseFloat(row.reduceBudgetCost) || 0;
};
//
defineExpose({
updateBudgetDetailData,
budgetForm,
budgetDetailData
});
//
const props = defineProps({
projectInfo: {
type: Object,
default: () => ({})
},
userList: {
type: Object,
default: () => ({})
}
});
@ -328,13 +317,6 @@ watch(
{ deep: true, immediate: true }
);
const userList = ref<UserVO[]>([]);
/** 查询用户列表 */
const getUsers = async () => {
const res = await getUserList({});
userList.value = res.data;
};
const computedAmountAndRate = async () => {
if (budgetForm.contractAmount) {
budgetForm.netContractAmount = (budgetForm.contractAmount / 1.13).toFixed(2);
@ -347,8 +329,11 @@ const computedAmountAndRate = async () => {
}
};
onMounted(() => {
getUsers();
//
defineExpose({
updateBudgetDetailData,
budgetForm,
budgetDetailData
});
// budgetForm.netContractAmount = computed(() => {

@ -224,8 +224,6 @@ const handleAddRows = () => {
reduceProposal: ''
})
}
showAddDialog.value = false
addRowCount.value = 1
}
//

@ -276,8 +276,6 @@ const handleAddRows = () => {
reduceProposal: ''
});
}
showAddDialog.value = false;
addRowCount.value = 1;
};
//

@ -115,16 +115,35 @@
<div class="material-dialog-content">
<!-- 左侧物料列表 -->
<div class="material-list-section">
<!-- 搜索框 -->
<!-- <div class="search-section">-->
<!-- <el-input v-model="materialSearchKeyword" placeholder="请输入物料号、材料名称或规格进行搜索" clearable @input="handleSearch">-->
<!-- <template #prefix>-->
<!-- <el-icon>-->
<!-- <Search />-->
<!-- </el-icon>-->
<!-- </template>-->
<!-- </el-input>-->
<!-- </div>-->
<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="materialQueryParamsRef" :model="materialQueryParams" :inline="true" label-width="100px">
<el-form-item label="SAP物料编码" prop="materialCode">
<el-input v-model="materialQueryParams.materialCode" placeholder="请输入SAP物料编码" clearable @keyup.enter="handleMaterialQuery" />
</el-form-item>
<el-form-item label="SAP物料名称" prop="materialName">
<el-input v-model="materialQueryParams.materialName" placeholder="请输入SAP物料名称" clearable @keyup.enter="handleMaterialQuery" />
</el-form-item>
<el-form-item label="物料品牌" prop="materialBrand">
<el-input v-model="materialQueryParams.materialBrand" placeholder="请输入物料品牌" clearable @keyup.enter="handleMaterialQuery" />
</el-form-item>
<el-form-item label="物料型号" prop="materialModel">
<el-input v-model="materialQueryParams.materialModel" placeholder="请输入物料型号" clearable @keyup.enter="handleMaterialQuery" />
</el-form-item>
<!-- <el-form-item label="激活标识" prop="activeFlag">-->
<!-- <el-select v-model="queryParams.activeFlag" placeholder="请选择激活标识" clearable>-->
<!-- <el-option v-for="dict in active_flag" :key="dict.value" :label="dict.label" :value="dict.value" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item>
<el-button type="primary" icon="Search" @click="handleMaterialQuery"></el-button>
<el-button icon="Refresh" @click="resetMaterialQuery"></el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<!-- 物料表格 -->
<el-table
@ -132,14 +151,14 @@
:data="materialList"
@selection-change="handleMaterialSelectionChange"
highlight-current-row
style="width: 100%; margin-top: 15px"
max-height="350"
style="width: 100%;"
v-loading="materialLoading"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="materialCode" label="物料号" width="120" />
<el-table-column prop="materialName" label="料名称" width="150" />
<el-table-column prop="materialBrand" label="品牌" />
<el-table-column prop="materialModel" label="型号" />
<el-table-column prop="materialCode" label="SAP物料编码" width="120" />
<el-table-column prop="materialName" label="SAP物料名称" width="150" />
<el-table-column prop="materialBrand" label="物料品牌" />
<el-table-column prop="materialModel" label="物料型号" />
<el-table-column prop="unitName" label="单位" width="80" />
<el-table-column prop="purchasePrice" label="单价(元)" width="100">
<template #default="scope">
@ -204,7 +223,9 @@ import { budgetMaterialCostVO } from '@/api/oa/erp/budgetInfo/market/budgetMater
import { listMaterialInfo } from '@/api/oa/erp/budgetInfo/index';
import { getBaseUnitInfoList } from '@/api/oa/base/unitInfo';
import { UnitInfoVO } from '@/api/oa/base/unitInfo/types';
import { MaterialInfoVO, MaterialInfoQuery } from '@/api/oa/base/materialInfo/types';
import { MaterialInfoVO, MaterialInfoQuery, MaterialInfoForm } from '@/api/oa/base/materialInfo/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// IDprops
const props = defineProps<{
@ -218,8 +239,6 @@ const toDeletedMaterialCostIdList = ref([]);
//
const selectedRows = ref([]);
//
const showAddDialog = ref(false);
const addRowCount = ref(1);
//
@ -234,12 +253,31 @@ const isUpdatingSelection = ref(false);
const materialList = ref<MaterialInfoVO[]>([]);
const materialTotal = ref(0);
const materialLoading = ref(false);
const materialQueryParams = ref({
pageNum: 1,
pageSize: 10,
params: {}
const data = reactive<{ materialQueryParams: MaterialInfoQuery }>({
materialQueryParams: {
pageNum: 1,
pageSize: 10,
materialCode: undefined,
materialName: undefined,
materialBrand: undefined,
materialModel: undefined,
unitId: undefined,
materialParameter: undefined,
purchasePrice: undefined,
foreignPrice: undefined,
stockingPeriod: undefined,
activeFlag: undefined,
orderByColumn: undefined,
isAsc: undefined,
params: {}
}
});
const { materialQueryParams } = toRefs(data);
const materialQueryParamsRef = ref<ElFormInstance>();
//
const handleSelectionChange = (selection: any[]) => {
selectedRows.value = selection;
@ -250,6 +288,18 @@ const handleShowMaterial = () => {
getMaterialList();
};
/** 搜索按钮操作 */
const handleMaterialQuery = () => {
materialQueryParams.value.pageNum = 1;
getMaterialList();
};
/** 重置按钮操作 */
const resetMaterialQuery = () => {
materialQueryParamsRef.value?.resetFields();
handleMaterialQuery();
};
/** 查询物料信息列表 */
const getMaterialList = async () => {
materialLoading.value = true;
@ -283,8 +333,6 @@ const handleAddRows = () => {
reduceProposal: ''
});
}
showAddDialog.value = false;
addRowCount.value = 1;
};
//
@ -309,15 +357,15 @@ const updateTableSelection = () => {
}
});
console.log('更新表格选择状态完成');
console.log(
'当前页物料:',
materialList.value.map((m) => m.materialCode)
);
console.log(
'已选择物料:',
selectedMaterials.value.map((s) => s.materialCode)
);
// console.log('');
// console.log(
// ':',
// materialList.value.map((m) => m.materialCode)
// );
// console.log(
// ':',
// selectedMaterials.value.map((s) => s.materialCode)
// );
}
isUpdatingSelection.value = false;
});
@ -327,7 +375,6 @@ const updateTableSelection = () => {
const handleMaterialSelectionChange = (selection: any[]) => {
//
if (isUpdatingSelection.value) {
console.log('跳过自动更新选择状态');
return;
}
@ -348,19 +395,19 @@ const handleMaterialSelectionChange = (selection: any[]) => {
}
});
console.log('用户操作选择变化');
console.log(
'当前页物料:',
currentPageMaterials.map((m) => m.materialCode)
);
console.log(
'表格选择:',
selection.map((s) => s.materialCode)
);
console.log(
'已选择物料:',
selectedMaterials.value.map((s) => s.materialCode)
);
// console.log('');
// console.log(
// ':',
// currentPageMaterials.map((m) => m.materialCode)
// );
// console.log(
// ':',
// selection.map((s) => s.materialCode)
// );
// console.log(
// ':',
// selectedMaterials.value.map((s) => s.materialCode)
// );
};
//
@ -397,12 +444,12 @@ const handleBatchDelete = () => {
//
const removeSelectedMaterial = (material: any) => {
console.log('删除物料:', material.materialCode);
// console.log(':', material.materialCode);
selectedMaterials.value = selectedMaterials.value.filter((selected) => selected.materialCode !== material.materialCode);
console.log(
'删除后已选择物料:',
selectedMaterials.value.map((s) => s.materialCode)
);
// console.log(
// ':',
// selectedMaterials.value.map((s) => s.materialCode)
// );
updateTableSelection();
};
@ -599,7 +646,7 @@ defineExpose({
.material-dialog-content {
display: flex;
gap: 20px;
height: 500px;
height: 600px;
}
.material-list-section {

@ -142,8 +142,6 @@ const handleAddRows = () => {
reduceProposal: ''
});
}
showAddDialog.value = false;
addRowCount.value = 1;
};
//
@ -213,8 +211,8 @@ const getSummaries = (param: any) => {
//
const getTotalAmount = () => {
const totalBudgetAmount = otherCostList.value.reduce((sum, item) => sum + item.price, 0);
const totalReducedAmount = otherCostList.value.reduce((sum, item) => sum + item.reducePrice, 0);
const totalBudgetAmount = otherCostList.value.reduce((sum, item) => sum + Number(item.price), 0);
const totalReducedAmount = otherCostList.value.reduce((sum, item) => sum + Number(item.reducePrice), 0);
return {
budgetAmount: totalBudgetAmount,
reducedAmount: totalReducedAmount

@ -265,8 +265,6 @@ const handleAddRows = () => {
reduceProposal: ''
});
}
showAddDialog.value = false;
addRowCount.value = 1;
};
//
@ -352,8 +350,8 @@ const getSummaries = (param: any) => {
//
const getTotalAmount = () => {
const totalBudgetAmount = travelCostList.value.reduce((sum, item) => sum + item.subtotalCosts, 0);
const totalReducedAmount = travelCostList.value.reduce((sum, item) => sum + item.reduceSubtotalCosts, 0);
const totalBudgetAmount = travelCostList.value.reduce((sum, item) => sum + Number(item.subtotalCosts), 0);
const totalReducedAmount = travelCostList.value.reduce((sum, item) => sum + Number(item.reduceSubtotalCosts), 0);
return {
budgetAmount: totalBudgetAmount,
reducedAmount: totalReducedAmount

@ -75,8 +75,6 @@
<script setup lang="ts">
import { ref, reactive, onMounted, computed, watch } from 'vue';
import { UserVO } from '@/api/system/user/types';
import { getUserList } from '@/api/system/user';
//
//
const rdBudgetInfoForm = reactive({
@ -114,35 +112,6 @@ const footerForm = reactive({
approveUserId: ''
});
//
// const userList = ref([
// { id: '1', name: '', department: '' },
// { id: '2', name: '', department: '' },
// { id: '3', name: '', department: '' },
// { id: '4', name: '', department: '' },
// { id: '5', name: '', department: '' }
// ]);
const userList = ref<UserVO[]>([]);
/** 查询用户列表 */
const getUsers = async () => {
const res = await getUserList({});
userList.value = res.data;
};
//
const creatorSearchQuery = ref('');
const reviewerSearchQuery = ref('');
//
const filteredCreatorList = computed(() => {
return userList.value.filter((user) => user.name.includes(creatorSearchQuery.value));
});
const filteredReviewerList = computed(() => {
return userList.value.filter((user) => user.name.includes(reviewerSearchQuery.value));
});
// ,
const formatNumber = (value: number) => {
if (!value) return '0.00';
@ -234,6 +203,10 @@ const props = defineProps({
projectInfo: {
type: Object,
default: () => ({})
},
userList: {
type: Object,
default: () => ({})
}
});
@ -245,7 +218,7 @@ watch(
rdBudgetInfoForm.projectId = newProjectInfo.projectId || '';
rdBudgetInfoForm.projectName = newProjectInfo.projectName || '';
rdBudgetInfoForm.projectCode = newProjectInfo.projectCode || '';
rdBudgetInfoForm.unitName = newProjectInfo.amountUnit || '万元';
rdBudgetInfoForm.unitName = '万元';
rdBudgetInfoForm.projectCategory = newProjectInfo.projectCategory || '';
}
},
@ -280,6 +253,7 @@ const getSummaries = ({ columns, data }: any) => {
}
}, 0);
sums[index] = formatNumber(sums[index]);
footerForm.budgetCost = sums[index];
} else {
sums[index] = '';
}
@ -287,10 +261,6 @@ const getSummaries = ({ columns, data }: any) => {
return sums;
};
onMounted(() => {
getUsers();
});
//
defineExpose({
updateCostItem,

@ -31,17 +31,17 @@
<el-table-column prop="sortOrder" label="序号" width="80" align="center" />
<el-table-column prop="techContent" label="内容" min-width="200">
<template #default="scope">
<el-input v-model="scope.row.techContent" placeholder="请输入咨询开发内容" />
<el-input v-model="scope.row.techContent" placeholder="请输入咨询开发内容" />
</template>
</el-table-column>
<el-table-column prop="unitId" label="单位" width="160">
<el-table-column prop="unitName" label="单位" width="160">
<template #default="scope">
<el-input v-model="scope.row.unitId" placeholder="请输入单位" />
<el-input v-model="scope.row.unitName" placeholder="请输入单位" />
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" width="200">
<template #default="scope">
<el-input v-model="scope.row.remark" placeholder="请输入备注" />
<el-input v-model="scope.row.remark" placeholder="请输入备注" />
</template>
</el-table-column>
<el-table-column prop="price" label="金额(万元)" width="160">

@ -36,9 +36,9 @@
<el-input v-model="scope.row.testingUnitName" placeholder="请输入测试化验单位" />
</template>
</el-table-column>
<el-table-column prop="unitId" label="单位" width="180">
<el-table-column prop="unitName" label="单位" width="180">
<template #default="scope">
<el-input v-model="scope.row.unitId" placeholder="请输入单位" />
<el-input v-model="scope.row.unitName" placeholder="请输入单位" />
</template>
</el-table-column>
<el-table-column prop="unitPrice" label="单价(元)" width="160">

Loading…
Cancel
Save