From c49686c4116300a6aee8064fcd52c77b8092c802 Mon Sep 17 00:00:00 2001 From: Timi Date: Mon, 3 Aug 2026 19:57:44 +0800 Subject: [PATCH] v0.0.18 --- .../GaoRegistrationEventRecordController.java | 10 +++ .../GaoRegistrationEventRecordMapper.java | 7 ++ .../GaoRegistrationEventRecordService.java | 7 ++ ...gistrationEventRecordServiceImplement.java | 65 ++++++++++++++++++- .../GaoCustomerRegistrationDayStatView.java | 33 ++++++++++ .../vo/GaoCustomerRegistrationRankView.java | 39 +++++++++++ .../GaoRegistrationEventRecordMapper.xml | 48 ++++++++++++++ 7 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerRegistrationDayStatView.java create mode 100644 src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerRegistrationRankView.java diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventRecordController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventRecordController.java index a341448..6cdfc4a 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventRecordController.java +++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventRecordController.java @@ -10,6 +10,7 @@ import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord; import com.imyeyu.api.modules.gao.service.GaoRegistrationEventRecordService; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView; import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationRankView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView; @@ -171,6 +172,15 @@ public class GaoRegistrationEventRecordController { return service.statAllCustomerByRange(req); } + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.STAT_READ) + @PostMapping("/customer/registration-rank") + /// 按时间范围查询客户登记排行榜 + public List customerRegistrationRank(@RequestBody(required = false) GaoRegistrationEventRecordRangeReq req) { + return service.listCustomerRegistrationRank(req); + } + @AOPLog @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.STAT_READ) diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRecordMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRecordMapper.java index 6862342..71c1dc3 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRecordMapper.java +++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRecordMapper.java @@ -3,6 +3,7 @@ package com.imyeyu.api.modules.gao.mapper; import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView; import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationDayStatView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView; @@ -77,6 +78,12 @@ public interface GaoRegistrationEventRecordMapper extends BaseMapper statAllCustomerByRange(@Param("beginRegisteredAt") Long beginRegisteredAt, @Param("endRegisteredAt") Long endRegisteredAt); + /// 按时间范围统计全部客户每日登记 + /// + /// @param req 范围查询请求 + /// @return 每个有登记客户的每日统计 + List statCustomerRegistrationDay(@Param("req") GaoRegistrationEventRecordRangeReq req); + /// 统计单个客户单个登记事件的每日登记事件记录数 /// /// @param customerId 客户 ID diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventRecordService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventRecordService.java index 923683e..6ad2a85 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventRecordService.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventRecordService.java @@ -3,6 +3,7 @@ package com.imyeyu.api.modules.gao.service; import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView; import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationRankView; import com.imyeyu.api.modules.gao.vo.GaoQuickRegistrationEventRecordReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq; @@ -100,6 +101,12 @@ public interface GaoRegistrationEventRecordService extends BaseService statAllCustomerByRange(GaoRegistrationEventRecordStatReq req); + /// 按时间范围查询客户登记排行榜 + /// + /// @param req 范围查询请求,不传时间为全部时间 + /// @return 客户登记排行榜 + List listCustomerRegistrationRank(GaoRegistrationEventRecordRangeReq req); + /// 按时间段统计单个客户单个登记事件每日趋势 /// /// @param req 趋势统计请求 diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventRecordServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventRecordServiceImplement.java index f84af31..0a00508 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventRecordServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventRecordServiceImplement.java @@ -17,6 +17,8 @@ import com.imyeyu.api.modules.gao.service.GaoRegistrationEventService; import com.imyeyu.api.modules.gao.service.GaoRegistrationEventRecordService; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView; import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationDayStatView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationRankView; import com.imyeyu.api.modules.gao.vo.GaoQuickRegistrationEventRecordReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq; @@ -62,6 +64,7 @@ import java.time.temporal.ChronoUnit; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -80,7 +83,7 @@ import java.util.stream.Collectors; @RequiredArgsConstructor public class GaoRegistrationEventRecordServiceImplement extends AbstractEntityService implements GaoRegistrationEventRecordService { - private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd"); + private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.BASIC_ISO_DATE; private static final DateTimeFormatter EXPORT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()); private final GaoRegistrationEventRecordMapper mapper; @@ -379,6 +382,29 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe return mapper.statAllCustomerByRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt()); } + @Override + public List listCustomerRegistrationRank(GaoRegistrationEventRecordRangeReq req) { + GaoRegistrationEventRecordRangeReq rangeReq = TimiJava.defaultIfNull(req, new GaoRegistrationEventRecordRangeReq()); + if (rangeReq.getBeginRegisteredAt() != null || rangeReq.getEndRegisteredAt() != null) { + checkStatRange(rangeReq.getBeginRegisteredAt(), rangeReq.getEndRegisteredAt()); + } + List dayStatList = mapper.statCustomerRegistrationDay(rangeReq); + Map> customerDayStatMap = dayStatList.stream() + .collect(Collectors.groupingBy(GaoCustomerRegistrationDayStatView::getCustomerId)); + List rankList = new ArrayList<>(); + for (Map.Entry> entry : customerDayStatMap.entrySet()) { + rankList.add(buildCustomerRegistrationRank(entry.getValue())); + } + rankList.sort(Comparator + .comparing(GaoCustomerRegistrationRankView::getTotalRegistrationDays, Comparator.nullsLast(Comparator.reverseOrder())) + .thenComparing(GaoCustomerRegistrationRankView::getTotalRegistrationCount, Comparator.nullsLast(Comparator.reverseOrder())) + .thenComparing(GaoCustomerRegistrationRankView::getLatestRegisteredAt, Comparator.nullsLast(Comparator.reverseOrder()))); + for (int index = 0; index < rankList.size(); index++) { + rankList.get(index).setRank(index + 1); + } + return rankList; + } + @Override public List statDailyByCustomerAndRegistrationEvent(GaoRegistrationEventRecordTrendStatReq req) { TimiException.required(req, "not found req"); @@ -555,6 +581,43 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe return list; } + private GaoCustomerRegistrationRankView buildCustomerRegistrationRank(List dayStatList) { + List sortedDayStatList = dayStatList.stream() + .sorted(Comparator.comparing(GaoCustomerRegistrationDayStatView::getDateValue, Comparator.nullsLast(Comparator.reverseOrder()))) + .toList(); + GaoCustomerRegistrationDayStatView first = sortedDayStatList.get(0); + GaoCustomerRegistrationRankView view = new GaoCustomerRegistrationRankView(); + view.setCustomerId(first.getCustomerId()); + view.setCustomerCode(first.getCustomerCode()); + view.setCustomerName(first.getCustomerName()); + view.setCustomerPhotoAttachmentId(first.getCustomerPhotoAttachmentId()); + view.setTotalRegistrationDays((long) sortedDayStatList.size()); + view.setTotalRegistrationCount(sortedDayStatList.stream().mapToLong(item -> TimiJava.defaultIfNull(item.getDailyCount(), 0L)).sum()); + view.setLatestRegisteredAt(sortedDayStatList.stream().map(GaoCustomerRegistrationDayStatView::getLatestRegisteredAt).filter(Objects::nonNull).max(Long::compareTo).orElse(null)); + view.setRecentContinuousRegistrationDays(countRecentContinuousRegistrationDays(sortedDayStatList)); + return view; + } + + private long countRecentContinuousRegistrationDays(List sortedDayStatList) { + if (sortedDayStatList.isEmpty() || sortedDayStatList.get(0).getDateValue() == null) { + return 0; + } + LocalDate expectedDate = LocalDate.parse(String.valueOf(sortedDayStatList.get(0).getDateValue()), DAY_FORMATTER); + long count = 0; + for (GaoCustomerRegistrationDayStatView item : sortedDayStatList) { + if (item.getDateValue() == null) { + continue; + } + LocalDate date = LocalDate.parse(String.valueOf(item.getDateValue()), DAY_FORMATTER); + if (!date.equals(expectedDate)) { + break; + } + count++; + expectedDate = expectedDate.minusDays(1); + } + return count; + } + private void loadTransient(List recordList) { if (recordList == null || recordList.isEmpty()) { return; diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerRegistrationDayStatView.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerRegistrationDayStatView.java new file mode 100644 index 0000000..902977c --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerRegistrationDayStatView.java @@ -0,0 +1,33 @@ +package com.imyeyu.api.modules.gao.vo; + +import lombok.Data; + +/// +/// 客户登记日期统计视图 +/// +/// @author Codex +/// @since 2026-08-03 +@Data +public class GaoCustomerRegistrationDayStatView { + + /// 客户 ID + private String customerId; + + /// 客户编码 + private String customerCode; + + /// 客户姓名 + private String customerName; + + /// 客户头像附件 ID + private String customerPhotoAttachmentId; + + /// 登记日期,格式 yyyyMMdd + private Integer dateValue; + + /// 当日登记次数 + private Long dailyCount; + + /// 当日最后登记时间 + private Long latestRegisteredAt; +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerRegistrationRankView.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerRegistrationRankView.java new file mode 100644 index 0000000..ee9fb11 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerRegistrationRankView.java @@ -0,0 +1,39 @@ +package com.imyeyu.api.modules.gao.vo; + +import lombok.Data; + +/// +/// 客户登记排行榜视图 +/// +/// @author Codex +/// @since 2026-08-03 +@Data +public class GaoCustomerRegistrationRankView { + + /// 排名 + private Integer rank; + + /// 客户 ID + private String customerId; + + /// 客户编码 + private String customerCode; + + /// 客户姓名 + private String customerName; + + /// 客户头像附件 ID + private String customerPhotoAttachmentId; + + /// 累计登记天数 + private Long totalRegistrationDays; + + /// 累计登记次数 + private Long totalRegistrationCount; + + /// 最近连续登记天数 + private Long recentContinuousRegistrationDays; + + /// 最后登记时间 + private Long latestRegisteredAt; +} diff --git a/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml b/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml index 6160ed8..12e0902 100644 --- a/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml +++ b/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml @@ -143,6 +143,54 @@ ORDER BY `latestRegisteredAt` DESC + +