package com.doumee.service.business.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.doumee.core.constants.Constants; import com.doumee.core.utils.Utils; import com.doumee.dao.business.*; import com.doumee.dao.business.model.*; import com.doumee.dao.dto.DataBoardQueryDTO; import com.doumee.dao.dto.FinanceQueryDTO; import com.doumee.dao.dto.TrendQueryDTO; import com.doumee.dao.vo.*; import com.doumee.service.business.DataBoardService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; @Slf4j @Service public class DataBoardServiceImpl implements DataBoardService { @Autowired private MemberMapper memberMapper; @Autowired private ShopInfoMapper shopInfoMapper; @Autowired private DriverInfoMapper driverInfoMapper; @Autowired private OrdersMapper ordersMapper; @Autowired private OrdersDetailMapper ordersDetailMapper; @Autowired private OtherOrdersMapper otherOrdersMapper; @Autowired private OrdersRefundMapper ordersRefundMapper; @Autowired private RevenueMapper revenueMapper; @Override public DataBoardVO overview(DataBoardQueryDTO query) { query.resolveDateRange(); DataBoardVO vo = new DataBoardVO(); // 会员总数(不受时间/门店影响,userType=0 会员身份) vo.setMemberCount(memberMapper.selectCount(new QueryWrapper().lambda() .eq(Member::getDeleted, Constants.ZERO) .eq(Member::getUserType, Constants.ZERO))); // 门店总数(auditStatus=3 正式版本) vo.setShopCount(shopInfoMapper.selectCount(new QueryWrapper().lambda() .eq(ShopInfo::getAuditStatus, Constants.THREE) .eq(ShopInfo::getVersionType, Constants.ZERO) .eq(ShopInfo::getDeleted, Constants.ZERO))); // 司机总数(auditStatus=3 正式版本) vo.setDriverCount(driverInfoMapper.selectCount(new QueryWrapper().lambda() .eq(DriverInfo::getAuditStatus, Constants.THREE) .eq(DriverInfo::getVersionType, Constants.ZERO) .eq(DriverInfo::getDeleted, Constants.ZERO))); // 周期总订单数 vo.setOrderCount(ordersMapper.selectCount(buildOrderQueryWrapper(query))); // 周期营收 List orders = ordersMapper.selectList(buildOrderQueryWrapper(query)); long orderRevenue = 0L; for (Orders o : orders) { long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L; long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L; long overdue = (o.getOverdueStatus() != null && o.getOverdueStatus() == 2 && o.getOverdueAmount() != null) ? o.getOverdueAmount() : 0L; orderRevenue += pay - refund + overdue; } // 加上逾期费用订单(OtherOrders type=2) QueryWrapper otherQw = new QueryWrapper<>(); otherQw.lambda() .eq(OtherOrders::getType, 2) .eq(OtherOrders::getPayStatus, Constants.ONE) .eq(OtherOrders::getDeleted, Constants.ZERO); if (query.getStartDate() != null) { otherQw.lambda().ge(OtherOrders::getPayTime, query.getStartDate()); } if (query.getEndDate() != null) { otherQw.lambda().le(OtherOrders::getPayTime, Utils.Date.getEnd(query.getEndDate())); } List otherOrders = otherOrdersMapper.selectList(otherQw); long otherRevenue = otherOrders.stream() .mapToLong(o -> o.getPayAccount() != null ? o.getPayAccount() : 0L).sum(); vo.setTotalRevenue(BigDecimal.valueOf(orderRevenue + otherRevenue) .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP)); // 行李类型占比 List orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList()); vo.setLuggageTypeList(buildLuggageTypeList(orderIds)); // 门店入驻率:auditStatus=3 的门店数 / 全部门店数 long totalShopCount = shopInfoMapper.selectCount(new QueryWrapper().lambda() .eq(ShopInfo::getVersionType, Constants.ZERO) .eq(ShopInfo::getDeleted, Constants.ZERO)); if (totalShopCount > 0) { vo.setShopSettlementRate(BigDecimal.valueOf(vo.getShopCount()) .multiply(BigDecimal.valueOf(100)) .divide(BigDecimal.valueOf(totalShopCount), 2, RoundingMode.HALF_UP)); } else { vo.setShopSettlementRate(BigDecimal.ZERO); } // 司机通过率:auditStatus=3 的司机数 / 全部司机数 long totalDriverCount = driverInfoMapper.selectCount(new QueryWrapper().lambda() .eq(DriverInfo::getVersionType, Constants.ZERO) .eq(DriverInfo::getDeleted, Constants.ZERO)); if (totalDriverCount > 0) { vo.setDriverPassRate(BigDecimal.valueOf(vo.getDriverCount()) .multiply(BigDecimal.valueOf(100)) .divide(BigDecimal.valueOf(totalDriverCount), 2, RoundingMode.HALF_UP)); } else { vo.setDriverPassRate(BigDecimal.ZERO); } // 周期退款单数 if (!orderIds.isEmpty()) { QueryWrapper refundQw = new QueryWrapper<>(); refundQw.lambda() .in(OrdersRefund::getOrderId, orderIds) .eq(OrdersRefund::getStatus, Constants.ONE) .eq(OrdersRefund::getDeleted, Constants.ZERO); List refundRecords = ordersRefundMapper.selectList(refundQw); vo.setRefundOrderCount(refundRecords.stream() .map(OrdersRefund::getOrderId).distinct().count()); } else { vo.setRefundOrderCount(0L); } return vo; } @Override public List memberTrend(TrendQueryDTO query) { TrendDateRange range = parseTrendDateRange(query); List members = memberMapper.selectList(new QueryWrapper().lambda() .eq(Member::getDeleted, Constants.ZERO) .eq(Member::getUserType, Constants.ZERO) .ge(Member::getCreateTime, range.startDate) .le(Member::getCreateTime, range.endDate)); SimpleDateFormat sdf = new SimpleDateFormat(range.pattern); Map map = members.stream() .collect(Collectors.groupingBy(m -> sdf.format(m.getCreateTime()), Collectors.counting())); return buildTrendList(range, (key, label) -> { MemberTrendVO vo = new MemberTrendVO(); vo.setDate(label); vo.setCount(map.getOrDefault(key, 0L)); return vo; }); } @Override public List orderTrend(TrendQueryDTO query) { TrendDateRange range = parseTrendDateRange(query); List orders = ordersMapper.selectList(new QueryWrapper().lambda() .ge(Orders::getCreateTime, range.startDate) .le(Orders::getCreateTime, range.endDate)); SimpleDateFormat sdf = new SimpleDateFormat(range.pattern); Map> grouped = orders.stream() .collect(Collectors.groupingBy(o -> sdf.format(o.getCreateTime()))); return buildTrendList(range, (key, label) -> { List dayOrders = grouped.getOrDefault(key, Collections.emptyList()); OrderTrendVO vo = new OrderTrendVO(); vo.setDate(label); vo.setLocalCount(dayOrders.stream().filter(o -> Constants.equalsInteger(o.getType(), Constants.ZERO)).count()); vo.setRemoteCount(dayOrders.stream().filter(o -> Constants.equalsInteger(o.getType(), Constants.ONE)).count()); return vo; }); } @Override public List revenueTrend(TrendQueryDTO query) { TrendDateRange range = parseTrendDateRange(query); SimpleDateFormat sdf = new SimpleDateFormat(range.pattern); List orders = ordersMapper.selectList(new QueryWrapper().lambda() .eq(Orders::getDeleted, Constants.ZERO) .in(Orders::getStatus, Constants.OrderStatus.waitDeposit.getKey(), Constants.OrderStatus.deposited.getKey(), Constants.OrderStatus.accepted.getKey(), Constants.OrderStatus.delivering.getKey(), Constants.OrderStatus.arrived.getKey(), Constants.OrderStatus.overdue.getKey(), Constants.OrderStatus.finished.getKey()) .ge(Orders::getCreateTime, range.startDate) .le(Orders::getCreateTime, range.endDate)); // 根据筛选出的订单主键查询已支付的逾期费用 List orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList()); Map overduePaidMap = new HashMap<>(); if (!orderIds.isEmpty()) { List overdueOrders = otherOrdersMapper.selectList(new QueryWrapper().lambda() .eq(OtherOrders::getType, 2) .eq(OtherOrders::getPayStatus, Constants.ONE) .eq(OtherOrders::getDeleted, Constants.ZERO) .in(OtherOrders::getOrderId, orderIds)); for (OtherOrders oo : overdueOrders) { long amt = oo.getPayAccount() != null ? oo.getPayAccount() : 0L; overduePaidMap.merge(oo.getOrderId(), amt, Long::sum); } } Map localOrderRevenue = new HashMap<>(); Map remoteOrderRevenue = new HashMap<>(); for (Orders o : orders) { String date = sdf.format(o.getCreateTime()); long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L; long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L; long overdue = overduePaidMap.getOrDefault(o.getId(), 0L); long rev = pay - refund + overdue; if (Constants.equalsInteger(o.getType(), Constants.ZERO)) { localOrderRevenue.merge(date, rev, Long::sum); } else { remoteOrderRevenue.merge(date, rev, Long::sum); } } return buildTrendList(range, (key, label) -> { RevenueTrendVO vo = new RevenueTrendVO(); vo.setDate(label); long local = localOrderRevenue.getOrDefault(key, 0L); long remote = remoteOrderRevenue.getOrDefault(key, 0L); vo.setLocalRevenue(BigDecimal.valueOf(local).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP)); vo.setRemoteRevenue(BigDecimal.valueOf(remote).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP)); return vo; }); } @Override public ShopPerformanceVO shopPerformance(DataBoardQueryDTO query) { query.resolveDateRange(); ShopPerformanceVO vo = new ShopPerformanceVO(); // 1. 总订单数 + 营收(status 1-6) QueryWrapper qw = buildOrderQueryWrapper(query); List orders = ordersMapper.selectList(qw); vo.setTotalOrderCount((long) orders.size()); long revenue = 0L; for (Orders o : orders) { long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L; long overdue = o.getOverdueAmount() != null ? o.getOverdueAmount() : 0L; long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L; revenue += pay + overdue - refund; } vo.setTotalRevenue(BigDecimal.valueOf(Math.max(revenue, 0L)) .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP)); // 2. 已完成订单数(status=7,同等筛选条件) QueryWrapper completedQw = new QueryWrapper<>(); completedQw.lambda() .eq(Orders::getDeleted, Constants.ZERO) .eq(Orders::getStatus, Constants.OrderStatus.finished.getKey()); if (query.getStartDate() != null) { completedQw.lambda().ge(Orders::getCreateTime, query.getStartDate()); } if (query.getEndDate() != null) { completedQw.lambda().le(Orders::getCreateTime, Utils.Date.getEnd(query.getEndDate())); } if (query.getShopId() != null) { completedQw.lambda().and(w -> w.eq(Orders::getDepositShopId, query.getShopId()) .or().eq(Orders::getTakeShopId, query.getShopId())); } vo.setCompletedCount(ordersMapper.selectCount(completedQw)); // 3. 已退款订单数(orders_refund status=1 的去重订单数) List orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList()); if (!orderIds.isEmpty()) { QueryWrapper refundQw = new QueryWrapper<>(); refundQw.lambda() .in(OrdersRefund::getOrderId, orderIds) .eq(OrdersRefund::getStatus, Constants.ONE) .eq(OrdersRefund::getDeleted, Constants.ZERO); List refundRecords = ordersRefundMapper.selectList(refundQw); long refundedOrderCount = refundRecords.stream() .map(OrdersRefund::getOrderId).distinct().count(); vo.setRefundedCount(refundedOrderCount); } else { vo.setRefundedCount(0L); } // 4. 订单完成率 & 退款率(分母 = status 1-6 + status 7) long totalCount = vo.getTotalOrderCount() + vo.getCompletedCount(); if (totalCount > 0) { BigDecimal hundred = BigDecimal.valueOf(100); vo.setCompletionRate(BigDecimal.valueOf(vo.getCompletedCount()) .multiply(hundred).divide(BigDecimal.valueOf(totalCount), 2, RoundingMode.HALF_UP)); vo.setRefundRate(BigDecimal.valueOf(vo.getRefundedCount()) .multiply(hundred).divide(BigDecimal.valueOf(totalCount), 2, RoundingMode.HALF_UP)); } else { vo.setCompletionRate(BigDecimal.ZERO); vo.setRefundRate(BigDecimal.ZERO); } return vo; } @Override public List luggageTypeList(DataBoardQueryDTO query) { query.resolveDateRange(); List orders = ordersMapper.selectList(buildOrderQueryWrapper(query)); List orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList()); return buildLuggageTypeList(orderIds); } @Override public List buildLuggageTypeList(List orderIds) { List luggageTypeList = new ArrayList<>(); if (orderIds != null && !orderIds.isEmpty()) { List details = ordersDetailMapper.selectList(new QueryWrapper().lambda() .in(OrdersDetail::getOrderId, orderIds) .eq(OrdersDetail::getDeleted, Constants.ZERO)); Map> grouped = details.stream() .filter(d -> StringUtils.isNotBlank(d.getLuggageName())) .collect(Collectors.groupingBy(OrdersDetail::getLuggageName)); for (Map.Entry> entry : grouped.entrySet()) { LuggageTypeItem item = new LuggageTypeItem(); item.setLuggageName(entry.getKey()); item.setOrderCount((long) entry.getValue().stream().map(OrdersDetail::getOrderId).distinct().count()); item.setLuggageCount((long) entry.getValue().stream() .mapToInt(d -> d.getNum() != null ? d.getNum() : 0).sum()); luggageTypeList.add(item); } } return luggageTypeList; } @Override public List financeOverview(FinanceQueryDTO query) { // 补齐日期:startDate 取月初,endDate 取月末 Calendar startCal = Calendar.getInstance(); startCal.setTime(query.getStartDate()); startCal.set(Calendar.DAY_OF_MONTH, 1); startCal.set(Calendar.HOUR_OF_DAY, 0); startCal.set(Calendar.MINUTE, 0); startCal.set(Calendar.SECOND, 0); startCal.set(Calendar.MILLISECOND, 0); query.setStartDate(startCal.getTime()); Calendar endCal = Calendar.getInstance(); endCal.setTime(query.getEndDate()); endCal.set(Calendar.DAY_OF_MONTH, endCal.getActualMaximum(Calendar.DAY_OF_MONTH)); endCal.set(Calendar.HOUR_OF_DAY, 23); endCal.set(Calendar.MINUTE, 59); endCal.set(Calendar.SECOND, 59); endCal.set(Calendar.MILLISECOND, 999); query.setEndDate(endCal.getTime()); List orders = ordersMapper.selectList(buildFinanceOrderQueryWrapper(query)); // 根据筛选出的订单主键查询已支付的逾期费用 List orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList()); Map overduePaidMap = new HashMap<>(); if (!orderIds.isEmpty()) { List overdueOrders = otherOrdersMapper.selectList(new QueryWrapper().lambda() .eq(OtherOrders::getType, 2) .eq(OtherOrders::getPayStatus, Constants.ONE) .eq(OtherOrders::getDeleted, Constants.ZERO) .in(OtherOrders::getOrderId, orderIds)); for (OtherOrders oo : overdueOrders) { long amt = oo.getPayAccount() != null ? oo.getPayAccount() : 0L; overduePaidMap.merge(oo.getOrderId(), amt, Long::sum); } } SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM"); Map> grouped = orders.stream() .collect(Collectors.groupingBy(o -> sdf.format(o.getCreateTime()))); // 生成完整年月列表 List months = new ArrayList<>(); Calendar loop = Calendar.getInstance(); loop.setTime(query.getStartDate()); loop.set(Calendar.DAY_OF_MONTH, 1); Calendar monthEnd = Calendar.getInstance(); monthEnd.setTime(query.getEndDate()); while (!loop.after(monthEnd)) { months.add(sdf.format(loop.getTime())); loop.add(Calendar.MONTH, 1); } BigDecimal hundred = BigDecimal.valueOf(100); List result = new ArrayList<>(); for (String month : months) { List monthOrders = grouped.getOrDefault(month, Collections.emptyList()); long storageRev = 0L, deliveryRev = 0L, shopFee = 0L, driverFeeTotal = 0L, refundTotal = 0L, overdueTotal = 0L; for (Orders o : monthOrders) { long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L; long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L; long overdue = overduePaidMap.getOrDefault(o.getId(), 0L); long actual = pay - refund + overdue; long depFee = o.getDepositShopFee() != null ? o.getDepositShopFee() : 0L; long takeFee = o.getTakeShopFee() != null ? o.getTakeShopFee() : 0L; long dFee = Constants.equalsInteger(o.getType(),Constants.ONE)&&o.getDriverFee() != null ? o.getDriverFee() : 0L; if (Constants.equalsInteger(o.getType(), Constants.ZERO)) { storageRev += actual; shopFee += depFee; } else { deliveryRev += actual; shopFee += depFee + takeFee; } driverFeeTotal += dFee; refundTotal += refund; overdueTotal += overdue; } long totalRev = storageRev + deliveryRev; long netRev = totalRev - shopFee - driverFeeTotal; FinanceOverviewVO vo = new FinanceOverviewVO(); vo.setDate(month); vo.setStorageRevenue(BigDecimal.valueOf(storageRev).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setDeliveryRevenue(BigDecimal.valueOf(deliveryRev).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setTotalRevenue(BigDecimal.valueOf(totalRev).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setShopFeeTotal(BigDecimal.valueOf(shopFee).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setDriverFeeTotal(BigDecimal.valueOf(driverFeeTotal).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setRefundAmount(BigDecimal.valueOf(refundTotal).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setOverdueAmount(BigDecimal.valueOf(overdueTotal).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setNetRevenue(BigDecimal.valueOf(netRev).divide(hundred, 2, RoundingMode.HALF_UP)); result.add(vo); } return result; } @Override public List shopTop(TrendQueryDTO query) { TrendDateRange range = parseTrendDateRange(query); List orders = ordersMapper.selectList(new QueryWrapper().lambda() .eq(Orders::getDeleted, Constants.ZERO) .eq(Orders::getStatus, Constants.OrderStatus.finished.getKey()) .ge(Orders::getCreateTime, range.startDate) .le(Orders::getCreateTime, range.endDate)); // 根据筛选出的订单主键查询已支付的逾期费用 List orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList()); Map overduePaidMap = new HashMap<>(); if (!orderIds.isEmpty()) { List overdueOrders = otherOrdersMapper.selectList(new QueryWrapper().lambda() .eq(OtherOrders::getType, 2) .eq(OtherOrders::getPayStatus, Constants.ONE) .eq(OtherOrders::getDeleted, Constants.ZERO) .in(OtherOrders::getOrderId, orderIds)); for (OtherOrders oo : overdueOrders) { long amt = oo.getPayAccount() != null ? oo.getPayAccount() : 0L; overduePaidMap.merge(oo.getOrderId(), amt, Long::sum); } } // 按门店ID归集: key = shopId Map map = new LinkedHashMap<>(); for (Orders o : orders) { long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L; long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L; long overdue = overduePaidMap.getOrDefault(o.getId(), 0L); boolean hasRefund = refund > 0; long rev = pay - refund + overdue; // 存件门店 if (o.getDepositShopId() != null) { long depFee = o.getDepositShopFee() != null ? o.getDepositShopFee() : 0L; long[] arr = map.computeIfAbsent(o.getDepositShopId(), k -> new long[4]); // [count, revenue, fee, refundCount] arr[0]++; arr[1] += rev; arr[2] += depFee; if (hasRefund) arr[3]++; } // 异地且有取件门店 if (Constants.equalsInteger(o.getType(), Constants.ONE) && o.getTakeShopId() != null) { long takeFee = o.getTakeShopFee() != null ? o.getTakeShopFee() : 0L; long[] arr = map.computeIfAbsent(o.getTakeShopId(), k -> new long[4]); arr[0]++; arr[1] += rev; arr[2] += takeFee; if (hasRefund) arr[3]++; } } // 批量查门店名称 Set shopIds = map.keySet(); Map shopNameMap = new HashMap<>(); if (!shopIds.isEmpty()) { List shops = shopInfoMapper.selectList(new QueryWrapper().lambda() .in(ShopInfo::getId, shopIds) .select(ShopInfo::getId, ShopInfo::getName)); for (ShopInfo s : shops) { shopNameMap.put(s.getId(), s.getName()); } } BigDecimal hundred = BigDecimal.valueOf(100); List result = new ArrayList<>(); for (Map.Entry entry : map.entrySet()) { long[] arr = entry.getValue(); ShopTopVO vo = new ShopTopVO(); vo.setShopId(entry.getKey()); vo.setShopName(shopNameMap.getOrDefault(entry.getKey(), "")); vo.setCompletedCount(arr[0]); vo.setTotalRevenue(BigDecimal.valueOf(arr[1]).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setShopFeeTotal(BigDecimal.valueOf(arr[2]).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setRefundCount(arr[3]); vo.setPenaltyAmount(BigDecimal.ZERO); result.add(vo); } result.sort((a, b) -> Long.compare(b.getCompletedCount(), a.getCompletedCount())); return result.size() > 10 ? result.subList(0, 10) : result; } @Override public List driverTop(TrendQueryDTO query) { TrendDateRange range = parseTrendDateRange(query); List orders = ordersMapper.selectList(new QueryWrapper().lambda() // .eq(Orders::getDeleted, Constants.ZERO) .in(Orders::getStatus, Constants.OrderStatus.waitDeposit.getKey(), Constants.OrderStatus.deposited.getKey(), Constants.OrderStatus.accepted.getKey(), Constants.OrderStatus.delivering.getKey(), Constants.OrderStatus.arrived.getKey(), Constants.OrderStatus.finished.getKey()) .eq(Orders::getType, Constants.ONE) .ge(Orders::getCreateTime, range.startDate) .le(Orders::getCreateTime, range.endDate)); System.out.println( orders.stream().map(i->i.getDriverFee()).reduce(0L,Long::sum) ); // 根据筛选出的订单主键查询已支付的逾期费用 List orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList()); Map overduePaidMap = new HashMap<>(); if (!orderIds.isEmpty()) { List overdueOrders = otherOrdersMapper.selectList(new QueryWrapper().lambda() .eq(OtherOrders::getType, 2) .eq(OtherOrders::getPayStatus, Constants.ONE) .eq(OtherOrders::getDeleted, Constants.ZERO) .in(OtherOrders::getOrderId, orderIds)); for (OtherOrders oo : overdueOrders) { long amt = oo.getPayAccount() != null ? oo.getPayAccount() : 0L; overduePaidMap.merge(oo.getOrderId(), amt, Long::sum); } } // 按司机归集: key = acceptDriver Map map = new LinkedHashMap<>(); for (Orders o : orders) { if (o.getAcceptDriver() == null) continue; long pay = o.getPayAmount() != null ? o.getPayAmount() : 0L; long refund = o.getRefundAmount() != null ? o.getRefundAmount() : 0L; long overdue = overduePaidMap.getOrDefault(o.getId(), 0L); long dFee = o.getDriverFee() != null ? o.getDriverFee() : 0L; long[] arr = map.computeIfAbsent(o.getAcceptDriver(), k -> new long[4]); // [count, revenue, fee, refundCount] arr[0]++; arr[1] += pay - refund + overdue; arr[2] += dFee; if (refund > 0) arr[3]++; } // 批量查司机姓名 Set driverIds = map.keySet(); Map driverNameMap = new HashMap<>(); if (!driverIds.isEmpty()) { List drivers = driverInfoMapper.selectList(new QueryWrapper().lambda() .in(DriverInfo::getId, driverIds) .select(DriverInfo::getMemberId, DriverInfo::getName)); for (DriverInfo d : drivers) { driverNameMap.put(d.getMemberId(), d.getName()); } } BigDecimal hundred = BigDecimal.valueOf(100); List result = new ArrayList<>(); for (Map.Entry entry : map.entrySet()) { long[] arr = entry.getValue(); DriverTopVO vo = new DriverTopVO(); vo.setDriverId(entry.getKey()); vo.setDriverName(driverNameMap.getOrDefault(entry.getKey(), "未知")); vo.setCompletedCount(arr[0]); vo.setTotalRevenue(BigDecimal.valueOf(arr[1]).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setDriverFeeTotal(BigDecimal.valueOf(arr[2]).divide(hundred, 2, RoundingMode.HALF_UP)); vo.setRefundCount(arr[3]); vo.setPenaltyAmount(BigDecimal.ZERO); result.add(vo); } result.sort((a, b) -> Long.compare(b.getCompletedCount(), a.getCompletedCount())); return result.size() > 10 ? result.subList(0, 10) : result; } // ========== 私有方法 ========== private QueryWrapper buildOrderQueryWrapper(DataBoardQueryDTO query) { QueryWrapper qw = new QueryWrapper<>(); qw.lambda() .eq(Orders::getDeleted, Constants.ZERO) .in(Orders::getStatus, Constants.OrderStatus.waitDeposit.getKey(), Constants.OrderStatus.deposited.getKey(), Constants.OrderStatus.accepted.getKey(), Constants.OrderStatus.delivering.getKey(), Constants.OrderStatus.arrived.getKey(), Constants.OrderStatus.finished.getKey()); if (query.getStartDate() != null) { qw.lambda().ge(Orders::getCreateTime, query.getStartDate()); } if (query.getEndDate() != null) { qw.lambda().le(Orders::getCreateTime, Utils.Date.getEnd(query.getEndDate())); } if (query.getShopId() != null) { qw.lambda().and(w -> w.eq(Orders::getDepositShopId, query.getShopId()) .or().eq(Orders::getTakeShopId, query.getShopId())); } return qw; } private QueryWrapper buildFinanceOrderQueryWrapper(FinanceQueryDTO query) { QueryWrapper qw = new QueryWrapper<>(); qw.lambda() .eq(Orders::getDeleted, Constants.ZERO) .in(Orders::getStatus, Constants.OrderStatus.waitDeposit.getKey(), Constants.OrderStatus.deposited.getKey(), Constants.OrderStatus.accepted.getKey(), Constants.OrderStatus.delivering.getKey(), Constants.OrderStatus.arrived.getKey(), Constants.OrderStatus.finished.getKey()); if (query.getStartDate() != null) { qw.lambda().ge(Orders::getCreateTime, query.getStartDate()); } if (query.getEndDate() != null) { qw.lambda().le(Orders::getCreateTime, Utils.Date.getEnd(query.getEndDate())); } return qw; } private TrendDateRange parseTrendDateRange(TrendQueryDTO query) { Calendar now = Calendar.getInstance(); TrendDateRange range = new TrendDateRange(); if (StringUtils.isNotBlank(query.getMonth())) { // 按月查询:yyyy-MM SimpleDateFormat parseSdf = new SimpleDateFormat("yyyy-MM"); Date monthDate; try { monthDate = parseSdf.parse(query.getMonth()); } catch (Exception e) { throw new IllegalArgumentException("month 格式错误,应为 yyyy-MM"); } Calendar monthCal = Calendar.getInstance(); monthCal.setTime(monthDate); // 当月1日起始 monthCal.set(Calendar.DAY_OF_MONTH, 1); monthCal.set(Calendar.HOUR_OF_DAY, 0); monthCal.set(Calendar.MINUTE, 0); monthCal.set(Calendar.SECOND, 0); monthCal.set(Calendar.MILLISECOND, 0); range.startDate = monthCal.getTime(); // 月末 monthCal.set(Calendar.DAY_OF_MONTH, monthCal.getActualMaximum(Calendar.DAY_OF_MONTH)); monthCal.set(Calendar.HOUR_OF_DAY, 23); monthCal.set(Calendar.MINUTE, 59); monthCal.set(Calendar.SECOND, 59); monthCal.set(Calendar.MILLISECOND, 999); Date monthEnd = monthCal.getTime(); // 不能超过当前时间 range.endDate = monthEnd.after(now.getTime()) ? now.getTime() : monthEnd; range.byMonth = true; range.pattern = "MM-dd"; } else if (StringUtils.isNotBlank(query.getYear())) { // 按年查询:yyyy int year = Integer.parseInt(query.getYear()); Calendar yearStart = Calendar.getInstance(); yearStart.set(Calendar.YEAR, year); yearStart.set(Calendar.MONTH, Calendar.JANUARY); yearStart.set(Calendar.DAY_OF_MONTH, 1); yearStart.set(Calendar.HOUR_OF_DAY, 0); yearStart.set(Calendar.MINUTE, 0); yearStart.set(Calendar.SECOND, 0); yearStart.set(Calendar.MILLISECOND, 0); range.startDate = yearStart.getTime(); Calendar yearEnd = Calendar.getInstance(); yearEnd.set(Calendar.YEAR, year); yearEnd.set(Calendar.MONTH, Calendar.DECEMBER); yearEnd.set(Calendar.DAY_OF_MONTH, 31); yearEnd.set(Calendar.HOUR_OF_DAY, 23); yearEnd.set(Calendar.MINUTE, 59); yearEnd.set(Calendar.SECOND, 59); yearEnd.set(Calendar.MILLISECOND, 999); Date end = yearEnd.getTime(); range.endDate = end.after(now.getTime()) ? now.getTime() : end; range.byMonth = false; range.pattern = "MM"; } else { throw new IllegalArgumentException("请传入 month 或 year 参数"); } return range; } private static class TrendDateRange { Date startDate; Date endDate; boolean byMonth; // true=按月查(按日返回),false=按年查(按月返回) String pattern; // SimpleDateFormat 格式 } @FunctionalInterface private interface TrendVOBuilder { T build(String key, String label); } private List buildTrendList(TrendDateRange range, TrendVOBuilder builder) { List result = new ArrayList<>(); SimpleDateFormat sdf = new SimpleDateFormat(range.pattern); if (range.byMonth) { // 按日循环 Calendar loop = Calendar.getInstance(); loop.setTime(range.startDate); Calendar end = Calendar.getInstance(); end.setTime(range.endDate); while (!loop.after(end)) { String dateStr = sdf.format(loop.getTime()); result.add(builder.build(dateStr, dateStr)); loop.add(Calendar.DAY_OF_MONTH, 1); } } else { // 按月循环 1~12,不能超过 endDate 所在月 Calendar endCal = Calendar.getInstance(); endCal.setTime(range.endDate); int endMonth = endCal.get(Calendar.MONTH); // 0-based for (int m = 0; m <= endMonth; m++) { String key = String.format("%02d", m + 1); String label = (m + 1) + "月"; result.add(builder.build(key, label)); } } return result; } }