Merge branch 'refs/heads/master' into 支付优化测试

This commit is contained in:
seesaw
2024-10-21 10:08:26 +08:00
9 changed files with 232 additions and 45 deletions

View File

@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.member.controller.admin.customizeExcel; package cn.iocoder.yudao.module.member.controller.admin.customizeExcel;
import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler; import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.member.controller.admin.customizeExcel.vo.OrderExcelVO; import cn.iocoder.yudao.module.member.controller.admin.customizeExcel.vo.OrderExcelVO;
import cn.iocoder.yudao.module.member.service.customizeExcel.CustomizeExcelService; import cn.iocoder.yudao.module.member.service.customizeExcel.CustomizeExcelService;
import cn.iocoder.yudao.module.member.util.CustomMergeStrategy;
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.converters.longconverter.LongStringConverter; import com.alibaba.excel.converters.longconverter.LongStringConverter;
@ -12,6 +14,9 @@ import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -23,9 +28,11 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@ -42,47 +49,98 @@ public class CustomizeExcelController {
@GetMapping("/orderExcel") @GetMapping("/orderExcel")
@Operation(summary = "导出订单详情") @Operation(summary = "导出订单详情")
@OperateLog(type = EXPORT) @OperateLog(type = EXPORT)
public void exportBusinessExcel(String startTime,String endTime, public void exportBusinessExcel(String startTime,String endTime,Long carteenId,
HttpServletResponse response) throws IOException { HttpServletResponse response) throws IOException {
List<OrderExcelVO> orderExcelVOS = excelService.exportOrderExcel(startTime, endTime); List<OrderExcelVO> orderExcelVOS = excelService.exportOrderExcel(startTime, endTime,carteenId);
// 导出 Excel // 导出 Excel
ExcelUtils.write(response, "订单详情统计.xls", "数据", OrderExcelVO.class, ExcelUtils.write(response, "订单详情统计.xls", "数据", OrderExcelVO.class,
orderExcelVOS); orderExcelVOS);
} }
@GetMapping("/orderExcel1")
@Operation(summary = "导出订单详情")
@OperateLog(type = EXPORT)
public void exportBusinessExcel1(String startTime,String endTime,Long carteenId,
HttpServletResponse response) throws IOException {
List<OrderExcelVO> orderExcelVOS = excelService.exportOrderExcel(startTime, endTime,carteenId);
exporOrderDate(orderExcelVOS,response);
}
/** /**
* 根据时间导出多个sheet 页 * 根据时间导出多个sheet 页
* @param list * @param
* @param data1
* @param response * @param response
* @throws IOException * @throws IOException
*/ */
public void exporOrderDate(List<OrderExcelVO> list,HttpServletResponse response) throws IOException { public void exporOrderDate(List<OrderExcelVO> data1,HttpServletResponse response) throws IOException {
Map<String, List<OrderExcelVO>> collect = list.stream().collect(Collectors.groupingBy(OrderExcelVO::getDayTime)); data1.forEach(f->
{
f.setDayTime(f.getDayTime().substring(0,10));
if(f.getNickname()==null ){
f.setNickname("null");
}
if(f.getMobile()==null){
f.setMobile("null");
}
});
Map<String, List<OrderExcelVO>> collect = data1.stream().collect(Collectors.groupingBy(OrderExcelVO::getDayTime));
// 按key时间排序将数据按时间顺序放入列表 // 按key时间排序将数据按时间顺序放入列表
List<Map.Entry<String, List<OrderExcelVO>>> sortedEntries = collect.entrySet() List<Map.Entry<String, List<OrderExcelVO>>> sortedEntries = collect.entrySet()
.stream() .stream()
.sorted(Map.Entry.comparingByKey()) // 按时间排序 .sorted(Map.Entry.comparingByKey()) // 按时间排序
.collect(Collectors.toList()); .collect(Collectors.toList());
// 创建输出流 long l = System.currentTimeMillis();
try (OutputStream outputStream = response.getOutputStream(); // 设置文件名和响应内容类型
ExcelWriter excelWriter = EasyExcel.write(outputStream).build()) { response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("订单详情统计.xlsx", StandardCharsets.UTF_8.name()));
int sheetIndex = 0; response.setContentType("application/vnd.ms-excel;charset=UTF-8");
// 逐个创建Sheet并写入每个时间段的数据 try (SXSSFWorkbook workbook = new SXSSFWorkbook(); OutputStream outputStream = response.getOutputStream()) {
for (Map.Entry<String, List<OrderExcelVO>> entry : sortedEntries) { for (Map.Entry<String, List<OrderExcelVO>> entry : sortedEntries) {
WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex, "数据 " + entry.getKey()) // 使用时间作为sheet // 创建一个Sheet
.head(OrderExcelVO.class) Sheet sheet = workbook.createSheet("数据"+entry.getKey());
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 自动列宽策略 // 处理数据和写入逻辑
.build(); createHeader(sheet, workbook); // 创建表头
// 写入数据到当前Sheet int rowNum = 1;
excelWriter.write(entry.getValue(), writeSheet); // 写入数据
sheetIndex++; for (OrderExcelVO order : data1) {
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(order.getDayTime());
row.createCell(1).setCellValue(order.getNickname());
row.createCell(2).setCellValue(order.getMobile());
row.createCell(3).setCellValue(order.getTimeSlot());
row.createCell(4).setCellValue(order.getTotalMoney().toString());
row.createCell(5).setCellValue(order.getDishesName());
row.createCell(5).setCellValue(order.getUnitPrice()==null?"0.00":order.getUnitPrice().toString());
row.createCell(7).setCellValue(order.getWeight());
row.createCell(8).setCellValue(order.getPrice().toString());
}
List<OrderExcelVO> data = entry.getValue();
List<List<String>> collect1 = Stream.of(data.stream().map(OrderExcelVO::getNickname).collect(Collectors.toList()), data.stream().map(OrderExcelVO::getMobile).collect(Collectors.toList()), data.stream().map(f -> f.getTotalMoney().toString()).collect(Collectors.toList())).collect(Collectors.toList());
Map<Integer, Integer> map = new HashMap<>();
map.put(1, 0); // 第三列合并
map.put(2, 1); // 第三列合并
map.put(3, 2); // 第三列合并
map.put(4, 2); // 第四列合并
CustomMergeStrategy customMergeStrategy = new CustomMergeStrategy(collect1, map);
customMergeStrategy.merge(sheet,4);
// 将数据写入输出流
} }
// 下载EXCEL返回给前段stream流 workbook.write(outputStream);
excelWriter.finish();
outputStream.flush(); outputStream.flush();
System.out.println( System.currentTimeMillis()-l);
} }
} }
// 创建表头
private void createHeader(Sheet sheet, SXSSFWorkbook workbook) {
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("日期");
header.createCell(1).setCellValue("用户名");
header.createCell(2).setCellValue("手机");
header.createCell(3).setCellValue("总价");
header.createCell(4).setCellValue("时间段");
header.createCell(5).setCellValue("菜名");
header.createCell(6).setCellValue("单价(元/50g");
header.createCell(7).setCellValue("重量g");
header.createCell(8).setCellValue("价格(元)");
}
} }

