v0.0.18
This commit is contained in:
+10
@@ -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<GaoCustomerRegistrationRankView> customerRegistrationRank(@RequestBody(required = false) GaoRegistrationEventRecordRangeReq req) {
|
||||
return service.listCustomerRegistrationRank(req);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.STAT_READ)
|
||||
|
||||
@@ -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<GaoRegistra
|
||||
/// @return 统计结果
|
||||
List<GaoCustomerRegisterStatView> statAllCustomerByRange(@Param("beginRegisteredAt") Long beginRegisteredAt, @Param("endRegisteredAt") Long endRegisteredAt);
|
||||
|
||||
/// 按时间范围统计全部客户每日登记
|
||||
///
|
||||
/// @param req 范围查询请求
|
||||
/// @return 每个有登记客户的每日统计
|
||||
List<GaoCustomerRegistrationDayStatView> statCustomerRegistrationDay(@Param("req") GaoRegistrationEventRecordRangeReq req);
|
||||
|
||||
/// 统计单个客户单个登记事件的每日登记事件记录数
|
||||
///
|
||||
/// @param customerId 客户 ID
|
||||
|
||||
+7
@@ -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<GaoRegist
|
||||
/// @return 统计结果
|
||||
List<GaoCustomerRegisterStatView> statAllCustomerByRange(GaoRegistrationEventRecordStatReq req);
|
||||
|
||||
/// 按时间范围查询客户登记排行榜
|
||||
///
|
||||
/// @param req 范围查询请求,不传时间为全部时间
|
||||
/// @return 客户登记排行榜
|
||||
List<GaoCustomerRegistrationRankView> listCustomerRegistrationRank(GaoRegistrationEventRecordRangeReq req);
|
||||
|
||||
/// 按时间段统计单个客户单个登记事件每日趋势
|
||||
///
|
||||
/// @param req 趋势统计请求
|
||||
|
||||
+64
-1
@@ -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<GaoRegistrationEventRecord, String> 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<GaoCustomerRegistrationRankView> listCustomerRegistrationRank(GaoRegistrationEventRecordRangeReq req) {
|
||||
GaoRegistrationEventRecordRangeReq rangeReq = TimiJava.defaultIfNull(req, new GaoRegistrationEventRecordRangeReq());
|
||||
if (rangeReq.getBeginRegisteredAt() != null || rangeReq.getEndRegisteredAt() != null) {
|
||||
checkStatRange(rangeReq.getBeginRegisteredAt(), rangeReq.getEndRegisteredAt());
|
||||
}
|
||||
List<GaoCustomerRegistrationDayStatView> dayStatList = mapper.statCustomerRegistrationDay(rangeReq);
|
||||
Map<String, List<GaoCustomerRegistrationDayStatView>> customerDayStatMap = dayStatList.stream()
|
||||
.collect(Collectors.groupingBy(GaoCustomerRegistrationDayStatView::getCustomerId));
|
||||
List<GaoCustomerRegistrationRankView> rankList = new ArrayList<>();
|
||||
for (Map.Entry<String, List<GaoCustomerRegistrationDayStatView>> 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<GaoRegistrationEventRecordDailyStatView> statDailyByCustomerAndRegistrationEvent(GaoRegistrationEventRecordTrendStatReq req) {
|
||||
TimiException.required(req, "not found req");
|
||||
@@ -555,6 +581,43 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
||||
return list;
|
||||
}
|
||||
|
||||
private GaoCustomerRegistrationRankView buildCustomerRegistrationRank(List<GaoCustomerRegistrationDayStatView> dayStatList) {
|
||||
List<GaoCustomerRegistrationDayStatView> 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<GaoCustomerRegistrationDayStatView> 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<GaoRegistrationEventRecord> recordList) {
|
||||
if (recordList == null || recordList.isEmpty()) {
|
||||
return;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -143,6 +143,54 @@
|
||||
ORDER BY `latestRegisteredAt` DESC
|
||||
</select>
|
||||
|
||||
<select id="statCustomerRegistrationDay" resultType="com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationDayStatView">
|
||||
SELECT
|
||||
r.`customer_id` AS `customerId`,
|
||||
c.`code` AS `customerCode`,
|
||||
c.`name` AS `customerName`,
|
||||
(
|
||||
SELECT a.`id`
|
||||
FROM `attachment` a
|
||||
WHERE
|
||||
a.`biz_type` = 'GAO_CUSTOMER'
|
||||
AND a.`biz_id` = c.`id`
|
||||
AND a.`attach_type` = 'PHOTO'
|
||||
AND a.`deleted_at` IS NULL
|
||||
AND (a.`destroy_at` IS NULL OR UNIX_TIMESTAMP() < a.`destroy_at`)
|
||||
ORDER BY a.`created_at` ASC
|
||||
LIMIT 1
|
||||
) AS `customerPhotoAttachmentId`,
|
||||
CAST(DATE_FORMAT(FROM_UNIXTIME(r.`registered_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
|
||||
COUNT(1) AS `dailyCount`,
|
||||
MAX(r.`registered_at`) AS `latestRegisteredAt`
|
||||
FROM `gao_registration_event_record` r
|
||||
LEFT JOIN `gao_customer` c ON r.`customer_id` = c.`id`
|
||||
WHERE
|
||||
r.`deleted_at` IS NULL
|
||||
AND c.`deleted_at` IS NULL
|
||||
<if test="req.beginRegisteredAt != null">
|
||||
AND r.`registered_at` >= #{req.beginRegisteredAt}
|
||||
</if>
|
||||
<if test="req.endRegisteredAt != null">
|
||||
AND r.`registered_at` <= #{req.endRegisteredAt}
|
||||
</if>
|
||||
<if test="req.registrationEventId != null and req.registrationEventId != ''">
|
||||
AND r.`registration_event_id` = #{req.registrationEventId}
|
||||
</if>
|
||||
<if test="req.registrationEventIdList != null and req.registrationEventIdList.size() > 0">
|
||||
AND r.`registration_event_id` IN
|
||||
<foreach collection="req.registrationEventIdList" item="registrationEventId" open="(" separator="," close=")">
|
||||
#{registrationEventId}
|
||||
</foreach>
|
||||
</if>
|
||||
GROUP BY
|
||||
r.`customer_id`,
|
||||
c.`code`,
|
||||
c.`name`,
|
||||
DATE_FORMAT(FROM_UNIXTIME(r.`registered_at` / 1000), '%Y%m%d')
|
||||
ORDER BY r.`customer_id` ASC, `dateValue` DESC
|
||||
</select>
|
||||
|
||||
<select id="statDailyCountByCustomerIdAndRegistrationEventIdRange" resultType="com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView">
|
||||
SELECT
|
||||
CAST(DATE_FORMAT(FROM_UNIXTIME(`registered_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
|
||||
|
||||
Reference in New Issue
Block a user