diff --git a/pom.xml b/pom.xml index c36e621..93cea25 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 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 c627f26..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, @@ -55,8 +58,11 @@ public class GaoRegistrationEvent extends UUIDEntity { /// 每个自然月一次 NATURAL_MONTH, - /// 累计限 N 次 - TOTAL_LIMIT + /// 事件总登记次数上限 + TOTAL_LIMIT, + + /// 单个客户总登记次数上限 + CUSTOMER_TOTAL_LIMIT } /// 登记事件名称 @@ -71,9 +77,6 @@ public class GaoRegistrationEvent extends UUIDEntity { /// 状态 private Status status; - /// true 为启用 - private Boolean enabled; - /// true 为登记时要求拍照 private Boolean requirePhoto; @@ -83,6 +86,12 @@ public class GaoRegistrationEvent extends UUIDEntity { /// 登记限制数值,按限制类型表示小时数或次数 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..6862342 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 @@ -43,6 +43,12 @@ public interface GaoRegistrationEventRecordMapper extends BaseMapper 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, "登记事件不可登记"); + 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 +346,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(); 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 b8809b7..1381064 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 @@ -6,11 +6,13 @@ import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent; import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventRoleRelationMapper; import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventMapper; import com.imyeyu.api.modules.gao.service.GaoRegistrationEventService; +import com.imyeyu.java.TimiJava; 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 org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -61,7 +63,18 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService< @Override public void update(GaoRegistrationEvent entity) { checkEntity(entity, true); - super.update(entity); + 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()); + current.setSort(entity.getSort()); + mapper.update(current); saveRoleRelation(entity.getId(), entity.getRoleCodeList()); } @@ -70,7 +83,6 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService< public void delete(String id) { GaoRegistrationEvent entity = get(id); entity.setStatus(GaoRegistrationEvent.Status.DELETED); - entity.setEnabled(false); super.update(entity); } @@ -83,8 +95,11 @@ 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; } @@ -102,16 +117,18 @@ 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.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()); } @@ -122,7 +139,8 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService< private void checkRegistrationLimit(GaoRegistrationEvent entity) { if (entity.getLimitType() == GaoRegistrationEvent.LimitType.INTERVAL_HOUR - || entity.getLimitType() == GaoRegistrationEvent.LimitType.TOTAL_LIMIT) { + || 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 +148,16 @@ 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()) { 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/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..6160ed8 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 + +