From 55bd8d702b5c26c684a2b1e7a2c8f9e0bf17d41b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=9D=E6=97=AD=E9=98=B3?= <1607842677@qq.com> Date: Thu, 2 Apr 2026 14:05:09 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=93=E7=AE=97=E7=89=A9=E6=96=99=E5=AF=BC?= =?UTF-8?q?=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ErpMaterialPickingController.java | 8 +- .../domain/bo/ErpMaterialPickingBo.java | 10 ++ .../domain/vo/ErpMaterialPickingExportVo.java | 137 ++++++++++++++++++ .../mapper/ErpMaterialPickingInfoMapper.java | 8 + .../service/IErpMaterialPickingService.java | 6 + .../impl/ErpMaterialPickingServiceImpl.java | 60 ++++++++ .../mapper/ErpMaterialPickingInfoMapper.xml | 59 +++++++- .../common/utils/poi/AnnotationUtils.java | 118 +++++++++++++++ .../utils/poi/CustomMergeCellHandler.java | 96 ++++++++++++ .../maintain/common/utils/poi/ExcelUtil.java | 62 ++++++++ .../poi/HeadTitleRowWhiteStyleHandler.java | 49 +++++++ .../common/utils/poi/MergeCellModel.java | 110 ++++++++++++++ .../MergedAnchorCellCenterStyleHandler.java | 49 +++++++ .../maintain/common/utils/poi/SheetPO.java | 56 +++++++ maintain-ui/src/views/business/car/index.vue | 2 +- .../settlementMaterial/info/index1.vue | 15 +- 16 files changed, 839 insertions(+), 6 deletions(-) create mode 100644 maintain-business/src/main/java/com/maintain/business/domain/vo/ErpMaterialPickingExportVo.java create mode 100644 maintain-common/src/main/java/com/maintain/common/utils/poi/AnnotationUtils.java create mode 100644 maintain-common/src/main/java/com/maintain/common/utils/poi/CustomMergeCellHandler.java create mode 100644 maintain-common/src/main/java/com/maintain/common/utils/poi/HeadTitleRowWhiteStyleHandler.java create mode 100644 maintain-common/src/main/java/com/maintain/common/utils/poi/MergeCellModel.java create mode 100644 maintain-common/src/main/java/com/maintain/common/utils/poi/MergedAnchorCellCenterStyleHandler.java create mode 100644 maintain-common/src/main/java/com/maintain/common/utils/poi/SheetPO.java diff --git a/maintain-business/src/main/java/com/maintain/business/controller/ErpMaterialPickingController.java b/maintain-business/src/main/java/com/maintain/business/controller/ErpMaterialPickingController.java index 86e1583..aa84be6 100644 --- a/maintain-business/src/main/java/com/maintain/business/controller/ErpMaterialPickingController.java +++ b/maintain-business/src/main/java/com/maintain/business/controller/ErpMaterialPickingController.java @@ -1,8 +1,11 @@ package com.maintain.business.controller; +import java.util.ArrayList; import java.util.List; import java.util.Arrays; +import com.maintain.business.domain.vo.ErpMaterialPickingExportVo; +import com.maintain.common.utils.poi.SheetPO; import lombok.RequiredArgsConstructor; import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.*; @@ -62,8 +65,9 @@ public class ErpMaterialPickingController extends BaseController { @Log(title = "物料出库", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(ErpMaterialPickingBo bo, HttpServletResponse response) { - List list = iErpMaterialPickingService.queryList(bo); - ExcelUtil.exportExcel(list, "物料出库", ErpMaterialPickingVo.class, response); + iErpMaterialPickingService.export(bo,response); +// List list = iErpMaterialPickingService.queryList(bo); +// ExcelUtil.exportExcel(list, "物料出库", ErpMaterialPickingVo.class, response); } /** diff --git a/maintain-business/src/main/java/com/maintain/business/domain/bo/ErpMaterialPickingBo.java b/maintain-business/src/main/java/com/maintain/business/domain/bo/ErpMaterialPickingBo.java index 81b9ade..509aa8b 100644 --- a/maintain-business/src/main/java/com/maintain/business/domain/bo/ErpMaterialPickingBo.java +++ b/maintain-business/src/main/java/com/maintain/business/domain/bo/ErpMaterialPickingBo.java @@ -131,4 +131,14 @@ public class ErpMaterialPickingBo extends BaseEntity { private List materialList; + /** + * 导出IDs + */ + private List ids; + + /** + * 单位IDS + */ + private List deptIds; + } diff --git a/maintain-business/src/main/java/com/maintain/business/domain/vo/ErpMaterialPickingExportVo.java b/maintain-business/src/main/java/com/maintain/business/domain/vo/ErpMaterialPickingExportVo.java new file mode 100644 index 0000000..4c861f4 --- /dev/null +++ b/maintain-business/src/main/java/com/maintain/business/domain/vo/ErpMaterialPickingExportVo.java @@ -0,0 +1,137 @@ +package com.maintain.business.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.HeadFontStyle; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; +import com.alibaba.excel.annotation.write.style.HeadStyle; +import com.alibaba.excel.enums.poi.BorderStyleEnum; +import com.alibaba.excel.enums.poi.FillPatternTypeEnum; +import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum; +import com.alibaba.excel.enums.poi.VerticalAlignmentEnum; +import com.maintain.common.annotation.ExcelDictFormat; +import com.maintain.common.convert.ExcelDictConvert; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @Author haoxuyang + * @Date 2026/4/2 9:24 + */ +@Data +@HeadRowHeight(value = 35) +@ContentRowHeight(value = 22) +/** 金黄表头、黑字、细边框(与 IndexedColors 调色板接近 #FFC107/#FFB800 效果) */ +@HeadStyle( + fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, + fillForegroundColor = 51, + horizontalAlignment = HorizontalAlignmentEnum.CENTER, + verticalAlignment = VerticalAlignmentEnum.CENTER, + borderLeft = BorderStyleEnum.THIN, + borderRight = BorderStyleEnum.THIN, + borderTop = BorderStyleEnum.THIN, + borderBottom = BorderStyleEnum.THIN, + leftBorderColor = 8, + rightBorderColor = 8, + topBorderColor = 8, + bottomBorderColor = 8 +) +@HeadFontStyle(color = 8) +public class ErpMaterialPickingExportVo { + + /** + * 序号 + */ + @ColumnWidth(15) + @ExcelProperty(index = 0, value = {"title", "序号"}) + private String index; + + /** + * 分公司 + */ + @ColumnWidth(15) + @ExcelProperty(index = 1, value = {"title", "分公司"}) + private String branchOffice; + + /** + * 车间 + */ + @ColumnWidth(15) + @ExcelProperty(index = 2, value = {"title", "车间"}) + private String workshopName; + + /** + * 仓库 + */ + @ColumnWidth(15) + @ExcelProperty(index = 3, value = {"title", "仓库"}) + private String warehouseName; + + /** + * 领料人 + */ + @ColumnWidth(15) + @ExcelProperty(index = 4, value = {"title", "领料人"}) + private String receiveUserName; + + /** + * 领料时间 + */ + @ColumnWidth(25) + @ExcelProperty(index = 5, value = {"title", "领料时间"}) + private Date receiveTime; + + /** + * 材料编码 + */ + @ColumnWidth(15) + @ExcelProperty(index = 6, value = {"title", "材料编码"}) + private String materialCode; + + /** + * 物资名称 + */ + @ColumnWidth(15) + @ExcelProperty(index = 7, value = {"title", "物资名称"}) + private String materialName; + + /** + * 规格 + */ + @ColumnWidth(15) + @ExcelProperty(index = 8, value = {"title", "规格"}) + private String materialSpecifications; + + /** + * 单位 + */ + @ColumnWidth(15) + @ExcelProperty(index = 9, value = {"title", "单位"}, converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "material_unit") + private String materialUnit; + + /** + * 入库价格 + */ + @ColumnWidth(15) + @ExcelProperty(index = 10, value = {"title", "入库价格"}) + private BigDecimal putawayPrice; + + /** + * 数量 + */ + @ColumnWidth(15) + @ExcelProperty(index = 11, value = {"title", "数量"}) + private BigDecimal collectNumber; + + /** + * 合计(元) + */ + @ColumnWidth(15) + @ExcelProperty(index = 12, value = {"title", "合计(元)"}) + private BigDecimal money; + +} diff --git a/maintain-business/src/main/java/com/maintain/business/mapper/ErpMaterialPickingInfoMapper.java b/maintain-business/src/main/java/com/maintain/business/mapper/ErpMaterialPickingInfoMapper.java index 8679c12..3b77403 100644 --- a/maintain-business/src/main/java/com/maintain/business/mapper/ErpMaterialPickingInfoMapper.java +++ b/maintain-business/src/main/java/com/maintain/business/mapper/ErpMaterialPickingInfoMapper.java @@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.toolkit.Constants; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.maintain.business.domain.ErpMaterialPickingInfo; import com.maintain.business.domain.ErpMaterialReturnsInfo; +import com.maintain.business.domain.bo.ErpMaterialPickingBo; +import com.maintain.business.domain.vo.ErpMaterialPickingExportVo; import com.maintain.business.domain.vo.ErpMaterialPickingInfoVo; import com.maintain.business.domain.vo.ErpMaterialReturnsInfoVo; import com.maintain.common.core.mapper.BaseMapperPlus; @@ -35,4 +37,10 @@ public interface ErpMaterialPickingInfoMapper extends BaseMapperPlus customQueryList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + /** + * 获取导出列表 + * @param bo 参数 + * @return 结果 + */ + List getExportList(ErpMaterialPickingBo bo); } diff --git a/maintain-business/src/main/java/com/maintain/business/service/IErpMaterialPickingService.java b/maintain-business/src/main/java/com/maintain/business/service/IErpMaterialPickingService.java index 4481063..aecd5f9 100644 --- a/maintain-business/src/main/java/com/maintain/business/service/IErpMaterialPickingService.java +++ b/maintain-business/src/main/java/com/maintain/business/service/IErpMaterialPickingService.java @@ -6,6 +6,7 @@ import com.maintain.business.domain.bo.ErpMaterialPickingBo; import com.maintain.common.core.page.TableDataInfo; import com.maintain.common.core.domain.PageQuery; +import javax.servlet.http.HttpServletResponse; import java.util.Collection; import java.util.List; @@ -63,4 +64,9 @@ public interface IErpMaterialPickingService { * 新增物料出库退料 */ Boolean insertReturnByBo(ErpMaterialPickingBo bo); + + /** + * 导出物料出库列表 + */ + void export(ErpMaterialPickingBo bo, HttpServletResponse response); } diff --git a/maintain-business/src/main/java/com/maintain/business/service/impl/ErpMaterialPickingServiceImpl.java b/maintain-business/src/main/java/com/maintain/business/service/impl/ErpMaterialPickingServiceImpl.java index 4bb1780..b13c271 100644 --- a/maintain-business/src/main/java/com/maintain/business/service/impl/ErpMaterialPickingServiceImpl.java +++ b/maintain-business/src/main/java/com/maintain/business/service/impl/ErpMaterialPickingServiceImpl.java @@ -1,8 +1,10 @@ package com.maintain.business.service.impl; +import java.util.Date; import cn.hutool.core.bean.BeanUtil; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.maintain.business.domain.*; import com.maintain.business.domain.bo.ErpMaterialPickingInfoAddBo; import com.maintain.business.domain.bo.ErpMaterialPickingInfoBo; @@ -22,6 +24,9 @@ import com.maintain.common.core.domain.PageQuery; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.maintain.common.utils.poi.ExcelUtil; +import com.maintain.common.utils.poi.MergeCellModel; +import com.maintain.common.utils.poi.SheetPO; import com.maintain.common.utils.redis.RedisUtils; import com.maintain.system.mapper.SysDeptMapper; import lombok.RequiredArgsConstructor; @@ -30,6 +35,7 @@ import com.maintain.business.domain.bo.ErpMaterialPickingBo; import com.maintain.business.service.IErpMaterialPickingService; import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @@ -446,4 +452,58 @@ public class ErpMaterialPickingServiceImpl implements IErpMaterialPickingService } return flag; } + + @Override + public void export(ErpMaterialPickingBo bo, HttpServletResponse response) { + String sheetName ="供应商材料消耗明细表"; + String title ="供应商铺货结算表"; + List sysDeptList = deptMapper.selectChildrenDeptById(LoginHelper.getDeptId(), null); + if (!sysDeptList.isEmpty()){ + bo.setDeptIds(sysDeptList.stream().map(SysDept::getDeptId).collect(Collectors.toList())); + } + List list = pickingInfoMapper.getExportList(bo); + //生成合并单元格信息 + List mergeCellList = new ArrayList<>(); + Integer centerMergedAnchorExcelRowIndex = null; + if (CollectionUtils.isNotEmpty(list)){ + list.forEach(item -> { + item.setIndex(String.valueOf(list.indexOf(item) + 1)); + }); + //合计统计 + ErpMaterialPickingExportVo erpMaterialPickingExportVo1 = new ErpMaterialPickingExportVo(); + // 合计文案须落在合并区域左上角列:index=0 为序号(Integer),合并 0~10 时左上角为空会“吃掉”7、8 列的合计文字 + erpMaterialPickingExportVo1.setIndex("合计"); + list.add(erpMaterialPickingExportVo1); + // 双行表头:第 0 行为大标题,第 1 行为列名;合计行 Excel 行号 = list.size() + 1 + int totalExcelRowIndex = list.size() + 1; + centerMergedAnchorExcelRowIndex = totalExcelRowIndex; + mergeCellList.add(MergeCellModel.createMergeCellModel(sheetName, totalExcelRowIndex, totalExcelRowIndex, 0, 10)); + //计算数量总和 + BigDecimal collectNumber = list.stream().map(ErpMaterialPickingExportVo::getCollectNumber).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); + erpMaterialPickingExportVo1.setCollectNumber(collectNumber); + //计算价格总和 + BigDecimal money = list.stream().map(ErpMaterialPickingExportVo::getMoney).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add); + erpMaterialPickingExportVo1.setMoney(money); + + //签名地方 + ErpMaterialPickingExportVo erpMaterialPickingExportVo2 = new ErpMaterialPickingExportVo(); + erpMaterialPickingExportVo2.setWorkshopName("车间仓库员签名:"); + erpMaterialPickingExportVo2.setMaterialSpecifications("车间负责人签名:"); + list.add(erpMaterialPickingExportVo2); + } + List sheetPOList = new ArrayList<>(); + SheetPO sheetPO = new SheetPO<>(); + sheetPOList.add(sheetPO); + Map titleMap = new HashMap<>(); + titleMap.put("title", title); + sheetPO.setData(list); + sheetPO.setTitleMap(titleMap); + sheetPO.setClazz(ErpMaterialPickingExportVo.class); + sheetPO.setSheetNo(1); + sheetPO.setMergeCellList(mergeCellList); + sheetPO.setSheetName(sheetName); + sheetPO.setWhiteFirstHeadRow(true); + sheetPO.setCenterMergedAnchorExcelRowIndex(centerMergedAnchorExcelRowIndex); + ExcelUtil.exportSheetSetTitle(response, title, sheetPOList); + } } diff --git a/maintain-business/src/main/resources/mapper/ErpMaterialPickingInfoMapper.xml b/maintain-business/src/main/resources/mapper/ErpMaterialPickingInfoMapper.xml index e2cf937..58168e2 100644 --- a/maintain-business/src/main/resources/mapper/ErpMaterialPickingInfoMapper.xml +++ b/maintain-business/src/main/resources/mapper/ErpMaterialPickingInfoMapper.xml @@ -49,5 +49,62 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ${ew.getCustomSqlSegment} - + diff --git a/maintain-common/src/main/java/com/maintain/common/utils/poi/AnnotationUtils.java b/maintain-common/src/main/java/com/maintain/common/utils/poi/AnnotationUtils.java new file mode 100644 index 0000000..17c3623 --- /dev/null +++ b/maintain-common/src/main/java/com/maintain/common/utils/poi/AnnotationUtils.java @@ -0,0 +1,118 @@ +package com.maintain.common.utils.poi; + +import org.apache.commons.lang3.StringUtils; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; + +/** + * 注解工具类 + */ +public class AnnotationUtils { + + /** + * 变更注解的属性值再处理业务,处理完业务之后恢复类的属性 + * + * @param clazz 注解所在的实体类 + * @param tClass 注解类 + * @param attrName 要修改的注解属性名 + * @param attrTypeEnum 要修改的注解属性的类型 + * @param valueMap 要设置的属性值 + */ + public static void changeAnnotationValueToDealProcess( + Class clazz, + Class tClass, + String attrName, + AttrTypeEnum attrTypeEnum, + Map valueMap, + DealProcess dealProcess) { + try { + + Map fieldAnnotationValueMap = new HashMap<>(); + + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + A annotation = field.getAnnotation(tClass); + if (annotation == null) continue; + Object value = setAnnotationValue(annotation, attrName, attrTypeEnum, valueMap); + String fieldName = field.getName(); + fieldAnnotationValueMap.put(fieldName, value); + } + + // 处理业务逻辑 + dealProcess.deal(); + + // 恢复 + for (Field field : fields) { + A annotation = field.getAnnotation(tClass); + String fieldName = field.getName(); + if (annotation == null) continue; + Object value = fieldAnnotationValueMap.get(fieldName); + + InvocationHandler handler = Proxy.getInvocationHandler(annotation); + Field memberValuesField = handler.getClass().getDeclaredField("memberValues"); + memberValuesField.setAccessible(true); + @SuppressWarnings("all") + Map memberValues = (Map) memberValuesField.get(handler); + memberValues.put(attrName, value); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 设置注解中的字段值 + * + * @param annotation 要修改的注解实例 + * @param attrName 要修改的注解属性名 + * @param attrTypeEnum 要修改的注解属性的类型 + * @param valueMap 替换属性集的map + */ + @SuppressWarnings("all") + private static Object setAnnotationValue(Annotation annotation, String attrName, + AttrTypeEnum attrTypeEnum, Map valueMap) throws NoSuchFieldException, IllegalAccessException { + InvocationHandler handler = Proxy.getInvocationHandler(annotation); + Field field = handler.getClass().getDeclaredField("memberValues"); + field.setAccessible(true); + Map memberValues = (Map) field.get(handler); + Object value = memberValues.get(attrName); + switch (attrTypeEnum) { + case STRING: { + String oldValue = (String) value; + String newValue = valueMap.get(oldValue); + if (StringUtils.isNotBlank(newValue)) { + memberValues.put(attrName, newValue); + } + } + break; + case STRING_ARR: { + String[] oldValue = (String[]) value; + String[] newValue = new String[oldValue.length]; + for (int i = 0; i < oldValue.length; i++) { + String replace = valueMap.get(oldValue[i]); + newValue[i] = replace != null ? replace : oldValue[i]; + } + memberValues.put(attrName, newValue); + } + break; + } + return value; + } + + public enum AttrTypeEnum { + STRING, + STRING_ARR + } + + public interface DealProcess { + + void deal() throws Exception; + + } + +} diff --git a/maintain-common/src/main/java/com/maintain/common/utils/poi/CustomMergeCellHandler.java b/maintain-common/src/main/java/com/maintain/common/utils/poi/CustomMergeCellHandler.java new file mode 100644 index 0000000..aea5bdd --- /dev/null +++ b/maintain-common/src/main/java/com/maintain/common/utils/poi/CustomMergeCellHandler.java @@ -0,0 +1,96 @@ +package com.maintain.common.utils.poi; + + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 自定义合并单元格处理器 + * 每次合并需要sheet页名称、指定开始行号、开始列号、结束行号、结束列号 + * 支持批量合并单元格 + * + * @author weibaoting + */ +public class CustomMergeCellHandler implements SheetWriteHandler { + /** + * 合并单元格信息 + */ + private List mergeCellList; + /** + * sheet页名称列表 + */ + private List sheetNameList; + + public CustomMergeCellHandler(List mergeCellList) { + if (CollUtil.isEmpty(mergeCellList)) { + return; + } + this.mergeCellList = mergeCellList.stream().filter(x -> + StrUtil.isNotBlank(x.getSheetName()) && x.getStartRowIndex() >= 0 && x.getEndRowIndex() >= 0 + && x.getStartColumnIndex() >= 0 && x.getEndColumnIndex() >= 0).collect(Collectors.toList()); + List sheetNameList = this.mergeCellList.stream().map(x -> x.getSheetName()).distinct().collect(Collectors.toList()); + if (CollUtil.isEmpty(sheetNameList)) { + return; + } + this.sheetNameList = sheetNameList; + } + + + @Override + public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + + } + + /** + * sheet页创建之后调用 + * + * @param writeWorkbookHolder + * @param writeSheetHolder + */ + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + Sheet sheet = writeSheetHolder.getSheet(); + //不需要合并单元格信息,或者当前sheet页不需要合并单元格信息 + if (CollUtil.isEmpty(mergeCellList) || sheetNameList.contains(sheet.getSheetName()) == false) { + return; + } + List sheetMergeCellList = mergeCellList.stream().filter(x -> + StrUtil.equals(x.getSheetName(), sheet.getSheetName())).collect(Collectors.toList()); + for (MergeCellModel mergeCellModel : sheetMergeCellList) { + //开始行号 + int startRowIndex = mergeCellModel.getStartRowIndex(); + //结束行号 + int endRowIndex = mergeCellModel.getEndRowIndex(); + //开始列号 + int startColumnIndex = mergeCellModel.getStartColumnIndex(); + //结束列号 + int endColumnIndex = mergeCellModel.getEndColumnIndex(); + //行号和列号非法(<0) + if (startColumnIndex < 0 || endColumnIndex < 0 || startRowIndex < 0 || endRowIndex < 0) { + continue; + } + //合并单元格区域只有一个单元格时,不合并 + if (endRowIndex == startRowIndex && endColumnIndex == startColumnIndex) { + continue; + } + //开始行号大于结束行号,或者开始列号大于结束列号 + if (startColumnIndex > endColumnIndex || startRowIndex > endRowIndex) { + continue; + } + //添加合并单元格区域 + CellRangeAddress cellRangeAddress = new CellRangeAddress(startRowIndex, endRowIndex, startColumnIndex, endColumnIndex); + sheet.addMergedRegionUnsafe(cellRangeAddress); + } + //删除合并单元格信息 + mergeCellList.removeAll(sheetMergeCellList); + sheetNameList = mergeCellList.stream().map(x -> x.getSheetName()).distinct().collect(Collectors.toList()); + } +} diff --git a/maintain-common/src/main/java/com/maintain/common/utils/poi/ExcelUtil.java b/maintain-common/src/main/java/com/maintain/common/utils/poi/ExcelUtil.java index cfb9c46..2e25d17 100644 --- a/maintain-common/src/main/java/com/maintain/common/utils/poi/ExcelUtil.java +++ b/maintain-common/src/main/java/com/maintain/common/utils/poi/ExcelUtil.java @@ -5,10 +5,15 @@ import cn.hutool.core.io.resource.ClassPathResource; import cn.hutool.core.util.IdUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum; import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.fill.FillConfig; import com.alibaba.excel.write.metadata.fill.FillWrapper; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; import com.maintain.common.convert.ExcelBigNumberConvert; import com.maintain.common.excel.*; @@ -16,6 +21,9 @@ import com.maintain.common.utils.StringUtils; import com.maintain.common.utils.file.FileUtils; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.springframework.http.HttpHeaders; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; @@ -23,6 +31,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; @@ -32,6 +43,7 @@ import java.util.Map; * * @author Lion Li */ +@Slf4j @NoArgsConstructor(access = AccessLevel.PRIVATE) public class ExcelUtil { @@ -377,4 +389,54 @@ public class ExcelUtil { return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx"; } + + /** + * 载Excel格式的数据-带自定义标题 + * + * @param response + * @param fileName + * @param sheetPOList + * @param + */ + public static void exportSheetSetTitle(HttpServletResponse response, String fileName, List sheetPOList) { + //导出 + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + try { + // 这里URLEncoder.encode可以防止中文乱码 + String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20"); + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + encodedFileName + ".xlsx"); + + //新建ExcelWriter + ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build(); + for (SheetPO sheetPO : sheetPOList) { + AnnotationUtils.changeAnnotationValueToDealProcess( + sheetPO.getClazz(), ExcelProperty.class, "value", AnnotationUtils.AttrTypeEnum.STRING_ARR, sheetPO.getTitleMap(), new AnnotationUtils.DealProcess() { + @Override + public void deal() { + ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet(sheetPO.getSheetNo(), sheetPO.getSheetName()) + .head(sheetPO.getClazz()) + .registerWriteHandler(new CustomMergeCellHandler(sheetPO.getMergeCellList())); + if (Boolean.TRUE.equals(sheetPO.getWhiteFirstHeadRow())) { + sheetBuilder.registerWriteHandler(new HeadTitleRowWhiteStyleHandler()); + } + if (sheetPO.getCenterMergedAnchorExcelRowIndex() != null) { + sheetBuilder.registerWriteHandler( + new MergedAnchorCellCenterStyleHandler(sheetPO.getCenterMergedAnchorExcelRowIndex(), 0)); + } + WriteSheet mainSheet = sheetBuilder.build(); + excelWriter.write(sheetPO.getData(), mainSheet); + } + } + ); + } + excelWriter.finish(); + log.info("数据导出完成"); + } catch (Exception e) { + // 重置response + log.error("文件下载失败" + e.getMessage()); + throw new RuntimeException("下载文件失败", e); + } + } + } diff --git a/maintain-common/src/main/java/com/maintain/common/utils/poi/HeadTitleRowWhiteStyleHandler.java b/maintain-common/src/main/java/com/maintain/common/utils/poi/HeadTitleRowWhiteStyleHandler.java new file mode 100644 index 0000000..6bc0ea5 --- /dev/null +++ b/maintain-common/src/main/java/com/maintain/common/utils/poi/HeadTitleRowWhiteStyleHandler.java @@ -0,0 +1,49 @@ +package com.maintain.common.utils.poi; + +import com.alibaba.excel.constant.OrderConstant; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.context.CellWriteHandlerContext; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Workbook; + +/** + * 多行表头时,仅将第一行(大标题行,relativeRowIndex=0)设为白底,其余表头行保持实体类上的 {@code @HeadStyle}。 + */ +public class HeadTitleRowWhiteStyleHandler implements CellWriteHandler { + + private CellStyle whiteTitleRowStyle; + + /** + * 在注解 {@code @HeadStyle} 等样式写入之后再执行(EasyExcel:order 越小越早)。 + */ + @Override + public int order() { + return OrderConstant.FILL_STYLE + 10000; + } + + @Override + public void afterCellDispose(CellWriteHandlerContext context) { + if (!Boolean.TRUE.equals(context.getHead())) { + return; + } + Integer relativeRowIndex = context.getRelativeRowIndex(); + if (relativeRowIndex == null || relativeRowIndex != 0) { + return; + } + Cell cell = context.getCell(); + if (cell == null) { + return; + } + Workbook workbook = context.getWriteWorkbookHolder().getWorkbook(); + if (whiteTitleRowStyle == null) { + whiteTitleRowStyle = workbook.createCellStyle(); + whiteTitleRowStyle.cloneStyleFrom(cell.getCellStyle()); + whiteTitleRowStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex()); + whiteTitleRowStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + } + cell.setCellStyle(whiteTitleRowStyle); + } +} diff --git a/maintain-common/src/main/java/com/maintain/common/utils/poi/MergeCellModel.java b/maintain-common/src/main/java/com/maintain/common/utils/poi/MergeCellModel.java new file mode 100644 index 0000000..46c3826 --- /dev/null +++ b/maintain-common/src/main/java/com/maintain/common/utils/poi/MergeCellModel.java @@ -0,0 +1,110 @@ +package com.maintain.common.utils.poi; + +import lombok.Getter; + +/** + * @Author weibaoting + * @Date 2023/2/2 0002 15:53 + * @Description + */ + +@Getter +public class MergeCellModel { + /** + * sheet名称 + */ + private String sheetName; + /** + * 开始行号 + */ + private int startRowIndex; + /** + * 开始列号 + */ + private int startColumnIndex; + /** + * 结束行号 + */ + private int endRowIndex; + /** + * 结束列号 + */ + private int endColumnIndex; + + private void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + private void setStartRowIndex(int startRowIndex) { + this.startRowIndex = startRowIndex; + } + + private void setStartColumnIndex(int startColumnIndex) { + this.startColumnIndex = startColumnIndex; + } + + private void setEndRowIndex(int endRowIndex) { + this.endRowIndex = endRowIndex; + } + + private void setEndColumnIndex(int endColumnIndex) { + this.endColumnIndex = endColumnIndex; + } + + public MergeCellModel() { + + } + + /** + * 生成合并列单元格信息 + * + * @param sheetName sheet页名称 + * @param rowIndex 行号 + * @param startColumnIndex 开始列号 + * @param endColumnIndex 结束列号 + * @return + */ + public static MergeCellModel createMergeColumnCellModel(String sheetName, int rowIndex, int startColumnIndex + , int endColumnIndex) { + return createMergeCellModel(sheetName, rowIndex, rowIndex, startColumnIndex, endColumnIndex); + } + + /** + * 生成合并单元格信息 + * + * @param sheetName sheet页名称 + * @param startRowIndex 开始行号 + * @param endRowIndex 结束行号 + * @param columnIndex 列号 + * @return + */ + public static MergeCellModel createMergeRowCellModel(String sheetName, int startRowIndex, int endRowIndex, int columnIndex) { + return createMergeCellModel(sheetName, startRowIndex, endRowIndex, columnIndex, columnIndex); + } + + /** + * 生成合并单元格信息 + * + * @param sheetName sheet页名称 + * @param startRowIndex 开始行号 + * @param endRowIndex 结束行号 + * @param startColumnIndex 开始列号 + * @param endColumnIndex 结束列号 + * @return + */ + public static MergeCellModel createMergeCellModel(String sheetName, int startRowIndex, int endRowIndex, int startColumnIndex + , int endColumnIndex) { + MergeCellModel mergeCellModel = new MergeCellModel(); + //sheet页名称 + mergeCellModel.setSheetName(sheetName); + //开始行号 + mergeCellModel.setStartRowIndex(startRowIndex); + //结束行号 + mergeCellModel.setEndRowIndex(endRowIndex); + //开始列号 + mergeCellModel.setStartColumnIndex(startColumnIndex); + //结束列号 + mergeCellModel.setEndColumnIndex(endColumnIndex); + return mergeCellModel; + } +} diff --git a/maintain-common/src/main/java/com/maintain/common/utils/poi/MergedAnchorCellCenterStyleHandler.java b/maintain-common/src/main/java/com/maintain/common/utils/poi/MergedAnchorCellCenterStyleHandler.java new file mode 100644 index 0000000..a6404bc --- /dev/null +++ b/maintain-common/src/main/java/com/maintain/common/utils/poi/MergedAnchorCellCenterStyleHandler.java @@ -0,0 +1,49 @@ +package com.maintain.common.utils.poi; + +import com.alibaba.excel.constant.OrderConstant; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.context.CellWriteHandlerContext; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.apache.poi.ss.usermodel.Workbook; + +/** + * 将指定数据行、指定列(一般为合并区域左上角)的单元格设为水平、垂直居中,用于合并后「合计」等文案居中显示。 + */ +public class MergedAnchorCellCenterStyleHandler implements CellWriteHandler { + + private final int excelRowIndex; + private final int columnIndex; + + public MergedAnchorCellCenterStyleHandler(int excelRowIndex, int columnIndex) { + this.excelRowIndex = excelRowIndex; + this.columnIndex = columnIndex; + } + + @Override + public int order() { + return OrderConstant.FILL_STYLE + 15000; + } + + @Override + public void afterCellDispose(CellWriteHandlerContext context) { + if (Boolean.TRUE.equals(context.getHead())) { + return; + } + Cell cell = context.getCell(); + if (cell == null) { + return; + } + if (cell.getRowIndex() != excelRowIndex || cell.getColumnIndex() != columnIndex) { + return; + } + Workbook workbook = context.getWriteWorkbookHolder().getWorkbook(); + CellStyle style = workbook.createCellStyle(); + style.cloneStyleFrom(cell.getCellStyle()); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + cell.setCellStyle(style); + } +} diff --git a/maintain-common/src/main/java/com/maintain/common/utils/poi/SheetPO.java b/maintain-common/src/main/java/com/maintain/common/utils/poi/SheetPO.java new file mode 100644 index 0000000..2718217 --- /dev/null +++ b/maintain-common/src/main/java/com/maintain/common/utils/poi/SheetPO.java @@ -0,0 +1,56 @@ +package com.maintain.common.utils.poi; + +import lombok.Data; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Author weibaoting + * @Date 2023/2/2 0002 17:00 + * @Description + */ +@Data +public class SheetPO { + + /** + * sheetNo + */ + private Integer sheetNo; + + /** + * sheet名称 + */ + private String sheetName; + + /** + * 标题替换 + */ + private Map titleMap = new HashMap<>(); + + /** + * 数据 + */ + private List data; + + /** + * 表头 + */ + private Class clazz; + + /** + * 需要合并的数据 + */ + private List mergeCellList; + + /** + * 多行表头时是否将第一行(大标题行)设为白底;第二行仍用实体类上的表头样式。默认 false。 + */ + private Boolean whiteFirstHeadRow; + + /** + * 若设置:对该 Excel 行号(0-based)、第 0 列锚点单元格水平垂直居中(用于合并单元格内文字居中,如合计行)。 + */ + private Integer centerMergedAnchorExcelRowIndex; +} diff --git a/maintain-ui/src/views/business/car/index.vue b/maintain-ui/src/views/business/car/index.vue index 3987813..97ec5dc 100644 --- a/maintain-ui/src/views/business/car/index.vue +++ b/maintain-ui/src/views/business/car/index.vue @@ -525,7 +525,7 @@ export default { handleUpdate(row) { getCar(row.id).then(res =>{ this.form = res.data - this.form.clientType = row.clientType + this.form.clientType = row.clientType+'' this.open = true; this.title = "修改车辆信息"; this.getCode() diff --git a/maintain-ui/src/views/business/settlementMaterial/info/index1.vue b/maintain-ui/src/views/business/settlementMaterial/info/index1.vue index 92639e6..e7aa323 100644 --- a/maintain-ui/src/views/business/settlementMaterial/info/index1.vue +++ b/maintain-ui/src/views/business/settlementMaterial/info/index1.vue @@ -43,6 +43,15 @@ v-hasPermi="['business:settlementMaterial:add']" >结算 + + 导出 + @@ -447,6 +456,7 @@ export default { }, // 多选框选中数据 handleSelectionChange(selection) { + this.ids = selection.map(item => item.id) // 如果没有选中任何项,直接禁用按钮 if (selection.length === 0) { this.multiple = true; // 禁用按钮 @@ -593,8 +603,9 @@ export default { /** 导出按钮操作 */ handleExport() { this.download('business/materialPicking/export', { - ...this.queryParams - }, `materialPicking_${new Date().getTime()}.xlsx`) + ...this.queryParams, + ids: this.ids + }, `供应商铺货结算.xlsx`) } } }; -- 2.22.0