From 833a303bb6615e9d6d252dd4f33d3fd3bd99eb5c Mon Sep 17 00:00:00 2001 From: Timi Date: Sat, 1 Aug 2026 16:51:53 +0800 Subject: [PATCH] v1.0.5 --- .../common/mapper/AttachmentMapper.java | 3 + .../common/service/AttachmentService.java | 11 ++ .../implement/AttachmentServiceImplement.java | 18 +++ .../gao/controller/GaoCustomerController.java | 22 ++++ .../GaoRegistrationEventRecordController.java | 19 ++- .../gao/controller/GaoUserController.java | 7 ++ .../api/modules/gao/entity/GaoCustomer.java | 1 - .../modules/gao/mapper/GaoCustomerMapper.java | 10 ++ .../mapper/GaoRegistrationEventMapper.java | 3 + .../GaoRegistrationEventRecordMapper.java | 10 +- ...aoRegistrationEventRoleRelationMapper.java | 13 ++ .../gao/service/GaoCustomerService.java | 6 + .../GaoRegistrationEventRecordService.java | 10 +- .../GaoCustomerServiceImplement.java | 119 +++++++++++++++--- ...gistrationEventRecordServiceImplement.java | 83 +++++++++--- .../GaoRegistrationEventServiceImplement.java | 27 +++- .../gao/vo/GaoCustomerGenderStatView.java | 18 +++ ...aoRegistrationEventRecordCalendarView.java | 30 +++++ ...aoRegistrationEventRecordListItemView.java | 33 +++++ .../V19__add_gao_customer_invited_count.sql | 12 ++ .../mapper/timi-server/AttachmentMapper.xml | 29 +++++ .../mapper/timi-server/GaoCustomerMapper.xml | 32 +++++ .../GaoRegistrationEventMapper.xml | 21 ++++ .../GaoRegistrationEventRecordMapper.xml | 35 +++++- 24 files changed, 530 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerGenderStatView.java create mode 100644 src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordCalendarView.java create mode 100644 src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordListItemView.java create mode 100644 src/main/resources/db/migration/timiserver/V19__add_gao_customer_invited_count.sql create mode 100644 src/main/resources/mapper/timi-server/AttachmentMapper.xml create mode 100644 src/main/resources/mapper/timi-server/GaoRegistrationEventMapper.xml diff --git a/src/main/java/com/imyeyu/api/modules/common/mapper/AttachmentMapper.java b/src/main/java/com/imyeyu/api/modules/common/mapper/AttachmentMapper.java index 8c4a12a..60e7d61 100644 --- a/src/main/java/com/imyeyu/api/modules/common/mapper/AttachmentMapper.java +++ b/src/main/java/com/imyeyu/api/modules/common/mapper/AttachmentMapper.java @@ -4,6 +4,7 @@ import com.imyeyu.api.modules.common.entity.Attachment; import com.imyeyu.spring.bean.Page; import com.imyeyu.spring.mapper.BaseMapper; import com.imyeyu.spring.mapper.RawMapper; +import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; @@ -31,6 +32,8 @@ public interface AttachmentMapper extends BaseMapper, RawMap List selectByBizId(Attachment.BizType bizType, String bizId, List attachTypes, Page page); + List selectByBizIdList(@Param("bizType") Attachment.BizType bizType, @Param("bizIdList") List bizIdList, @Param("attachTypes") List attachTypes); + long countByBizId(Attachment.BizType bizType, String bizId, List attachTypes); /** diff --git a/src/main/java/com/imyeyu/api/modules/common/service/AttachmentService.java b/src/main/java/com/imyeyu/api/modules/common/service/AttachmentService.java index aa0e137..ddd367c 100644 --- a/src/main/java/com/imyeyu/api/modules/common/service/AttachmentService.java +++ b/src/main/java/com/imyeyu/api/modules/common/service/AttachmentService.java @@ -9,6 +9,7 @@ import com.imyeyu.spring.service.BaseService; import java.io.InputStream; import java.util.List; +import java.util.Map; /** * 附件服务 @@ -50,6 +51,16 @@ public interface AttachmentService extends BaseService { */ List listByBizId(Attachment.BizType bizType, String bizId, String... attachTypes); + /** + * 根据多个业务 ID 批量获取附件。 + * + * @param bizType 业务类型 + * @param bizIdList 业务 ID 列表 + * @param attachTypes 附件类型,可为 null + * @return 按业务 ID 分组的附件列表 + */ + Map> mapByBizIdList(Attachment.BizType bizType, List bizIdList, String... attachTypes); + /** * 根据业务获取所有附件 * diff --git a/src/main/java/com/imyeyu/api/modules/common/service/implement/AttachmentServiceImplement.java b/src/main/java/com/imyeyu/api/modules/common/service/implement/AttachmentServiceImplement.java index 0abacf8..4346370 100644 --- a/src/main/java/com/imyeyu/api/modules/common/service/implement/AttachmentServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/common/service/implement/AttachmentServiceImplement.java @@ -43,7 +43,9 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -310,6 +312,22 @@ public class AttachmentServiceImplement extends AbstractEntityService> mapByBizIdList(Attachment.BizType bizType, List bizIdList, String... attachTypes) { + if (bizIdList == null || bizIdList.isEmpty()) { + return Map.of(); + } + List normalizedBizIdList = bizIdList.stream() + .filter(TimiJava::isNotEmpty) + .distinct() + .toList(); + if (normalizedBizIdList.isEmpty()) { + return Map.of(); + } + return mapper.selectByBizIdList(bizType, new ArrayList<>(normalizedBizIdList), List.of(attachTypes)).stream() + .collect(Collectors.groupingBy(Attachment::getBizId)); + } + @Override public long countByBizId(Attachment.BizType bizType, String bizId, String... attachTypes) { return mapper.countByBizId(bizType, bizId, List.of(attachTypes)); diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerController.java index f3e3bf6..cdf5038 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerController.java +++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerController.java @@ -1,5 +1,6 @@ package com.imyeyu.api.modules.gao.controller; +import com.fasterxml.jackson.annotation.JsonView; import com.imyeyu.api.modules.gao.bean.GaoPermissionCode; import com.imyeyu.api.modules.gao.bean.GaoRoleCode; import com.imyeyu.api.bean.RoleMatchMode; @@ -12,6 +13,7 @@ import com.imyeyu.api.modules.gao.service.GaoRegistrationEventService; import com.imyeyu.api.modules.gao.service.GaoCustomerService; import com.imyeyu.api.modules.gao.service.GaoRegistrationEventRecordService; import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView; import com.imyeyu.api.modules.gao.vo.GaoCustomerInviteUpdateReq; import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq; import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq; @@ -21,6 +23,7 @@ import com.imyeyu.spring.annotation.IgnoreGlobalReturn; import com.imyeyu.spring.annotation.RequestRateLimit; import com.imyeyu.spring.bean.Page; import com.imyeyu.spring.bean.PageResult; +import com.imyeyu.spring.util.ResponseView; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; @@ -57,6 +60,7 @@ public class GaoCustomerController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) @PostMapping("/list") + @JsonView(ResponseView.Public.class) public PageResult list(@RequestBody Page page) { PageResult result = service.page(page); fillLastSignInAt(result.getList()); @@ -67,6 +71,7 @@ public class GaoCustomerController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) @PostMapping("/search") + @JsonView(ResponseView.Public.class) public List search(@RequestBody GaoCustomerSearchReq req) { return service.search(req); } @@ -75,6 +80,7 @@ public class GaoCustomerController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) @PostMapping("/search/page") + @JsonView(ResponseView.Public.class) public PageResult searchPage(@RequestBody Page page) { return service.searchPage(page); } @@ -95,6 +101,7 @@ public class GaoCustomerController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) @PostMapping("/detail") + @JsonView(ResponseView.Public.class) public GaoCustomer detail(@RequestParam String id) { return service.get(id); } @@ -103,6 +110,7 @@ public class GaoCustomerController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) @PostMapping("/detail/code") + @JsonView(ResponseView.Public.class) public GaoCustomer detailByCode(@RequestParam String code) { return service.getByCode(code); } @@ -111,6 +119,7 @@ public class GaoCustomerController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) @PostMapping("/detail/code/nullable") + @JsonView(ResponseView.Public.class) public GaoCustomer nullableDetailByCode(@RequestParam String code) { return service.getNullableByCode(code); } @@ -119,6 +128,7 @@ public class GaoCustomerController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) @PostMapping("/invited/list") + @JsonView(ResponseView.Public.class) public List invitedList(@RequestParam String introducerCustomerId) { return service.listInvited(introducerCustomerId); } @@ -127,6 +137,7 @@ public class GaoCustomerController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_CREATE) @PostMapping("/create") + @JsonView(ResponseView.Public.class) public GaoCustomer create(@RequestBody GaoCustomer customer) { service.create(customer); return customer; @@ -135,6 +146,7 @@ public class GaoCustomerController { @AOPLog @RequestRateLimit @PostMapping("/quick/register") + @JsonView(ResponseView.Public.class) public GaoRegistrationEventRecord quickRegister(@RequestBody GaoQuickRegistrationEventRecordReq req) { return registrationEventRecordService.quickRegister(req); } @@ -167,6 +179,7 @@ public class GaoCustomerController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) @PostMapping("/invite/detail") + @JsonView(ResponseView.Public.class) public GaoCustomer inviteDetail(@RequestParam String customerId) { return service.get(customerId); } @@ -196,6 +209,15 @@ public class GaoCustomerController { return service.statDailyTrend(req); } + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) + @PostMapping("/stat/gender") + /// 统计客户性别分布 + public List genderStat() { + return service.statGender(); + } + private void fillLastSignInAt(List customerList) { if (customerList == null || customerList.isEmpty()) { return; 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 e01922d..4f8a3f8 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 @@ -1,5 +1,6 @@ package com.imyeyu.api.modules.gao.controller; +import com.fasterxml.jackson.annotation.JsonView; import com.imyeyu.api.modules.gao.bean.GaoPermissionCode; import com.imyeyu.api.modules.gao.bean.GaoRoleCode; import com.imyeyu.api.bean.RoleMatchMode; @@ -10,7 +11,9 @@ 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.GaoRegistrationEventRecordCreateReq; +import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordStatReq; @@ -20,6 +23,7 @@ import com.imyeyu.spring.annotation.IgnoreGlobalReturn; import com.imyeyu.spring.annotation.RequestRateLimit; import com.imyeyu.spring.bean.Page; import com.imyeyu.spring.bean.PageResult; +import com.imyeyu.spring.util.ResponseView; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; @@ -49,6 +53,7 @@ public class GaoRegistrationEventRecordController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ) @PostMapping("/list") + @JsonView(ResponseView.Public.class) public PageResult list(@RequestBody Page page) { return service.page(page); } @@ -57,7 +62,7 @@ public class GaoRegistrationEventRecordController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ) @PostMapping("/range/page") - public PageResult rangePage(@RequestBody Page page) { + public PageResult rangePage(@RequestBody Page page) { return service.pageByRange(page); } @@ -65,6 +70,7 @@ public class GaoRegistrationEventRecordController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ) @PostMapping("/detail") + @JsonView(ResponseView.Public.class) public GaoRegistrationEventRecord detail(@RequestParam String id) { return service.get(id); } @@ -72,6 +78,7 @@ public class GaoRegistrationEventRecordController { @AOPLog @RequestRateLimit @PostMapping("/create") + @JsonView(ResponseView.Public.class) public GaoRegistrationEventRecord create(@RequestBody GaoRegistrationEventRecordCreateReq req) { return service.createRecord(req); } @@ -96,6 +103,7 @@ public class GaoRegistrationEventRecordController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ) @PostMapping("/period/list") + @JsonView(ResponseView.Public.class) public List periodList(@RequestBody GaoRegistrationEventRecordPeriodReq req) { return service.listByRegistrationEventAndPeriod(req); } @@ -104,10 +112,19 @@ public class GaoRegistrationEventRecordController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ) @PostMapping("/range/list") + @JsonView(ResponseView.Public.class) public List rangeList(@RequestBody GaoRegistrationEventRecordRangeReq req) { return service.listByRange(req); } + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ) + @PostMapping("/range/calendar/list") + public List calendarRangeList(@RequestBody GaoRegistrationEventRecordRangeReq req) { + return service.listCalendarByRange(req); + } + @AOPLog @RequestRateLimit @IgnoreGlobalReturn diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoUserController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoUserController.java index 3f09d56..1d38644 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoUserController.java +++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoUserController.java @@ -1,5 +1,6 @@ package com.imyeyu.api.modules.gao.controller; +import com.fasterxml.jackson.annotation.JsonView; import com.imyeyu.api.bean.ModuleCode; import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission; import com.imyeyu.api.modules.gao.annotation.RequireGaoRole; @@ -13,6 +14,7 @@ import com.imyeyu.spring.annotation.AOPLog; import com.imyeyu.spring.annotation.RequestRateLimit; import com.imyeyu.spring.bean.Page; import com.imyeyu.spring.bean.PageResult; +import com.imyeyu.spring.util.ResponseView; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -40,6 +42,7 @@ public class GaoUserController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.USER_READ) @PostMapping("/list") + @JsonView(ResponseView.Public.class) public PageResult list(@RequestBody Page page) { return service.pageWithUser(page); } @@ -48,6 +51,7 @@ public class GaoUserController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.USER_READ) @PostMapping("/detail") + @JsonView(ResponseView.Public.class) public GaoUser detail(@RequestParam String id) { return service.get(id); } @@ -56,6 +60,7 @@ public class GaoUserController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.USER_READ) @PostMapping("/detail/user") + @JsonView(ResponseView.Public.class) public GaoUser detailByUserId(@RequestParam String userId) { return service.getByUserId(userId); } @@ -64,6 +69,7 @@ public class GaoUserController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.USER_CREATE) @PostMapping("/create") + @JsonView(ResponseView.Public.class) public GaoUser create(@RequestBody GaoUser gaoUser) { service.create(gaoUser); return service.get(gaoUser.getId()); @@ -73,6 +79,7 @@ public class GaoUserController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.USER_UPDATE) @PostMapping("/update") + @JsonView(ResponseView.Public.class) public GaoUser update(@RequestBody GaoUser gaoUser) { service.update(gaoUser); return service.get(gaoUser.getId()); diff --git a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoCustomer.java b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoCustomer.java index 56da14b..06403ec 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoCustomer.java +++ b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoCustomer.java @@ -72,7 +72,6 @@ public class GaoCustomer extends UUIDEntity { @Transient private User creatorUser; - @Transient private Long invitedCount; @Transient diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoCustomerMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoCustomerMapper.java index 89002fa..3c6aa26 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoCustomerMapper.java +++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoCustomerMapper.java @@ -2,6 +2,7 @@ package com.imyeyu.api.modules.gao.mapper; import com.imyeyu.api.modules.gao.entity.GaoCustomer; import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView; import com.imyeyu.spring.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; @@ -21,6 +22,8 @@ public interface GaoCustomerMapper extends BaseMapper { @Select("SELECT * FROM `gao_customer` WHERE `name` = #{name} AND `deleted_at` IS NULL LIMIT 1") GaoCustomer selectByName(@Param("name") String name); + List selectByIdList(@Param("idList") List idList); + List search(@Param("keyword") String keyword, @Param("introducerCustomerId") String introducerCustomerId); Long countSearch(@Param("keyword") String keyword, @Param("introducerCustomerId") String introducerCustomerId); @@ -31,6 +34,8 @@ public interface GaoCustomerMapper extends BaseMapper { Long countInvited(@Param("introducerCustomerId") String introducerCustomerId); + void updateInvitedCountDelta(@Param("customerId") String customerId, @Param("delta") Long delta); + /// 统计每日新增客户数 /// /// @param beginCreatedAt 开始创建时间 @@ -43,4 +48,9 @@ public interface GaoCustomerMapper extends BaseMapper { /// @param beginCreatedAt 开始创建时间 /// @return 客户总数 Long countCreatedBefore(@Param("beginCreatedAt") Long beginCreatedAt); + + /// 统计客户性别分布 + /// + /// @return 性别统计列表 + List statGender(); } diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventMapper.java index 01d8a56..3fd8c2c 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventMapper.java +++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventMapper.java @@ -2,6 +2,7 @@ package com.imyeyu.api.modules.gao.mapper; import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent; import com.imyeyu.spring.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; @@ -13,6 +14,8 @@ import java.util.List; /// @since 2026-07-27 public interface GaoRegistrationEventMapper extends BaseMapper { + List selectByIdList(@Param("idList") List idList); + @Select("SELECT * FROM `gao_registration_event` WHERE `enabled` = TRUE AND `deleted_at` IS NULL ORDER BY `sort` ASC, `created_at` ASC") List selectEnabledList(); } 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 bfb8655..63adbc8 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,7 +3,9 @@ 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.GaoRegistrationEventRecordCalendarView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq; import com.imyeyu.spring.mapper.BaseMapper; @@ -104,6 +106,12 @@ public interface GaoRegistrationEventRecordMapper extends BaseMapper selectByRange(@Param("req") GaoRegistrationEventRecordRangeReq req); + /// 按任意时间范围查询日历轻量记录 + /// + /// @param req 范围查询请求 + /// @return 日历轻量记录列表 + List selectCalendarByRange(@Param("req") GaoRegistrationEventRecordRangeReq req); + /// 按任意时间范围统计登记事件记录 /// /// @param req 范围查询请求 @@ -116,5 +124,5 @@ public interface GaoRegistrationEventRecordMapper extends BaseMapper selectPageByRange(@Param("req") GaoRegistrationEventRecordRangeReq req, @Param("offset") Long offset, @Param("size") Long size); + List selectPageByRange(@Param("req") GaoRegistrationEventRecordRangeReq req, @Param("offset") Long offset, @Param("size") Long size); } diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRoleRelationMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRoleRelationMapper.java index 7d10ae1..0a66c9d 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRoleRelationMapper.java +++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRoleRelationMapper.java @@ -18,6 +18,19 @@ public interface GaoRegistrationEventRoleRelationMapper extends BaseMapper selectRoleCodeListByRegistrationEventId(@Param("registrationEventId") String registrationEventId); + @Select({ + "" + }) + List selectByRegistrationEventIdList(@Param("registrationEventIdList") List registrationEventIdList); + @Update("UPDATE `gao_registration_event_role_relation` SET `deleted_at` = UNIX_TIMESTAMP() WHERE `registration_event_id` = #{registrationEventId} AND `deleted_at` IS NULL") void deleteByRegistrationEventId(@Param("registrationEventId") String registrationEventId); } diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerService.java index 5b61f5d..928e23f 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerService.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerService.java @@ -2,6 +2,7 @@ package com.imyeyu.api.modules.gao.service; import com.imyeyu.api.modules.gao.entity.GaoCustomer; import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView; import com.imyeyu.api.modules.gao.vo.GaoCustomerInviteUpdateReq; import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq; import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq; @@ -76,4 +77,9 @@ public interface GaoCustomerService extends BaseService { /// @param req 趋势统计请求 /// @return 每日趋势列表 List statDailyTrend(GaoCustomerTrendStatReq req); + + /// 统计客户性别分布 + /// + /// @return 性别统计列表 + List statGender(); } 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 8985d94..b294147 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 @@ -4,8 +4,10 @@ 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.GaoQuickRegistrationEventRecordReq; +import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordStatReq; @@ -42,11 +44,17 @@ public interface GaoRegistrationEventRecordService extends BaseService listByRange(GaoRegistrationEventRecordRangeReq req); + /// 按任意时间范围查询日历轻量记录 + /// + /// @param req 范围查询请求 + /// @return 日历轻量记录列表 + List listCalendarByRange(GaoRegistrationEventRecordRangeReq req); + /// 按任意时间范围分页查询登记事件记录 /// /// @param page 分页参数 /// @return 登记事件记录分页结果 - PageResult pageByRange(Page page); + PageResult pageByRange(Page page); /// 按任意时间范围导出登记事件记录 Excel /// diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerServiceImplement.java index 786ee64..dbcc4fd 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerServiceImplement.java @@ -10,6 +10,7 @@ import com.imyeyu.api.modules.gao.service.GaoCustomerService; import com.imyeyu.api.modules.user.service.UserLoginService; import com.imyeyu.api.modules.user.service.UserService; import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView; import com.imyeyu.api.modules.gao.vo.GaoCustomerInviteUpdateReq; import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq; import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq; @@ -41,6 +42,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; /// /// 客户服务实现 @@ -70,20 +73,30 @@ public class GaoCustomerServiceImplement extends AbstractEntityService search(GaoCustomerSearchReq req) { req = resolveSearchReq(req); List list = mapper.search(req.getKeyword(), req.getIntroducerCustomerId()); - list.forEach(this::loadTransient); + loadListTransient(list); return list; } @@ -136,7 +149,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService list = mapper.searchPage(req.getKeyword(), req.getIntroducerCustomerId(), page.getIndex() * page.getSize(), page.getSize()); - list.forEach(this::loadTransient); + loadListTransient(list); PageResult result = new PageResult<>(); result.setTotal(total); result.setList(list); @@ -146,6 +159,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService list = search(req); + loadIntroducerCustomer(list); try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream output = new ByteArrayOutputStream()) { Sheet sheet = workbook.createSheet("客户列表"); CellStyle titleStyle = workbook.createCellStyle(); @@ -193,7 +207,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService listInvited(String introducerCustomerId) { TimiException.required(introducerCustomerId, "not found introducerCustomerId"); List list = mapper.selectInvitedList(introducerCustomerId); - list.forEach(this::loadTransient); + loadListTransient(list); return list; } @@ -203,9 +217,11 @@ public class GaoCustomerServiceImplement extends AbstractEntityService statGender() { + return mapper.statGender(); + } + private void checkDailyStatRange(LocalDate beginDate, LocalDate endDate) { long days = ChronoUnit.DAYS.between(beginDate, endDate) + 1; TimiException.requiredTrue(days <= 366, "daily stat range too large"); @@ -257,9 +280,11 @@ public class GaoCustomerServiceImplement extends AbstractEntityService customerList) { + loadAttachmentList(customerList); + } + + private void loadIntroducerCustomer(List customerList) { + if (customerList == null || customerList.isEmpty()) { + return; + } + List introducerCustomerIdList = customerList.stream() + .map(GaoCustomer::getIntroducerCustomerId) + .filter(TimiJava::isNotEmpty) + .distinct() + .toList(); + if (introducerCustomerIdList.isEmpty()) { + return; + } + Map introducerCustomerMap = mapper.selectByIdList(new ArrayList<>(introducerCustomerIdList)).stream() + .collect(Collectors.toMap(GaoCustomer::getId, item -> item, (left, right) -> left)); + for (GaoCustomer customer : customerList) { + customer.setIntroducerCustomer(introducerCustomerMap.get(customer.getIntroducerCustomerId())); + } + } + + private void loadAttachmentList(List customerList) { + if (customerList == null || customerList.isEmpty()) { + return; + } + List customerIdList = customerList.stream() + .map(GaoCustomer::getId) + .filter(TimiJava::isNotEmpty) + .distinct() + .toList(); + Map> attachmentMap = attachmentService.mapByBizIdList(Attachment.BizType.GAO_CUSTOMER, customerIdList, GaoCustomer.AttachType.PHOTO.name()); + for (GaoCustomer customer : customerList) { + customer.setAttachmentList(attachmentMap.getOrDefault(customer.getId(), List.of())); + } + } + + private void syncIntroducerInvitedCount(String oldIntroducerCustomerId, String newIntroducerCustomerId) { + String normalizedOldIntroducerCustomerId = normalizeText(oldIntroducerCustomerId); + String normalizedNewIntroducerCustomerId = normalizeText(newIntroducerCustomerId); + if (Objects.equals(normalizedOldIntroducerCustomerId, normalizedNewIntroducerCustomerId)) { + return; + } + changeInvitedCount(normalizedOldIntroducerCustomerId, -1L); + changeInvitedCount(normalizedNewIntroducerCustomerId, 1L); + } + + private void changeInvitedCount(String customerId, long delta) { + String normalizedCustomerId = normalizeText(customerId); + if (normalizedCustomerId == null || delta == 0) { + return; + } + mapper.updateInvitedCountDelta(normalizedCustomerId, delta); + } + + private String normalizeText(String value) { + if (value == null) { + return null; + } + String trimmedValue = value.trim(); + return trimmedValue.isEmpty() ? null : trimmedValue; } private void saveAttachment(String customerId, List attachmentList) { 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 5f61a61..921a6fc 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 @@ -8,6 +8,8 @@ import com.imyeyu.api.modules.common.vo.attach.BizUpdateReq; import com.imyeyu.api.modules.gao.entity.GaoCustomer; import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent; import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord; +import com.imyeyu.api.modules.gao.mapper.GaoCustomerMapper; +import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventMapper; import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventRecordMapper; import com.imyeyu.api.modules.gao.service.GaoCustomerService; import com.imyeyu.api.modules.gao.service.GaoRegistrationEventService; @@ -15,8 +17,10 @@ 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.GaoQuickRegistrationEventRecordReq; +import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView; +import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordStatReq; @@ -24,6 +28,7 @@ import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordTrendStatReq; import com.imyeyu.api.modules.user.service.RoleChecker; import com.imyeyu.api.modules.user.service.UserLoginService; import com.imyeyu.api.modules.user.service.UserService; +import com.imyeyu.api.modules.user.mapper.UserMapper; import com.imyeyu.java.TimiJava; import com.imyeyu.java.bean.timi.TimiException; import com.imyeyu.spring.bean.Page; @@ -55,6 +60,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.StringJoiner; +import java.util.function.Function; +import java.util.stream.Collectors; /// /// 登记事件记录服务实现 @@ -69,6 +76,9 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe private static final DateTimeFormatter EXPORT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()); private final GaoRegistrationEventRecordMapper mapper; + private final GaoCustomerMapper customerMapper; + private final GaoRegistrationEventMapper registrationEventMapper; + private final UserMapper userMapper; private final AttachmentService attachmentService; private final RoleChecker roleChecker; private final UserLoginService userLoginService; @@ -137,7 +147,7 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe @Override public GaoRegistrationEventRecord get(String id) { GaoRegistrationEventRecord record = super.get(id); - loadTransient(record); + loadTransient(List.of(record)); return record; } @@ -148,7 +158,7 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe TimiException.required(req.getPeriodType(), "not found req.periodType"); TimiException.required(req.getPeriodValue(), "not found req.periodValue"); List list = mapper.selectByRegistrationEventAndPeriod(req.getRegistrationEventId(), req.getPeriodType(), req.getPeriodValue()); - list.forEach(this::loadTransient); + loadTransient(list); return list; } @@ -157,12 +167,19 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe TimiException.required(req, "not found req"); checkStatRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt()); List list = mapper.selectByRange(req); - list.forEach(this::loadTransient); + loadTransient(list); return list; } @Override - public PageResult pageByRange(Page page) { + public List listCalendarByRange(GaoRegistrationEventRecordRangeReq req) { + TimiException.required(req, "not found req"); + checkStatRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt()); + return mapper.selectCalendarByRange(req); + } + + @Override + public PageResult pageByRange(Page page) { TimiException.required(page, "not found page"); TimiException.required(page.getIndex(), "not found page.index"); TimiException.required(page.getSize(), "not found page.size"); @@ -171,9 +188,8 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe GaoRegistrationEventRecordRangeReq req = TimiJava.defaultIfNull(page.getEqualsExample(), new GaoRegistrationEventRecordRangeReq()); checkStatRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt()); Long total = TimiJava.defaultIfNull(mapper.countByRange(req), 0L); - List list = mapper.selectPageByRange(req, page.getIndex() * page.getSize(), page.getSize()); - list.forEach(this::loadTransient); - PageResult result = new PageResult<>(); + List list = mapper.selectPageByRange(req, page.getIndex() * page.getSize(), page.getSize()); + PageResult result = new PageResult<>(); result.setTotal(total); result.setList(list); return result; @@ -236,7 +252,7 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe return Collections.emptyList(); } List list = mapper.selectLatestByCustomerIdListAndRegistrationEventId(customerIdList, registrationEventId); - list.forEach(this::loadTransient); + loadTransient(list); return list; } @@ -279,7 +295,7 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe public List listLatestByCustomerId(String customerId) { TimiException.required(customerId, "not found customerId"); List list = mapper.selectLatestByCustomerId(customerId); - list.forEach(this::loadTransient); + loadTransient(list); return list; } @@ -340,16 +356,51 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe return list; } - private void loadTransient(GaoRegistrationEventRecord record) { - if (record == null) { + private void loadTransient(List recordList) { + if (recordList == null || recordList.isEmpty()) { return; } - record.setCustomer(customerService.get(record.getCustomerId())); - record.setRegistrationEvent(registrationEventService.get(record.getRegistrationEventId())); - if (TimiJava.isNotEmpty(record.getOperatorUserId())) { - record.setOperator(userService.get(record.getOperatorUserId())); + List customerIdList = recordList.stream() + .map(GaoRegistrationEventRecord::getCustomerId) + .filter(TimiJava::isNotEmpty) + .distinct() + .toList(); + Map customerMap = customerMapper.selectByIdList(new ArrayList<>(customerIdList)).stream() + .collect(Collectors.toMap(GaoCustomer::getId, Function.identity(), (left, right) -> left)); + + List registrationEventIdList = recordList.stream() + .map(GaoRegistrationEventRecord::getRegistrationEventId) + .filter(TimiJava::isNotEmpty) + .distinct() + .toList(); + Map registrationEventMap = registrationEventMapper.selectByIdList(new ArrayList<>(registrationEventIdList)).stream() + .collect(Collectors.toMap(GaoRegistrationEvent::getId, Function.identity(), (left, right) -> left)); + + List operatorUserIdList = recordList.stream() + .map(GaoRegistrationEventRecord::getOperatorUserId) + .filter(TimiJava::isNotEmpty) + .distinct() + .toList(); + Map userMap = userMapper.listByIdList(new ArrayList<>(operatorUserIdList)).stream() + .collect(Collectors.toMap(com.imyeyu.api.modules.user.entity.User::getId, Function.identity(), (left, right) -> left)); + + List recordIdList = recordList.stream() + .map(GaoRegistrationEventRecord::getId) + .filter(TimiJava::isNotEmpty) + .distinct() + .toList(); + Map> attachmentMap = attachmentService.mapByBizIdList( + Attachment.BizType.GAO_REGISTRATION_EVENT_RECORD, + recordIdList, + GaoRegistrationEventRecord.AttachType.PHOTO.name() + ); + + for (GaoRegistrationEventRecord record : recordList) { + record.setCustomer(customerMap.get(record.getCustomerId())); + record.setRegistrationEvent(registrationEventMap.get(record.getRegistrationEventId())); + record.setOperator(userMap.get(record.getOperatorUserId())); + record.setAttachmentList(attachmentMap.getOrDefault(record.getId(), List.of())); } - record.setAttachmentList(attachmentService.listByBizId(Attachment.BizType.GAO_REGISTRATION_EVENT_RECORD, record.getId(), GaoRegistrationEventRecord.AttachType.PHOTO.name())); } private void checkDailyStatRange(LocalDate beginDate, LocalDate endDate) { diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventServiceImplement.java index 1f819ee..0cfbdc8 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventServiceImplement.java @@ -15,9 +15,12 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /// /// 登记事件服务实现 @@ -39,9 +42,7 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService< @Override public PageResult pageWithRegistrationEventLimit(Page page) { PageResult result = page(page); - if (result.getList() != null) { - result.getList().forEach(this::loadRegistrationEventLimit); - } + loadRegistrationEventLimit(result.getList()); return result; } @@ -78,7 +79,7 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService< @Override public List listEnabled() { List list = mapper.selectEnabledList(); - list.forEach(this::loadRegistrationEventLimit); + loadRegistrationEventLimit(list); return list; } @@ -124,4 +125,22 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService< private void loadRegistrationEventLimit(GaoRegistrationEvent registrationEvent) { registrationEvent.setRoleCodeList(roleRelationMapper.selectRoleCodeListByRegistrationEventId(registrationEvent.getId())); } + + private void loadRegistrationEventLimit(List registrationEventList) { + if (registrationEventList == null || registrationEventList.isEmpty()) { + return; + } + List registrationEventIdList = registrationEventList.stream() + .map(GaoRegistrationEvent::getId) + .distinct() + .toList(); + Map> roleCodeMap = roleRelationMapper.selectByRegistrationEventIdList(new ArrayList<>(registrationEventIdList)).stream() + .collect(Collectors.groupingBy( + GaoRegistrationEventRoleRelation::getRegistrationEventId, + Collectors.mapping(GaoRegistrationEventRoleRelation::getRoleCode, Collectors.toList()) + )); + for (GaoRegistrationEvent registrationEvent : registrationEventList) { + registrationEvent.setRoleCodeList(roleCodeMap.getOrDefault(registrationEvent.getId(), List.of())); + } + } } diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerGenderStatView.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerGenderStatView.java new file mode 100644 index 0000000..f1185d6 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoCustomerGenderStatView.java @@ -0,0 +1,18 @@ +package com.imyeyu.api.modules.gao.vo; + +import lombok.Data; + +/// +/// 客户性别统计视图 +/// +/// @author Codex +/// @since 2026-08-01 +@Data +public class GaoCustomerGenderStatView { + + /// 性别编码,未知时为 UNKNOWN + private String genderCode; + + /// 客户数量 + private Long count; +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordCalendarView.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordCalendarView.java new file mode 100644 index 0000000..3ee29a9 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordCalendarView.java @@ -0,0 +1,30 @@ +package com.imyeyu.api.modules.gao.vo; + +import lombok.Data; + +/// +/// 登记事件记录日历轻量视图 +/// +/// @author Codex +/// @since 2026-08-01 +@Data +public class GaoRegistrationEventRecordCalendarView { + + /// 记录 ID + private String id; + + /// 客户 ID + private String customerId; + + /// 客户编码 + private String customerCode; + + /// 客户姓名 + private String customerName; + + /// 登记事件 ID + private String registrationEventId; + + /// 登记时间 + private Long registeredAt; +} diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordListItemView.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordListItemView.java new file mode 100644 index 0000000..5bca512 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordListItemView.java @@ -0,0 +1,33 @@ +package com.imyeyu.api.modules.gao.vo; + +import lombok.Data; + +/// +/// 登记事件记录列表项视图 +/// +/// @author Codex +/// @since 2026-08-01 +@Data +public class GaoRegistrationEventRecordListItemView { + + /// 记录 ID + private String id; + + /// 客户 ID + private String customerId; + + /// 客户姓名 + private String customerName; + + /// 客户头像附件 ID + private String customerPhotoAttachmentId; + + /// 登记事件 ID + private String registrationEventId; + + /// 登记事件名称 + private String registrationEventName; + + /// 登记时间 + private Long registeredAt; +} diff --git a/src/main/resources/db/migration/timiserver/V19__add_gao_customer_invited_count.sql b/src/main/resources/db/migration/timiserver/V19__add_gao_customer_invited_count.sql new file mode 100644 index 0000000..42ce511 --- /dev/null +++ b/src/main/resources/db/migration/timiserver/V19__add_gao_customer_invited_count.sql @@ -0,0 +1,12 @@ +ALTER TABLE `gao_customer` +ADD COLUMN `invited_count` BIGINT NOT NULL DEFAULT 0 COMMENT '邀请客户数' AFTER `introducer_customer_id`; + +UPDATE `gao_customer` AS `customer` +SET `invited_count` = ( + SELECT COUNT(1) + FROM `gao_customer` AS `invitee` + WHERE + `invitee`.`introducer_customer_id` = `customer`.`id` + AND `invitee`.`deleted_at` IS NULL +) +WHERE `customer`.`deleted_at` IS NULL; diff --git a/src/main/resources/mapper/timi-server/AttachmentMapper.xml b/src/main/resources/mapper/timi-server/AttachmentMapper.xml new file mode 100644 index 0000000..e06d291 --- /dev/null +++ b/src/main/resources/mapper/timi-server/AttachmentMapper.xml @@ -0,0 +1,29 @@ + + + + + diff --git a/src/main/resources/mapper/timi-server/GaoCustomerMapper.xml b/src/main/resources/mapper/timi-server/GaoCustomerMapper.xml index 15e9d46..b7db501 100644 --- a/src/main/resources/mapper/timi-server/GaoCustomerMapper.xml +++ b/src/main/resources/mapper/timi-server/GaoCustomerMapper.xml @@ -28,6 +28,18 @@ ORDER BY `created_at` DESC + + + + UPDATE `gao_customer` + SET + `invited_count` = GREATEST(IFNULL(`invited_count`, 0) + #{delta}, 0), + `updated_at` = UNIX_TIMESTAMP() * 1000 + WHERE + `id` = #{customerId} + AND `deleted_at` IS NULL + + + + diff --git a/src/main/resources/mapper/timi-server/GaoRegistrationEventMapper.xml b/src/main/resources/mapper/timi-server/GaoRegistrationEventMapper.xml new file mode 100644 index 0000000..8c53a1c --- /dev/null +++ b/src/main/resources/mapper/timi-server/GaoRegistrationEventMapper.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml b/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml index ae7cf84..0ba640f 100644 --- a/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml +++ b/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml @@ -259,6 +259,20 @@ ORDER BY r.`registered_at` DESC, r.`created_at` DESC + + - SELECT - r.* + r.`id` AS `id`, + r.`customer_id` AS `customerId`, + 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`, + r.`registration_event_id` AS `registrationEventId`, + e.`name` AS `registrationEventName`, + r.`registered_at` AS `registeredAt` WHERE