|
@@ -53,135 +53,119 @@ public class DashboardServiceImpl implements DashboardService {
|
|
|
public Map<String, Object> getOverviewData() {
|
|
public Map<String, Object> getOverviewData() {
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
|
|
|
|
|
- // 今日开始时间
|
|
|
|
|
LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
|
|
LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
|
|
|
LocalDateTime todayEnd = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
|
|
LocalDateTime todayEnd = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
|
|
|
-
|
|
|
|
|
- // 昨日同时段时间(当前时间往前推一天)
|
|
|
|
|
LocalDateTime yesterdayStart = todayStart.minusDays(1);
|
|
LocalDateTime yesterdayStart = todayStart.minusDays(1);
|
|
|
LocalDateTime yesterdayEnd = LocalDateTime.now().minusDays(1);
|
|
LocalDateTime yesterdayEnd = LocalDateTime.now().minusDays(1);
|
|
|
|
|
|
|
|
- // 今日销售额和订单量
|
|
|
|
|
- LambdaQueryWrapper<Order> todayWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
- todayWrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
|
|
|
- .ge(Order::getPayTime, todayStart)
|
|
|
|
|
- .le(Order::getPayTime, todayEnd);
|
|
|
|
|
-
|
|
|
|
|
- List<Order> todayOrdersList = orderService.list(todayWrapper);
|
|
|
|
|
|
|
+ // 今日销售额和订单量 — SQL 聚合,不拉全量订单到内存
|
|
|
|
|
+ Map<String, Object> todayStats = orderService.getBaseMapper().selectMaps(
|
|
|
|
|
+ new LambdaQueryWrapper<Order>()
|
|
|
|
|
+ .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
|
|
|
+ .ge(Order::getPayTime, todayStart)
|
|
|
|
|
+ .le(Order::getPayTime, todayEnd)
|
|
|
|
|
+ .select(Order::getTotalAmount)
|
|
|
|
|
+ ).stream().collect(HashMap::new, (m, row) -> {
|
|
|
|
|
+ m.put("cnt", ((Number) m.getOrDefault("cnt", 0)).intValue() + 1);
|
|
|
|
|
+ BigDecimal amt = row.get("total_amount") != null ? (BigDecimal) row.get("total_amount") : BigDecimal.ZERO;
|
|
|
|
|
+ m.put("sum", ((BigDecimal) m.getOrDefault("sum", BigDecimal.ZERO)).add(amt));
|
|
|
|
|
+ }, (a, b) -> {});
|
|
|
|
|
+ BigDecimal todaySales = (BigDecimal) todayStats.getOrDefault("sum", BigDecimal.ZERO);
|
|
|
|
|
+ int todayOrderCount = (int) todayStats.getOrDefault("cnt", 0);
|
|
|
|
|
|
|
|
- BigDecimal todaySales = todayOrdersList.stream()
|
|
|
|
|
- .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
|
|
|
|
|
- .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
result.put("todaySales", todaySales.setScale(2, RoundingMode.HALF_UP).toString());
|
|
result.put("todaySales", todaySales.setScale(2, RoundingMode.HALF_UP).toString());
|
|
|
-
|
|
|
|
|
- int todayOrderCount = todayOrdersList.size();
|
|
|
|
|
result.put("todayOrders", todayOrderCount);
|
|
result.put("todayOrders", todayOrderCount);
|
|
|
-
|
|
|
|
|
- String todayAvgPrice = todayOrderCount > 0
|
|
|
|
|
- ? todaySales.divide(BigDecimal.valueOf(todayOrderCount), 2, RoundingMode.HALF_UP).toString()
|
|
|
|
|
- : "0.00";
|
|
|
|
|
- result.put("todayAvgPrice", todayAvgPrice);
|
|
|
|
|
-
|
|
|
|
|
- LambdaQueryWrapper<Order> yesterdayWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
- yesterdayWrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
|
|
|
|
|
+ result.put("todayAvgPrice", todayOrderCount > 0
|
|
|
|
|
+ ? todaySales.divide(BigDecimal.valueOf(todayOrderCount), 2, RoundingMode.HALF_UP).toString()
|
|
|
|
|
+ : "0.00");
|
|
|
|
|
+
|
|
|
|
|
+ // 昨日 — 同样用 SQL 聚合
|
|
|
|
|
+ Map<String, Object> yesterdayStats = orderService.getBaseMapper().selectMaps(
|
|
|
|
|
+ new LambdaQueryWrapper<Order>()
|
|
|
|
|
+ .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
|
.ge(Order::getPayTime, yesterdayStart)
|
|
.ge(Order::getPayTime, yesterdayStart)
|
|
|
- .le(Order::getPayTime, yesterdayEnd);
|
|
|
|
|
-
|
|
|
|
|
- List<Order> yesterdayOrders = orderService.list(yesterdayWrapper);
|
|
|
|
|
-
|
|
|
|
|
- BigDecimal yesterdaySales = yesterdayOrders.stream()
|
|
|
|
|
- .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
|
|
|
|
|
- .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
- int yesterdayOrderCount = yesterdayOrders.size();
|
|
|
|
|
- BigDecimal yesterdayAvgPrice = yesterdayOrderCount > 0
|
|
|
|
|
- ? yesterdaySales.divide(BigDecimal.valueOf(yesterdayOrderCount), 2, RoundingMode.HALF_UP)
|
|
|
|
|
|
|
+ .le(Order::getPayTime, yesterdayEnd)
|
|
|
|
|
+ .select(Order::getTotalAmount)
|
|
|
|
|
+ ).stream().collect(HashMap::new, (m, row) -> {
|
|
|
|
|
+ m.put("cnt", ((Number) m.getOrDefault("cnt", 0)).intValue() + 1);
|
|
|
|
|
+ BigDecimal amt = row.get("total_amount") != null ? (BigDecimal) row.get("total_amount") : BigDecimal.ZERO;
|
|
|
|
|
+ m.put("sum", ((BigDecimal) m.getOrDefault("sum", BigDecimal.ZERO)).add(amt));
|
|
|
|
|
+ }, (a, b) -> {});
|
|
|
|
|
+ BigDecimal yesterdaySales = (BigDecimal) yesterdayStats.getOrDefault("sum", BigDecimal.ZERO);
|
|
|
|
|
+ int yesterdayOrderCount = (int) yesterdayStats.getOrDefault("cnt", 0);
|
|
|
|
|
+ BigDecimal yesterdayAvgPrice = yesterdayOrderCount > 0
|
|
|
|
|
+ ? yesterdaySales.divide(BigDecimal.valueOf(yesterdayOrderCount), 2, RoundingMode.HALF_UP)
|
|
|
: BigDecimal.ZERO;
|
|
: BigDecimal.ZERO;
|
|
|
|
|
|
|
|
result.put("todaySalesCompare", formatCompare(todaySales.subtract(yesterdaySales)));
|
|
result.put("todaySalesCompare", formatCompare(todaySales.subtract(yesterdaySales)));
|
|
|
result.put("todayOrdersCompare", formatCompare(todayOrderCount - yesterdayOrderCount));
|
|
result.put("todayOrdersCompare", formatCompare(todayOrderCount - yesterdayOrderCount));
|
|
|
- BigDecimal todayAvg = todayOrderCount > 0
|
|
|
|
|
- ? todaySales.divide(BigDecimal.valueOf(todayOrderCount), 2, RoundingMode.HALF_UP)
|
|
|
|
|
|
|
+ BigDecimal todayAvg = todayOrderCount > 0
|
|
|
|
|
+ ? todaySales.divide(BigDecimal.valueOf(todayOrderCount), 2, RoundingMode.HALF_UP)
|
|
|
: BigDecimal.ZERO;
|
|
: BigDecimal.ZERO;
|
|
|
result.put("todayAvgPriceCompare", formatCompare(todayAvg.subtract(yesterdayAvgPrice)));
|
|
result.put("todayAvgPriceCompare", formatCompare(todayAvg.subtract(yesterdayAvgPrice)));
|
|
|
|
|
|
|
|
// 设备状态统计
|
|
// 设备状态统计
|
|
|
long totalDevices = deviceService.count();
|
|
long totalDevices = deviceService.count();
|
|
|
long onlineDevices = deviceService.lambdaQuery()
|
|
long onlineDevices = deviceService.lambdaQuery()
|
|
|
- .eq(Device::getStatus, DeviceConstants.STATUS_ONLINE)
|
|
|
|
|
- .count();
|
|
|
|
|
- long offlineDevices = totalDevices - onlineDevices;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ .eq(Device::getStatus, DeviceConstants.STATUS_ONLINE).count();
|
|
|
result.put("onlineDevices", onlineDevices);
|
|
result.put("onlineDevices", onlineDevices);
|
|
|
- result.put("offlineDevices", offlineDevices);
|
|
|
|
|
|
|
+ result.put("offlineDevices", totalDevices - onlineDevices);
|
|
|
|
|
|
|
|
- // 待处理事项统计
|
|
|
|
|
// 未支付订单数
|
|
// 未支付订单数
|
|
|
long unpaidOrders = orderService.lambdaQuery()
|
|
long unpaidOrders = orderService.lambdaQuery()
|
|
|
- .eq(Order::getStatus, OrderConstants.STATUS_PENDING_PAYMENT)
|
|
|
|
|
- .count();
|
|
|
|
|
|
|
+ .eq(Order::getStatus, OrderConstants.STATUS_PENDING_PAYMENT).count();
|
|
|
result.put("unpaidOrders", unpaidOrders);
|
|
result.put("unpaidOrders", unpaidOrders);
|
|
|
|
|
+ result.put("pendingTasks", (int) unpaidOrders);
|
|
|
|
|
+ result.put("abnormalActivities", 0);
|
|
|
|
|
+ result.put("pendingAfterSale", 0);
|
|
|
|
|
|
|
|
- // 计算总待处理事项
|
|
|
|
|
- int pendingTasks = (int) unpaidOrders; // 可添加更多待处理事项
|
|
|
|
|
- result.put("pendingTasks", pendingTasks);
|
|
|
|
|
- result.put("abnormalActivities", 0); // TODO: 异常活动数
|
|
|
|
|
- result.put("pendingAfterSale", 0); // TODO: 售后待处理数
|
|
|
|
|
-
|
|
|
|
|
- // ========== 前端期望的字段 ==========
|
|
|
|
|
- // 总用户数
|
|
|
|
|
|
|
+ // 总用户数、今日新增
|
|
|
long totalUsers = userService.count();
|
|
long totalUsers = userService.count();
|
|
|
result.put("totalUsers", totalUsers);
|
|
result.put("totalUsers", totalUsers);
|
|
|
-
|
|
|
|
|
- // 今日新增用户数
|
|
|
|
|
long todayNewUsers = userService.lambdaQuery()
|
|
long todayNewUsers = userService.lambdaQuery()
|
|
|
- .ge(User::getCreateTime, todayStart)
|
|
|
|
|
- .le(User::getCreateTime, todayEnd)
|
|
|
|
|
- .count();
|
|
|
|
|
|
|
+ .ge(User::getCreateTime, todayStart).le(User::getCreateTime, todayEnd).count();
|
|
|
result.put("todayNewUsers", todayNewUsers);
|
|
result.put("todayNewUsers", todayNewUsers);
|
|
|
-
|
|
|
|
|
- // 总订单数(已支付)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 总订单数 + 总收入 — SQL 聚合
|
|
|
long totalOrders = orderService.lambdaQuery()
|
|
long totalOrders = orderService.lambdaQuery()
|
|
|
- .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
|
|
|
- .count();
|
|
|
|
|
|
|
+ .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID).count();
|
|
|
result.put("totalOrders", totalOrders);
|
|
result.put("totalOrders", totalOrders);
|
|
|
-
|
|
|
|
|
- // 总收入(所有已支付订单)
|
|
|
|
|
- LambdaQueryWrapper<Order> allPaidWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
- allPaidWrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID);
|
|
|
|
|
- List<Order> allPaidOrders = orderService.list(allPaidWrapper);
|
|
|
|
|
- BigDecimal totalRevenue = allPaidOrders.stream()
|
|
|
|
|
- .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
|
|
|
|
|
- .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
|
|
+ Map<String, Object> allPaidStats = orderService.getBaseMapper().selectMaps(
|
|
|
|
|
+ new LambdaQueryWrapper<Order>()
|
|
|
|
|
+ .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
|
|
|
+ .select(Order::getTotalAmount)
|
|
|
|
|
+ ).stream().collect(HashMap::new, (m, row) -> {
|
|
|
|
|
+ BigDecimal amt = row.get("total_amount") != null ? (BigDecimal) row.get("total_amount") : BigDecimal.ZERO;
|
|
|
|
|
+ m.put("sum", ((BigDecimal) m.getOrDefault("sum", BigDecimal.ZERO)).add(amt));
|
|
|
|
|
+ }, (a, b) -> {});
|
|
|
|
|
+ BigDecimal totalRevenue = (BigDecimal) allPaidStats.getOrDefault("sum", BigDecimal.ZERO);
|
|
|
result.put("totalRevenue", totalRevenue.setScale(2, RoundingMode.HALF_UP).toString());
|
|
result.put("totalRevenue", totalRevenue.setScale(2, RoundingMode.HALF_UP).toString());
|
|
|
-
|
|
|
|
|
- // 今日收入
|
|
|
|
|
result.put("todayRevenue", todaySales.setScale(2, RoundingMode.HALF_UP).toString());
|
|
result.put("todayRevenue", todaySales.setScale(2, RoundingMode.HALF_UP).toString());
|
|
|
-
|
|
|
|
|
- // 设备总数
|
|
|
|
|
result.put("totalDevices", totalDevices);
|
|
result.put("totalDevices", totalDevices);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 门店统计
|
|
// 门店统计
|
|
|
long totalShops = shopService.count();
|
|
long totalShops = shopService.count();
|
|
|
long activeShops = shopService.lambdaQuery()
|
|
long activeShops = shopService.lambdaQuery()
|
|
|
- .eq(Shop::getStatus, CommonStatus.ENABLED.getCode())
|
|
|
|
|
- .count();
|
|
|
|
|
|
|
+ .eq(Shop::getStatus, CommonStatus.ENABLED.getCode()).count();
|
|
|
result.put("totalShops", totalShops);
|
|
result.put("totalShops", totalShops);
|
|
|
result.put("activeShops", activeShops);
|
|
result.put("activeShops", activeShops);
|
|
|
|
|
|
|
|
- // 本月销售额和订单量
|
|
|
|
|
|
|
+ // 本月销售额和订单量 — SQL 聚合
|
|
|
LocalDateTime monthStart = LocalDateTime.of(LocalDate.now().withDayOfMonth(1), LocalTime.MIN);
|
|
LocalDateTime monthStart = LocalDateTime.of(LocalDate.now().withDayOfMonth(1), LocalTime.MIN);
|
|
|
- LocalDateTime monthEnd = LocalDateTime.now();
|
|
|
|
|
-
|
|
|
|
|
- LambdaQueryWrapper<Order> monthPaidWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
- monthPaidWrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
|
|
|
- .ge(Order::getPayTime, monthStart)
|
|
|
|
|
- .le(Order::getPayTime, monthEnd);
|
|
|
|
|
- List<Order> monthPaidOrders = orderService.list(monthPaidWrapper);
|
|
|
|
|
- BigDecimal monthSales = monthPaidOrders.stream()
|
|
|
|
|
- .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
|
|
|
|
|
- .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
- result.put("monthSales", monthSales.setScale(2, RoundingMode.HALF_UP).toString());
|
|
|
|
|
- result.put("monthOrders", monthPaidOrders.size());
|
|
|
|
|
|
|
+ Map<String, Object> monthStats = orderService.getBaseMapper().selectMaps(
|
|
|
|
|
+ new LambdaQueryWrapper<Order>()
|
|
|
|
|
+ .eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
|
|
|
+ .ge(Order::getPayTime, monthStart)
|
|
|
|
|
+ .le(Order::getPayTime, LocalDateTime.now())
|
|
|
|
|
+ .select(Order::getTotalAmount)
|
|
|
|
|
+ ).stream().collect(HashMap::new, (m, row) -> {
|
|
|
|
|
+ m.put("cnt", ((Number) m.getOrDefault("cnt", 0)).intValue() + 1);
|
|
|
|
|
+ BigDecimal amt = row.get("total_amount") != null ? (BigDecimal) row.get("total_amount") : BigDecimal.ZERO;
|
|
|
|
|
+ m.put("sum", ((BigDecimal) m.getOrDefault("sum", BigDecimal.ZERO)).add(amt));
|
|
|
|
|
+ }, (a, b) -> {});
|
|
|
|
|
+ result.put("monthSales", ((BigDecimal) monthStats.getOrDefault("sum", BigDecimal.ZERO))
|
|
|
|
|
+ .setScale(2, RoundingMode.HALF_UP).toString());
|
|
|
|
|
+ result.put("monthOrders", monthStats.getOrDefault("cnt", 0));
|
|
|
|
|
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
@@ -226,40 +210,37 @@ public class DashboardServiceImpl implements DashboardService {
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 查询订单数据
|
|
|
|
|
|
|
+ // 查询订单 — 只取需要的字段,不拉全部列
|
|
|
LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
|
|
LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
|
|
|
wrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
wrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
|
.ge(Order::getPayTime, startTime)
|
|
.ge(Order::getPayTime, startTime)
|
|
|
- .le(Order::getPayTime, endTime);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ .le(Order::getPayTime, endTime)
|
|
|
|
|
+ .select(Order::getPayTime, Order::getTotalAmount, Order::getUserId);
|
|
|
List<Order> orders = orderService.list(wrapper);
|
|
List<Order> orders = orderService.list(wrapper);
|
|
|
|
|
|
|
|
BigDecimal totalSales = orders.stream()
|
|
BigDecimal totalSales = orders.stream()
|
|
|
.map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
|
|
.map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
result.put("totalSales", totalSales.setScale(2, RoundingMode.HALF_UP).toString());
|
|
result.put("totalSales", totalSales.setScale(2, RoundingMode.HALF_UP).toString());
|
|
|
-
|
|
|
|
|
int totalOrders = orders.size();
|
|
int totalOrders = orders.size();
|
|
|
result.put("totalOrders", totalOrders);
|
|
result.put("totalOrders", totalOrders);
|
|
|
|
|
+ result.put("avgOrderPrice", totalOrders > 0
|
|
|
|
|
+ ? totalSales.divide(BigDecimal.valueOf(totalOrders), 2, RoundingMode.HALF_UP).toString()
|
|
|
|
|
+ : "0.00");
|
|
|
|
|
|
|
|
- BigDecimal avgOrderPrice = totalOrders > 0
|
|
|
|
|
- ? totalSales.divide(BigDecimal.valueOf(totalOrders), 2, RoundingMode.HALF_UP)
|
|
|
|
|
- : BigDecimal.ZERO;
|
|
|
|
|
- result.put("avgOrderPrice", avgOrderPrice.toString());
|
|
|
|
|
-
|
|
|
|
|
|
|
+ // 对比期 — 同样只取需要的字段
|
|
|
LambdaQueryWrapper<Order> compareWrapper = new LambdaQueryWrapper<>();
|
|
LambdaQueryWrapper<Order> compareWrapper = new LambdaQueryWrapper<>();
|
|
|
compareWrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
compareWrapper.eq(Order::getPayStatus, OrderConstants.PAY_STATUS_PAID)
|
|
|
.ge(Order::getPayTime, compareStartTime)
|
|
.ge(Order::getPayTime, compareStartTime)
|
|
|
- .le(Order::getPayTime, compareEndTime);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ .le(Order::getPayTime, compareEndTime)
|
|
|
|
|
+ .select(Order::getPayTime, Order::getTotalAmount, Order::getUserId);
|
|
|
List<Order> compareOrders = orderService.list(compareWrapper);
|
|
List<Order> compareOrders = orderService.list(compareWrapper);
|
|
|
-
|
|
|
|
|
BigDecimal compareSales = compareOrders.stream()
|
|
BigDecimal compareSales = compareOrders.stream()
|
|
|
.map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
|
|
.map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
int compareOrderCount = compareOrders.size();
|
|
int compareOrderCount = compareOrders.size();
|
|
|
- BigDecimal compareAvgPrice = compareOrderCount > 0
|
|
|
|
|
- ? compareSales.divide(BigDecimal.valueOf(compareOrderCount), 2, RoundingMode.HALF_UP)
|
|
|
|
|
|
|
+ BigDecimal compareAvgPrice = compareOrderCount > 0
|
|
|
|
|
+ ? compareSales.divide(BigDecimal.valueOf(compareOrderCount), 2, RoundingMode.HALF_UP)
|
|
|
: BigDecimal.ZERO;
|
|
: BigDecimal.ZERO;
|
|
|
|
|
|
|
|
result.put("salesGrowth", formatGrowth(totalSales, compareSales));
|
|
result.put("salesGrowth", formatGrowth(totalSales, compareSales));
|
|
@@ -267,112 +248,73 @@ public class DashboardServiceImpl implements DashboardService {
|
|
|
result.put("avgOrderGrowth", formatGrowth(avgOrderPrice, compareAvgPrice));
|
|
result.put("avgOrderGrowth", formatGrowth(avgOrderPrice, compareAvgPrice));
|
|
|
|
|
|
|
|
BigDecimal grossProfit = totalSales.multiply(new BigDecimal("0.3"));
|
|
BigDecimal grossProfit = totalSales.multiply(new BigDecimal("0.3"));
|
|
|
- BigDecimal profitMargin = totalSales.compareTo(BigDecimal.ZERO) > 0
|
|
|
|
|
|
|
+ BigDecimal profitMargin = totalSales.compareTo(BigDecimal.ZERO) > 0
|
|
|
? grossProfit.divide(totalSales, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))
|
|
? grossProfit.divide(totalSales, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))
|
|
|
: BigDecimal.ZERO;
|
|
: BigDecimal.ZERO;
|
|
|
BigDecimal compareGrossProfit = compareSales.multiply(new BigDecimal("0.3"));
|
|
BigDecimal compareGrossProfit = compareSales.multiply(new BigDecimal("0.3"));
|
|
|
-
|
|
|
|
|
result.put("grossProfit", grossProfit.setScale(2, RoundingMode.HALF_UP).toString());
|
|
result.put("grossProfit", grossProfit.setScale(2, RoundingMode.HALF_UP).toString());
|
|
|
result.put("profitMargin", profitMargin.setScale(1, RoundingMode.HALF_UP).toString() + "%");
|
|
result.put("profitMargin", profitMargin.setScale(1, RoundingMode.HALF_UP).toString() + "%");
|
|
|
result.put("profitGrowth", formatGrowth(grossProfit, compareGrossProfit));
|
|
result.put("profitGrowth", formatGrowth(grossProfit, compareGrossProfit));
|
|
|
result.put("marginGrowth", "+0%");
|
|
result.put("marginGrowth", "+0%");
|
|
|
|
|
|
|
|
// 用户统计
|
|
// 用户统计
|
|
|
- // 新增用户数
|
|
|
|
|
long newUsers = userService.lambdaQuery()
|
|
long newUsers = userService.lambdaQuery()
|
|
|
- .ge(User::getCreateTime, startTime)
|
|
|
|
|
- .le(User::getCreateTime, endTime)
|
|
|
|
|
- .count();
|
|
|
|
|
|
|
+ .ge(User::getCreateTime, startTime).le(User::getCreateTime, endTime).count();
|
|
|
result.put("newUsers", newUsers);
|
|
result.put("newUsers", newUsers);
|
|
|
|
|
|
|
|
- // 成交用户数(去重)
|
|
|
|
|
Set<Long> transactUserIds = new HashSet<>();
|
|
Set<Long> transactUserIds = new HashSet<>();
|
|
|
- for (Order order : orders) {
|
|
|
|
|
- if (order.getUserId() != null) {
|
|
|
|
|
- transactUserIds.add(order.getUserId());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ for (Order order : orders) { if (order.getUserId() != null) transactUserIds.add(order.getUserId()); }
|
|
|
result.put("transactUsers", transactUserIds.size());
|
|
result.put("transactUsers", transactUserIds.size());
|
|
|
-
|
|
|
|
|
- BigDecimal customerPrice = transactUserIds.size() > 0
|
|
|
|
|
- ? totalSales.divide(BigDecimal.valueOf(transactUserIds.size()), 2, RoundingMode.HALF_UP)
|
|
|
|
|
- : BigDecimal.ZERO;
|
|
|
|
|
- result.put("customerPrice", customerPrice.toString());
|
|
|
|
|
|
|
+ result.put("customerPrice", transactUserIds.size() > 0
|
|
|
|
|
+ ? totalSales.divide(BigDecimal.valueOf(transactUserIds.size()), 2, RoundingMode.HALF_UP).toString()
|
|
|
|
|
+ : "0.00");
|
|
|
|
|
|
|
|
long compareNewUsers = userService.lambdaQuery()
|
|
long compareNewUsers = userService.lambdaQuery()
|
|
|
- .ge(User::getCreateTime, compareStartTime)
|
|
|
|
|
- .le(User::getCreateTime, compareEndTime)
|
|
|
|
|
- .count();
|
|
|
|
|
-
|
|
|
|
|
|
|
+ .ge(User::getCreateTime, compareStartTime).le(User::getCreateTime, compareEndTime).count();
|
|
|
Set<Long> compareTransactUserIds = new HashSet<>();
|
|
Set<Long> compareTransactUserIds = new HashSet<>();
|
|
|
- for (Order order : compareOrders) {
|
|
|
|
|
- if (order.getUserId() != null) {
|
|
|
|
|
- compareTransactUserIds.add(order.getUserId());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- BigDecimal compareCustomerPrice = compareTransactUserIds.size() > 0
|
|
|
|
|
- ? compareSales.divide(BigDecimal.valueOf(compareTransactUserIds.size()), 2, RoundingMode.HALF_UP)
|
|
|
|
|
|
|
+ for (Order order : compareOrders) { if (order.getUserId() != null) compareTransactUserIds.add(order.getUserId()); }
|
|
|
|
|
+ BigDecimal compareCustomerPrice = compareTransactUserIds.size() > 0
|
|
|
|
|
+ ? compareSales.divide(BigDecimal.valueOf(compareTransactUserIds.size()), 2, RoundingMode.HALF_UP)
|
|
|
: BigDecimal.ZERO;
|
|
: BigDecimal.ZERO;
|
|
|
|
|
|
|
|
result.put("newUsersGrowth", formatGrowth(newUsers, compareNewUsers));
|
|
result.put("newUsersGrowth", formatGrowth(newUsers, compareNewUsers));
|
|
|
result.put("transactGrowth", formatGrowth(transactUserIds.size(), compareTransactUserIds.size()));
|
|
result.put("transactGrowth", formatGrowth(transactUserIds.size(), compareTransactUserIds.size()));
|
|
|
result.put("customerGrowth", formatGrowth(customerPrice, compareCustomerPrice));
|
|
result.put("customerGrowth", formatGrowth(customerPrice, compareCustomerPrice));
|
|
|
|
|
|
|
|
- List<String> dates = new ArrayList<>();
|
|
|
|
|
- List<BigDecimal> salesData = new ArrayList<>();
|
|
|
|
|
- List<Integer> ordersData = new ArrayList<>();
|
|
|
|
|
-
|
|
|
|
|
- DateTimeFormatter formatter = type.equals("yesterday")
|
|
|
|
|
- ? DateTimeFormatter.ofPattern("H:00")
|
|
|
|
|
- : DateTimeFormatter.ofPattern("MM-dd");
|
|
|
|
|
-
|
|
|
|
|
|
|
+ // 按时间分组:一次遍历,按天/小时聚合销售额和订单数
|
|
|
|
|
+ Map<String, BigDecimal> dateSalesMap = new LinkedHashMap<>();
|
|
|
|
|
+ Map<String, Integer> dateOrdersMap = new LinkedHashMap<>();
|
|
|
if ("yesterday".equals(type)) {
|
|
if ("yesterday".equals(type)) {
|
|
|
for (int i = 0; i < 24; i++) {
|
|
for (int i = 0; i < 24; i++) {
|
|
|
- LocalDateTime hourStart = startTime.withHour(i);
|
|
|
|
|
- LocalDateTime hourEnd = hourStart.withMinute(59).withSecond(59);
|
|
|
|
|
-
|
|
|
|
|
- dates.add(String.format("%d:00", i));
|
|
|
|
|
-
|
|
|
|
|
- final int hour = i;
|
|
|
|
|
- BigDecimal hourSales = orders.stream()
|
|
|
|
|
- .filter(o -> o.getPayTime() != null && o.getPayTime().getHour() == hour)
|
|
|
|
|
- .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
|
|
|
|
|
- .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
- long hourOrders = orders.stream()
|
|
|
|
|
- .filter(o -> o.getPayTime() != null && o.getPayTime().getHour() == hour)
|
|
|
|
|
- .count();
|
|
|
|
|
-
|
|
|
|
|
- salesData.add(hourSales);
|
|
|
|
|
- ordersData.add((int) hourOrders);
|
|
|
|
|
|
|
+ String key = i + ":00";
|
|
|
|
|
+ dateSalesMap.put(key, BigDecimal.ZERO);
|
|
|
|
|
+ dateOrdersMap.put(key, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ for (Order o : orders) {
|
|
|
|
|
+ if (o.getPayTime() != null) {
|
|
|
|
|
+ String key = o.getPayTime().getHour() + ":00";
|
|
|
|
|
+ dateSalesMap.merge(key, o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
+ dateOrdersMap.merge(key, 1, Integer::sum);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
for (int i = 0; i < days; i++) {
|
|
for (int i = 0; i < days; i++) {
|
|
|
LocalDate date = startTime.toLocalDate().plusDays(i);
|
|
LocalDate date = startTime.toLocalDate().plusDays(i);
|
|
|
- LocalDateTime dayStart = date.atStartOfDay();
|
|
|
|
|
- LocalDateTime dayEnd = date.atTime(LocalTime.MAX);
|
|
|
|
|
-
|
|
|
|
|
- dates.add(date.format(DateTimeFormatter.ofPattern("MM-dd")));
|
|
|
|
|
-
|
|
|
|
|
- BigDecimal daySales = orders.stream()
|
|
|
|
|
- .filter(o -> o.getPayTime() != null
|
|
|
|
|
- && !o.getPayTime().isBefore(dayStart)
|
|
|
|
|
- && !o.getPayTime().isAfter(dayEnd))
|
|
|
|
|
- .map(o -> o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO)
|
|
|
|
|
- .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
- long dayOrders = orders.stream()
|
|
|
|
|
- .filter(o -> o.getPayTime() != null
|
|
|
|
|
- && !o.getPayTime().isBefore(dayStart)
|
|
|
|
|
- && !o.getPayTime().isAfter(dayEnd))
|
|
|
|
|
- .count();
|
|
|
|
|
-
|
|
|
|
|
- salesData.add(daySales);
|
|
|
|
|
- ordersData.add((int) dayOrders);
|
|
|
|
|
|
|
+ String key = date.format(DateTimeFormatter.ofPattern("MM-dd"));
|
|
|
|
|
+ dateSalesMap.put(key, BigDecimal.ZERO);
|
|
|
|
|
+ dateOrdersMap.put(key, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ for (Order o : orders) {
|
|
|
|
|
+ if (o.getPayTime() != null) {
|
|
|
|
|
+ String key = o.getPayTime().toLocalDate().format(DateTimeFormatter.ofPattern("MM-dd"));
|
|
|
|
|
+ dateSalesMap.merge(key, o.getTotalAmount() != null ? o.getTotalAmount() : BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
+ dateOrdersMap.merge(key, 1, Integer::sum);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- result.put("dates", dates);
|
|
|
|
|
- result.put("salesData", salesData);
|
|
|
|
|
- result.put("ordersData", ordersData);
|
|
|
|
|
|
|
+ result.put("dates", new ArrayList<>(dateSalesMap.keySet()));
|
|
|
|
|
+ result.put("salesData", new ArrayList<>(dateSalesMap.values()));
|
|
|
|
|
+ result.put("ordersData", new ArrayList<>(dateOrdersMap.values()));
|
|
|
|
|
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|