diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerChartController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerChartController.java new file mode 100644 index 0000000..3bec34d --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerChartController.java @@ -0,0 +1,47 @@ +package com.imyeyu.api.modules.gao.controller; + +import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission; +import com.imyeyu.api.modules.gao.bean.GaoPermissionCode; +import com.imyeyu.api.modules.gao.service.GaoCustomerChartService; +import com.imyeyu.api.modules.gao.vo.GaoCustomerChartReq; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordCalendarView; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordDailyStatView; +import com.imyeyu.spring.annotation.AOPLog; +import com.imyeyu.spring.annotation.RequestRateLimit; +import lombok.RequiredArgsConstructor; +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; + +import java.util.List; + +/// GAO 客户报表接口 +/// +/// @author Codex +/// @since 2026-08-11 +@RestController +@RequiredArgsConstructor +@RequestMapping("/gao/customer/chart") +public class GaoCustomerChartController { + + private final GaoCustomerChartService service; + + /// 查询客户登记每日统计,可同时支撑登记趋势和登记事件结构图表 + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.STAT_READ) + @PostMapping("/event/record/daily") + public List eventRecordDaily(@RequestBody GaoCustomerChartReq req) { + return service.eventRecordDailyStat(req); + } + + /// 查询客户登记日历记录 + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.STAT_READ) + @PostMapping("/event/record/calendar") + public List eventRecordCalendar(@RequestBody GaoCustomerChartReq req) { + return service.eventRecordCalendar(req); + } +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreChartController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreChartController.java new file mode 100644 index 0000000..88a004e --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoStoreChartController.java @@ -0,0 +1,68 @@ +package com.imyeyu.api.modules.gao.controller; + +import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission; +import com.imyeyu.api.modules.gao.bean.GaoPermissionCode; +import com.imyeyu.api.modules.gao.service.GaoStoreChartService; +import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStateView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordCalendarView; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoStoreChartReq; +import com.imyeyu.spring.annotation.AOPLog; +import com.imyeyu.spring.annotation.RequestRateLimit; +import lombok.RequiredArgsConstructor; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/// GAO 门店报表接口 +/// +/// @author Codex +/// @since 2026-08-11 +@RestController +@RequiredArgsConstructor +@RequestMapping("/gao/store/chart") +public class GaoStoreChartController { + + private final GaoStoreChartService service; + + /// 查询客户增长趋势 + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.STAT_READ) + @PostMapping("/customer/daily") + public List customerDaily(@RequestBody GaoStoreChartReq req) { + return service.customerDailyTrend(req); + } + + /// 查询客户性别统计 + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.STAT_READ) + @PostMapping("/customer/gender") + public List customerGender(@RequestParam String storeId) { + return service.customerGender(storeId); + } + + /// 查询登记事件每日统计,可同时支撑登记趋势和事件结构图表 + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.STAT_READ) + @PostMapping("/event/record/daily") + public List eventRecordDaily(@RequestBody GaoStoreChartReq req) { + return service.eventRecordDailyStat(req); + } + + /// 查询登记事件日历记录 + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.STAT_READ) + @PostMapping("/event/record/calendar") + public List eventRecordCalendar(@RequestBody GaoStoreChartReq req) { + return service.eventRecordCalendar(req); + } +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoEventRecordMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoEventRecordMapper.java index f5ac28f..cbd2f00 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoEventRecordMapper.java +++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoEventRecordMapper.java @@ -1,9 +1,13 @@ package com.imyeyu.api.modules.gao.mapper; import com.imyeyu.api.modules.gao.entity.GaoEventRecord; +import com.imyeyu.api.modules.gao.vo.GaoCustomerChartReq; import com.imyeyu.api.modules.gao.vo.GaoCustomerEventRankView; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordCalendarView; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordDailyStatView; import com.imyeyu.api.modules.gao.vo.GaoEventRecordPage; import com.imyeyu.api.modules.gao.vo.GaoEventRecordRankPage; +import com.imyeyu.api.modules.gao.vo.GaoStoreChartReq; import com.imyeyu.spring.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; @@ -49,4 +53,28 @@ public interface GaoEventRecordMapper extends BaseMapper /// @param page 排行榜分页请求 /// @return 客户登记排行榜 List selectRankByRange(GaoEventRecordRankPage page); + + /// 按时间范围和事件批量统计每日登记数 + /// + /// @param req 门店报表查询请求 + /// @return 每日登记数 + List stateDailyByRange(GaoStoreChartReq req); + + /// 按时间范围查询登记日历记录 + /// + /// @param req 门店报表查询请求 + /// @return 日历记录列表 + List selectCalendarByRange(GaoStoreChartReq req); + + /// 按客户、时间范围和事件批量统计每日登记数 + /// + /// @param req 客户报表查询请求 + /// @return 每日登记数 + List stateCustomerDailyByRange(GaoCustomerChartReq req); + + /// 按客户和时间范围查询登记日历记录 + /// + /// @param req 客户报表查询请求 + /// @return 日历记录列表 + List selectCustomerCalendarByRange(GaoCustomerChartReq req); } diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerChartService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerChartService.java new file mode 100644 index 0000000..252a50f --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerChartService.java @@ -0,0 +1,20 @@ +package com.imyeyu.api.modules.gao.service; + +import com.imyeyu.api.modules.gao.vo.GaoCustomerChartReq; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordCalendarView; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordDailyStatView; + +import java.util.List; + +/// 客户报表服务 +/// +/// @author Codex +/// @since 2026-08-11 +public interface GaoCustomerChartService { + + /// 查询客户登记每日统计 + List eventRecordDailyStat(GaoCustomerChartReq req); + + /// 查询客户登记日历记录 + List eventRecordCalendar(GaoCustomerChartReq req); +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/GaoStoreChartService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoStoreChartService.java new file mode 100644 index 0000000..da556d5 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoStoreChartService.java @@ -0,0 +1,28 @@ +package com.imyeyu.api.modules.gao.service; + +import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStateView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordCalendarView; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoStoreChartReq; + +import java.util.List; + +/// 门店报表服务 +/// +/// @author Codex +/// @since 2026-08-11 +public interface GaoStoreChartService { + + /// 查询客户每日趋势 + List customerDailyTrend(GaoStoreChartReq req); + + /// 查询客户性别统计 + List customerGender(String storeId); + + /// 查询登记事件每日统计 + List eventRecordDailyStat(GaoStoreChartReq req); + + /// 查询登记事件日历记录 + List eventRecordCalendar(GaoStoreChartReq req); +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerChartServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerChartServiceImplement.java new file mode 100644 index 0000000..e2e1d32 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerChartServiceImplement.java @@ -0,0 +1,44 @@ +package com.imyeyu.api.modules.gao.service.implement; + +import com.imyeyu.api.modules.gao.mapper.GaoEventRecordMapper; +import com.imyeyu.api.modules.gao.service.GaoCustomerChartService; +import com.imyeyu.api.modules.gao.vo.GaoCustomerChartReq; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordCalendarView; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordDailyStatView; +import com.imyeyu.java.bean.timi.TimiException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +/// 客户报表服务实现 +/// +/// @author Codex +/// @since 2026-08-11 +@Service +@RequiredArgsConstructor +public class GaoCustomerChartServiceImplement implements GaoCustomerChartService { + + private final GaoEventRecordMapper eventRecordMapper; + + @Override + public List eventRecordDailyStat(GaoCustomerChartReq req) { + checkRangeReq(req); + return eventRecordMapper.stateCustomerDailyByRange(req); + } + + @Override + public List eventRecordCalendar(GaoCustomerChartReq req) { + checkRangeReq(req); + return eventRecordMapper.selectCustomerCalendarByRange(req); + } + + private void checkRangeReq(GaoCustomerChartReq req) { + TimiException.required(req, "not found req"); + TimiException.required(req.getStoreId(), "not found req.storeId"); + TimiException.required(req.getCustomerId(), "not found req.customerId"); + TimiException.required(req.getBeginAt(), "not found req.beginAt"); + TimiException.required(req.getEndAt(), "not found req.endAt"); + TimiException.requiredTrue(req.getBeginAt() <= req.getEndAt(), "req.endAt lt req.beginAt"); + } +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoStoreChartServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoStoreChartServiceImplement.java new file mode 100644 index 0000000..00f02ff --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoStoreChartServiceImplement.java @@ -0,0 +1,64 @@ +package com.imyeyu.api.modules.gao.service.implement; + +import com.imyeyu.api.modules.gao.mapper.GaoEventRecordMapper; +import com.imyeyu.api.modules.gao.service.GaoCustomerService; +import com.imyeyu.api.modules.gao.service.GaoStoreChartService; +import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStateView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStateReq; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordCalendarView; +import com.imyeyu.api.modules.gao.vo.GaoEventRecordDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoStoreChartReq; +import com.imyeyu.java.bean.timi.TimiException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +/// 门店报表服务实现 +/// +/// @author Codex +/// @since 2026-08-11 +@Service +@RequiredArgsConstructor +public class GaoStoreChartServiceImplement implements GaoStoreChartService { + + private final GaoCustomerService customerService; + private final GaoEventRecordMapper eventRecordMapper; + + @Override + public List customerDailyTrend(GaoStoreChartReq req) { + checkRangeReq(req); + GaoCustomerTrendStateReq statReq = new GaoCustomerTrendStateReq(); + statReq.setStoreId(req.getStoreId()); + statReq.setBeginCreatedAt(req.getBeginAt()); + statReq.setEndCreatedAt(req.getEndAt()); + return customerService.stateDailyTrend(statReq); + } + + @Override + public List customerGender(String storeId) { + TimiException.required(storeId, "not found storeId"); + return customerService.stateGender(storeId); + } + + @Override + public List eventRecordDailyStat(GaoStoreChartReq req) { + checkRangeReq(req); + return eventRecordMapper.stateDailyByRange(req); + } + + @Override + public List eventRecordCalendar(GaoStoreChartReq req) { + checkRangeReq(req); + return eventRecordMapper.selectCalendarByRange(req); + } + + private void checkRangeReq(GaoStoreChartReq req) { + TimiException.required(req, "not found req"); + TimiException.required(req.getStoreId(), "not found req.storeId"); + TimiException.required(req.getBeginAt(), "not found req.beginAt"); + TimiException.required(req.getEndAt(), "not found req.endAt"); + TimiException.requiredTrue(req.getBeginAt() <= req.getEndAt(), "req.endAt lt req.beginAt"); + } +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerChartReq.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerChartReq.java new file mode 100644 index 0000000..8b0c6ad --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerChartReq.java @@ -0,0 +1,28 @@ +package com.imyeyu.api.modules.gao.vo; + +import lombok.Data; + +import java.util.List; + +/// 客户报表查询请求 +/// +/// @author Codex +/// @since 2026-08-11 +@Data +public class GaoCustomerChartReq { + + /// 门店 ID + private String storeId; + + /// 客户 ID + private String customerId; + + /// 开始时间 + private Long beginAt; + + /// 结束时间 + private Long endAt; + + /// 登记事件 ID 列表 + private List eventIdList; +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoEventRecordCalendarView.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoEventRecordCalendarView.java new file mode 100644 index 0000000..5a9722d --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoEventRecordCalendarView.java @@ -0,0 +1,29 @@ +package com.imyeyu.api.modules.gao.vo; + +import lombok.Data; + +/// 登记事件日历记录视图 +/// +/// @author Codex +/// @since 2026-08-11 +@Data +public class GaoEventRecordCalendarView { + + /// 登记记录 ID + private String id; + + /// 客户 ID + private String customerId; + + /// 客户编码 + private String customerCode; + + /// 客户姓名 + private String customerName; + + /// 登记事件 ID + private String eventId; + + /// 登记时间 + private Long registeredAt; +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoEventRecordDailyStatView.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoEventRecordDailyStatView.java new file mode 100644 index 0000000..039a326 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoEventRecordDailyStatView.java @@ -0,0 +1,20 @@ +package com.imyeyu.api.modules.gao.vo; + +import lombok.Data; + +/// 登记事件每日统计视图 +/// +/// @author Codex +/// @since 2026-08-11 +@Data +public class GaoEventRecordDailyStatView { + + /// 登记事件 ID + private String eventId; + + /// 日期值,格式为 yyyyMMdd + private Integer dateValue; + + /// 当日登记数 + private Long dailyCount; +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoStoreChartReq.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoStoreChartReq.java new file mode 100644 index 0000000..f3c343a --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoStoreChartReq.java @@ -0,0 +1,25 @@ +package com.imyeyu.api.modules.gao.vo; + +import lombok.Data; + +import java.util.List; + +/// 门店报表查询请求 +/// +/// @author Codex +/// @since 2026-08-11 +@Data +public class GaoStoreChartReq { + + /// 门店 ID + private String storeId; + + /// 开始时间 + private Long beginAt; + + /// 结束时间 + private Long endAt; + + /// 登记事件 ID 列表 + private List eventIdList; +} diff --git a/src/main/resources/mapper/timi-server/GaoEventRecordMapper.xml b/src/main/resources/mapper/timi-server/GaoEventRecordMapper.xml index 2a05053..796b272 100644 --- a/src/main/resources/mapper/timi-server/GaoEventRecordMapper.xml +++ b/src/main/resources/mapper/timi-server/GaoEventRecordMapper.xml @@ -203,4 +203,93 @@ ORDER BY `rank` LIMIT #{offset}, #{limit} + + + r.`store_id` = #{storeId} + AND r.`registered_at` >= #{beginAt} + AND r.`registered_at` <= #{endAt} + AND r.`deleted_at` IS NULL + + AND r.`event_id` IN + + #{eventId} + + + + + + + + r.`store_id` = #{storeId} + AND r.`customer_id` = #{customerId} + AND r.`registered_at` >= #{beginAt} + AND r.`registered_at` <= #{endAt} + AND r.`deleted_at` IS NULL + + AND r.`event_id` IN + + #{eventId} + + + + +