From 4065a867a4dbd58d6142ce893df567e1f52a1935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E4=B8=89=E7=82=AE?= <15856818120@163.com> Date: Thu, 22 Jan 2026 10:36:44 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E7=BB=93=E7=AE=97=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E9=A2=86=E9=80=80=E6=96=99=E6=98=8E=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/mybatis/cost/ProjectCostMapper.xml | 360 ++++----- .../cost/beans/ProjectLeaseCostDetail.java | 743 ++++++++++-------- .../cost/service/ProjectCostServiceImpl.java | 347 +++++++- 3 files changed, 913 insertions(+), 537 deletions(-) diff --git a/resources/mybatis/cost/ProjectCostMapper.xml b/resources/mybatis/cost/ProjectCostMapper.xml index ba90d0e..6b62827 100644 --- a/resources/mybatis/cost/ProjectCostMapper.xml +++ b/resources/mybatis/cost/ProjectCostMapper.xml @@ -1,177 +1,183 @@ - - - - - - - - - - - - - insert into wf_project_settlement_details( - ID, - SETTLEMENT_ID, - OPERATE_TYPE, - MACHINE_TYPE_ID, - MACHINE_TYPE_NAME, - MACHINE_CODE, - MACHINE_MODEL, - MACHINE_UNIT, - PRICE, - LEASE_NUM, - RETURN_NUM, - LEASE_UNIT, - OPERATE_PERSON_NAME, - OPERATE_DATE, - TASK_CODE - ) values - - ( - #{item.id}, - #{item.settlementId}, - #{item.operateType}, - #{item.machineTypeId}, - #{item.machineTypeName}, - #{item.machineCode}, - #{item.machineModel}, - #{item.machineUnit}, - #{item.price}, - #{item.leaseNum}, - #{item.returnNum}, - #{item.leaseUnit}, - #{item.operatePersonName}, - #{item.operateDate}, - #{item.taskCode} - ) - - - - \ No newline at end of file + + + + + + + + + + + + + insert into wf_project_settlement_details( + ID, + SETTLEMENT_ID, + OPERATE_TYPE, + MACHINE_TYPE_ID, + MACHINE_TYPE_NAME, + MACHINE_CODE, + MACHINE_MODEL, + MACHINE_UNIT, + PRICE, + LEASE_NUM, + RETURN_NUM, + LEASE_UNIT, + OPERATE_PERSON_NAME, + OPERATE_DATE, + TASK_CODE + ) values + + ( + #{item.id}, + #{item.settlementId}, + #{item.operateType}, + #{item.machineTypeId}, + #{item.machineTypeName}, + #{item.machineCode}, + #{item.machineModel}, + #{item.machineUnit}, + #{item.price}, + #{item.leaseNum}, + #{item.returnNum}, + #{item.leaseUnit}, + #{item.operatePersonName}, + #{item.operateDate}, + #{item.taskCode} + ) + + + + diff --git a/src/com/bonus/cost/beans/ProjectLeaseCostDetail.java b/src/com/bonus/cost/beans/ProjectLeaseCostDetail.java index dc040aa..5d04a52 100644 --- a/src/com/bonus/cost/beans/ProjectLeaseCostDetail.java +++ b/src/com/bonus/cost/beans/ProjectLeaseCostDetail.java @@ -1,327 +1,416 @@ -package com.bonus.cost.beans; - -import com.fasterxml.jackson.annotation.JsonFormat; - -import java.util.Map; - -/** - * 工程领退物资明细实体类 - * - * @author syruan - */ -public class ProjectLeaseCostDetail { - - /** - * 主键 - */ - private Integer id; - - /** - * 机具名称 - */ - private String machineName; - - /** - * 机具类型名称 - */ - private String machineTypeName; - - /** - * 机具类型ID - */ - private Integer machineTypeId; - - /** - * 机具规格 - */ - private String machineModel; - - /** - * 租赁单价/天 - */ - private Double price; - - /** - * 物资单位 - */ - private String machineUnit; - - /** - * 设备编码 - */ - private String machineCode; - - /** - * 备注 - */ - private String remark; - - /** - * 协议号 - */ - private String protocolNumber; - - /** - * 任务单号 - */ - private String taskCode; - - /** - * 工程名称 - */ - private String projectName; - - /** - * 工程ID - */ - private String projectId; - - /** - * 领料单位 - */ - private String leaseUnit; - - /** - * 操作类型(1领料 2退料) - */ - private Byte operateType; - - /** - * 是否数量管理(0编码管理 1数量管理) - */ - private Byte isCount; - - /** - * 领料数量 - */ - private Integer leaseNum; - - /** - * 退料数量 - */ - private Integer returnNum; - - /** - * 操作人员名称 - */ - private String operatePersonName; - - /** - * 操作日期 - */ - @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") - private String operateDate; - - /** - * 操作时间 注意:数据库字段为varchar类型,需要自定义转换逻辑 格式应为"yyyy-MM-dd HH:mm:ss" - */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") - private String operateTime; - - /** - * 查询开始时间 - */ - private String startTime; - - /** - * 查询结束时间 - */ - private String endTime; - - /** - * 查询关键字 - */ - private Map keyWord; - - public Map getKeyWord() { - return keyWord; - } - - public void setKeyWord(Map keyWord) { - this.keyWord = keyWord; - } - - public Double getPrice() { - return price; - } - - public void setPrice(Double price) { - this.price = price; - } - - public Integer getMachineTypeId() { - return machineTypeId; - } - - public void setMachineTypeId(Integer machineTypeId) { - this.machineTypeId = machineTypeId; - } - - public Byte getIsCount() { - return isCount; - } - - public void setIsCount(Byte isCount) { - this.isCount = isCount; - } - - public String getMachineUnit() { - return machineUnit; - } - - public void setMachineUnit(String machineUnit) { - this.machineUnit = machineUnit; - } - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public Byte getOperateType() { - return operateType; - } - - public void setOperateType(Byte operateType) { - this.operateType = operateType; - } - - public String getMachineName() { - return machineName; - } - - public void setMachineName(String machineName) { - this.machineName = machineName; - } - - public Integer getReturnNum() { - return returnNum; - } - - public void setReturnNum(Integer returnNum) { - this.returnNum = returnNum; - } - - public String getMachineModel() { - return machineModel; - } - - public void setMachineModel(String machineModel) { - this.machineModel = machineModel; - } - - public String getMachineCode() { - return machineCode; - } - - public void setMachineCode(String machineCode) { - this.machineCode = machineCode; - } - - public String getRemark() { - return remark; - } - - public void setRemark(String remark) { - this.remark = remark; - } - - public String getProtocolNumber() { - return protocolNumber; - } - - public void setProtocolNumber(String protocolNumber) { - this.protocolNumber = protocolNumber; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public String getProjectId() { - return projectId; - } - - public void setProjectId(String projectId) { - this.projectId = projectId; - } - - public String getLeaseUnit() { - return leaseUnit; - } - - public void setLeaseUnit(String leaseUnit) { - this.leaseUnit = leaseUnit; - } - - public Integer getLeaseNum() { - return leaseNum; - } - - public void setLeaseNum(Integer leaseNum) { - this.leaseNum = leaseNum; - } - - public String getOperatePersonName() { - return operatePersonName; - } - - public void setOperatePersonName(String operatePersonName) { - this.operatePersonName = operatePersonName; - } - - public String getOperateDate() { - return operateDate; - } - - public void setOperateDate(String operateDate) { - this.operateDate = operateDate; - } - - public String getTaskCode() { - return taskCode; - } - - public void setTaskCode(String taskCode) { - this.taskCode = taskCode; - } - - public String getEndTime() { - return endTime; - } - - public void setEndTime(String endTime) { - this.endTime = endTime; - } - - public String getStartTime() { - return startTime; - } - - public void setStartTime(String startTime) { - this.startTime = startTime; - } - - public String getOperateTime() { - return operateTime; - } - - public void setOperateTime(String operateTime) { - this.operateTime = operateTime; - } - - public String getMachineTypeName() { - return machineTypeName; - } - - public void setMachineTypeName(String machineTypeName) { - this.machineTypeName = machineTypeName; - } -} +package com.bonus.cost.beans; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.math.BigDecimal; +import java.util.Map; + +/** + * 工程领退物资明细实体类 + * + * @author syruan + */ +public class ProjectLeaseCostDetail { + + /** + * 主键 + */ + private Integer id; + + /** + * 机具名称 + */ + private String machineName; + + /** + * 机具类别 + */ + private String machineCodeName; + + /** + * 机具类型名称 + */ + private String machineTypeName; + + /** + * 机具类型ID + */ + private Integer machineTypeId; + + /** + * 机具规格 + */ + private String machineModel; + + /** + * 租赁单价/天 + */ + private Double price; + + /** + * 物资单位 + */ + private String machineUnit; + + /** + * 设备编码 + */ + private String machineCode; + + private String oldMachineCode; + + /** + * 备注 + */ + private String remark; + + /** + * 协议号 + */ + private String protocolNumber; + + /** + * 任务单号 + */ + private String taskCode; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 工程ID + */ + private String projectId; + + /** + * 领料单位 + */ + private String leaseUnit; + + /** + * 操作类型(1领料 2退料) + */ + private Byte operateType; + + /** + * 是否数量管理(0编码管理 1数量管理) + */ + private Byte isCount; + + /** + * 领料数量 + */ + private Integer leaseNum; + + /** + * 退料数量 + */ + private Integer returnNum; + + /** + * 操作人员名称 + */ + private String operatePersonName; + + /** + * 累计领料数量 + */ + private BigDecimal totalLeaseQuantity; + + /** + * 累计退料数量 + */ + private BigDecimal totalReturnQuantity; + + /** + * 领退料差额 + */ + private BigDecimal differenceQuantity; + + /** + * 操作日期 + */ + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private String operateDate; + + /** + * 操作时间 注意:数据库字段为varchar类型,需要自定义转换逻辑 格式应为"yyyy-MM-dd HH:mm:ss" + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private String operateTime; + + /** + * 查询开始时间 + */ + private String startTime; + + /** + * 查询结束时间 + */ + private String endTime; + + /** + * 租赁单位 + */ + private String bsName; + + /** + * 序号(第几次领料) + */ + private Integer sequence; + + /** + * 查询关键字 + */ + private Map keyWord; + + public Map getKeyWord() { + return keyWord; + } + + public void setKeyWord(Map keyWord) { + this.keyWord = keyWord; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + + public Integer getMachineTypeId() { + return machineTypeId; + } + + public void setMachineTypeId(Integer machineTypeId) { + this.machineTypeId = machineTypeId; + } + + public Byte getIsCount() { + return isCount; + } + + public void setIsCount(Byte isCount) { + this.isCount = isCount; + } + + public String getMachineUnit() { + return machineUnit; + } + + public void setMachineUnit(String machineUnit) { + this.machineUnit = machineUnit; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Byte getOperateType() { + return operateType; + } + + public void setOperateType(Byte operateType) { + this.operateType = operateType; + } + + public String getMachineName() { + return machineName; + } + + public void setMachineName(String machineName) { + this.machineName = machineName; + } + + public Integer getReturnNum() { + return returnNum; + } + + public void setReturnNum(Integer returnNum) { + this.returnNum = returnNum; + } + + public String getMachineModel() { + return machineModel; + } + + public void setMachineModel(String machineModel) { + this.machineModel = machineModel; + } + + public String getMachineCode() { + return machineCode; + } + + public void setMachineCode(String machineCode) { + this.machineCode = machineCode; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getProtocolNumber() { + return protocolNumber; + } + + public void setProtocolNumber(String protocolNumber) { + this.protocolNumber = protocolNumber; + } + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public String getProjectId() { + return projectId; + } + + public void setProjectId(String projectId) { + this.projectId = projectId; + } + + public String getLeaseUnit() { + return leaseUnit; + } + + public void setLeaseUnit(String leaseUnit) { + this.leaseUnit = leaseUnit; + } + + public Integer getLeaseNum() { + return leaseNum; + } + + public void setLeaseNum(Integer leaseNum) { + this.leaseNum = leaseNum; + } + + public String getOperatePersonName() { + return operatePersonName; + } + + public void setOperatePersonName(String operatePersonName) { + this.operatePersonName = operatePersonName; + } + + public String getOperateDate() { + return operateDate; + } + + public void setOperateDate(String operateDate) { + this.operateDate = operateDate; + } + + public String getTaskCode() { + return taskCode; + } + + public void setTaskCode(String taskCode) { + this.taskCode = taskCode; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getOperateTime() { + return operateTime; + } + + public void setOperateTime(String operateTime) { + this.operateTime = operateTime; + } + + public String getMachineTypeName() { + return machineTypeName; + } + + public void setMachineTypeName(String machineTypeName) { + this.machineTypeName = machineTypeName; + } + + public String getOldMachineCode() { + return oldMachineCode; + } + + public void setOldMachineCode(String oldMachineCode) { + this.oldMachineCode = oldMachineCode; + } + + public String getBsName() { + return bsName; + } + + public void setBsName(String bsName) { + this.bsName = bsName; + } + + public String getMachineCodeName() { + return machineCodeName; + } + + public void setMachineCodeName(String machineCodeName) { + this.machineCodeName = machineCodeName; + } + + public Integer getSequence() { + return sequence; + } + + public void setSequence(Integer sequence) { + this.sequence = sequence; + } + + public BigDecimal getTotalLeaseQuantity() { + return totalLeaseQuantity; + } + + public void setTotalLeaseQuantity(BigDecimal totalLeaseQuantity) { + this.totalLeaseQuantity = totalLeaseQuantity; + } + + public BigDecimal getTotalReturnQuantity() { + return totalReturnQuantity; + } + + public void setTotalReturnQuantity(BigDecimal totalReturnQuantity) { + this.totalReturnQuantity = totalReturnQuantity; + } + + public BigDecimal getDifferenceQuantity() { + return differenceQuantity; + } + + public void setDifferenceQuantity(BigDecimal differenceQuantity) { + this.differenceQuantity = differenceQuantity; + } +} diff --git a/src/com/bonus/cost/service/ProjectCostServiceImpl.java b/src/com/bonus/cost/service/ProjectCostServiceImpl.java index 75fb7f8..b2eeeaf 100644 --- a/src/com/bonus/cost/service/ProjectCostServiceImpl.java +++ b/src/com/bonus/cost/service/ProjectCostServiceImpl.java @@ -21,11 +21,14 @@ import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.util.CellRangeAddress; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.OutputStream; +import java.math.BigDecimal; import java.net.URLEncoder; +import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -50,7 +53,7 @@ public class ProjectCostServiceImpl implements ProjectCostService { /** * 安全转换为Double类型 - * + * * @param obj 要转换的对象 * @param defaultValue 默认值 * @return 转换后的Double值 @@ -84,7 +87,7 @@ public class ProjectCostServiceImpl implements ProjectCostService { /** * 安全转换为Integer类型 - * + * * @param obj 要转换的对象 * @param defaultValue 默认值 * @return 转换后的Integer值 @@ -344,7 +347,7 @@ public class ProjectCostServiceImpl implements ProjectCostService { LocalDateTime endtime = LocalDateTime.parse("2025-05-26 14:21:00", formatter); long daysBetween = java.time.Duration.between(operateTime, endtime).toDays(); System.err.println(daysBetween); - + } @Override @@ -431,9 +434,6 @@ public class ProjectCostServiceImpl implements ProjectCostService { for (Map.Entry> entry : groupedByMachineType.entrySet()) { String machineTypeId = entry.getKey(); List items = entry.getValue(); - if("531".equals(machineTypeId)) { - System.err.println(machineTypeId); - } // 按操作时间排序 items.sort(Comparator.comparing(ProjectLeaseCostDetail::getOperateTime, Comparator.nullsFirst(Comparator.naturalOrder()))); @@ -500,7 +500,7 @@ public class ProjectCostServiceImpl implements ProjectCostService { // 如果统计期间内没有操作,计算从开始时间到结束时间的费用 LocalDateTime endTimeForInitialSegment = firstOperateTimeInPeriod != null ? firstOperateTimeInPeriod : endDate; long daysBetween = getDay(startDate, endTimeForInitialSegment); - + LocalDateTime lastTimes = LocalDateTime.parse(o.getEndTime()+" 23:59:59", formatter); if(lastTimes.equals(endTimeForInitialSegment)) { daysBetween+=1; @@ -562,8 +562,8 @@ public class ProjectCostServiceImpl implements ProjectCostService { if (daysBetween < 1) { daysBetween = 1; } - - + + // 计算该时间段的租赁费用 double segmentAmount = currentCount * unitPrice * daysBetween; totalItemAmount += segmentAmount; @@ -706,14 +706,14 @@ public class ProjectCostServiceImpl implements ProjectCostService { result.put("totalAmount", totalAmount); // 总金额 return result; } - + public long getDay(LocalDateTime operateTime,LocalDateTime endtime) { LocalDate startDate = operateTime.toLocalDate(); LocalDate endDate = endtime.toLocalDate(); long naturalDays = ChronoUnit.DAYS.between(startDate, endDate); - System.out.println("自然日天数差(正确结果):" + naturalDays); + System.out.println("自然日天数差(正确结果):" + naturalDays); return naturalDays; - + } @Override @@ -848,7 +848,8 @@ public class ProjectCostServiceImpl implements ProjectCostService { // 合并领料和退料记录 List leaseDetails = queryProjectLeaseDetails(queryParam); List returnDetails = queryProjectReturnDetails(queryParam); - + //计算差额 + calculateMaterialDifference(leaseDetails, returnDetails); List allDetails = new ArrayList<>(); if (leaseDetails != null) { allDetails.addAll(leaseDetails); @@ -927,10 +928,99 @@ public class ProjectCostServiceImpl implements ProjectCostService { } } } + } return calculation; } + /** + * 计算领退料差额 + * @param leaseDetails 领料明细列表 + * @param returnDetails 退料明细列表 + * @return 计算后的领料明细列表(包含差额) + */ + public List calculateMaterialDifference( + List leaseDetails, + List returnDetails) { + + // 1. 按物料类型分组领料数据 + Map> leaseByMaterial = + leaseDetails.stream() + .sorted(Comparator.comparing(ProjectLeaseCostDetail::getOperateTime)) + .collect(Collectors.groupingBy( + ProjectLeaseCostDetail::getMachineTypeId, + LinkedHashMap::new, // 保持顺序 + Collectors.toList() + )); + + // 2. 按物料类型分组退料数据 + Map> returnByMaterial = + returnDetails.stream() + .sorted(Comparator.comparing(ProjectLeaseCostDetail::getOperateTime)) + .collect(Collectors.groupingBy( + ProjectLeaseCostDetail::getMachineTypeId, + LinkedHashMap::new, + Collectors.toList() + )); + + // 3. 处理每个物料类型 + List result = new ArrayList<>(); + + for (Map.Entry> entry : leaseByMaterial.entrySet()) { + Integer materialType = entry.getKey(); + List materialLeases = entry.getValue(); + List materialReturns = + returnByMaterial.getOrDefault(materialType, new ArrayList<>()); + + // 计算该物料的累计差额 + List calculated = + calculateForSingleMaterial(materialLeases, materialReturns); + + result.addAll(calculated); + } + + return result; + } + + /** + * 计算单个物料的领退料差额 + */ + private List calculateForSingleMaterial( + List leases, + List returns) { + + List result = new ArrayList<>(); + + // 初始化累计量 + BigDecimal totalReturn = BigDecimal.ZERO; + + // 累计退料 + for (ProjectLeaseCostDetail detail : returns) { + BigDecimal returnQty = detail.getReturnNum() != null ? + BigDecimal.valueOf(detail.getReturnNum()) : BigDecimal.ZERO; + totalReturn = totalReturn.add(returnQty); + } + + // 按时间顺序处理每次领料 + for (ProjectLeaseCostDetail lease : leases) { + + //比较当前退料数量和领料数量 + if(BigDecimal.valueOf(lease.getLeaseNum()).compareTo(totalReturn)>=0){ + lease.setDifferenceQuantity(BigDecimal.valueOf(lease.getLeaseNum()).subtract(totalReturn)); + totalReturn = BigDecimal.ZERO; + }else { + lease.setDifferenceQuantity(BigDecimal.ZERO); + //获取剩余的退料数量 + totalReturn = totalReturn.subtract(BigDecimal.valueOf(lease.getLeaseNum())); + } + + result.add(lease); + } + + return result; + } + + @Override public boolean deleteCalculation(Integer id) { return projectCostDao.deleteCalculation(id) > 0; @@ -938,7 +1028,7 @@ public class ProjectCostServiceImpl implements ProjectCostService { /** * 封装导出Excel的方法,适用于只有HttpServletResponse的情况 - * + * * @param fileName 文件名 * @param sheetName sheet名称 * @param headers 表头 @@ -1781,46 +1871,106 @@ public class ProjectCostServiceImpl implements ProjectCostService { // 准备Excel数据 String fileName = "领退记录表_" + calculation.getProjectName() + "_" + calculation.getId() + ".xls"; - String sheetName = "领退记录表"; + String sheetName = "领用、差缺明细表"; + String sheetName2 = "退料明细表"; // 表头 - 增加规格型号字段 - String[] headers = { "序号", "物资类型", "规格型号", "操作类型", "操作时间", "数量", "单位", "操作人", "任务编号" }; + /*String[] headers = { "序号", "物资类型", "规格型号", "操作类型", "操作时间", "数量", "单位", "操作人", "任务编号" };*/ + String[] headers = { "领料日期", "工程名称", "库房", "类别", "机具设备名称", "规格型号", "编码", + "新编码", "单位", "数量", "差额", "租赁单位", "备注" }; + String[] headers2 = { "退料工程名称", "退料单位", "退料日期", "库房", "类别", "机具设备名称", "规格", + "编号", "单位", "数量", "备注" }; // 列宽 - 添加规格型号列宽 - int[] widths = { 256 * 5, 256 * 15, 256 * 15, 256 * 10, 256 * 18, 256 * 10, 256 * 10, 256 * 10, 256 * 15 }; + int[] widths = { 256 * 15,256 * 30,256 * 15,256 * 15,256 * 20,256 * 20,256 * 20,256 * 10,256 * 10, 256 * 10, 256 * 10, 256 * 20, 256 * 10 }; + int[] widths2 = { 256 * 30,256 * 15,256 * 15,256 * 15,256 * 18,256 * 20,256 * 20,256 * 10,256 * 10, 256 * 10, 256 * 10 }; // 数据格式(1:String left; 2:String center; 3:String right; 4:int right; 5:float // right) - int[] formats = { 4, 2, 2, 2, 2, 4, 2, 2, 2 }; - + int[] formats = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2 }; + int[] formats2 = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2 }; // 准备数据 List> dataList = new ArrayList<>(); - + List> dataList2 = new ArrayList<>(); // 获取所有物资的领退记录 List details = calculation.getDetails(); if (details != null && !details.isEmpty()) { int index = 1; + int index2 = 1; for (ProjectCostCalculationDetail detail : details) { List operRecords = detail.getDetails(); if (operRecords != null && !operRecords.isEmpty()) { for (ProjectLeaseCostDetail record : operRecords) { - Map row = new HashMap<>(); - row.put("序号", index++); - row.put("物资类型", record.getMachineTypeName()); - row.put("规格型号", record.getMachineModel()); // 添加规格型号字段 - row.put("操作类型", record.getOperateType() == 1 ? "领料" : "退料"); - row.put("操作时间", record.getOperateTime()); - row.put("数量", record.getOperateType() == 1 ? record.getLeaseNum() : record.getReturnNum()); - row.put("单位", record.getMachineUnit()); - row.put("操作人", record.getOperatePersonName()); - row.put("任务编号", record.getTaskCode()); - dataList.add(row); + if (record.getOperateType() == 1){ + Map row = new HashMap<>(); + row.put("领料日期", record.getOperateTime().substring(0,10)); + row.put("工程名称", calculation.getProjectName()); + if ("牵张设备".equals(record.getMachineCodeName()) ||"施工机械".equals(record.getMachineCodeName()) ||"仪器设备".equals(record.getMachineCodeName())){ + row.put("库房", "设备库"); + }else { + row.put("库房", "机具库"); + } + row.put("类别", record.getMachineCodeName()); // 添加规格型号字段 + row.put("机具设备名称", record.getMachineTypeName()); + row.put("规格型号", record.getMachineModel()); + row.put("编码", record.getOldMachineCode()); + row.put("新编码", record.getMachineCode()); + row.put("单位", record.getMachineUnit()); + row.put("数量", record.getOperateType() == 1 ? record.getLeaseNum() : record.getReturnNum()); + row.put("差额", record.getDifferenceQuantity().compareTo(BigDecimal.valueOf(record.getLeaseNum())) > 0 ? record.getLeaseNum():record.getDifferenceQuantity()); + row.put("租赁单位", record.getBsName()); + row.put("备注",null); + dataList.add(row); + }else { + Map row = new HashMap<>(); + row.put("退料工程名称", calculation.getProjectName()); + row.put("退料单位", record.getBsName()); + row.put("退料日期", record.getOperateTime().substring(0,10)); // 添加规格型号字段 + if ("牵张设备".equals(record.getMachineCodeName()) ||"施工机械".equals(record.getMachineCodeName()) ||"仪器设备".equals(record.getMachineCodeName())){ + row.put("库房", "设备库"); + }else { + row.put("库房", "机具库"); + } + row.put("类别", record.getMachineCodeName()); // 添加规格型号字段 + row.put("机具设备名称", record.getMachineTypeName()); + row.put("规格", record.getMachineModel()); + row.put("编号", record.getOldMachineCode()); + row.put("单位", record.getMachineUnit()); + row.put("数量", record.getOperateType() == 1 ? record.getLeaseNum() : record.getReturnNum()); + row.put("备注",null); + dataList2.add(row); + } + } } } } + // 设置文件名 + String filename = ""; + try { + filename = URLEncoder.encode(fileName, "UTF-8"); + } catch (Exception e) { + filename = fileName; + } + // 设置响应头 + response.setHeader("Content-disposition", "attachment;filename=" + filename); + response.setContentType("application/vnd.ms-excel"); + response.setHeader("Pragma", "No-cache"); + + // 创建一个工作簿 + HSSFWorkbook wb = new HSSFWorkbook(); + // 创建一个sheet + HSSFSheet sheet = wb.createSheet(sheetName); + // 创建一个sheet + HSSFSheet sheet2 = wb.createSheet(sheetName2); // 调用导出方法 - exportExcel(fileName, sheetName, headers, widths, formats, dataList, response); + exportExcelNew(wb, sheet, headers, widths, formats, dataList, response); + exportExcelNew(wb, sheet2, headers2, widths2, formats2, dataList2, response); + // 输出文件 + OutputStream ouputStream = response.getOutputStream(); + wb.write(ouputStream); + ouputStream.flush(); + ouputStream.close(); } /** @@ -1835,4 +1985,135 @@ public class ProjectCostServiceImpl implements ProjectCostService { } return totalDays; } -} \ No newline at end of file + + /** + * 封装导出Excel的方法,适用于只有HttpServletResponse的情况 + * + * @param wb 文件名 + * @param sheet sheet名称 + * @param headers 表头 + * @param widths 列宽 + * @param formats 数据格式 + * @param dataList 数据列表 + * @param response HttpServletResponse对象 + * @throws Exception 导出异常 + */ + private void exportExcelNew(HSSFWorkbook wb, HSSFSheet sheet, String[] headers, int[] widths, int[] formats, + List> dataList, javax.servlet.http.HttpServletResponse response) throws Exception { + try { + + + // 创建表头 + int headerrow = 0; + if (headers != null) { + HSSFRow row = sheet.createRow(headerrow); + // 设置表头行高 - 调高表头高度 + row.setHeight((short) 500); // 设置为原高度的约2倍 + + // 表头样式 + HSSFCellStyle style = wb.createCellStyle(); + HSSFFont font = wb.createFont(); + font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); + font.setFontName("微软雅黑"); + font.setFontHeightInPoints((short) 11); + style.setFont(font); + style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平居中 + style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中 + style.setBorderBottom(HSSFCellStyle.BORDER_THIN); + style.setBorderLeft(HSSFCellStyle.BORDER_THIN); + style.setBorderRight(HSSFCellStyle.BORDER_THIN); + style.setBorderTop(HSSFCellStyle.BORDER_THIN); + + // 设置淡黄色背景 + style.setFillForegroundColor((short) 0x2B); // 修改为更明确的淡黄色,0x2B是淡黄色(light yellow) + style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); + + for (int i = 0; i < headers.length; i++) { + sheet.setColumnWidth((short) i, (short) widths[i]); + HSSFCell cell = row.createCell(i); + cell.setCellValue(headers[i]); + cell.setCellStyle(style); + } + headerrow++; + } + + // 表格主体 + if (dataList != null) { + List styleList = new ArrayList(); + + if (headers != null) { + for (int i = 0; i < headers.length; i++) { // 列数 + HSSFCellStyle style = wb.createCellStyle(); + HSSFFont font = wb.createFont(); + font.setFontName("微软雅黑"); + font.setFontHeightInPoints((short) 10); + style.setFont(font); + style.setBorderBottom(HSSFCellStyle.BORDER_THIN); + style.setBorderLeft(HSSFCellStyle.BORDER_THIN); + style.setBorderRight(HSSFCellStyle.BORDER_THIN); + style.setBorderTop(HSSFCellStyle.BORDER_THIN); + // 添加垂直居中对齐 + style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); + + if (formats[i] == 1) { + style.setAlignment(HSSFCellStyle.ALIGN_LEFT); + } else if (formats[i] == 2) { + style.setAlignment(HSSFCellStyle.ALIGN_CENTER); + } else if (formats[i] == 3) { + style.setAlignment(HSSFCellStyle.ALIGN_RIGHT); + } else if (formats[i] == 4) { + style.setAlignment(HSSFCellStyle.ALIGN_RIGHT); + // int类型 + style.setDataFormat(HSSFDataFormat.getBuiltinFormat("0")); + } else if (formats[i] == 5) { + // float类型 + style.setAlignment(HSSFCellStyle.ALIGN_RIGHT); + style.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0.00")); + } else if (formats[i] == 6) { + // 百分比类型 + style.setAlignment(HSSFCellStyle.ALIGN_RIGHT); + style.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00%")); + } + styleList.add(style); + } + } + + for (Map stringObjectMap : dataList) { // 行数 + HSSFRow row = sheet.createRow(headerrow); + int j = 0; + for (String key : headers) { // 列数 + HSSFCell cell = row.createCell(j); + Object o = stringObjectMap.get(key); + if (o == null || "".equals(o)) { + cell.setCellValue(""); + } else if (formats[j] == 4) { + // int + try { + cell.setCellValue(Long.parseLong(String.valueOf(o))); + } catch (Exception e) { + cell.setCellValue(0); + } + } else if (formats[j] == 5 || formats[j] == 6) { + // float + try { + cell.setCellValue(Double.parseDouble(String.valueOf(o))); + } catch (Exception e) { + cell.setCellValue(0.0); + } + } else { + cell.setCellValue(String.valueOf(o)); + } + + cell.setCellStyle(styleList.get(j)); + j++; + } + headerrow++; + } + } + + + } catch (Exception e) { + throw new Exception("导出Excel异常", e); + } + } +} From eb6d66c27912baa24cd39097955490214f794b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E4=B8=89=E7=82=AE?= <15856818120@163.com> Date: Thu, 22 Jan 2026 15:24:01 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E9=A2=86=E6=96=99=E6=98=8E=E7=BB=86?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=90=88=E5=B9=B6=E5=90=8C=E4=B8=80=E5=A4=A9?= =?UTF-8?q?=E5=90=8C=E4=B8=80=E5=9E=8B=E5=8F=B7=E6=9C=BA=E5=85=B7=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cost/service/ProjectCostServiceImpl.java | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/src/com/bonus/cost/service/ProjectCostServiceImpl.java b/src/com/bonus/cost/service/ProjectCostServiceImpl.java index b2eeeaf..26f0ad7 100644 --- a/src/com/bonus/cost/service/ProjectCostServiceImpl.java +++ b/src/com/bonus/cost/service/ProjectCostServiceImpl.java @@ -28,7 +28,6 @@ import org.springframework.transaction.annotation.Transactional; import java.io.OutputStream; import java.math.BigDecimal; import java.net.URLEncoder; -import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -849,7 +848,7 @@ public class ProjectCostServiceImpl implements ProjectCostService { List leaseDetails = queryProjectLeaseDetails(queryParam); List returnDetails = queryProjectReturnDetails(queryParam); //计算差额 - calculateMaterialDifference(leaseDetails, returnDetails); + leaseDetails =calculateMaterialDifference(leaseDetails, returnDetails); List allDetails = new ArrayList<>(); if (leaseDetails != null) { allDetails.addAll(leaseDetails); @@ -1000,9 +999,45 @@ public class ProjectCostServiceImpl implements ProjectCostService { BigDecimal.valueOf(detail.getReturnNum()) : BigDecimal.ZERO; totalReturn = totalReturn.add(returnQty); } + List leasesNew = new ArrayList<>(); + + // 使用 Map 按日期分组,同一天的合并一起 + Map mergedMap = new LinkedHashMap<>(); + + for (ProjectLeaseCostDetail detail : leases) { + if ("牵张设备".equals(detail.getMachineCodeName()) ||"施工机械".equals(detail.getMachineCodeName()) ||"仪器设备".equals(detail.getMachineCodeName())){ + leasesNew.add(detail); + }else { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String dateOnly = detail.getOperateTime().substring(0, 10); + LocalDate dateKey = LocalDate.parse(dateOnly, + formatter); + if (mergedMap.containsKey(dateKey)) { + // 已存在该日期的记录,合并数量 + ProjectLeaseCostDetail existing = mergedMap.get(dateKey); + + // 累加 leaseNum + existing.setLeaseNum( + (existing.getLeaseNum() != null ? existing.getLeaseNum() : 0) + + (detail.getLeaseNum() != null ? detail.getLeaseNum() : 0) + ); + + } else { + // 新日期的记录,创建副本(避免修改原对象) + mergedMap.put(dateKey, detail); + } + } + + } + + //保存合并后的数据 + for (Map.Entry entry : mergedMap.entrySet()) { + ProjectLeaseCostDetail materialLeases = entry.getValue(); + leasesNew.add(materialLeases); + } // 按时间顺序处理每次领料 - for (ProjectLeaseCostDetail lease : leases) { + for (ProjectLeaseCostDetail lease : leasesNew) { //比较当前退料数量和领料数量 if(BigDecimal.valueOf(lease.getLeaseNum()).compareTo(totalReturn)>=0){ @@ -1894,8 +1929,6 @@ public class ProjectCostServiceImpl implements ProjectCostService { // 获取所有物资的领退记录 List details = calculation.getDetails(); if (details != null && !details.isEmpty()) { - int index = 1; - int index2 = 1; for (ProjectCostCalculationDetail detail : details) { List operRecords = detail.getDetails(); if (operRecords != null && !operRecords.isEmpty()) { @@ -1916,7 +1949,7 @@ public class ProjectCostServiceImpl implements ProjectCostService { row.put("新编码", record.getMachineCode()); row.put("单位", record.getMachineUnit()); row.put("数量", record.getOperateType() == 1 ? record.getLeaseNum() : record.getReturnNum()); - row.put("差额", record.getDifferenceQuantity().compareTo(BigDecimal.valueOf(record.getLeaseNum())) > 0 ? record.getLeaseNum():record.getDifferenceQuantity()); + row.put("差额", record.getDifferenceQuantity()); row.put("租赁单位", record.getBsName()); row.put("备注",null); dataList.add(row); From 693bbe661092a7c274364bbe90d62e9d01bad257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E4=B8=89=E7=82=AE?= <15856818120@163.com> Date: Thu, 22 Jan 2026 15:54:28 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E9=A2=86=E6=96=99=E6=98=8E=E7=BB=86?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=90=88=E5=B9=B6=E5=90=8C=E4=B8=80=E5=A4=A9?= =?UTF-8?q?=E5=90=8C=E4=B8=80=E5=9E=8B=E5=8F=B7=E6=9C=BA=E5=85=B7=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cost/service/ProjectCostServiceImpl.java | 93 +++++++++++-------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/src/com/bonus/cost/service/ProjectCostServiceImpl.java b/src/com/bonus/cost/service/ProjectCostServiceImpl.java index 26f0ad7..89d33bd 100644 --- a/src/com/bonus/cost/service/ProjectCostServiceImpl.java +++ b/src/com/bonus/cost/service/ProjectCostServiceImpl.java @@ -1,6 +1,5 @@ package com.bonus.cost.service; -import com.bonus.core.ExcelUtils; import com.bonus.cost.beans.ProjectCostCalculation; import com.bonus.cost.beans.ProjectCostCalculationDetail; import com.bonus.cost.beans.ProjectCostCalculationSegment; @@ -19,9 +18,7 @@ import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.util.CellRangeAddress; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.format.annotation.DateTimeFormat; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -847,6 +844,9 @@ public class ProjectCostServiceImpl implements ProjectCostService { // 合并领料和退料记录 List leaseDetails = queryProjectLeaseDetails(queryParam); List returnDetails = queryProjectReturnDetails(queryParam); + //同一天的统一类型的机具进行合并 + leaseDetails = mergeByDay(leaseDetails,1); + returnDetails = mergeByDay(returnDetails,2); //计算差额 leaseDetails =calculateMaterialDifference(leaseDetails, returnDetails); List allDetails = new ArrayList<>(); @@ -932,6 +932,55 @@ public class ProjectCostServiceImpl implements ProjectCostService { return calculation; } + + /** + * 根据 operateDate 按天合并,累加 leaseNum + */ + public List mergeByDay(List leases, int i) { + List leasesNew = new ArrayList<>(); + + // 使用 Map 按日期分组,同一天的合并一起 + Map mergedMap = new LinkedHashMap<>(); + + for (ProjectLeaseCostDetail returnDetail : leases) { + if ("牵张设备".equals(returnDetail.getMachineCodeName()) ||"施工机械".equals(returnDetail.getMachineCodeName()) ||"仪器设备".equals(returnDetail.getMachineCodeName())){ + leasesNew.add(returnDetail); + }else { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + String dateOnly = returnDetail.getOperateTime().substring(0, 10); + LocalDate dateKey = LocalDate.parse(dateOnly, + formatter); + if (mergedMap.containsKey(dateKey)) { + // 已存在该日期的记录,合并数量 + ProjectLeaseCostDetail existing = mergedMap.get(dateKey); + if (i==1){ + // 累加 leaseNum + existing.setLeaseNum( + (existing.getLeaseNum() != null ? existing.getLeaseNum() : 0) + + (returnDetail.getLeaseNum() != null ? returnDetail.getLeaseNum() : 0) + ); + }else { + // 累加 leaseNum + existing.setReturnNum( + (existing.getReturnNum() != null ? existing.getReturnNum() : 0) + + (returnDetail.getReturnNum() != null ? returnDetail.getReturnNum() : 0) + ); + } + } else { + // 新日期的记录,创建副本(避免修改原对象) + mergedMap.put(dateKey, returnDetail); + } + } + + } + + //保存合并后的数据 + for (Map.Entry entry : mergedMap.entrySet()) { + ProjectLeaseCostDetail materialLeases = entry.getValue(); + leasesNew.add(materialLeases); + } + return leasesNew; + } /** * 计算领退料差额 * @param leaseDetails 领料明细列表 @@ -999,45 +1048,9 @@ public class ProjectCostServiceImpl implements ProjectCostService { BigDecimal.valueOf(detail.getReturnNum()) : BigDecimal.ZERO; totalReturn = totalReturn.add(returnQty); } - List leasesNew = new ArrayList<>(); - - // 使用 Map 按日期分组,同一天的合并一起 - Map mergedMap = new LinkedHashMap<>(); - - for (ProjectLeaseCostDetail detail : leases) { - if ("牵张设备".equals(detail.getMachineCodeName()) ||"施工机械".equals(detail.getMachineCodeName()) ||"仪器设备".equals(detail.getMachineCodeName())){ - leasesNew.add(detail); - }else { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - String dateOnly = detail.getOperateTime().substring(0, 10); - LocalDate dateKey = LocalDate.parse(dateOnly, - formatter); - if (mergedMap.containsKey(dateKey)) { - // 已存在该日期的记录,合并数量 - ProjectLeaseCostDetail existing = mergedMap.get(dateKey); - - // 累加 leaseNum - existing.setLeaseNum( - (existing.getLeaseNum() != null ? existing.getLeaseNum() : 0) + - (detail.getLeaseNum() != null ? detail.getLeaseNum() : 0) - ); - - } else { - // 新日期的记录,创建副本(避免修改原对象) - mergedMap.put(dateKey, detail); - } - } - - } - - //保存合并后的数据 - for (Map.Entry entry : mergedMap.entrySet()) { - ProjectLeaseCostDetail materialLeases = entry.getValue(); - leasesNew.add(materialLeases); - } // 按时间顺序处理每次领料 - for (ProjectLeaseCostDetail lease : leasesNew) { + for (ProjectLeaseCostDetail lease : leases) { //比较当前退料数量和领料数量 if(BigDecimal.valueOf(lease.getLeaseNum()).compareTo(totalReturn)>=0){