diff --git a/ebike-feign/src/main/java/com/ebike/feign/clients/UserFeignClient.java b/ebike-feign/src/main/java/com/ebike/feign/clients/UserFeignClient.java index 640cc69..b9a641b 100644 --- a/ebike-feign/src/main/java/com/ebike/feign/clients/UserFeignClient.java +++ b/ebike-feign/src/main/java/com/ebike/feign/clients/UserFeignClient.java @@ -3,9 +3,13 @@ package com.ebike.feign.clients; import com.cdzy.common.model.response.JsonResult; import com.ebike.feign.component.FeignTokenInterceptor; import com.ebike.feign.config.ExampleFeignConfiguration; +import com.ebike.feign.model.dto.FeignEbikeOrderStatisticsDto; import com.ebike.feign.model.vo.FeignEbikeRefundOrderDetailVo; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; /** @@ -25,4 +29,13 @@ public interface UserFeignClient { */ @GetMapping("/ebikeRefund/api/refundOrderDetail") JsonResult refundOrderDetail(@RequestParam("refundId") Long refundId); + + /** + * 查询不同运营商的订单数据及订单金额 + * + * @param dto 订单请求参数 + * @return 订单数据及订单金额 + */ + @PostMapping("/ebikeOrder/api/getOrderStatistics") + JsonResult getOrderStatistics(@RequestBody @Validated FeignEbikeOrderStatisticsDto dto); } diff --git a/ebike-feign/src/main/java/com/ebike/feign/model/dto/FeignEbikeOrderStatisticsDto.java b/ebike-feign/src/main/java/com/ebike/feign/model/dto/FeignEbikeOrderStatisticsDto.java new file mode 100644 index 0000000..ca29b8a --- /dev/null +++ b/ebike-feign/src/main/java/com/ebike/feign/model/dto/FeignEbikeOrderStatisticsDto.java @@ -0,0 +1,31 @@ +package com.ebike.feign.model.dto; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 订单统计请求参数 + * + * @author yanglei + * @since 2026-01-16 11:06 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class FeignEbikeOrderStatisticsDto { + + /** + * 运营商id + */ + private Long operatorId; + + /** + * 时间 1-今天 2-近7天 3-近30天 + */ + @NotNull(message = "日期指标不能为空") + private Integer timeRange; +} diff --git a/ebike-feign/src/main/java/com/ebike/feign/model/vo/FeignEbikeOrderStatisticsVo.java b/ebike-feign/src/main/java/com/ebike/feign/model/vo/FeignEbikeOrderStatisticsVo.java new file mode 100644 index 0000000..fd731fe --- /dev/null +++ b/ebike-feign/src/main/java/com/ebike/feign/model/vo/FeignEbikeOrderStatisticsVo.java @@ -0,0 +1,44 @@ +package com.ebike.feign.model.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * @author yanglei + * @since 2026-01-16 11:23 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FeignEbikeOrderStatisticsVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 运营商id + */ + private Long operatorId; + + /** + * 订单数量 + */ + private Integer orderCount; + + /** + * 订单金额 + */ + private BigDecimal orderAmount; + + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDateTime createTime; +} diff --git a/ebike-operations/src/main/java/com/cdzy/operations/controller/EbikeStatisticsController.java b/ebike-operations/src/main/java/com/cdzy/operations/controller/EbikeStatisticsController.java new file mode 100644 index 0000000..d98683e --- /dev/null +++ b/ebike-operations/src/main/java/com/cdzy/operations/controller/EbikeStatisticsController.java @@ -0,0 +1,46 @@ +package com.cdzy.operations.controller; + +import cn.dev33.satoken.stp.StpUtil; +import com.cdzy.common.enums.Code; +import com.cdzy.common.ex.EbikeException; +import com.cdzy.common.model.response.CommonStaffInfo; +import com.cdzy.common.model.response.JsonResult; +import com.ebike.feign.clients.UserFeignClient; +import com.ebike.feign.model.dto.FeignEbikeOrderStatisticsDto; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author yanglei + * @since 2026-01-16 15:15 + */ +@RestController +@RequestMapping("/statistics") +public class EbikeStatisticsController { + + @Resource + private UserFeignClient userFeignClient; + + /** + * 查询用户订单统计 + * + * @param dto 参数参数 + * @return 用户订单数据统计 + */ + @PostMapping("/getOrderStatistics") + public JsonResult getOrderStatistics(@RequestBody @Validated FeignEbikeOrderStatisticsDto dto) { + Long staffId = StpUtil.getLoginIdAsLong(); + CommonStaffInfo staffInfo = StpUtil.getSession().getModel(staffId.toString(), CommonStaffInfo.class); + dto.setOperatorId(staffInfo.getOperatorId()); + JsonResult jsonResult = userFeignClient.getOrderStatistics(dto); + if (jsonResult.getCode() != Code.SUCCESS) { + throw new EbikeException(jsonResult.getMessage()); + } + return JsonResult.success(jsonResult.getData()); + } + +} diff --git a/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java b/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java index f1c86b1..618783c 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java @@ -199,17 +199,4 @@ public class EbikePaymentServiceImpl extends ServiceImpl getOrderStatistics(@RequestBody @Validated FeignEbikeOrderStatisticsDto dto) { + List result = ebikeOrderService.getOrderStatistics(dto); + return JsonResult.success(result); + } } diff --git a/ebike-user/src/main/java/com/cdzy/user/enums/TimeRangeEnum.java b/ebike-user/src/main/java/com/cdzy/user/enums/TimeRangeEnum.java new file mode 100644 index 0000000..21facc1 --- /dev/null +++ b/ebike-user/src/main/java/com/cdzy/user/enums/TimeRangeEnum.java @@ -0,0 +1,42 @@ +package com.cdzy.user.enums; + +import com.cdzy.user.utils.DateUtils; + +import java.time.LocalDateTime; + +/** + * @author yanglei + * @since 2026-01-16 14:42 + */ + +public enum TimeRangeEnum { + TODAY(1), + SEVEN_DAYS_RANGE(2), + THIRTY_DAYS_RANGE(3); + + private final int code; + + TimeRangeEnum(int code) { + this.code = code; + } + + public static TimeRangeEnum fromCode(Integer code) { + if (code == null) { + return null; + } + for (TimeRangeEnum range : values()) { + if (range.code == code) { + return range; + } + } + throw new IllegalArgumentException("Invalid timeRange code: " + code); + } + + public LocalDateTime[] getRange() { + return switch (this) { + case TODAY -> DateUtils.getTodayRange(); + case SEVEN_DAYS_RANGE -> DateUtils.getLast7DaysRange(); + case THIRTY_DAYS_RANGE -> DateUtils.getLast30DaysRange(); + }; + } +} diff --git a/ebike-user/src/main/java/com/cdzy/user/mapper/EbikeOrderMapper.java b/ebike-user/src/main/java/com/cdzy/user/mapper/EbikeOrderMapper.java index 2ed2959..1d53009 100644 --- a/ebike-user/src/main/java/com/cdzy/user/mapper/EbikeOrderMapper.java +++ b/ebike-user/src/main/java/com/cdzy/user/mapper/EbikeOrderMapper.java @@ -2,8 +2,10 @@ package com.cdzy.user.mapper; import com.cdzy.user.model.entity.EbikeOrder; import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo; +import com.ebike.feign.model.vo.FeignEbikeOrderStatisticsVo; import com.mybatisflex.core.BaseMapper; +import java.time.LocalDateTime; import java.util.List; /** @@ -21,4 +23,15 @@ public interface EbikeOrderMapper extends BaseMapper { * @return 营收统计 */ List selectRevenueComparison(); + + + /** + * 查询不同运营商的订单数据及订单金额 + * + * @param operatorId 运营商id + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 订单数据及订单金额 + */ + List getOrderStatistics(Long operatorId, LocalDateTime startTime, LocalDateTime endTime); } diff --git a/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java b/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java index 4ff96af..a5c8f1b 100644 --- a/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java +++ b/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java @@ -9,7 +9,9 @@ import com.cdzy.user.model.vo.EbikeOrderDetailVo; import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo; import com.cdzy.user.model.vo.EbikeUserAllOrdersVo; import com.ebike.feign.model.dto.FeignEbikeDto; +import com.ebike.feign.model.dto.FeignEbikeOrderStatisticsDto; import com.ebike.feign.model.vo.FeignEbikeBikeRadiusVo; +import com.ebike.feign.model.vo.FeignEbikeOrderStatisticsVo; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.service.IService; @@ -113,4 +115,13 @@ public interface EbikeOrderService extends IService { * @return 订单详情 */ EbikeOrderDetailVo getInfo(Long orderId); + + + /** + * 查询不同运营商的订单数据及订单金额 + * + * @param dto 订单请求参数 + * @return 订单数据及订单金额 + */ + List getOrderStatistics(FeignEbikeOrderStatisticsDto dto); } diff --git a/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderServiceImpl.java b/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderServiceImpl.java index b1145e7..ec7ccec 100644 --- a/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderServiceImpl.java +++ b/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderServiceImpl.java @@ -10,6 +10,7 @@ import com.cdzy.user.enums.EbikePaymentMethod; import com.cdzy.user.enums.EbikePaymentTradeStatus; import com.cdzy.user.enums.OrderStatus; import com.cdzy.user.enums.OrderType; +import com.cdzy.user.enums.TimeRangeEnum; import com.cdzy.user.mapper.EbikeOrderMapper; import com.cdzy.user.model.dto.EbikeCostDetailDto; import com.cdzy.user.model.dto.EbikeUserCyclingDto; @@ -29,10 +30,12 @@ import com.cdzy.user.service.EbikeUserRealInfoService; import com.cdzy.user.utils.StringUtils; import com.ebike.feign.clients.OperationsFeignClient; import com.ebike.feign.model.dto.FeignEbikeDto; +import com.ebike.feign.model.dto.FeignEbikeOrderStatisticsDto; import com.ebike.feign.model.dto.FeignEbikeUserBikeInfo; import com.ebike.feign.model.dto.FeignEbikeUserLockDto; import com.ebike.feign.model.vo.EbikeLockVo; import com.ebike.feign.model.vo.FeignEbikeBikeRadiusVo; +import com.ebike.feign.model.vo.FeignEbikeOrderStatisticsVo; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.spring.service.impl.ServiceImpl; @@ -352,6 +355,17 @@ public class EbikeOrderServiceImpl extends ServiceImpl getOrderStatistics(FeignEbikeOrderStatisticsDto dto) { + TimeRangeEnum timeRange = TimeRangeEnum.fromCode(dto.getTimeRange()); + LocalDateTime[] range = timeRange.getRange(); + return this.mapper.getOrderStatistics( + dto.getOperatorId(), + range[0], + range[1] + ); + } + /** * 计算增长率并格式化为百分比字符串 * diff --git a/ebike-user/src/main/java/com/cdzy/user/utils/DateUtils.java b/ebike-user/src/main/java/com/cdzy/user/utils/DateUtils.java new file mode 100644 index 0000000..e1426bc --- /dev/null +++ b/ebike-user/src/main/java/com/cdzy/user/utils/DateUtils.java @@ -0,0 +1,241 @@ +package com.cdzy.user.utils; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; + +/** + * 时间工具类 + * + * @author yanglei + * @since 2026-01-16 14:29 + */ + +public class DateUtils { + + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + /** + * 获取今天的开始时间(00:00:00) + */ + public static LocalDateTime getTodayStart() { + return LocalDateTime.of(LocalDate.now(), LocalTime.MIN); + } + + /** + * 获取今天的结束时间(23:59:59) + */ + public static LocalDateTime getTodayEnd() { + return LocalDateTime.of(LocalDate.now(), LocalTime.MAX); + } + + /** + * 获取今天的时间范围 + * @return 包含开始时间和结束时间的数组 [startTime, endTime] + */ + public static LocalDateTime[] getTodayRange() { + return new LocalDateTime[]{getTodayStart(), getTodayEnd()}; + } + + /** + * 获取近7天的时间范围(包括今天) + * @return 包含开始时间和结束时间的数组 [startTime, endTime] + */ + public static LocalDateTime[] getLast7DaysRange() { + LocalDateTime end = getTodayEnd(); + LocalDateTime start = getTodayStart().minusDays(6); + return new LocalDateTime[]{start, end}; + } + + /** + * 获取近30天的时间范围(包括今天) + * @return 包含开始时间和结束时间的数组 [startTime, endTime] + */ + public static LocalDateTime[] getLast30DaysRange() { + LocalDateTime end = getTodayEnd(); + LocalDateTime start = getTodayStart().minusDays(29); + return new LocalDateTime[]{start, end}; + } + + /** + * 获取指定天数前的时间范围 + * @param days 天数 + * @return 包含开始时间和结束时间的数组 [startTime, endTime] + */ + public static LocalDateTime[] getLastDaysRange(int days) { + LocalDateTime end = getTodayEnd(); + LocalDateTime start = getTodayStart().minusDays(days - 1); + return new LocalDateTime[]{start, end}; + } + + /** + * 获取本周的时间范围 + * @return 包含开始时间和结束时间的数组 [startTime, endTime] + */ + public static LocalDateTime[] getThisWeekRange() { + LocalDate today = LocalDate.now(); + LocalDate startOfWeek = today.with(java.time.DayOfWeek.MONDAY); + LocalDate endOfWeek = today.with(java.time.DayOfWeek.SUNDAY); + + LocalDateTime start = LocalDateTime.of(startOfWeek, LocalTime.MIN); + LocalDateTime end = LocalDateTime.of(endOfWeek, LocalTime.MAX); + return new LocalDateTime[]{start, end}; + } + + /** + * 获取本月的时间范围 + * @return 包含开始时间和结束时间的数组 [startTime, endTime] + */ + public static LocalDateTime[] getThisMonthRange() { + LocalDate today = LocalDate.now(); + LocalDate startOfMonth = today.withDayOfMonth(1); + LocalDate endOfMonth = today.withDayOfMonth(today.lengthOfMonth()); + + LocalDateTime start = LocalDateTime.of(startOfMonth, LocalTime.MIN); + LocalDateTime end = LocalDateTime.of(endOfMonth, LocalTime.MAX); + return new LocalDateTime[]{start, end}; + } + + /** + * 获取今天日期字符串(yyyy-MM-dd) + */ + public static String getTodayDateString() { + return LocalDate.now().format(DATE_FORMATTER); + } + + /** + * 获取现在日期时间字符串(yyyy-MM-dd HH:mm:ss) + */ + public static String getNowDateTimeString() { + return LocalDateTime.now().format(DATETIME_FORMATTER); + } + + /** + * 获取近7天每天的日期列表(包括今天) + * @return 日期字符串列表,格式:yyyy-MM-dd + */ + public static List getLast7DaysDateList() { + return getDateList(7); + } + + /** + * 获取近30天每天的日期列表(包括今天) + * @return 日期字符串列表,格式:yyyy-MM-dd + */ + public static List getLast30DaysDateList() { + return getDateList(30); + } + + /** + * 获取指定天数的日期列表 + * @param days 天数 + * @return 日期字符串列表,格式:yyyy-MM-dd + */ + public static List getDateList(int days) { + List dateList = new ArrayList<>(); + LocalDate today = LocalDate.now(); + + for (int i = days - 1; i >= 0; i--) { + LocalDate date = today.minusDays(i); + dateList.add(date.format(DATE_FORMATTER)); + } + + return dateList; + } + + /** + * 获取两个日期之间的所有日期列表 + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 日期字符串列表,格式:yyyy-MM-dd + */ + public static List getDateRangeList(LocalDate startDate, LocalDate endDate) { + List dateList = new ArrayList<>(); + long daysBetween = ChronoUnit.DAYS.between(startDate, endDate); + + for (long i = 0; i <= daysBetween; i++) { + LocalDate date = startDate.plusDays(i); + dateList.add(date.format(DATE_FORMATTER)); + } + + return dateList; + } + + /** + * 格式化LocalDateTime为字符串 + * @param dateTime 时间 + * @return 格式化后的字符串 yyyy-MM-dd HH:mm:ss + */ + public static String formatDateTime(LocalDateTime dateTime) { + return dateTime != null ? dateTime.format(DATETIME_FORMATTER) : null; + } + + /** + * 格式化LocalDate为字符串 + * @param date 日期 + * @return 格式化后的字符串 yyyy-MM-dd + */ + public static String formatDate(LocalDate date) { + return date != null ? date.format(DATE_FORMATTER) : null; + } + + /** + * 字符串转LocalDateTime + * @param dateTimeStr 时间字符串 yyyy-MM-dd HH:mm:ss + */ + public static LocalDateTime parseDateTime(String dateTimeStr) { + return LocalDateTime.parse(dateTimeStr, DATETIME_FORMATTER); + } + + /** + * 字符串转LocalDate + * @param dateStr 日期字符串 yyyy-MM-dd + */ + public static LocalDate parseDate(String dateStr) { + return LocalDate.parse(dateStr, DATE_FORMATTER); + } + + /** + * 获取指定日期的开始时间 + * @param date 日期 + * @return 当天的开始时间 + */ + public static LocalDateTime getStartOfDay(LocalDate date) { + return LocalDateTime.of(date, LocalTime.MIN); + } + + /** + * 获取指定日期的结束时间 + * @param date 日期 + * @return 当天的结束时间 + */ + public static LocalDateTime getEndOfDay(LocalDate date) { + return LocalDateTime.of(date, LocalTime.MAX); + } + + /** + * 获取指定日期的前n天 + * @param date 基准日期 + * @param days 天数 + * @return 前n天的日期 + */ + public static LocalDate getDaysBefore(LocalDate date, int days) { + return date.minusDays(days); + } + + /** + * 获取指定日期的后n天 + * @param date 基准日期 + * @param days 天数 + * @return 后n天的日期 + */ + public static LocalDate getDaysAfter(LocalDate date, int days) { + return date.plusDays(days); + } + +} diff --git a/ebike-user/src/main/resources/mapper/EbikeOrderMapper.xml b/ebike-user/src/main/resources/mapper/EbikeOrderMapper.xml index 3defbb2..42c1c1b 100644 --- a/ebike-user/src/main/resources/mapper/EbikeOrderMapper.xml +++ b/ebike-user/src/main/resources/mapper/EbikeOrderMapper.xml @@ -55,4 +55,25 @@ ORDER BY operator_id; + + \ No newline at end of file