package com.tourguide.modules.order.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.tourguide.common.exception.BusinessException; import com.tourguide.modules.order.domain.OrderStatus; import com.tourguide.modules.order.domain.RefundStatus; import com.tourguide.modules.order.dto.GuideEarningItemResponse; import com.tourguide.modules.order.dto.GuideEarningsResponse; import com.tourguide.modules.order.entity.TourOrder; import com.tourguide.modules.order.mapper.TourOrderMapper; import com.tourguide.modules.user.service.GuideUserService; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; /** 查询导游已完成订单的业绩快照。 */ @Service public class GuideEarningsService { private final TourOrderMapper orderMapper; private final GuideUserService guideUserService; public GuideEarningsService(TourOrderMapper orderMapper, GuideUserService guideUserService) { this.orderMapper = orderMapper; this.guideUserService = guideUserService; } public GuideEarningsResponse get(Long guideId, String serviceType, String scenicName, LocalDate date, long pageNum, long pageSize) { guideUserService.findEnabledById(guideId); validateServiceType(serviceType); long safePage = Math.max(pageNum, 1); long safeSize = Math.min(Math.max(pageSize, 1), 100); LocalDate today = LocalDate.now(); BigDecimal todayEarnings = safeAmount(orderMapper.selectGuideEarningSum( guideId, today.atStartOfDay(), today.plusDays(1).atStartOfDay())); LocalDate monthStart = today.withDayOfMonth(1); BigDecimal monthEarnings = safeAmount(orderMapper.selectGuideEarningSum( guideId, monthStart.atStartOfDay(), monthStart.plusMonths(1).atStartOfDay())); LambdaQueryWrapper query = new LambdaQueryWrapper() .eq(TourOrder::getGuideId, guideId) .eq(TourOrder::getStatus, OrderStatus.COMPLETED.getCode()) .isNotNull(TourOrder::getGuideEarningAmount) .and(wrapper -> wrapper.isNull(TourOrder::getRefundStatus) .or().ne(TourOrder::getRefundStatus, RefundStatus.REFUNDED.getCode())) .like(StringUtils.hasText(serviceType), TourOrder::getOrderType, serviceType) .eq(StringUtils.hasText(scenicName), TourOrder::getScenicName, StringUtils.hasText(scenicName) ? scenicName.trim() : null) .ge(date != null, TourOrder::getCompletedAt, date == null ? null : date.atStartOfDay()) .lt(date != null, TourOrder::getCompletedAt, date == null ? null : date.plusDays(1).atStartOfDay()) .orderByDesc(TourOrder::getCompletedAt) .orderByDesc(TourOrder::getId); Page result = orderMapper.selectPage(new Page(safePage, safeSize), query); List records = result.getRecords().stream() .map(GuideEarningItemResponse::new) .collect(Collectors.toList()); return new GuideEarningsResponse(todayEarnings, monthEarnings, orderMapper.selectGuideEarningScenics(guideId), records, result.getTotal(), result.getCurrent(), result.getSize()); } private void validateServiceType(String serviceType) { if (StringUtils.hasText(serviceType) && !"QUICK".equals(serviceType) && !"PREMIUM".equals(serviceType)) { throw new BusinessException(400, "讲解类型不支持"); } } private BigDecimal safeAmount(BigDecimal amount) { return amount == null ? BigDecimal.ZERO.setScale(2) : amount; } }