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<Member>().lambda()
|
.eq(Member::getDeleted, Constants.ZERO)
|
.eq(Member::getUserType, Constants.ZERO)));
|
// 门店总数(auditStatus=3 正式版本)
|
vo.setShopCount(shopInfoMapper.selectCount(new QueryWrapper<ShopInfo>().lambda()
|
.eq(ShopInfo::getAuditStatus, Constants.THREE)
|
.eq(ShopInfo::getVersionType, Constants.ZERO)
|
.eq(ShopInfo::getDeleted, Constants.ZERO)));
|
// 司机总数(auditStatus=3 正式版本)
|
vo.setDriverCount(driverInfoMapper.selectCount(new QueryWrapper<DriverInfo>().lambda()
|
.eq(DriverInfo::getAuditStatus, Constants.THREE)
|
.eq(DriverInfo::getVersionType, Constants.ZERO)
|
.eq(DriverInfo::getDeleted, Constants.ZERO)));
|
|
// 周期总订单数
|
vo.setOrderCount(ordersMapper.selectCount(buildOrderQueryWrapper(query)));
|
|
// 周期营收
|
List<Orders> 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<OtherOrders> 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> 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<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
|
vo.setLuggageTypeList(buildLuggageTypeList(orderIds));
|
|
// 门店入驻率:auditStatus=3 的门店数 / 全部门店数
|
long totalShopCount = shopInfoMapper.selectCount(new QueryWrapper<ShopInfo>().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<DriverInfo>().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<OrdersRefund> refundQw = new QueryWrapper<>();
|
refundQw.lambda()
|
.in(OrdersRefund::getOrderId, orderIds)
|
.eq(OrdersRefund::getStatus, Constants.ONE)
|
.eq(OrdersRefund::getDeleted, Constants.ZERO);
|
List<OrdersRefund> refundRecords = ordersRefundMapper.selectList(refundQw);
|
vo.setRefundOrderCount(refundRecords.stream()
|
.map(OrdersRefund::getOrderId).distinct().count());
|
} else {
|
vo.setRefundOrderCount(0L);
|
}
|
|
return vo;
|
}
|
|
@Override
|
public List<MemberTrendVO> memberTrend(TrendQueryDTO query) {
|
TrendDateRange range = parseTrendDateRange(query);
|
List<Member> members = memberMapper.selectList(new QueryWrapper<Member>().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<String, Long> map = members.stream()
|
.collect(Collectors.groupingBy(m -> sdf.format(m.getCreateTime()), Collectors.counting()));
|
|
return buildTrendList(range, (date) -> {
|
MemberTrendVO vo = new MemberTrendVO();
|
vo.setDate(date);
|
vo.setCount(map.getOrDefault(date, 0L));
|
return vo;
|
});
|
}
|
|
@Override
|
public List<OrderTrendVO> orderTrend(TrendQueryDTO query) {
|
TrendDateRange range = parseTrendDateRange(query);
|
List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda()
|
.ge(Orders::getCreateTime, range.startDate)
|
.le(Orders::getCreateTime, range.endDate));
|
|
SimpleDateFormat sdf = new SimpleDateFormat(range.pattern);
|
Map<String, List<Orders>> grouped = orders.stream()
|
.collect(Collectors.groupingBy(o -> sdf.format(o.getCreateTime())));
|
|
return buildTrendList(range, (date) -> {
|
List<Orders> dayOrders = grouped.getOrDefault(date, Collections.emptyList());
|
OrderTrendVO vo = new OrderTrendVO();
|
vo.setDate(date);
|
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<RevenueTrendVO> revenueTrend(TrendQueryDTO query) {
|
TrendDateRange range = parseTrendDateRange(query);
|
SimpleDateFormat sdf = new SimpleDateFormat(range.pattern);
|
|
List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().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<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
|
Map<Integer, Long> overduePaidMap = new HashMap<>();
|
if (!orderIds.isEmpty()) {
|
List<OtherOrders> overdueOrders = otherOrdersMapper.selectList(new QueryWrapper<OtherOrders>().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<String, Long> localOrderRevenue = new HashMap<>();
|
Map<String, Long> 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, (date) -> {
|
RevenueTrendVO vo = new RevenueTrendVO();
|
vo.setDate(date);
|
long local = localOrderRevenue.getOrDefault(date, 0L);
|
long remote = remoteOrderRevenue.getOrDefault(date, 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<Orders> qw = buildOrderQueryWrapper(query);
|
List<Orders> 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<Orders> 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<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
|
if (!orderIds.isEmpty()) {
|
QueryWrapper<OrdersRefund> refundQw = new QueryWrapper<>();
|
refundQw.lambda()
|
.in(OrdersRefund::getOrderId, orderIds)
|
.eq(OrdersRefund::getStatus, Constants.ONE)
|
.eq(OrdersRefund::getDeleted, Constants.ZERO);
|
List<OrdersRefund> 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<LuggageTypeItem> luggageTypeList(DataBoardQueryDTO query) {
|
query.resolveDateRange();
|
List<Orders> orders = ordersMapper.selectList(buildOrderQueryWrapper(query));
|
List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
|
return buildLuggageTypeList(orderIds);
|
}
|
|
@Override
|
public List<LuggageTypeItem> buildLuggageTypeList(List<Integer> orderIds) {
|
List<LuggageTypeItem> luggageTypeList = new ArrayList<>();
|
if (orderIds != null && !orderIds.isEmpty()) {
|
List<OrdersDetail> details = ordersDetailMapper.selectList(new QueryWrapper<OrdersDetail>().lambda()
|
.in(OrdersDetail::getOrderId, orderIds)
|
.eq(OrdersDetail::getDeleted, Constants.ZERO));
|
Map<String, List<OrdersDetail>> grouped = details.stream()
|
.filter(d -> StringUtils.isNotBlank(d.getLuggageName()))
|
.collect(Collectors.groupingBy(OrdersDetail::getLuggageName));
|
for (Map.Entry<String, List<OrdersDetail>> 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<FinanceOverviewVO> 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> orders = ordersMapper.selectList(buildFinanceOrderQueryWrapper(query));
|
|
// 根据筛选出的订单主键查询已支付的逾期费用
|
List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
|
Map<Integer, Long> overduePaidMap = new HashMap<>();
|
if (!orderIds.isEmpty()) {
|
List<OtherOrders> overdueOrders = otherOrdersMapper.selectList(new QueryWrapper<OtherOrders>().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<String, List<Orders>> grouped = orders.stream()
|
.collect(Collectors.groupingBy(o -> sdf.format(o.getCreateTime())));
|
|
// 生成完整年月列表
|
List<String> 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<FinanceOverviewVO> result = new ArrayList<>();
|
for (String month : months) {
|
List<Orders> 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<ShopTopVO> shopTop(TrendQueryDTO query) {
|
TrendDateRange range = parseTrendDateRange(query);
|
List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().lambda()
|
.eq(Orders::getDeleted, Constants.ZERO)
|
.eq(Orders::getStatus, Constants.OrderStatus.finished.getKey())
|
.ge(Orders::getCreateTime, range.startDate)
|
.le(Orders::getCreateTime, range.endDate));
|
|
// 根据筛选出的订单主键查询已支付的逾期费用
|
List<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
|
Map<Integer, Long> overduePaidMap = new HashMap<>();
|
if (!orderIds.isEmpty()) {
|
List<OtherOrders> overdueOrders = otherOrdersMapper.selectList(new QueryWrapper<OtherOrders>().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<Integer, long[]> 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<Integer> shopIds = map.keySet();
|
Map<Integer, String> shopNameMap = new HashMap<>();
|
if (!shopIds.isEmpty()) {
|
List<ShopInfo> shops = shopInfoMapper.selectList(new QueryWrapper<ShopInfo>().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<ShopTopVO> result = new ArrayList<>();
|
for (Map.Entry<Integer, long[]> 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<DriverTopVO> driverTop(TrendQueryDTO query) {
|
TrendDateRange range = parseTrendDateRange(query);
|
List<Orders> orders = ordersMapper.selectList(new QueryWrapper<Orders>().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<Integer> orderIds = orders.stream().map(Orders::getId).collect(Collectors.toList());
|
Map<Integer, Long> overduePaidMap = new HashMap<>();
|
if (!orderIds.isEmpty()) {
|
List<OtherOrders> overdueOrders = otherOrdersMapper.selectList(new QueryWrapper<OtherOrders>().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<Integer, long[]> 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<Integer> driverIds = map.keySet();
|
Map<Integer, String> driverNameMap = new HashMap<>();
|
if (!driverIds.isEmpty()) {
|
List<DriverInfo> drivers = driverInfoMapper.selectList(new QueryWrapper<DriverInfo>().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<DriverTopVO> result = new ArrayList<>();
|
for (Map.Entry<Integer, long[]> 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<Orders> buildOrderQueryWrapper(DataBoardQueryDTO query) {
|
QueryWrapper<Orders> 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<Orders> buildFinanceOrderQueryWrapper(FinanceQueryDTO query) {
|
QueryWrapper<Orders> 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> {
|
T build(String date);
|
}
|
|
private <T> List<T> buildTrendList(TrendDateRange range, TrendVOBuilder<T> builder) {
|
List<T> 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)) {
|
result.add(builder.build(sdf.format(loop.getTime())));
|
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 label = String.format("%02d", m + 1);
|
result.add(builder.build(label));
|
}
|
}
|
return result;
|
}
|
}
|