商品导出
This commit is contained in:
@@ -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 -> "下架";
|
||||||
|
|||||||
@@ -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 -> "未知状态";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user