diff --git a/pom.xml b/pom.xml
index c36e621..f46456d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -173,7 +173,7 @@
com.imyeyu.spring
timi-spring
- 0.0.17
+ 0.0.18
com.imyeyu.network
@@ -188,7 +188,7 @@
com.imyeyu.java
timi-java
- 0.0.6
+ 0.0.7
com.imyeyu.utils
@@ -230,6 +230,10 @@
spring-boot-starter-freemarker
${springboot.version}
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
org.springframework.boot
spring-boot-starter-data-mongodb
diff --git a/src/main/java/com/imyeyu/api/config/BeanConfig.java b/src/main/java/com/imyeyu/api/config/BeanConfig.java
index ad7f099..00a701e 100644
--- a/src/main/java/com/imyeyu/api/config/BeanConfig.java
+++ b/src/main/java/com/imyeyu/api/config/BeanConfig.java
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.imyeyu.utils.Time;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -22,6 +23,7 @@ public class BeanConfig {
@Bean
public ObjectMapper jackson() {
return JsonMapper.builder()
+ .addModule(new JavaTimeModule())
.serializationInclusion(JsonInclude.Include.NON_NULL)
.defaultDateFormat(Time.dateTime)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
diff --git a/src/main/java/com/imyeyu/api/config/WebConfig.java b/src/main/java/com/imyeyu/api/config/WebConfig.java
index 6357124..d457568 100644
--- a/src/main/java/com/imyeyu/api/config/WebConfig.java
+++ b/src/main/java/com/imyeyu/api/config/WebConfig.java
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.imyeyu.api.annotation.EnableSettingInterceptor;
import com.imyeyu.api.annotation.RequestRateLimitInterceptor;
import com.imyeyu.api.annotation.RequireCorePermissionInterceptor;
@@ -78,6 +79,7 @@ public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List> converters) {
JsonMapper jsonMapper = JsonMapper.builder()
+ .addModule(new JavaTimeModule())
// 设置默认属性包含规则:忽略 null 值
.serializationInclusion(JsonInclude.Include.NON_NULL)
// 日期格式化
diff --git a/src/main/java/com/imyeyu/api/modules/common/service/implement/TempFileServiceImplement.java b/src/main/java/com/imyeyu/api/modules/common/service/implement/TempFileServiceImplement.java
index 65ba27e..d068d59 100644
--- a/src/main/java/com/imyeyu/api/modules/common/service/implement/TempFileServiceImplement.java
+++ b/src/main/java/com/imyeyu/api/modules/common/service/implement/TempFileServiceImplement.java
@@ -46,8 +46,8 @@ public class TempFileServiceImplement implements TempFileService {
public List create(List files, Long ttl) throws TimiException {
Logger logger = new Logger();
- logger.setModule("TEMP_FILE");
- logger.setOperation("STORE");
+ logger.setModule(Logger.Module.COMMON);
+ logger.setOperation("TEMP_FILE_STORE");
logger.setIp(TimiSpring.getRequestIP());
try {
logger.setContent(jackson.writeValueAsString(logRequestArgs(files, ttl)));
@@ -116,8 +116,8 @@ public class TempFileServiceImplement implements TempFileService {
@Override
public void save(TempFileSaveReq request) {
Logger logger = new Logger();
- logger.setModule("TEMP_FILE");
- logger.setOperation("SAVE");
+ logger.setModule(Logger.Module.COMMON);
+ logger.setOperation("TEMP_FILE_SAVE");
logger.setIp(TimiSpring.getRequestIP());
try {
logger.setContent(jackson.writeValueAsString(request));
diff --git a/src/main/java/com/imyeyu/api/modules/gao/bean/GaoPermissionCode.java b/src/main/java/com/imyeyu/api/modules/gao/bean/GaoPermissionCode.java
index 5f150b8..cfc07be 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/bean/GaoPermissionCode.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/bean/GaoPermissionCode.java
@@ -14,6 +14,8 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
CUSTOMER_READ("CUSTOMER:READ", "客户读取"),
+ CUSTOMER_EXPORT("CUSTOMER:EXPORT", "客户导出", true),
+
CUSTOMER_UPDATE("CUSTOMER:UPDATE", "客户修改"),
CUSTOMER_DELETE("CUSTOMER:DELETE", "客户删除"),
@@ -30,6 +32,8 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
REGISTRATION_EVENT_RECORD_READ("REGISTRATION_EVENT_RECORD:READ", "登记事件记录读取"),
+ REGISTRATION_EVENT_RECORD_EXPORT("REGISTRATION_EVENT_RECORD:EXPORT", "登记事件记录导出", true),
+
REGISTRATION_EVENT_RECORD_UPDATE("REGISTRATION_EVENT_RECORD:UPDATE", "登记事件记录修改"),
REGISTRATION_EVENT_RECORD_DELETE("REGISTRATION_EVENT_RECORD:DELETE", "登记事件记录删除"),
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 cdf5038..480a64b 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
@@ -88,7 +88,7 @@ public class GaoCustomerController {
@AOPLog
@RequestRateLimit
@IgnoreGlobalReturn
- @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
+ @RequireGaoPermission(GaoPermissionCode.CUSTOMER_EXPORT)
@PostMapping("/export")
public void export(@RequestBody GaoCustomerSearchReq req, HttpServletResponse resp) throws IOException {
String fileName = URLEncoder.encode("客户列表.xlsx", "UTF-8").replace("+", "%20");
diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventController.java
index e9e7319..0063ad6 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventController.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventController.java
@@ -72,6 +72,14 @@ public class GaoRegistrationEventController {
service.update(registrationEvent);
}
+ @AOPLog
+ @RequestRateLimit
+ @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_UPDATE)
+ @PostMapping("/sort")
+ public void sort(@RequestBody List idList) {
+ service.sort(idList);
+ }
+
@AOPLog
@RequestRateLimit
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_DELETE)
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 4f8a3f8..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;
@@ -79,8 +80,8 @@ public class GaoRegistrationEventRecordController {
@RequestRateLimit
@PostMapping("/create")
@JsonView(ResponseView.Public.class)
- public GaoRegistrationEventRecord create(@RequestBody GaoRegistrationEventRecordCreateReq req) {
- return service.createRecord(req);
+ public List create(@RequestBody GaoRegistrationEventRecordCreateReq req) {
+ return service.createRecords(req);
}
@AOPLog
@@ -128,7 +129,7 @@ public class GaoRegistrationEventRecordController {
@AOPLog
@RequestRateLimit
@IgnoreGlobalReturn
- @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
+ @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_EXPORT)
@PostMapping("/range/export")
public void rangeExport(@RequestBody GaoRegistrationEventRecordRangeReq req, HttpServletResponse resp) throws IOException {
String fileName = URLEncoder.encode("登记事件记录.xlsx", "UTF-8").replace("+", "%20");
@@ -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/entity/GaoCustomer.java b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoCustomer.java
index 06403ec..a37ed88 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
@@ -1,5 +1,7 @@
package com.imyeyu.api.modules.gao.entity;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.JsonNode;
import com.imyeyu.api.modules.common.entity.Attachment;
import com.imyeyu.api.modules.user.entity.User;
@@ -9,6 +11,7 @@ import com.imyeyu.spring.entity.UUIDEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import java.time.LocalDate;
import java.util.List;
///
@@ -30,6 +33,18 @@ public class GaoCustomer extends UUIDEntity {
PHOTO
}
+ ///
+ /// 出生日期使用的历法
+ ///
+ public enum BirthdateCalendar {
+
+ /// 公历
+ SOLAR,
+
+ /// 农历
+ LUNAR
+ }
+
/// 客户编码
private String code;
@@ -42,6 +57,22 @@ public class GaoCustomer extends UUIDEntity {
/// 年龄
private Integer age;
+ /// 出生日期,数据库只保存公历日期
+ @JsonFormat(pattern = "yyyy-MM-dd")
+ private LocalDate birthdate;
+
+ /// 出生日期录入时使用的历法
+ private BirthdateCalendar birthdateCalendar;
+
+ @JsonIgnore
+ @Transient
+ private boolean birthdateProvided;
+
+ public void setBirthdate(LocalDate birthdate) {
+ this.birthdate = birthdate;
+ this.birthdateProvided = true;
+ }
+
/// 电话
private String telephone;
diff --git a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoRegistrationEvent.java b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoRegistrationEvent.java
index f6a290a..40a792b 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoRegistrationEvent.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoRegistrationEvent.java
@@ -23,6 +23,9 @@ public class GaoRegistrationEvent extends UUIDEntity {
/// @since 2026-08-01
public enum Status {
+ /// 草稿,未发布不可登记
+ DRAFT,
+
/// 可登记
ACTIVE,
@@ -38,7 +41,7 @@ public class GaoRegistrationEvent extends UUIDEntity {
///
/// @author Codex
/// @since 2026-08-01
- public enum RegistrationLimitType {
+ public enum LimitType {
/// 不限制
NONE,
@@ -55,8 +58,11 @@ public class GaoRegistrationEvent extends UUIDEntity {
/// 每个自然月一次
NATURAL_MONTH,
- /// 累计限 N 次
- TOTAL_LIMIT
+ /// 事件总登记次数上限
+ TOTAL_LIMIT,
+
+ /// 单个客户总登记次数上限
+ CUSTOMER_TOTAL_LIMIT
}
/// 登记事件名称
@@ -71,18 +77,21 @@ public class GaoRegistrationEvent extends UUIDEntity {
/// 状态
private Status status;
- /// true 为启用
- private Boolean enabled;
-
/// true 为登记时要求拍照
private Boolean requirePhoto;
/// 登记限制类型
- private RegistrationLimitType limitType;
+ private LimitType limitType;
/// 登记限制数值,按限制类型表示小时数或次数
private Integer limitValue;
+ /// 可登记起始时间戳,毫秒,空为不限制
+ private Long beginAt;
+
+ /// 可登记终止时间戳,毫秒,空为不限制
+ private Long endAt;
+
/// 排序值
private Integer sort;
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 196ae83..5ccd039 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
@@ -3,7 +3,6 @@ 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;
@@ -16,6 +15,5 @@ public interface GaoRegistrationEventMapper extends BaseMapper selectByIdList(@Param("idList") List idList);
- @Select("SELECT * FROM `gao_registration_event` WHERE `enabled` = TRUE AND (`status` IS NULL OR `status` = 'ACTIVE') AND `deleted_at` IS NULL ORDER BY `sort` ASC, `created_at` ASC")
- List selectEnabledList();
+ List selectEnabledList(@Param("now") Long now);
}
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 31df65a..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;
@@ -43,6 +44,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 b294147..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;
@@ -26,11 +27,11 @@ import java.util.List;
/// @since 2026-07-27
public interface GaoRegistrationEventRecordService extends BaseService {
- /// 创建登记事件记录
+ /// 批量创建登记事件记录
///
- /// @param req 创建请求
- /// @return 创建后的登记事件记录
- GaoRegistrationEventRecord createRecord(GaoRegistrationEventRecordCreateReq req);
+ /// @param req 批量创建请求
+ /// @return 创建后的登记事件记录列表
+ List createRecords(GaoRegistrationEventRecordCreateReq req);
/// 快速录入客户并创建登记事件记录
///
@@ -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/GaoRegistrationEventService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventService.java
index 893a77a..f6f609c 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventService.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventService.java
@@ -30,4 +30,9 @@ public interface GaoRegistrationEventService extends BaseService listRoleCode(String registrationEventId);
+
+ /// 按客户端提交的顺序更新登记事件排序
+ ///
+ /// @param idList 登记事件 ID 列表
+ void sort(List idList);
}
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 d8b0fcd..3d5ec18 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
@@ -1,5 +1,6 @@
package com.imyeyu.api.modules.gao.service.implement;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
import com.imyeyu.api.modules.common.entity.Attachment;
import com.imyeyu.api.modules.common.service.AttachmentService;
@@ -7,21 +8,25 @@ import com.imyeyu.api.modules.common.vo.attach.BizUpdateReq;
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
import com.imyeyu.api.modules.gao.mapper.GaoCustomerMapper;
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;
+import com.imyeyu.api.modules.system.entity.Logger;
+import com.imyeyu.api.modules.system.service.LoggerService;
+import com.imyeyu.api.modules.user.service.UserLoginService;
+import com.imyeyu.api.modules.user.service.UserService;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
+import com.imyeyu.spring.TimiSpring;
import com.imyeyu.spring.bean.Page;
import com.imyeyu.spring.bean.PageResult;
import com.imyeyu.spring.mapper.BaseMapper;
import com.imyeyu.spring.service.AbstractEntityService;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
@@ -35,6 +40,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
+import java.time.Period;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
@@ -50,6 +56,7 @@ import java.util.stream.Collectors;
///
/// @author Codex
/// @since 2026-07-27
+@Slf4j
@Service
@RequiredArgsConstructor
public class GaoCustomerServiceImplement extends AbstractEntityService implements GaoCustomerService {
@@ -58,7 +65,9 @@ public class GaoCustomerServiceImplement extends AbstractEntityService page(Page page) {
+ PageResult result = super.page(page);
+ loadListTransient(result.getList());
+ return result;
+ }
+
@Override
public void create(GaoCustomer entity) {
- checkEntity(entity, false);
- entity.setCreatorUserId(userLoginService.getRequireLoginUserId());
- entity.setInvitedCount(0L);
- super.create(entity);
- saveAttachment(entity.getId(), resolveAttachmentList(entity));
- changeInvitedCount(entity.getIntroducerCustomerId(), 1L);
- loadDetailTransient(entity);
+ Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_CREATE");
+ try {
+ logger.setContent(jackson.writeValueAsString(entity));
+ checkEntity(entity, false);
+ entity.setCreatorUserId(userLoginService.getRequireLoginUserId());
+ entity.setInvitedCount(0L);
+ super.create(entity);
+ saveAttachment(entity.getId(), resolveAttachmentList(entity));
+ changeInvitedCount(entity.getIntroducerCustomerId(), 1L);
+ loadDetailTransient(entity);
+ logger.setLevel(Logger.Level.INFO);
+ logger.setResult(entity.getId());
+ } catch (TimiException e) {
+ logger.setLevel(Logger.Level.WARN);
+ logger.setException(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.setLevel(Logger.Level.ERROR);
+ logger.setException(TimiJava.serializeThrowable(e));
+ log.error("新增 GAO 客户失败", e);
+ throw new TimiException(TimiCode.ERROR, "新增 GAO 客户失败", e);
+ } finally {
+ loggerService.create(logger);
+ }
}
@Override
public void update(GaoCustomer entity) {
- GaoCustomer dbCustomer = checkEntity(entity, true);
- super.update(entity);
- saveAttachment(entity.getId(), resolveAttachmentList(entity));
- syncIntroducerInvitedCount(dbCustomer.getIntroducerCustomerId(), entity.getIntroducerCustomerId());
+ Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_UPDATE");
+ try {
+ logger.setContent(jackson.writeValueAsString(entity));
+ TimiException.required(entity, "not found customer");
+ TimiException.required(entity.getId(), "not found customer.id");
+ GaoCustomer dbCustomer = super.get(entity.getId());
+ if (!entity.isBirthdateProvided()) {
+ entity.setBirthdate(dbCustomer.getBirthdate());
+ entity.setBirthdateCalendar(dbCustomer.getBirthdateCalendar());
+ }
+ checkEntity(entity, true);
+ mapper.update(entity);
+ saveAttachment(entity.getId(), resolveAttachmentList(entity));
+ syncIntroducerInvitedCount(dbCustomer.getIntroducerCustomerId(), entity.getIntroducerCustomerId());
+ logger.setLevel(Logger.Level.INFO);
+ logger.setResult(entity.getId());
+ } catch (TimiException e) {
+ logger.setLevel(Logger.Level.WARN);
+ logger.setException(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.setLevel(Logger.Level.ERROR);
+ logger.setException(TimiJava.serializeThrowable(e));
+ log.error("修改 GAO 客户失败", e);
+ throw new TimiException(TimiCode.ERROR, "修改 GAO 客户失败", e);
+ } finally {
+ loggerService.create(logger);
+ }
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void delete(String id) {
- GaoCustomer customer = super.get(id);
- super.delete(id);
- changeInvitedCount(customer.getIntroducerCustomerId(), -1L);
+ Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_DELETE");
+ try {
+ logger.setContent(id);
+ GaoCustomer customer = super.get(id);
+ super.delete(id);
+ changeInvitedCount(customer.getIntroducerCustomerId(), -1L);
+ logger.setLevel(Logger.Level.INFO);
+ logger.setResult(id);
+ } catch (TimiException e) {
+ logger.setLevel(Logger.Level.WARN);
+ logger.setException(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.setLevel(Logger.Level.ERROR);
+ logger.setException(TimiJava.serializeThrowable(e));
+ log.error("删除 GAO 客户失败", e);
+ throw new TimiException(TimiCode.ERROR, "删除 GAO 客户失败", e);
+ } finally {
+ loggerService.create(logger);
+ }
}
@Override
@@ -177,13 +251,15 @@ public class GaoCustomerServiceImplement extends AbstractEntityService customerList) {
+ if (customerList != null) {
+ customerList.forEach(this::refreshAge);
+ }
loadAttachmentList(customerList);
}
+ /// 根据出生日期计算当前周岁。出生日期为空时保留旧数据中的手工年龄。
+ private void refreshAge(GaoCustomer customer) {
+ if (customer.getBirthdate() == null) {
+ return;
+ }
+ LocalDate today = LocalDate.now();
+ TimiException.requiredTrue(!customer.getBirthdate().isAfter(today), "customer.birthdate invalid");
+ customer.setAge(Period.between(customer.getBirthdate(), today).getYears());
+ }
+
private void loadIntroducerCustomer(List customerList) {
if (customerList == null || customerList.isEmpty()) {
return;
@@ -443,6 +571,13 @@ public class GaoCustomerServiceImplement 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;
+ private final ObjectMapper jackson;
private final GaoCustomerMapper customerMapper;
private final GaoRegistrationEventMapper registrationEventMapper;
private final UserMapper userMapper;
private final AttachmentService attachmentService;
+ private final LoggerService loggerService;
private final RoleChecker roleChecker;
private final UserLoginService userLoginService;
private final UserService userService;
@@ -93,57 +106,147 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
- public GaoRegistrationEventRecord createRecord(GaoRegistrationEventRecordCreateReq req) {
- TimiException.required(req, "not found req");
- TimiException.required(req.getRegistrationEventId(), "not found req.registrationEventId");
- String customerId = resolveCustomerId(req);
- GaoRegistrationEvent registrationEvent = registrationEventService.get(req.getRegistrationEventId());
- checkRegistrationEventPermission(registrationEvent);
- long registeredAt = TimiJava.defaultIfNull(req.getRegisteredAt(), Time.now());
- checkRegistrationEventCreatable(registrationEvent, customerId, registeredAt);
- if (Boolean.TRUE.equals(registrationEvent.getRequirePhoto())) {
- TimiException.requiredTrue(req.getAttachmentIdList() != null && !req.getAttachmentIdList().isEmpty(), "required record photo");
+ public List createRecords(GaoRegistrationEventRecordCreateReq req) {
+ Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_RECORD_BATCH_CREATE");
+ try {
+ TimiException.required(req, "not found req");
+ TimiException.requiredTrue(req.getCustomerIdList() != null && !req.getCustomerIdList().isEmpty(), "customerIdList is empty");
+ logger.setContent(jackson.writeValueAsString(req));
+ List recordList = new ArrayList<>();
+ for (int index = 0; index < req.getCustomerIdList().size(); index++) {
+ String customerId = req.getCustomerIdList().get(index);
+ GaoRegistrationEventRecordCreateReq customerReq = copyCreateReq(req);
+ customerReq.setAttachmentIdList(0 == index && canUseSourceTempFileList(req.getAttachmentIdList())
+ ? req.getAttachmentIdList()
+ : duplicateTempFileList(req.getAttachmentIdList()));
+ recordList.add(doCreateRecord(customerReq, customerId));
+ }
+ logger.setLevel(Logger.Level.INFO);
+ logger.setResult(recordList.stream().map(GaoRegistrationEventRecord::getId).collect(Collectors.joining(",")));
+ return recordList;
+ } catch (TimiException e) {
+ logger.setLevel(Logger.Level.WARN);
+ logger.setException(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.setLevel(Logger.Level.ERROR);
+ logger.setException(TimiJava.serializeThrowable(e));
+ log.error("批量新增 GAO 登记记录失败", e);
+ throw new TimiException(TimiCode.ERROR, "批量新增 GAO 登记记录失败", e);
+ } finally {
+ loggerService.create(logger);
}
+ }
- GaoRegistrationEventRecord record = new GaoRegistrationEventRecord();
- record.setCustomerId(customerId);
- record.setRegistrationEventId(req.getRegistrationEventId());
- record.setOperatorUserId(userLoginService.getRequireLoginUserId());
- record.setRemark(req.getRemark());
- record.setRegisteredAt(registeredAt);
- super.create(record);
- saveAttachment(record.getId(), buildPhotoAttachmentList(req.getAttachmentIdList()));
- return get(record.getId());
+ private List duplicateTempFileList(List sourceIdList) {
+ if (sourceIdList == null) {
+ return null;
+ }
+ List targetIdList = new ArrayList<>();
+ for (String sourceId : sourceIdList) {
+ if (sourceId == null || sourceId.isBlank()) {
+ continue;
+ }
+ Attachment source = attachmentService.get(sourceId.trim());
+ TimiException.required(source, "not found attachment");
+ TimiException.required(source.getMongoId(), "not found attachment.mongoId");
+ Attachment target = new Attachment();
+ target.setBizType(Attachment.BizType.TEMP_FILE);
+ target.setName(source.getName());
+ target.setInputStream(new ByteArrayInputStream(attachmentService.readAllByMongoId(source.getMongoId())));
+ attachmentService.create(target);
+ targetIdList.add(target.getId());
+ }
+ return targetIdList;
+ }
+
+ private boolean canUseSourceTempFileList(List sourceIdList) {
+ if (sourceIdList == null || sourceIdList.isEmpty()) {
+ return true;
+ }
+ for (String sourceId : sourceIdList) {
+ if (sourceId == null || sourceId.isBlank()) {
+ continue;
+ }
+ Attachment source = attachmentService.get(sourceId.trim());
+ if (source == null || source.getBizType() != Attachment.BizType.TEMP_FILE) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private GaoRegistrationEventRecordCreateReq copyCreateReq(GaoRegistrationEventRecordCreateReq source) {
+ GaoRegistrationEventRecordCreateReq target = new GaoRegistrationEventRecordCreateReq();
+ target.setRegistrationEventId(source.getRegistrationEventId());
+ target.setRemark(source.getRemark());
+ target.setRegisteredAt(source.getRegisteredAt());
+ return target;
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public GaoRegistrationEventRecord quickRegister(GaoQuickRegistrationEventRecordReq req) {
- TimiException.required(req, "not found req");
- TimiException.required(req.getCustomerCode(), "not found req.customerCode");
- TimiException.required(req.getRegistrationEventId(), "not found req.registrationEventId");
- GaoCustomer customer = customerService.getOrQuickCreateByCode(req.getCustomerCode());
- GaoRegistrationEventRecordCreateReq recordReq = new GaoRegistrationEventRecordCreateReq();
- recordReq.setCustomerId(customer.getId());
- recordReq.setRegistrationEventId(req.getRegistrationEventId());
- recordReq.setRemark(req.getRemark());
- recordReq.setAttachmentIdList(req.getAttachmentIdList());
- return createRecord(recordReq);
+ Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_RECORD_QUICK_REGISTER");
+ try {
+ logger.setContent(jackson.writeValueAsString(req));
+ TimiException.required(req, "not found req");
+ TimiException.required(req.getCustomerCode(), "not found req.customerCode");
+ TimiException.required(req.getRegistrationEventId(), "not found req.registrationEventId");
+ GaoCustomer customer = customerService.getOrQuickCreateByCode(req.getCustomerCode());
+ GaoRegistrationEventRecordCreateReq recordReq = new GaoRegistrationEventRecordCreateReq();
+ recordReq.setCustomerIdList(List.of(customer.getId()));
+ recordReq.setRegistrationEventId(req.getRegistrationEventId());
+ recordReq.setRemark(req.getRemark());
+ recordReq.setAttachmentIdList(req.getAttachmentIdList());
+ GaoRegistrationEventRecord record = createRecords(recordReq).get(0);
+ logger.setLevel(Logger.Level.INFO);
+ logger.setResult(record.getId());
+ return record;
+ } catch (TimiException e) {
+ logger.setLevel(Logger.Level.WARN);
+ logger.setException(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.setLevel(Logger.Level.ERROR);
+ logger.setException(TimiJava.serializeThrowable(e));
+ log.error("GAO 快速登记失败", e);
+ throw new TimiException(TimiCode.ERROR, "GAO 快速登记失败", e);
+ } finally {
+ loggerService.create(logger);
+ }
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void update(GaoRegistrationEventRecord entity) {
- TimiException.required(entity, "not found record");
- TimiException.required(entity.getId(), "not found record.id");
- TimiException.required(entity.getCustomerId(), "not found record.customerId");
- TimiException.required(entity.getRegistrationEventId(), "not found record.registrationEventId");
- customerService.get(entity.getCustomerId());
- GaoRegistrationEvent registrationEvent = registrationEventService.get(entity.getRegistrationEventId());
- checkRegistrationEventPermission(registrationEvent);
- entity.setRegisteredAt(TimiJava.defaultIfNull(entity.getRegisteredAt(), Time.now()));
- super.update(entity);
- saveAttachment(entity.getId(), resolveAttachmentList(entity));
+ Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_RECORD_UPDATE");
+ try {
+ logger.setContent(jackson.writeValueAsString(entity));
+ TimiException.required(entity, "not found record");
+ TimiException.required(entity.getId(), "not found record.id");
+ TimiException.required(entity.getCustomerId(), "not found record.customerId");
+ TimiException.required(entity.getRegistrationEventId(), "not found record.registrationEventId");
+ customerService.get(entity.getCustomerId());
+ GaoRegistrationEvent registrationEvent = registrationEventService.get(entity.getRegistrationEventId());
+ checkRegistrationEventPermission(registrationEvent);
+ entity.setRegisteredAt(TimiJava.defaultIfNull(entity.getRegisteredAt(), Time.now()));
+ super.update(entity);
+ saveAttachment(entity.getId(), resolveAttachmentList(entity));
+ logger.setLevel(Logger.Level.INFO);
+ logger.setResult(entity.getId());
+ } catch (TimiException e) {
+ logger.setLevel(Logger.Level.WARN);
+ logger.setException(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.setLevel(Logger.Level.ERROR);
+ logger.setException(TimiJava.serializeThrowable(e));
+ log.error("修改 GAO 登记记录失败", e);
+ throw new TimiException(TimiCode.ERROR, "修改 GAO 登记记录失败", e);
+ } finally {
+ loggerService.create(logger);
+ }
}
@Override
@@ -279,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");
@@ -301,33 +427,53 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
return list;
}
- private String resolveCustomerId(GaoRegistrationEventRecordCreateReq req) {
- if (TimiJava.isNotEmpty(req.getCustomerId())) {
- customerService.get(req.getCustomerId());
- return req.getCustomerId();
+ private String resolveCustomerId(String customerId) {
+ TimiException.required(customerId, "not found customerId");
+ customerService.get(customerId);
+ return customerId;
+ }
+
+ private GaoRegistrationEventRecord doCreateRecord(GaoRegistrationEventRecordCreateReq req, String customerId) {
+ TimiException.required(req, "not found req");
+ TimiException.required(req.getRegistrationEventId(), "not found req.registrationEventId");
+ customerId = resolveCustomerId(customerId);
+ GaoRegistrationEvent registrationEvent = registrationEventService.get(req.getRegistrationEventId());
+ checkRegistrationEventPermission(registrationEvent);
+ long registeredAt = TimiJava.defaultIfNull(req.getRegisteredAt(), Time.now());
+ checkRegistrationEventCreatable(registrationEvent, customerId, registeredAt);
+ if (Boolean.TRUE.equals(registrationEvent.getRequirePhoto())) {
+ TimiException.requiredTrue(req.getAttachmentIdList() != null && !req.getAttachmentIdList().isEmpty(), "required record photo");
}
- TimiException.required(req.getCustomerCode(), "not found req.customerCode");
- GaoCustomer customer = customerService.getByCode(req.getCustomerCode());
- return customer.getId();
+
+ GaoRegistrationEventRecord record = new GaoRegistrationEventRecord();
+ record.setCustomerId(customerId);
+ record.setRegistrationEventId(req.getRegistrationEventId());
+ record.setOperatorUserId(userLoginService.getRequireLoginUserId());
+ record.setRemark(req.getRemark());
+ record.setRegisteredAt(registeredAt);
+ super.create(record);
+ saveAttachment(record.getId(), buildPhotoAttachmentList(req.getAttachmentIdList()));
+ return get(record.getId());
}
private void checkRegistrationEventPermission(GaoRegistrationEvent registrationEvent) {
List roleCodeList = registrationEventService.listRoleCode(registrationEvent.getId());
- if (roleCodeList != null && !roleCodeList.isEmpty()) {
- roleChecker.checkAny(ModuleCode.GAO, roleCodeList.toArray(String[]::new));
- }
+ TimiException.requiredTrue(roleCodeList != null && !roleCodeList.isEmpty(), "登记事件未配置可登记角色");
+ roleChecker.checkAny(ModuleCode.GAO, roleCodeList.toArray(String[]::new));
}
private void checkRegistrationEventCreatable(GaoRegistrationEvent registrationEvent, String customerId, long registeredAt) {
- TimiException.requiredTrue(Boolean.TRUE.equals(registrationEvent.getEnabled()), "登记事件未启用");
TimiException.requiredTrue(registrationEvent.getStatus() == null || registrationEvent.getStatus() == GaoRegistrationEvent.Status.ACTIVE, "登记事件不可登记");
- GaoRegistrationEvent.RegistrationLimitType limitType = TimiJava.defaultIfNull(registrationEvent.getLimitType(), GaoRegistrationEvent.RegistrationLimitType.NONE);
+ TimiException.requiredTrue(registrationEvent.getBeginAt() == null || registrationEvent.getBeginAt() <= registeredAt, "登记事件未到可登记时间");
+ TimiException.requiredTrue(registrationEvent.getEndAt() == null || registeredAt <= registrationEvent.getEndAt(), "登记事件已过可登记时间");
+ GaoRegistrationEvent.LimitType limitType = TimiJava.defaultIfNull(registrationEvent.getLimitType(), GaoRegistrationEvent.LimitType.NONE);
switch (limitType) {
case DAILY_HALF_DAY -> checkRegistrationLimitRange(customerId, registrationEvent.getId(), getHalfDayBegin(registeredAt), getHalfDayEnd(registeredAt), "该客户当前半日已登记该事件");
case NATURAL_DAY -> checkRegistrationLimitRange(customerId, registrationEvent.getId(), getDayBegin(registeredAt), getDayEnd(registeredAt), "该客户当日已登记该事件");
case INTERVAL_HOUR -> checkIntervalHourRegistrationLimit(registrationEvent, customerId, registeredAt);
case NATURAL_MONTH -> checkRegistrationLimitRange(customerId, registrationEvent.getId(), getMonthBegin(registeredAt), getMonthEnd(registeredAt), "该客户当月已登记该事件");
- case TOTAL_LIMIT -> checkTotalRegistrationLimit(registrationEvent, customerId);
+ case TOTAL_LIMIT -> checkTotalRegistrationLimit(registrationEvent);
+ case CUSTOMER_TOTAL_LIMIT -> checkCustomerTotalRegistrationLimit(registrationEvent, customerId);
default -> {
}
}
@@ -345,13 +491,20 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
checkRegistrationLimitRange(customerId, registrationEvent.getId(), beginRegisteredAt, registeredAt, "该客户登记该事件间隔不足");
}
- private void checkTotalRegistrationLimit(GaoRegistrationEvent registrationEvent, String customerId) {
+ private void checkCustomerTotalRegistrationLimit(GaoRegistrationEvent registrationEvent, String customerId) {
Integer limitValue = registrationEvent.getLimitValue();
- TimiException.requiredTrue(limitValue != null && 0 < limitValue, "登记事件累计次数配置错误");
+ TimiException.requiredTrue(limitValue != null && 0 < limitValue, "登记事件单客户总次数配置错误");
Long count = mapper.countByCustomerIdAndRegistrationEventId(customerId, registrationEvent.getId());
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < limitValue, "该客户登记该事件次数已达上限");
}
+ private void checkTotalRegistrationLimit(GaoRegistrationEvent registrationEvent) {
+ Integer limitValue = registrationEvent.getLimitValue();
+ TimiException.requiredTrue(limitValue != null && 0 < limitValue, "登记事件总次数配置错误");
+ Long count = mapper.countByRegistrationEventId(registrationEvent.getId());
+ TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < limitValue, "登记事件总次数已达上限");
+ }
+
private long getDayBegin(long registeredAt) {
ZoneId zoneId = ZoneId.systemDefault();
return Instant.ofEpochMilli(registeredAt).atZone(zoneId).toLocalDate().atStartOfDay(zoneId).toInstant().toEpochMilli();
@@ -428,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/service/implement/GaoRegistrationEventServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventServiceImplement.java
index 9e5b922..eda704e 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
@@ -1,17 +1,24 @@
package com.imyeyu.api.modules.gao.service.implement;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
-import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRoleRelation;
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent;
-import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventRoleRelationMapper;
+import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRoleRelation;
import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventMapper;
+import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventRoleRelationMapper;
import com.imyeyu.api.modules.gao.service.GaoRegistrationEventService;
+import com.imyeyu.api.modules.system.entity.Logger;
+import com.imyeyu.api.modules.system.service.LoggerService;
+import com.imyeyu.java.TimiJava;
+import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.spring.bean.Page;
import com.imyeyu.spring.bean.PageResult;
import com.imyeyu.spring.mapper.BaseMapper;
import com.imyeyu.spring.service.AbstractEntityService;
+import com.imyeyu.utils.Time;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -25,12 +32,17 @@ import java.util.stream.Collectors;
///
/// 登记事件服务实现
///
-/// @author Codex
-/// @since 2026-07-27
+/// @author 夜雨
+/// @since 2026-07-27 09:00
+@Slf4j
@Service
@RequiredArgsConstructor
public class GaoRegistrationEventServiceImplement extends AbstractEntityService implements GaoRegistrationEventService {
+ private final ObjectMapper jackson;
+
+ private final LoggerService loggerService;
+
private final GaoRegistrationEventMapper mapper;
private final GaoRegistrationEventRoleRelationMapper roleRelationMapper;
@@ -42,9 +54,7 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
@Override
public PageResult pageWithRegistrationEventLimit(Page page) {
PageResult result = page(page);
- result.setList(result.getList().stream()
- .filter(item -> item.getStatus() != GaoRegistrationEvent.Status.DELETED)
- .toList());
+ result.setList(result.getList().stream().filter(item -> item.getStatus() != GaoRegistrationEvent.Status.DELETED).toList());
loadRegistrationEventLimit(result.getList());
return result;
}
@@ -52,26 +62,90 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void create(GaoRegistrationEvent entity) {
- checkEntity(entity, false);
- super.create(entity);
- saveRoleRelation(entity.getId(), entity.getRoleCodeList());
+ Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_CREATE");
+ try {
+ logger.setContent(jackson.writeValueAsString(entity));
+ checkEntity(entity, false);
+ super.create(entity);
+ saveRoleRelation(entity.getId(), entity.getRoleCodeList());
+ logger.setLevel(Logger.Level.INFO);
+ logger.setResult(entity.getId());
+ } catch (TimiException e) {
+ logger.setLevel(Logger.Level.WARN);
+ logger.setException(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.setLevel(Logger.Level.ERROR);
+ logger.setException(TimiJava.serializeThrowable(e));
+ log.error("新增 GAO 登记事件失败", e);
+ throw new TimiException(TimiCode.ERROR, "新增 GAO 登记事件失败", e);
+ } finally {
+ loggerService.create(logger);
+ }
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void update(GaoRegistrationEvent entity) {
- checkEntity(entity, true);
- super.update(entity);
- saveRoleRelation(entity.getId(), entity.getRoleCodeList());
+ Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_UPDATE");
+ try {
+ logger.setContent(jackson.writeValueAsString(entity));
+ Integer sort = entity.getSort();
+ checkEntity(entity, true);
+ GaoRegistrationEvent current = get(entity.getId());
+ current.setName(entity.getName());
+ current.setDescription(entity.getDescription());
+ current.setColor(entity.getColor());
+ current.setStatus(entity.getStatus());
+ current.setRequirePhoto(entity.getRequirePhoto());
+ current.setLimitType(entity.getLimitType());
+ current.setLimitValue(entity.getLimitValue());
+ current.setBeginAt(entity.getBeginAt());
+ current.setEndAt(entity.getEndAt());
+ if (sort != null) {
+ current.setSort(sort);
+ }
+ mapper.update(current);
+ saveRoleRelation(entity.getId(), entity.getRoleCodeList());
+ logger.setLevel(Logger.Level.INFO);
+ logger.setResult(entity.getId());
+ } catch (TimiException e) {
+ logger.setLevel(Logger.Level.WARN);
+ logger.setException(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.setLevel(Logger.Level.ERROR);
+ logger.setException(TimiJava.serializeThrowable(e));
+ log.error("修改 GAO 登记事件失败", e);
+ throw new TimiException(TimiCode.ERROR, "修改 GAO 登记事件失败", e);
+ } finally {
+ loggerService.create(logger);
+ }
}
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void delete(String id) {
- GaoRegistrationEvent entity = get(id);
- entity.setStatus(GaoRegistrationEvent.Status.DELETED);
- entity.setEnabled(false);
- super.update(entity);
+ Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_DELETE");
+ try {
+ logger.setContent(id);
+ GaoRegistrationEvent entity = get(id);
+ entity.setStatus(GaoRegistrationEvent.Status.DELETED);
+ super.update(entity);
+ logger.setLevel(Logger.Level.INFO);
+ logger.setResult(id);
+ } catch (TimiException e) {
+ logger.setLevel(Logger.Level.WARN);
+ logger.setException(e.getMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.setLevel(Logger.Level.ERROR);
+ logger.setException(TimiJava.serializeThrowable(e));
+ log.error("删除 GAO 登记事件失败", e);
+ throw new TimiException(TimiCode.ERROR, "删除 GAO 登记事件失败", e);
+ } finally {
+ loggerService.create(logger);
+ }
}
@Override
@@ -83,8 +157,9 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
@Override
public List listEnabled() {
- List list = mapper.selectEnabledList();
+ List list = mapper.selectEnabledList(Time.now());
loadRegistrationEventLimit(list);
+ list = list.stream().filter(item -> !TimiJava.isEmpty(item.getRoleCodeList())).toList();
return list;
}
@@ -93,6 +168,22 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
return roleRelationMapper.selectRoleCodeListByRegistrationEventId(registrationEventId);
}
+ @Transactional(TimiServerDBConfig.ROLLBACKER)
+ @Override
+ public void sort(List idList) {
+ if (idList == null || idList.isEmpty()) {
+ return;
+ }
+ List distinctIdList = new ArrayList<>(new LinkedHashSet<>(idList));
+ Map eventMap = mapper.selectByIdList(distinctIdList).stream().collect(Collectors.toMap(GaoRegistrationEvent::getId, item -> item));
+ TimiException.requiredTrue(eventMap.size() == distinctIdList.size(), "not found registrationEvent");
+ for (int index = 0; index < distinctIdList.size(); index++) {
+ GaoRegistrationEvent registrationEvent = eventMap.get(distinctIdList.get(index));
+ registrationEvent.setSort(index);
+ mapper.update(registrationEvent);
+ }
+ }
+
private void checkEntity(GaoRegistrationEvent entity, boolean requireId) {
TimiException.required(entity, "not found registrationEvent");
if (requireId) {
@@ -102,16 +193,17 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
if (entity.getStatus() == null) {
entity.setStatus(GaoRegistrationEvent.Status.ACTIVE);
}
- if (entity.getEnabled() == null) {
- entity.setEnabled(true);
- }
if (entity.getRequirePhoto() == null) {
entity.setRequirePhoto(false);
}
if (entity.getLimitType() == null) {
- entity.setLimitType(GaoRegistrationEvent.RegistrationLimitType.NONE);
+ entity.setLimitType(GaoRegistrationEvent.LimitType.NONE);
}
+ TimiException.requiredTrue(entity.getRoleCodeList() != null && entity.getRoleCodeList()
+ .stream()
+ .anyMatch(item -> item != null && !item.isBlank()), "not found registrationEvent.roleCodeList");
checkRegistrationLimit(entity);
+ checkRegisterablePeriod(entity);
if (entity.getColor() != null) {
entity.setColor(entity.getColor().trim());
}
@@ -121,8 +213,7 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
}
private void checkRegistrationLimit(GaoRegistrationEvent entity) {
- if (entity.getLimitType() == GaoRegistrationEvent.RegistrationLimitType.INTERVAL_HOUR
- || entity.getLimitType() == GaoRegistrationEvent.RegistrationLimitType.TOTAL_LIMIT) {
+ if (entity.getLimitType() == GaoRegistrationEvent.LimitType.INTERVAL_HOUR || entity.getLimitType() == GaoRegistrationEvent.LimitType.TOTAL_LIMIT || entity.getLimitType() == GaoRegistrationEvent.LimitType.CUSTOMER_TOTAL_LIMIT) {
TimiException.required(entity.getLimitValue(), "not found registrationEvent.limitValue");
TimiException.requiredTrue(0 < entity.getLimitValue(), "registrationEvent.limitValue lte 0");
return;
@@ -130,6 +221,13 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
entity.setLimitValue(null);
}
+ private void checkRegisterablePeriod(GaoRegistrationEvent entity) {
+ if (entity.getBeginAt() == null && entity.getEndAt() == null) {
+ return;
+ }
+ TimiException.requiredTrue(entity.getBeginAt() == null || entity.getEndAt() == null || entity.getBeginAt() <= entity.getEndAt(), "registrationEvent.beginAt gt registrationEvent.endAt");
+ }
+
private void saveRoleRelation(String registrationEventId, List roleCodeList) {
roleRelationMapper.deleteByRegistrationEventId(registrationEventId);
if (roleCodeList == null || roleCodeList.isEmpty()) {
@@ -147,23 +245,14 @@ 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())
- ));
+ 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/service/implement/GaoUserServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoUserServiceImplement.java
index 2ae6121..1ec583b 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoUserServiceImplement.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoUserServiceImplement.java
@@ -1,10 +1,13 @@
package com.imyeyu.api.modules.gao.service.implement;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.imyeyu.api.bean.ModuleCode;
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
import com.imyeyu.api.modules.gao.entity.GaoUser;
import com.imyeyu.api.modules.gao.mapper.GaoUserMapper;
import com.imyeyu.api.modules.gao.service.GaoUserService;
+import com.imyeyu.api.modules.system.entity.Logger;
+import com.imyeyu.api.modules.system.service.LoggerService;
import com.imyeyu.api.modules.user.entity.Role;
import com.imyeyu.api.modules.user.entity.User;
import com.imyeyu.api.modules.user.mapper.UserMapper;
@@ -14,12 +17,14 @@ import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeReq;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
+import com.imyeyu.spring.TimiSpring;
import com.imyeyu.spring.bean.Page;
import com.imyeyu.spring.bean.PageResult;
import com.imyeyu.spring.mapper.BaseMapper;
import com.imyeyu.spring.service.AbstractEntityService;
import com.imyeyu.utils.Time;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -34,11 +39,14 @@ import java.util.stream.Collectors;
///
/// @author Codex
/// @since 2026-07-30
+@Slf4j
@Service
@RequiredArgsConstructor
public class GaoUserServiceImplement extends AbstractEntityService implements GaoUserService {
private final GaoUserMapper mapper;
+ private final ObjectMapper jackson;
+ private final LoggerService loggerService;
private final UserMapper userMapper;
private final UserService userService;
private final RoleService roleService;
@@ -51,20 +59,54 @@ public class GaoUserServiceImplement extends AbstractEntityService customerIdList = new ArrayList<>();
/// 登记事件 ID
private String registrationEventId;
diff --git a/src/main/java/com/imyeyu/api/modules/system/entity/Logger.java b/src/main/java/com/imyeyu/api/modules/system/entity/Logger.java
index 3efbb96..65d4ab8 100644
--- a/src/main/java/com/imyeyu/api/modules/system/entity/Logger.java
+++ b/src/main/java/com/imyeyu/api/modules/system/entity/Logger.java
@@ -17,6 +17,21 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
public class Logger implements IDEntity, Creatable {
+ ///
+ ///
+ /// @author 夜雨
+ /// @since 2026-08-03 11:43
+ public enum Module {
+
+ SYSTEM,
+
+ COMMON,
+
+ USER,
+
+ GAO,
+ }
+
/**
* 日志级别
*
@@ -43,7 +58,7 @@ public class Logger implements IDEntity, Creatable {
private Level level;
/** 模块名称 */
- private String module;
+ private Module module;
/** 操作描述 */
private String operation;
@@ -69,7 +84,26 @@ public class Logger implements IDEntity, Creatable {
/** 创建时间 */
private Long createdAt;
- public Logger(Level level) {
+ public Logger(Module module, String operation) {
+ this.module = module;
+ this.operation = operation;
+ }
+
+ public Logger(Module module, Level level, String operation) {
+ this.module = module;
this.level = level;
+ this.operation = operation;
+ }
+
+ public static Logger info(Module module, String operation) {
+ return new Logger(module, Level.INFO, operation);
+ }
+
+ public static Logger warning(Module module, String operation) {
+ return new Logger(module, Level.WARN, operation);
+ }
+
+ public static Logger error(Module module, String operation) {
+ return new Logger(module, Level.ERROR, operation);
}
}
diff --git a/src/main/java/com/imyeyu/api/modules/system/service/LoggerService.java b/src/main/java/com/imyeyu/api/modules/system/service/LoggerService.java
index 7d4b2fe..45e4463 100644
--- a/src/main/java/com/imyeyu/api/modules/system/service/LoggerService.java
+++ b/src/main/java/com/imyeyu/api/modules/system/service/LoggerService.java
@@ -16,41 +16,29 @@ public interface LoggerService extends GettableService, Pageable
void createSync(Logger logger);
- void create(Logger.Level level, String module, String operation, String userId, String content, String result);
+ void create(Logger.Module module, Logger.Level level, String operation, String content, String result);
- default void info(String module, String operation, String userId) {
- create(Logger.Level.INFO, module, operation, userId, null, null);
+ default void info(Logger.Module module, String operation) {
+ create(module, Logger.Level.INFO, operation, null, null);
}
- default void info(String module, String operation, String content, String result) {
- create(Logger.Level.INFO, module, operation, null, content, result);
+ default void info(Logger.Module module, String operation, String content, String result) {
+ create(module, Logger.Level.INFO, operation, content, result);
}
- default void info(String module, String operation, String userId, String content, String result) {
- create(Logger.Level.INFO, module, operation, userId, content, result);
+ default void warning(Logger.Module module, String operation) {
+ create(module, Logger.Level.WARN, operation, null, null);
}
- default void warning(String module, String operation, String userId) {
- create(Logger.Level.WARN, module, operation, userId, null, null);
+ default void warning(Logger.Module module, String operation, String content, String result) {
+ create(module, Logger.Level.WARN, operation, content, result);
}
- default void warning(String module, String operation, String content, String result) {
- create(Logger.Level.WARN, module, operation, null, content, result);
+ default void error(Logger.Module module, String operation) {
+ create(module, Logger.Level.ERROR, operation, null, null);
}
- default void warning(String module, String operation, String userId, String content, String result) {
- create(Logger.Level.WARN, module, operation, userId, content, result);
- }
-
- default void error(String module, String operation, String userId) {
- create(Logger.Level.ERROR, module, operation, userId, null, null);
- }
-
- default void error(String module, String operation, String content, String result) {
- create(Logger.Level.ERROR, module, operation, null, content, result);
- }
-
- default void error(String module, String operation, String userId, String content, String result) {
- create(Logger.Level.ERROR, module, operation, userId, content, result);
+ default void error(Logger.Module module, String operation, String content, String result) {
+ create(module, Logger.Level.ERROR, operation, content, result);
}
}
diff --git a/src/main/java/com/imyeyu/api/modules/system/service/implement/LoggerServiceImplement.java b/src/main/java/com/imyeyu/api/modules/system/service/implement/LoggerServiceImplement.java
index 4a7ac4e..5e849c8 100644
--- a/src/main/java/com/imyeyu/api/modules/system/service/implement/LoggerServiceImplement.java
+++ b/src/main/java/com/imyeyu/api/modules/system/service/implement/LoggerServiceImplement.java
@@ -3,6 +3,10 @@ package com.imyeyu.api.modules.system.service.implement;
import com.imyeyu.api.modules.system.entity.Logger;
import com.imyeyu.api.modules.system.mapper.LoggerMapper;
import com.imyeyu.api.modules.system.service.LoggerService;
+import com.imyeyu.api.modules.user.entity.User;
+import com.imyeyu.api.modules.user.service.UserLoginService;
+import com.imyeyu.java.TimiJava;
+import com.imyeyu.spring.TimiSpring;
import com.imyeyu.spring.mapper.BaseMapper;
import com.imyeyu.spring.service.AbstractEntityService;
import lombok.RequiredArgsConstructor;
@@ -18,6 +22,8 @@ import org.springframework.stereotype.Service;
@RequiredArgsConstructor
public class LoggerServiceImplement extends AbstractEntityService implements LoggerService {
+ private final UserLoginService userLoginService;
+
private final LoggerMapper mapper;
@Override
@@ -28,19 +34,23 @@ public class LoggerServiceImplement extends AbstractEntityService super.create(logger));
+ Thread.startVirtualThread(() -> createSync(logger));
}
@Override
public void createSync(Logger logger) {
+ if (TimiJava.isEmpty(logger.getUserId())) {
+ User loginUser = userLoginService.getLoginUser();
+ if (TimiJava.isNotEmpty(loginUser)) {
+ logger.setUserId(loginUser.getId());
+ }
+ }
+ logger.setIp(TimiJava.defaultIfEmpty(logger.getIp(), TimiSpring.getRequestIP()));
super.create(logger);
}
- public void create(Logger.Level level, String module, String operation, String userId, String content, String result) {
- Logger log = new Logger(level);
- log.setModule(module);
- log.setOperation(operation);
- log.setUserId(userId);
+ public void create(Logger.Module module, Logger.Level level, String operation, String content, String result) {
+ Logger log = new Logger(module, level, operation);
log.setContent(content);
log.setResult(result);
create(log);
diff --git a/src/main/java/com/imyeyu/api/modules/user/service/implement/UserLoginServiceImplement.java b/src/main/java/com/imyeyu/api/modules/user/service/implement/UserLoginServiceImplement.java
index ca9c817..8977985 100644
--- a/src/main/java/com/imyeyu/api/modules/user/service/implement/UserLoginServiceImplement.java
+++ b/src/main/java/com/imyeyu/api/modules/user/service/implement/UserLoginServiceImplement.java
@@ -25,8 +25,8 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
/// 用户登录服务实现
///
@@ -95,7 +95,9 @@ public class UserLoginServiceImplement implements UserLoginService, TimiJava {
@Override
public User getLoginUser() {
String token = TimiSpring.getToken();
- TimiException.required(token, "not found token");
+ if (TimiJava.isEmpty(token)) {
+ return null;
+ }
String userId = redisUserToken.get(getUserTokenKey(token));
if (TimiJava.isEmpty(userId)) {
return null;
diff --git a/src/main/java/com/imyeyu/api/util/InitBuiltinUser.java b/src/main/java/com/imyeyu/api/util/InitBuiltinUser.java
index 7ca70d9..5850f68 100644
--- a/src/main/java/com/imyeyu/api/util/InitBuiltinUser.java
+++ b/src/main/java/com/imyeyu/api/util/InitBuiltinUser.java
@@ -1,10 +1,11 @@
package com.imyeyu.api.util;
-import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
import com.imyeyu.api.bean.ModuleCode;
+import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
import com.imyeyu.api.modules.common.bean.ImageType;
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
+import com.imyeyu.api.modules.system.entity.Logger;
import com.imyeyu.api.modules.system.service.LoggerService;
import com.imyeyu.api.modules.user.bean.BootstrapData;
import com.imyeyu.api.modules.user.bean.BuiltinAuthRegistry;
@@ -92,7 +93,13 @@ public class InitBuiltinUser implements ApplicationRunner {
userService.create(user);
String logContent = "初始化 %s 自举用户成功,请立即修改密码:%s".formatted(BootstrapData.SYS_USER_NAME, password);
- loggerService.info("SYSTEM", "INITIALIZE_SYSTEM_USER", user.getId(), logContent, null);
+
+ Logger logger = new Logger();
+ logger.setModule(Logger.Module.SYSTEM);
+ logger.setOperation("INITIALIZE_SYSTEM_USER");
+ logger.setUserId(user.getId());
+ logger.setContent(logContent);
+ loggerService.create(logger);
}
// 授权系统用户角色
{
diff --git a/src/main/resources/db/migration/timiserver/V21__adjust_gao_registration_event_rule.sql b/src/main/resources/db/migration/timiserver/V21__adjust_gao_registration_event_rule.sql
new file mode 100644
index 0000000..6052d40
--- /dev/null
+++ b/src/main/resources/db/migration/timiserver/V21__adjust_gao_registration_event_rule.sql
@@ -0,0 +1,7 @@
+ALTER TABLE `gao_registration_event`
+ DROP KEY `idx_gao_registration_event_status`,
+ DROP COLUMN `enabled`,
+ MODIFY COLUMN `status` VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态,DRAFT 草稿,ACTIVE 可登记,INACTIVE 不可登记,DELETED 已删除',
+ ADD COLUMN `begin_at` BIGINT NULL COMMENT '可登记起始时间戳,毫秒,空为不限制' AFTER `limit_value`,
+ ADD COLUMN `end_at` BIGINT NULL COMMENT '可登记终止时间戳,毫秒,空为不限制' AFTER `begin_at`,
+ ADD KEY `idx_gao_registration_event_status` (`status`, `deleted_at`, `sort`, `created_at`);
diff --git a/src/main/resources/db/migration/timiserver/V22__add_gao_customer_birthdate.sql b/src/main/resources/db/migration/timiserver/V22__add_gao_customer_birthdate.sql
new file mode 100644
index 0000000..99e8167
--- /dev/null
+++ b/src/main/resources/db/migration/timiserver/V22__add_gao_customer_birthdate.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `gao_customer`
+ ADD COLUMN `birthdate` DATE NULL COMMENT '出生日期,统一保存为公历' AFTER `gender`,
+ ADD COLUMN `birthdate_calendar` VARCHAR(16) NOT NULL DEFAULT 'SOLAR' COMMENT '出生日期录入历法,SOLAR 公历,LUNAR 农历' AFTER `birthdate`;
diff --git a/src/main/resources/mapper/timi-server/GaoRegistrationEventMapper.xml b/src/main/resources/mapper/timi-server/GaoRegistrationEventMapper.xml
index 8c53a1c..9709039 100644
--- a/src/main/resources/mapper/timi-server/GaoRegistrationEventMapper.xml
+++ b/src/main/resources/mapper/timi-server/GaoRegistrationEventMapper.xml
@@ -18,4 +18,16 @@
AND `deleted_at` IS NULL
+
+
diff --git a/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml b/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml
index ae8ec61..12e0902 100644
--- a/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml
+++ b/src/main/resources/mapper/timi-server/GaoRegistrationEventRecordMapper.xml
@@ -42,6 +42,15 @@
AND `deleted_at` IS NULL
+
+
+
+