From 392b42c4891cf2e6beda57ab32c51598f290f4b7 Mon Sep 17 00:00:00 2001 From: mitao <2763622819@qq.com> Date: 星期五, 14 三月 2025 20:56:27 +0800 Subject: [PATCH] bug修改 --- ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/MgtBusinessDataService.java | 311 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 302 insertions(+), 9 deletions(-) diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/MgtBusinessDataService.java b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/MgtBusinessDataService.java index db8ee35..1b9284e 100644 --- a/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/MgtBusinessDataService.java +++ b/ruoyi-modules/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/MgtBusinessDataService.java @@ -1,44 +1,175 @@ package com.ruoyi.order.service.impl; +import com.alibaba.excel.EasyExcel; +import com.google.common.collect.Lists; +import com.ruoyi.common.core.enums.AuctionOrderTypeEnum; +import com.ruoyi.common.core.enums.OrderFromEnum; +import com.ruoyi.common.core.enums.OrderTypeEnum; import com.ruoyi.common.core.enums.TimeTypeEnum; import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.utils.DateUtils; +import com.ruoyi.common.core.utils.page.CollUtils; import com.ruoyi.order.controller.management.dto.MgtOrderStaticsQuery; +import com.ruoyi.order.controller.management.vo.MgtAmountChartVO; +import com.ruoyi.order.controller.management.vo.MgtCountChartVO; +import com.ruoyi.order.controller.management.vo.MgtOrderStaticsChartVO; import com.ruoyi.order.controller.management.vo.MgtOrderStaticsVO; import com.ruoyi.order.service.IOrderService; +import com.ruoyi.system.api.domain.Order; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; /** * @author mitao * @date 2024/6/19 */ +@Slf4j @Service @RequiredArgsConstructor public class MgtBusinessDataService { private final IOrderService orderService; + /** + * 获取业务数据统计 + * + * @param query 订单统计查询对象 + * @return MgtOrderStaticsVO + */ public MgtOrderStaticsVO getOverview(MgtOrderStaticsQuery query) { - LocalDateTime now = LocalDateTime.now(); - LocalDateTime startTime = null; - LocalDateTime endTime = null; - getTimeByTimeType(query, startTime, endTime, now); - return null; + + List<LocalDateTime> timeByTimeType = getTimeByTimeType(query); + LocalDateTime startTime = timeByTimeType.get(0); + LocalDateTime endTime = timeByTimeType.get(1); + List<Order> orderList = orderService.getStaticsOrderList(startTime, endTime); + MgtOrderStaticsVO mgtOrderStaticsVO = new MgtOrderStaticsVO(); + if (CollUtils.isNotEmpty(orderList)) { + /* ***************************************商城订单统计*************************************** */ + // 商城订单统计-订单总数 + long mallOrderTotalCount = orderList.stream() + .filter(order -> !order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS)) + .count(); + // 商城订单统计-商城订单 + long mallOrderCount = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.COMMODITY_ORDER)) + .count(); + // 商城订单统计-秒杀订单 + long seckillOrderCount = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.SNAP_ORDERS)) + .count(); + // 商城订单统计-团购订单 + long groupPurchaseOrderCount = orderList.stream() + .filter(order -> order.getOrderFrom() + .equals(OrderFromEnum.GROUP_PURCHASE_ORDERS)) + .count(); + // 商城订单统计-订单总金额 + BigDecimal mallOrderTotalAmount = orderList.stream() + .filter(order -> !order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS)) + .map(Order::getTotalAmount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + // 商城订单统计 - 商城总金额 + BigDecimal mallTotalAmount = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.COMMODITY_ORDER)) + .map(Order::getTotalAmount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + // 商城订单统计-秒杀总金额 + BigDecimal seckillTotalAmount = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.SNAP_ORDERS)) + .map(Order::getTotalAmount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + + // 商城订单统计-团购总金额 + BigDecimal groupPurchaseTotalAmount = orderList.stream() + .filter(order -> order.getOrderFrom() + .equals(OrderFromEnum.GROUP_PURCHASE_ORDERS)) + .map(Order::getTotalAmount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + + mgtOrderStaticsVO.setMallOrderTotalCount(mallOrderTotalCount); + mgtOrderStaticsVO.setMallOrderCount(mallOrderCount); + mgtOrderStaticsVO.setSeckillOrderCount(seckillOrderCount); + mgtOrderStaticsVO.setGroupPurchaseOrderCount(groupPurchaseOrderCount); + + mgtOrderStaticsVO.setMallOrderTotalAmount(mallOrderTotalAmount); + mgtOrderStaticsVO.setMallTotalAmount(mallTotalAmount); + mgtOrderStaticsVO.setSeckillTotalAmount(seckillTotalAmount); + mgtOrderStaticsVO.setGroupPurchaseTotalAmount(groupPurchaseTotalAmount); + + /* ***************************************拍卖订单统计*************************************** */ + // 拍卖订单统计-订单总数 + long auctionOrderTotalCount = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS)) + .count(); + // 拍卖订单统计-拍卖商品订单 + long auctionGoodsOrderCount = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS) + && order.getAuctionOrderType() + .equals(AuctionOrderTypeEnum.REGULAR_ITEMS)) + .count(); + // 拍卖订单统计-拍卖场订单 + long auctionSalesroomOrderCount = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS) + && order.getAuctionOrderType() + .equals(AuctionOrderTypeEnum.AUCTION_ITEMS)) + .count(); + // 拍卖订单统计-订单总金额 + BigDecimal auctionOrderTotalAmount = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS)) + .map(Order::getTotalAmount) + .reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + // 拍卖订单统计-拍卖商品总金额 + BigDecimal auctionGoodsTotalAmount = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS) + && order.getAuctionOrderType() + .equals(AuctionOrderTypeEnum.REGULAR_ITEMS) + ) + .map(Order::getTotalAmount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + // 拍卖订单统计-拍卖场总金额 + BigDecimal auctionSalesroomTotalAmount = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS) + && order.getAuctionOrderType() + .equals(AuctionOrderTypeEnum.AUCTION_ITEMS)) + .map(Order::getTotalAmount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + + mgtOrderStaticsVO.setAuctionOrderTotalCount(auctionOrderTotalCount); + mgtOrderStaticsVO.setAuctionGoodsOrderCount(auctionGoodsOrderCount); + mgtOrderStaticsVO.setAuctionSalesroomOrderCount(auctionSalesroomOrderCount); + + mgtOrderStaticsVO.setAuctionOrderTotalAmount(auctionOrderTotalAmount); + mgtOrderStaticsVO.setAuctionGoodsTotalAmount(auctionGoodsTotalAmount); + mgtOrderStaticsVO.setAuctionSalesroomTotalAmount(auctionSalesroomTotalAmount); + } + return mgtOrderStaticsVO; } - private static void getTimeByTimeType(MgtOrderStaticsQuery query, LocalDateTime startTime, - LocalDateTime endTime, LocalDateTime now) { + private List<LocalDateTime> getTimeByTimeType(MgtOrderStaticsQuery query) { + LocalDateTime startTime; + LocalDateTime endTime; + List<LocalDateTime> range = new ArrayList<>(); + LocalDateTime now = LocalDateTime.now(); if (Objects.equals(TimeTypeEnum.TODAY.getCode(), query.getTimeType())) { startTime = DateUtils.getDayStart(now); endTime = DateUtils.getDayEnd(now); } else if (Objects.equals(TimeTypeEnum.PAST_SEVEN_DAYS.getCode(), query.getTimeType())) { - startTime = DateUtils.getDayStart(now.minusDays(7)); + startTime = DateUtils.getDayStart(now.minusDays(6)); // 过去七天 为过去六天加今天 endTime = DateUtils.getDayEnd(now); } else if (Objects.equals(TimeTypeEnum.PAST_THIRTY_DAYS.getCode(), query.getTimeType())) { - startTime = DateUtils.getDayStart(now.minusDays(30)); + startTime = DateUtils.getDayStart(now.minusDays(29)); // 过去30天 为过去29天加今天 endTime = DateUtils.getDayEnd(now); } else if (Objects.equals(TimeTypeEnum.CUSTOM.getCode(), query.getTimeType())) { if (Objects.isNull(query.getStartTime()) || Objects.isNull(query.getEndTime())) { @@ -50,5 +181,167 @@ startTime = DateUtils.getDayStart(now); endTime = DateUtils.getDayEnd(now); } + range.add(startTime); + range.add(endTime); + return range; + } + + /** + * 获取图表数据 + * + * @return MgtOrderStaticsChartVO + */ + public MgtOrderStaticsChartVO getChart() { + LocalDateTime now = LocalDateTime.now(); + LocalDateTime startTime = DateUtils.getDayStart(now.minusDays(29)); + LocalDateTime endTime = DateUtils.getDayEnd(now); + List<LocalDate> datesBetween = getDatesBetween(startTime.toLocalDate(), + endTime.toLocalDate()); + // 根据开始时间和结束时间,获取这个范围的每一天的日期 + List<Order> orderList = orderService.getStaticsOrderList(startTime, endTime); + ExecutorService executorService = Executors.newFixedThreadPool(4); + // 商城订单总数 + CompletableFuture<List<MgtCountChartVO>> mallOrderCountFuture = CompletableFuture.supplyAsync( + () -> getMgtCountChartVOS(datesBetween, orderList, OrderTypeEnum.MALL_ODER), + executorService); + // 商城订单总金额 + CompletableFuture<List<MgtAmountChartVO>> mallOrderTotalAmountFuture = CompletableFuture.supplyAsync( + () -> getMgtAmountChartVOS(datesBetween, orderList, OrderTypeEnum.MALL_ODER), + executorService); + // 拍卖订单总数 + CompletableFuture<List<MgtCountChartVO>> auctionOrderCountFuture = CompletableFuture.supplyAsync( + () -> getMgtCountChartVOS(datesBetween, orderList, OrderTypeEnum.AUCTION_ORDER), + executorService); + // 拍卖订单总金额 + CompletableFuture<List<MgtAmountChartVO>> auctionOrderTotalAmountFuture = CompletableFuture.supplyAsync( + () -> getMgtAmountChartVOS(datesBetween, orderList, OrderTypeEnum.AUCTION_ORDER), + executorService); + // 使用 join 方法阻塞当前线程,直到所有任务完成 + CompletableFuture.allOf(mallOrderCountFuture, + mallOrderTotalAmountFuture, auctionOrderCountFuture, auctionOrderTotalAmountFuture) + .join(); + MgtOrderStaticsChartVO mgtOrderStaticsChartVO = new MgtOrderStaticsChartVO(); + try { + // 设置结果 + mgtOrderStaticsChartVO.setMallOrderCountList(mallOrderCountFuture.get()); + mgtOrderStaticsChartVO.setMallOrderTotalAmountList(mallOrderTotalAmountFuture.get()); + mgtOrderStaticsChartVO.setAuctionOrderCountList(auctionOrderCountFuture.get()); + mgtOrderStaticsChartVO.setAuctionOrderTotalAmountList( + auctionOrderTotalAmountFuture.get()); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } finally { + executorService.shutdown(); // 确保关闭线程池 + } + return mgtOrderStaticsChartVO; + } + + @NotNull + private static List<MgtAmountChartVO> getMgtAmountChartVOS(List<LocalDate> datesBetween, + List<Order> orderList, OrderTypeEnum type) { + Map<String, BigDecimal> orderTotalAmountMap; + if (type.equals(OrderTypeEnum.MALL_ODER)) { + orderTotalAmountMap = orderList.stream() + .filter(order -> !order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS)) + .collect(Collectors.groupingBy(order -> order.getOrderTime().toLocalDate() + .format(DateTimeFormatter.ofPattern("MM-dd")), + Collectors.reducing(BigDecimal.ZERO, Order::getTotalAmount, + BigDecimal::add))); + } else if (type.equals(OrderTypeEnum.AUCTION_ORDER)) { + orderTotalAmountMap = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS)) + .collect(Collectors.groupingBy(order -> order.getOrderTime().toLocalDate() + .format(DateTimeFormatter.ofPattern("MM-dd")), + Collectors.reducing(BigDecimal.ZERO, Order::getTotalAmount, + BigDecimal::add))); + } else { + orderTotalAmountMap = null; + } + if (orderTotalAmountMap != null) { + return datesBetween.stream().map(date -> { + MgtAmountChartVO mgtAmountChartVO = new MgtAmountChartVO(); + mgtAmountChartVO.setDate(date.format(DateTimeFormatter.ofPattern("MM-dd"))); + BigDecimal orderTotalAmount = orderTotalAmountMap.get( + date.format(DateTimeFormatter.ofPattern("MM-dd"))); + mgtAmountChartVO.setValue( + orderTotalAmount == null ? BigDecimal.ZERO : orderTotalAmount); + return mgtAmountChartVO; + }).collect(Collectors.toList()); + } else { + return CollUtils.emptyList(); + } + } + + @NotNull + private static List<MgtCountChartVO> getMgtCountChartVOS(List<LocalDate> datesBetween, + List<Order> orderList, OrderTypeEnum type) { + Map<String, Long> orderCountMap; + if (type.equals(OrderTypeEnum.MALL_ODER)) { + orderCountMap = orderList.stream() + .filter(order -> !order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS)) + .collect(Collectors.groupingBy(order -> order.getOrderTime().toLocalDate() + .format(DateTimeFormatter.ofPattern("MM-dd")), + Collectors.counting())); + } else if (type.equals(OrderTypeEnum.AUCTION_ORDER)) { + orderCountMap = orderList.stream() + .filter(order -> order.getOrderFrom().equals(OrderFromEnum.AUCTION_ORDERS)) + .collect(Collectors.groupingBy(order -> order.getOrderTime().toLocalDate() + .format(DateTimeFormatter.ofPattern("MM-dd")), + Collectors.counting())); + } else { + orderCountMap = null; + } + if (orderCountMap != null) { + return datesBetween.stream().map(date -> { + MgtCountChartVO mgtCountChartVO = new MgtCountChartVO(); + mgtCountChartVO.setDate(date.format(DateTimeFormatter.ofPattern("MM-dd"))); + Long orderCount = orderCountMap.get( + date.format(DateTimeFormatter.ofPattern("MM-dd"))); + mgtCountChartVO.setValue(orderCount == null ? 0L : orderCount); + return mgtCountChartVO; + }).collect(Collectors.toList()); + } else { + return CollUtils.emptyList(); + } + } + + public List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate) { + // 检查开始日期是否晚于结束日期 + if (startDate.isAfter(endDate)) { + throw new IllegalArgumentException("开始日期必须早于结束日期"); + } + + // 使用ChronoUnit.DAYS.between计算日期差,并生成日期范围的流 + long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate); + + // 使用Stream.iterate生成日期序列,再用limit限制天数,最后collect收集结果 + return Stream.iterate(startDate, date -> date.plusDays(1)) + .limit(numOfDaysBetween + 1) // 加1是因为包含结束日期 + .collect(Collectors.toList()); + } + + /** + * 业务数据导出 + * + * @param query + * @param response + */ + public void exportBusinessData(MgtOrderStaticsQuery query, HttpServletResponse response) { + MgtOrderStaticsVO overview = getOverview(query); + // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman + response.setContentType( + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系 + try { + String fileName = URLEncoder.encode("业务数据", "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", + "attachment;filename*=utf-8''" + fileName + ".xlsx"); + EasyExcel.write(response.getOutputStream(), MgtOrderStaticsVO.class) + .sheet("业务数据") + .doWrite(Lists.newArrayList(overview)); + } catch (Exception e) { + throw new RuntimeException(e); + } } } -- Gitblit v1.7.1