商品导出

This commit is contained in:
gong
2026-01-30 14:13:02 +08:00
parent 73929aaac5
commit 496c931678
5 changed files with 318 additions and 148 deletions

View File

@@ -2,12 +2,11 @@ package com.czg.product.dto;
import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
/** /**
* 商品导出 * 商品导出
@@ -17,112 +16,61 @@ import java.util.List;
@Data @Data
public class ProductExportDTO { public class ProductExportDTO {
@Data
public static class ProductSkuExportDTO {
@ExcelProperty("条形码")
private String barCode;
@ExcelProperty("原价")
private BigDecimal originPrice;
@ExcelProperty("成本价")
private BigDecimal costPrice;
@ExcelProperty("会员价")
private BigDecimal memberPrice;
@ExcelProperty("售价")
private BigDecimal salePrice;
@ExcelProperty("起售数量")
private Integer suitNum;
@ExcelProperty("规格详情")
private String specInfo;
@ExcelProperty("是否上架")
private Integer isGrounding;
@ExcelProperty("规格名称")
private String name;
}
@Data
public static class ProductGroupExportDTO {
@ExcelProperty("套餐内商品总数")
private Integer count;
@ExcelProperty("套餐选几")
private Integer number;
@ExcelProperty("套餐名称")
private String title;
@ExcelProperty("套餐内商品列表")
private List<FoodExportDTO> goods = new ArrayList<>();
@Data
public static class FoodExportDTO {
@ExcelProperty("商品名称")
private String proName;
@ExcelProperty("规格名称")
private String skuName;
}
}
@ExcelProperty("商品名称") @ExcelProperty("商品名称")
@ColumnWidth(20)
private String name; private String name;
@ExcelProperty("商品分类名称") @ExcelProperty("商品分类")
@ColumnWidth(15)
private String categoryName; private String categoryName;
@ExcelProperty("条码") @ExcelProperty("条码")
@ColumnWidth(20)
private String barCode; private String barCode;
@ExcelProperty("商品规格名称") @ExcelProperty("商品规格")
@ColumnWidth(20)
private String specFullName; private String specFullName;
@ExcelProperty("售价") @ExcelProperty("售价")
@ColumnWidth(10)
private BigDecimal price; private BigDecimal price;
@ExcelProperty("会员价") @ExcelProperty("会员价")
@ColumnWidth(10)
private BigDecimal memberPrice; private BigDecimal memberPrice;
@ExcelProperty("成本价")
@ColumnWidth(10)
private BigDecimal costPrice;
@ExcelProperty("商品单位名称") @ExcelProperty("商品单位")
@ColumnWidth(10)
private String unitName; private String unitName;
/** /**
* 商品类型 single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券 * 商品类型 single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券
*/ */
@ExcelProperty("商品类型") @ExcelProperty("商品类型")
@ColumnWidth(15)
private String type; private String type;
/**
* 套餐类型 0 固定套餐 1可选套餐
*/
@ExcelIgnore
private Integer groupType;
@ExcelProperty("套餐类型")
private String groupTypeRemark;
/** /**
* 可用开始时间 * 可用开始时间
*/ */
@ExcelProperty("可用开始时间") @ExcelProperty("可用开始时间")
@ColumnWidth(16)
private LocalTime startTime; private LocalTime startTime;
/** /**
* 可用结束时间 * 可用结束时间
*/ */
@ExcelProperty("可用结束时间") @ExcelProperty("可用结束时间")
@ColumnWidth(16)
private LocalTime endTime; private LocalTime endTime;
/** /**
* 商品级库存数量 * 商品级库存数量
*/ */
@ExcelProperty("库存数量") @ExcelProperty("库存数量")
@ColumnWidth(10)
private Integer stockNumber; private Integer stockNumber;
/** /**
@@ -131,16 +79,10 @@ public class ProductExportDTO {
@ExcelIgnore @ExcelIgnore
private Integer isSale; private Integer isSale;
@ExcelProperty("是否上架") @ExcelProperty("是否上架")
@ColumnWidth(10)
private String isSaleRemark; private String isSaleRemark;
@ExcelIgnore
private List<ProductSkuExportDTO> skuList;
@ExcelIgnore
private List<ProductGroupExportDTO> proGroupVo;
public String getType() { public String getType() {
return switch (type) { return switch (type) {
case "single" -> "单规格商品"; case "single" -> "单规格商品";
@@ -152,17 +94,6 @@ public class ProductExportDTO {
}; };
} }
public String getGroupTypeRemark() {
if (!"package".equals(type)) {
return "";
}
return switch (groupType) {
case 0 -> "固定套餐";
case 1 -> "可选套餐";
case null, default -> "未知类型";
};
}
public String getIsSaleRemark() { public String getIsSaleRemark() {
return switch (isSale) { return switch (isSale) {
case 0 -> "下架"; case 0 -> "下架";

View File

@@ -0,0 +1,101 @@
package com.czg.product.dto;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
/**
* 套餐商品导出
* @author yjjie
* @date 2026/1/30 10:26
*/
@Data
@Accessors(chain = true)
public class ProductPackageExportDTO {
@ExcelProperty("套餐名称")
@ColumnWidth(20)
private String name;
@ExcelProperty("套餐分类")
@ColumnWidth(15)
private String categoryName;
@ExcelProperty("售价")
@ColumnWidth(10)
private BigDecimal price;
@ExcelProperty("会员价")
@ColumnWidth(10)
private BigDecimal memberPrice;
/**
* 商品类型 single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券
*/
@ExcelIgnore()
private String type;
/**
* 套餐类型 0 固定套餐 1可选套餐
*/
@ExcelIgnore
private Integer groupType;
@ExcelProperty("套餐类型")
@ColumnWidth(15)
private String groupTypeRemark;
@ExcelProperty("组名称")
@ColumnWidth(15)
private String groupTitleName;
@ExcelProperty("商品名称")
@ColumnWidth(21)
private String groupProductName;
@ExcelProperty("商品单位")
@ColumnWidth(10)
private String unitName;
@ExcelProperty("套餐内选择数量")
@ColumnWidth(10)
private String groupProductNumber;
/**
* 商品级库存数量
*/
@ExcelProperty("库存数量")
@ColumnWidth(10)
private Integer stockNumber;
/**
* 是否上架
*/
@ExcelIgnore
private Integer isSale;
@ExcelProperty("是否上架")
@ColumnWidth(10)
private String isSaleRemark;
public String getGroupTypeRemark() {
if (!"package".equals(type)) {
return "";
}
return switch (groupType) {
case 0 -> "固定套餐";
case 1 -> "可选套餐";
case null, default -> "未知类型";
};
}
public String getIsSaleRemark() {
return switch (isSale) {
case 0 -> "下架";
case 1 -> "上架";
case null, default -> "未知状态";
};
}
}