View File

@ -9,7 +9,7 @@ import java.util.List;
@Data @Data
public class BusinessDataVO { public class BusinessDataVO {
private BusinessRespVO old; private BusinessRespVO now;
private List<BusinessRespVO> businessList; private List<BusinessRespVO> businessList;

View File

@ -11,5 +11,5 @@ import java.util.List;
public interface CustomizeExcelMapper { public interface CustomizeExcelMapper {
List<OrderExcelVO> selectOrder(@Param("startTime")String startTime, @Param("endTime")String endTime); List<OrderExcelVO> selectOrder(@Param("startTime")String startTime, @Param("endTime")String endTime, @Param("carteenId")Long carteenId);
} }

View File

@ -166,6 +166,9 @@ public class BusinessServiceImpl implements BusinessService {
@Override @Override
public BusinessDataVO getDay(String time,Long carteenId) { public BusinessDataVO getDay(String time,Long carteenId) {
Integer nowDay = MemberTimeUtils.getDay(time);
time = MemberTimeUtils.getYearMonth(time);
BusinessDataVO businessDataVO = new BusinessDataVO(); BusinessDataVO businessDataVO = new BusinessDataVO();
LambdaQueryWrapper<BusinessDO> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<BusinessDO> wrapper = new LambdaQueryWrapper<>();
@ -210,17 +213,14 @@ public class BusinessServiceImpl implements BusinessService {
if(CollectionUtil.isNotEmpty(previousList)){ if(CollectionUtil.isNotEmpty(previousList)){
BeanUtil.copyProperties(previousList.get(0), old); BeanUtil.copyProperties(previousList.get(0), old);
}else { }else {
old.setTurnover(BigDecimal.ZERO).setOrderSum(0).setReduce(BigDecimal.ZERO).setWeigh(BigDecimal.ZERO) old = getInitBusinessRespVO();
.setBreakfast(BigDecimal.ZERO).setLunch(BigDecimal.ZERO).setDinner(BigDecimal.ZERO);
} }
// 循环遍历该月的每一天 // 循环遍历该月的每一天
for (int day = 1; day <= daysInMonth; day++) { for (int day = 1; day <= daysInMonth; day++) {
BusinessRespVO bean = new BusinessRespVO(); BusinessRespVO bean = new BusinessRespVO();
if(map.get(day) == null){ if(map.get(day) == null){
bean.setTurnover(BigDecimal.ZERO).setOrderSum(0).setReduce(BigDecimal.ZERO).setWeigh(BigDecimal.ZERO) bean = getInitBusinessRespVO().setTime(String.valueOf(day));
.setBreakfast(BigDecimal.ZERO).setLunch(BigDecimal.ZERO).setDinner(BigDecimal.ZERO)
.setTime(String.valueOf(day));
}else { }else {
bean = BeanUtils.toBean(map.get(day), BusinessRespVO.class); bean = BeanUtils.toBean(map.get(day), BusinessRespVO.class);
bean.setTime(String.valueOf(day)); bean.setTime(String.valueOf(day));
@ -234,7 +234,7 @@ public class BusinessServiceImpl implements BusinessService {
monthData.put(day,bean); monthData.put(day,bean);
} }
businessDataVO.setNow(monthData.get(nowDay));
businessDataVO.setBusinessList(new ArrayList<>(monthData.values())); businessDataVO.setBusinessList(new ArrayList<>(monthData.values()));
return businessDataVO; return businessDataVO;
} }
@ -254,10 +254,7 @@ public class BusinessServiceImpl implements BusinessService {
int totalWeeksOfMonth = MemberTimeUtils.getTotalWeeksOfMonth(time); int totalWeeksOfMonth = MemberTimeUtils.getTotalWeeksOfMonth(time);
for (int i = 1; i <= totalWeeksOfMonth; i++) { for (int i = 1; i <= totalWeeksOfMonth; i++) {
BusinessRespVO bean = new BusinessRespVO(); BusinessRespVO bean = getInitBusinessRespVO().setTime(String.valueOf(i));
bean.setTurnover(BigDecimal.ZERO).setOrderSum(0).setReduce(BigDecimal.ZERO).setWeigh(BigDecimal.ZERO)
.setBreakfast(BigDecimal.ZERO).setLunch(BigDecimal.ZERO).setDinner(BigDecimal.ZERO)
.setTime(String.valueOf(i));
map.put(i,bean); map.put(i,bean);
} }
@ -281,6 +278,7 @@ public class BusinessServiceImpl implements BusinessService {
@Override @Override
public BusinessDataVO getMonth(String time,Long carteenId) { public BusinessDataVO getMonth(String time,Long carteenId) {
time = MemberTimeUtils.getYearMonth(time);
BusinessDataVO businessDataVO = new BusinessDataVO(); BusinessDataVO businessDataVO = new BusinessDataVO();
@ -295,10 +293,8 @@ public class BusinessServiceImpl implements BusinessService {
Map<Integer,BusinessRespVO> map = new HashMap<>(); Map<Integer,BusinessRespVO> map = new HashMap<>();
//时间处理 //时间处理
for (int i = 1; i <= 12; i++) { for (int i = 1; i <= 12; i++) {
BusinessRespVO bean = new BusinessRespVO(); BusinessRespVO bean = getInitBusinessRespVO();
bean.setTurnover(BigDecimal.ZERO).setOrderSum(0).setReduce(BigDecimal.ZERO).setWeigh(BigDecimal.ZERO) bean.setTime(String.valueOf(i));
.setBreakfast(BigDecimal.ZERO).setLunch(BigDecimal.ZERO).setDinner(BigDecimal.ZERO)
.setTime(String.valueOf(i));
map.put(i,bean); map.put(i,bean);
} }
//数据统计 //数据统计
@ -319,9 +315,7 @@ public class BusinessServiceImpl implements BusinessService {
previousWrapper.orderByAsc(BusinessDO::getCreateTime); previousWrapper.orderByAsc(BusinessDO::getCreateTime);
previousWrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", previousYear+"-12"); previousWrapper.apply("DATE_FORMAT(create_time, '%Y-%m') = {0}", previousYear+"-12");
List<BusinessDO> previousList = businessMapper.selectList(previousWrapper); List<BusinessDO> previousList = businessMapper.selectList(previousWrapper);
BusinessRespVO previousVO = new BusinessRespVO(); BusinessRespVO previousVO = getInitBusinessRespVO();
previousVO.setTurnover(BigDecimal.ZERO).setOrderSum(0).setReduce(BigDecimal.ZERO).setWeigh(BigDecimal.ZERO)
.setBreakfast(BigDecimal.ZERO).setLunch(BigDecimal.ZERO).setDinner(BigDecimal.ZERO);
for (BusinessDO businessDO : previousList) { for (BusinessDO businessDO : previousList) {
handleBusiness(businessDO,previousVO); handleBusiness(businessDO,previousVO);
} }
@ -334,6 +328,8 @@ public class BusinessServiceImpl implements BusinessService {
} }
} }
int month = MemberTimeUtils.getMonthFromYearMonthString(time);
businessDataVO.setNow(map.get(month));
businessDataVO.setBusinessList(new ArrayList<>(map.values())); businessDataVO.setBusinessList(new ArrayList<>(map.values()));
return businessDataVO; return businessDataVO;
@ -346,7 +342,9 @@ public class BusinessServiceImpl implements BusinessService {
//订单数 //订单数
businessRespVO.setOrderSum(businessRespVO.getOrderSum()+businessDO.getOrderSum()); businessRespVO.setOrderSum(businessRespVO.getOrderSum()+businessDO.getOrderSum());
//均单价 //均单价
businessRespVO.setPriceAvg(businessDO.getTurnover().divide(new BigDecimal(businessDO.getOrderSum()), 2, RoundingMode.HALF_UP)); if(businessRespVO.getOrderSum()!=0){
businessRespVO.setPriceAvg(businessRespVO.getTurnover().divide(new BigDecimal(businessRespVO.getOrderSum().toString()), 2, RoundingMode.HALF_UP));
}
//减免金额 //减免金额
businessRespVO.setReduce(businessRespVO.getReduce().add(businessDO.getReduce())); businessRespVO.setReduce(businessRespVO.getReduce().add(businessDO.getReduce()));
//重量 //重量
@ -367,4 +365,11 @@ public class BusinessServiceImpl implements BusinessService {
today.setPriceAvgCompare(today.getPriceAvg().subtract(last.getPriceAvg())); today.setPriceAvgCompare(today.getPriceAvg().subtract(last.getPriceAvg()));
} }
BusinessRespVO getInitBusinessRespVO() {
BusinessRespVO previousVO = new BusinessRespVO();
previousVO.setTurnover(BigDecimal.ZERO).setOrderSum(0).setReduce(BigDecimal.ZERO).setWeigh(BigDecimal.ZERO)
.setBreakfast(BigDecimal.ZERO).setLunch(BigDecimal.ZERO).setDinner(BigDecimal.ZERO).setPriceAvg(BigDecimal.ZERO);
return previousVO;
}
} }

View File

@ -10,5 +10,5 @@ import java.util.List;
public interface CustomizeExcelService { public interface CustomizeExcelService {
List<OrderExcelVO> exportOrderExcel(String startTime,String endTime); List<OrderExcelVO> exportOrderExcel(String startTime,String endTime,Long carteenId);
} }

View File

@ -17,7 +17,7 @@ public class CustomizeExcelServiceImpl implements CustomizeExcelService {
@Override @Override
public List<OrderExcelVO> exportOrderExcel(String startTime, String endTime) { public List<OrderExcelVO> exportOrderExcel(String startTime, String endTime,Long carteenId) {
return customizeExcelMapper.selectOrder(startTime,endTime); return customizeExcelMapper.selectOrder(startTime,endTime,carteenId);
} }
} }

View File

@ -0,0 +1,102 @@
package cn.iocoder.yudao.module.member.util;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.util.ObjectUtils;
import java.util.*;
public class CustomMergeStrategy {
/**
* 分组,每几行合并一次
*/
private final List<List<Integer>> mergeColDataGroupCountList;
/**
* 目标合并列index
*/
private final Map<Integer, Integer> targetColumnIndex;
/**
* 需要开始合并单元格的首行index
*/
private Integer rowIndex;
//存放合并的
private Map<Integer,List<Integer>> aaa=new HashMap<>();
/**
* mergeColDataList为待合并目标列的值
*/
public CustomMergeStrategy(List<List<String>> mergeColDataList, Map<Integer, Integer> targetColumnIndex) {
this.mergeColDataGroupCountList = getGroupCountList(mergeColDataList);
this.targetColumnIndex = targetColumnIndex;
}
public void merge(Sheet sheet,int i) {
rowIndex = 1; // 假设从第二行开始合并,第一行为表头
// 遍历所有行
Iterator<Row> rowIterator = sheet.rowIterator();
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
int i1=0;
Iterator<Cell> cellIterator = row.cellIterator();
while (cellIterator.hasNext()) {
if(i1>i){
return;
}
Cell cell = cellIterator.next();
if (null == rowIndex) {
rowIndex = cell.getRowIndex();
}
// 仅从首行以及目标列的单元格开始合并,忽略其他
if (targetColumnIndex.get(cell.getColumnIndex())!=null) {
//找到对应的需要合并的列
mergeGroupColumn(sheet, targetColumnIndex.get(cell.getColumnIndex()),cell.getColumnIndex());
}
i1++;
}
}
}
private void mergeGroupColumn(Sheet sheet, Integer index,Integer i) {
int rowCount = rowIndex;
for (Integer count : mergeColDataGroupCountList.get(index)) {
if (count == 1) {
rowCount += count;
continue;
}
// 合并单元格
CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1,
i, i);
sheet.addMergedRegion(cellRangeAddress);
rowCount += count;
}
}
/**
* 该方法将目标列根据值是否相同连续可合并,存储可合并的行数
*/
private List<List<Integer>> getGroupCountList(List<List<String>> exportDataList) {
if (ObjectUtils.isEmpty(exportDataList)) {
return new ArrayList<>();
}
List<List<Integer>> groupCountListList = new ArrayList<>();
for (List<String> dataList : exportDataList) {
List<Integer> groupCountList = new ArrayList<>();
int count = 1;
for (int i = 1; i < dataList.size(); i++) {
if (dataList.get(i).equals(dataList.get(i - 1))) {
count++;
} else {
groupCountList.add(count);
count = 1;
}
}
// 处理完最后一条后
groupCountList.add(count);
groupCountListList.add(groupCountList);
}
return groupCountListList;
}
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.member.util;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.YearMonth; import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.WeekFields; import java.time.temporal.WeekFields;
import java.util.Locale; import java.util.Locale;
@ -41,4 +42,25 @@ public class MemberTimeUtils {
// 返回年份 // 返回年份
return yearMonth.getYear(); return yearMonth.getYear();
} }
public static int getMonthFromYearMonthString(String yearMonthString) {
// 使用YearMonth类解析字符串
YearMonth yearMonth = YearMonth.parse(yearMonthString);
// 返回年份
return yearMonth.getMonth().getValue();
}
public static String getYearMonth(String time) {
// 解析成 LocalDate
LocalDate date = LocalDate.parse(time);
// 获取年份和月份,并格式化为 yyyy-MM 格式
return date.format(DateTimeFormatter.ofPattern("yyyy-MM"));
}
public static Integer getDay(String time) {
LocalDate date = LocalDate.parse(time);
return date.getDayOfMonth();
}
} }

View File

@ -27,7 +27,7 @@
from member_order_detail md from member_order_detail md
left join member_dish_order mo on md.order_id = mo.id left join member_dish_order mo on md.order_id = mo.id
left join member_user mu on mu.id = mo.user_id left join member_user mu on mu.id = mo.user_id
where DATE_FORMAT(md.create_time, '%Y%m%d') between #{startTime} and #{endTime} where DATE_FORMAT(md.create_time, '%Y%m%d') between #{startTime} and #{endTime} and mo.store_id = #{carteenId}
order by mo.user_id,order_id order by mo.user_id,order_id
</select> </select>