商品导出

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

@@ -13,12 +13,14 @@ import com.alibaba.fastjson2.JSONWriter;
import com.czg.constant.CacheConstant;
import com.czg.constants.SystemConstants;
import com.czg.excel.ExcelExportUtil;
import com.czg.excel.SheetData;
import com.czg.exception.CzgException;
import com.czg.product.dto.*;
import com.czg.product.entity.*;
import com.czg.product.enums.*;
import com.czg.product.param.*;
import com.czg.product.service.*;
import com.czg.product.vo.ProductGroupVo;
import com.czg.product.vo.ProductStatisticsVo;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
@@ -47,6 +49,7 @@ import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.TextStyle;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
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) {
records.forEach(record -> {
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);
if (CollUtil.isNotEmpty(skuList)) {
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
public void exportProductList(ProductDTO param, HttpServletResponse response) {
// 1. 查询并构建完整数据
QueryWrapper queryWrapper = buildFullQueryWrapper(param);
List<ProductDTO> records = super.listAs(queryWrapper, ProductDTO.class);
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<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) {
OnceAbsoluteMergeStrategy name = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 0, 0);
handlers.add(name);
OnceAbsoluteMergeStrategy category = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 1, 1);
handlers.add(category);
OnceAbsoluteMergeStrategy unit = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 6, 6);
handlers.add(unit);
OnceAbsoluteMergeStrategy type = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 7, 7);
handlers.add(type);
OnceAbsoluteMergeStrategy groupType = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 8, 8);
handlers.add(groupType);
OnceAbsoluteMergeStrategy startTime = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 9, 9);
handlers.add(startTime);
OnceAbsoluteMergeStrategy endTime = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 10, 10);
handlers.add(endTime);
OnceAbsoluteMergeStrategy stockNumber = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 11, 11);
handlers.add(stockNumber);
OnceAbsoluteMergeStrategy createTime = new OnceAbsoluteMergeStrategy(first, first + exportDTO.getSkuList().size() - 1, 12, 12);
handlers.add(createTime);
for (ProductDTO dto : records) {
if ("package".equals(dto.getType())) continue; // 跳过套餐
int firstRow = dataList.size() + 1;
if (dto.getSkuList() != null && !dto.getSkuList().isEmpty()) {
for (ProdSkuDTO sku : dto.getSkuList()) {
ProductExportDTO exportDto = new ProductExportDTO();
BeanUtil.copyProperties(dto, exportDto);
exportDto.setSpecFullName(sku.getSpecInfo());
exportDto.setPrice(sku.getSalePrice());
exportDto.setMemberPrice(sku.getMemberPrice());
exportDto.setIsSale(sku.getIsGrounding());
exportDto.setBarCode(sku.getBarCode());
exportDto.setCostPrice(sku.getCostPrice());
dataList.add(exportDto);
}
int skuCount = dto.getSkuList().size();
if (skuCount > 1) {
mergeColumns(handlers, firstRow, firstRow + skuCount - 1,
0, 1, 7, 8, 9, 10, 11); // 多列合并
}
} 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