View File

@@ -1,9 +1,12 @@
package com.czg.excel; package com.czg.excel;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.builder.ExcelWriterBuilder; import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.write.metadata.style.WriteCellStyle;
@@ -248,54 +251,66 @@ public class ExcelExportUtil {
} }
/** /**
* 带合并单元格的商品导出到Response * 带合并单元格的导出到Response
* 多sheet导出到response
* *
* @param data 数据列表 * @param sheetDataList 数据列表
* @param fileName 文件名 * @param fileName 文件名
* @param response HttpServletResponse * @param response HttpServletResponse
* @param <T> 数据类型
*/ */
public static <T> void exportProductWithMergeToResponse(List<T> data, Class<T> clazz, public static void exportMultipleSheetsToResponse(List<SheetData> sheetDataList,
String fileName, String fileName,
HttpServletResponse response, List<SheetWriteHandler> handlers) { HttpServletResponse response) {
if (data == null) { if (CollectionUtil.isEmpty(sheetDataList)) {
data = Collections.emptyList(); throw new CzgException("数据列表不能为空");
} }
setResponseHeader(response, fileName, DEFAULT_CONFIG); setResponseHeader(response, fileName, DEFAULT_CONFIG);
try (OutputStream outputStream = response.getOutputStream()) { try (OutputStream outputStream = response.getOutputStream()) {
// 创建样式策略 - 设置表头和内容都居中 // 创建样式策略
WriteCellStyle headStyle = new WriteCellStyle(); WriteCellStyle headStyle = new WriteCellStyle();
headStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); headStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
headStyle.setVerticalAlignment(VerticalAlignment.CENTER);
WriteCellStyle contentStyle = new WriteCellStyle(); WriteCellStyle contentStyle = new WriteCellStyle();
contentStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); contentStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
contentStyle.setVerticalAlignment(VerticalAlignment.CENTER);
HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(headStyle, contentStyle); HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(headStyle, contentStyle);
// 创建写入器 - 必须指定clazz // 创建ExcelWriter
ExcelWriterBuilder builder = EasyExcel.write(outputStream, clazz) ExcelWriterBuilder builder = EasyExcel.write(outputStream)
.autoCloseStream(true) .autoCloseStream(true)
.registerConverter(new LocalTimeConverter()) .registerConverter(new LocalTimeConverter())
.registerWriteHandler(styleStrategy); .registerWriteHandler(styleStrategy);
if (handlers != null && !handlers.isEmpty()) {
for (SheetWriteHandler h : handlers) {
builder.registerWriteHandler(h);
}
}
ExcelWriter excelWriter = builder.build(); ExcelWriter excelWriter = builder.build();
WriteSheet writeSheet = EasyExcel.writerSheet(DEFAULT_CONFIG.getDefaultSheetName()).build(); // 逐个写入sheet
for (int i = 0; i < sheetDataList.size(); i++) {
SheetData sheetData = sheetDataList.get(i);
String sheetName = StrUtil.isNotBlank(sheetData.getSheetName())
? sheetData.getSheetName()
: DEFAULT_CONFIG.getDefaultSheetName() + (i + 1);
ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet(sheetName);
// 注册该sheet的合并处理器
if (sheetData.getHandlers() != null && !sheetData.getHandlers().isEmpty()) {
for (SheetWriteHandler handler : sheetData.getHandlers()) {
sheetBuilder.registerWriteHandler(handler);
}
}
WriteSheet writeSheet = sheetBuilder.head(sheetData.getClazz()).build();
excelWriter.write(sheetData.getData(), writeSheet);
}
excelWriter.write(data, writeSheet);
excelWriter.finish(); excelWriter.finish();
log.info("多sheet商品Excel导出成功文件名{},共{}个sheet", fileName, sheetDataList.size());
log.info("带合并单元格的商品Excel导出成功文件名{},数据量:{}", fileName, data.size());
} catch (IOException e) { } catch (IOException e) {
log.error("带合并单元格的商品Excel导出失败", e); log.error("多sheet商品Excel导出失败", e);
throw new CzgException("Excel导出失败", e); throw new CzgException("Excel导出失败", e);
} }
} }

View File

@@ -0,0 +1,21 @@
package com.czg.excel;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 多sheet导出数据封装类
* @author yjjie
* @date 2026/1/30 10:53
*/
@Data
@Accessors(chain = true)
public class SheetData {
private List<?> data;
private Class<?> clazz;
private String sheetName;
private List<SheetWriteHandler> handlers;
}

View File

@@ -13,12 +13,14 @@ import com.alibaba.fastjson2.JSONWriter;
import com.czg.constant.CacheConstant; import com.czg.constant.CacheConstant;
import com.czg.constants.SystemConstants; import com.czg.constants.SystemConstants;
import com.czg.excel.ExcelExportUtil; import com.czg.excel.ExcelExportUtil;
import com.czg.excel.SheetData;
import com.czg.exception.CzgException; import com.czg.exception.CzgException;
import com.czg.product.dto.*; import com.czg.product.dto.*;
import com.czg.product.entity.*; import com.czg.product.entity.*;
import com.czg.product.enums.*; import com.czg.product.enums.*;
import com.czg.product.param.*; import com.czg.product.param.*;
import com.czg.product.service.*; import com.czg.product.service.*;
import com.czg.product.vo.ProductGroupVo;
import com.czg.product.vo.ProductStatisticsVo; import com.czg.product.vo.ProductStatisticsVo;
import com.czg.sa.StpKit; import com.czg.sa.StpKit;
import com.czg.service.RedisService; import com.czg.service.RedisService;
@@ -47,6 +49,7 @@ import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.format.TextStyle; import java.time.format.TextStyle;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.czg.constant.CacheConstant.ADMIN_CLIENT_PRODUCT_LIST; import static com.czg.constant.CacheConstant.ADMIN_CLIENT_PRODUCT_LIST;
@@ -141,6 +144,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
private void buildProductExtInfo(List<ProductDTO> records) { private void buildProductExtInfo(List<ProductDTO> records) {
records.forEach(record -> { records.forEach(record -> {
record.setIsSaleTime(calcIsSaleTime(record.getDays(), record.getStartTime(), record.getEndTime())); record.setIsSaleTime(calcIsSaleTime(record.getDays(), record.getStartTime(), record.getEndTime()));
record.setProGroupVo(JSONArray.parseArray(record.getGroupSnap().toString(), ProductGroupVo.class));
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query().eq(ProdSku::getProductId, record.getId()).eq(ProdSku::getIsDel, SystemConstants.OneZero.ZERO), ProdSkuDTO.class); List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query().eq(ProdSku::getProductId, record.getId()).eq(ProdSku::getIsDel, SystemConstants.OneZero.ZERO), ProdSkuDTO.class);
if (CollUtil.isNotEmpty(skuList)) { if (CollUtil.isNotEmpty(skuList)) {
Optional<BigDecimal> lowPriceIsPresent = skuList.stream().map(obj -> NumberUtil.nullToZero(obj.getSalePrice())).min(BigDecimal::compareTo); Optional<BigDecimal> lowPriceIsPresent = skuList.stream().map(obj -> NumberUtil.nullToZero(obj.getSalePrice())).min(BigDecimal::compareTo);
@@ -180,53 +184,151 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
@Override @Override
public void exportProductList(ProductDTO param, HttpServletResponse response) { public void exportProductList(ProductDTO param, HttpServletResponse response) {
// 1. 查询并构建完整数据
QueryWrapper queryWrapper = buildFullQueryWrapper(param); QueryWrapper queryWrapper = buildFullQueryWrapper(param);
List<ProductDTO> records = super.listAs(queryWrapper, ProductDTO.class); List<ProductDTO> records = super.listAs(queryWrapper, ProductDTO.class);
buildProductExtInfo(records); buildProductExtInfo(records);
// 2. 分别处理普通商品和套餐商品
SheetData normalSheet = buildNormalProductSheet(records);
SheetData packageSheet = buildPackageProductSheet(records);
// 3. 导出
List<SheetData> dataList = List.of(normalSheet, packageSheet);
ExcelExportUtil.exportMultipleSheetsToResponse(dataList, "商品列表", response);
}
// -----------------------------
// 普通商品处理
// -----------------------------
private SheetData buildNormalProductSheet(List<ProductDTO> records) {
List<SheetWriteHandler> handlers = new ArrayList<>(); List<SheetWriteHandler> handlers = new ArrayList<>();
List<ProductExportDTO> dataList = new ArrayList<>(); List<ProductExportDTO> dataList = new ArrayList<>();
records.forEach(exportDTO -> {
int first = dataList.size() + 1;
if (exportDTO.getSkuList() != null && !exportDTO.getSkuList().isEmpty()) {
exportDTO.getSkuList().forEach(sku -> {
ProductExportDTO dto = new ProductExportDTO();
BeanUtil.copyProperties(exportDTO, dto);
dto.setSpecFullName(sku.getSpecInfo());
dto.setPrice(sku.getSalePrice());
dto.setMemberPrice(sku.getMemberPrice());
dto.setIsSale(sku.getIsGrounding());
dto.setBarCode(sku.getBarCode());
dataList.add(dto);
});
if (exportDTO.getSkuList().size() > 1) { for (ProductDTO dto : records) {
OnceAbsoluteMergeStrategy name = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 0, 0); if ("package".equals(dto.getType())) continue; // 跳过套餐
handlers.add(name);
OnceAbsoluteMergeStrategy category = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 1, 1); int firstRow = dataList.size() + 1;
handlers.add(category);
OnceAbsoluteMergeStrategy unit = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 6, 6); if (dto.getSkuList() != null && !dto.getSkuList().isEmpty()) {
handlers.add(unit); for (ProdSkuDTO sku : dto.getSkuList()) {
OnceAbsoluteMergeStrategy type = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 7, 7); ProductExportDTO exportDto = new ProductExportDTO();
handlers.add(type); BeanUtil.copyProperties(dto, exportDto);
OnceAbsoluteMergeStrategy groupType = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 8, 8); exportDto.setSpecFullName(sku.getSpecInfo());
handlers.add(groupType); exportDto.setPrice(sku.getSalePrice());
OnceAbsoluteMergeStrategy startTime = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 9, 9); exportDto.setMemberPrice(sku.getMemberPrice());
handlers.add(startTime); exportDto.setIsSale(sku.getIsGrounding());
OnceAbsoluteMergeStrategy endTime = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 10, 10); exportDto.setBarCode(sku.getBarCode());
handlers.add(endTime); exportDto.setCostPrice(sku.getCostPrice());
OnceAbsoluteMergeStrategy stockNumber = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 11, 11); dataList.add(exportDto);
handlers.add(stockNumber); }
OnceAbsoluteMergeStrategy createTime = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 12, 12);
handlers.add(createTime); int skuCount = dto.getSkuList().size();
if (skuCount > 1) {
mergeColumns(handlers, firstRow, firstRow + skuCount - 1,
0, 1, 7, 8, 9, 10, 11); // 多列合并
} }
} else { } else {
dataList.add(BeanUtil.copyProperties(exportDTO, ProductExportDTO.class)); dataList.add(BeanUtil.copyProperties(dto, ProductExportDTO.class));
} }
}); }
ExcelExportUtil.exportProductWithMergeToResponse(dataList, ProductExportDTO.class, "商品列表", response, handlers); return new SheetData()
.setSheetName("普通商品")
.setData(dataList)
.setClazz(ProductExportDTO.class)
.setHandlers(handlers);
}
// -----------------------------
// 套餐商品处理
// -----------------------------
private SheetData buildPackageProductSheet(List<ProductDTO> records) {
List<SheetWriteHandler> handlers = new ArrayList<>();
List<ProductPackageExportDTO> dataList = new ArrayList<>();
for (ProductDTO exportDTO : records) {
if (!"package".equals(exportDTO.getType())) continue;
if (exportDTO.getProGroupVo() == null || exportDTO.getProGroupVo().isEmpty()) {
dataList.add(BeanUtil.copyProperties(exportDTO, ProductPackageExportDTO.class));
continue;
}
int sheetFirstRow = dataList.size() + 1;
boolean needOuterMerge = exportDTO.getProGroupVo().size() > 1;
for (ProductGroupVo proGroupDTO : exportDTO.getProGroupVo()) {
int groupFirstRow = dataList.size() + 1;
List<ProductGroupVo.Food> goods = proGroupDTO.getGoods();
int groupSize = goods.size();
// 添加每条商品记录
for (ProductGroupVo.Food good : goods) {
ProductPackageExportDTO pkgDto = new ProductPackageExportDTO()
.setName(exportDTO.getName())
.setCategoryName(exportDTO.getCategoryName())
.setUnitName(exportDTO.getUnitName())
.setPrice(getMainSkuPrice(exportDTO))
.setMemberPrice(getMainSkuMemberPrice(exportDTO))
.setType(exportDTO.getType())
.setGroupType(exportDTO.getGroupType())
.setStockNumber(exportDTO.getStockNumber())
.setIsSale(getMainSkuIsSale(exportDTO))
.setGroupTitleName(proGroupDTO.getTitle())
.setGroupProductNumber(Optional.ofNullable(proGroupDTO.getNumber()).map(String::valueOf).orElse(""))
.setGroupProductName(good.getProName() + " " + good.getSkuName());
dataList.add(pkgDto);
}
// 组内合并:如果该组有多个商品
if (groupSize > 1) {
needOuterMerge = true;
mergeColumns(handlers, groupFirstRow, groupFirstRow + groupSize - 1, 5, 8);
}
}
// 外层合并:整个套餐的信息(名称、分类等)
if (needOuterMerge) {
int lastRow = dataList.size();
mergeColumns(handlers, sheetFirstRow, lastRow, 0, 1, 2, 3, 4);
}
}
return new SheetData()
.setSheetName("套餐商品")
.setData(dataList)
.setClazz(ProductPackageExportDTO.class)
.setHandlers(handlers);
}
// -----------------------------
// 辅助方法:提取主 SKU 信息(避免重复 getFirst()
// -----------------------------
private BigDecimal getMainSkuPrice(ProductDTO dto) {
return dto.getSkuList().isEmpty() ? null : dto.getSkuList().getFirst().getSalePrice();
}
private BigDecimal getMainSkuMemberPrice(ProductDTO dto) {
return dto.getSkuList().isEmpty() ? null : dto.getSkuList().getFirst().getMemberPrice();
}
private Integer getMainSkuIsSale(ProductDTO dto) {
return dto.getSkuList().isEmpty() ? null : dto.getSkuList().getFirst().getIsSale();
}
// -----------------------------
// 合并工具方法:支持多列合并
// -----------------------------
private void mergeColumns(List<SheetWriteHandler> handlers, int firstRow, int lastRow, int... columns) {
for (int col : columns) {
addMergeHandler(handlers, firstRow, lastRow, col, col);
}
}
private void addMergeHandler(List<SheetWriteHandler> handlers, int firstRow, int lastRow, int firstCol, int lastCol) {
OnceAbsoluteMergeStrategy strategy = new OnceAbsoluteMergeStrategy(firstRow, lastRow, firstCol, lastCol);
handlers.add(strategy);
} }
@Override @Override