diff --git a/pom.xml b/pom.xml
index 4b26d3f..79c07ea 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
com.imyeyu.timiserverapi
TimiServerAPI
- 1.0.26
+ 1.0.27
jar
TimiServerAPI
imyeyu.com API
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 7b46191..b66ff8a 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
@@ -43,6 +43,8 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
EVENT_RECORD_READ("EVENT_RECORD:READ", "登记事件记录读取", false, false),
+ EVENT_RECORD_VERIFY("EVENT_RECORD:VERIFY", "登记事件核销", true, false),
+
EVENT_RECORD_EXPORT("EVENT_RECORD:EXPORT", "登记事件记录导出", true, false),
EVENT_RECORD_UPDATE("EVENT_RECORD:UPDATE", "登记事件记录修改", false, false),
diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoEventRecordController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoEventRecordController.java
index 44a6a25..46f0fa8 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoEventRecordController.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoEventRecordController.java
@@ -111,10 +111,24 @@ public class GaoEventRecordController {
record.getCustomer().setAttachmentList(attachmentService.listByBizId(Attachment.BizType.GAO_CUSTOMER, record.getCustomerId()));
record.setEvent(eventService.get(record.getEventId()));
record.setOperator(userService.get(record.getOperatorUserId()));
+ if (record.getVerifierUserId() != null) {
+ record.setVerifier(userService.get(record.getVerifierUserId()));
+ }
record.setAttachmentList(attachmentService.listByBizId(Attachment.BizType.GAO_EVENT_RECORD, record.getId()));
return record;
}
+ @AOPLog
+ @RequestRateLimit
+ @RequireGaoPermission(GaoPermissionCode.EVENT_RECORD_VERIFY)
+ @PostMapping("/verify")
+ public void verify(@RequestParam String id) {
+ GaoEventRecord record = service.get(id);
+ TimiException.required(record, "not found event record");
+ storeScopeService.checkStoreId(record.getStoreId());
+ service.verify(id);
+ }
+
@AOPLog
@RequestRateLimit
@RequireGaoPermission(GaoPermissionCode.EVENT_RECORD_CREATE)
diff --git a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoEvent.java b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoEvent.java
index df33b56..28ff496 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoEvent.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoEvent.java
@@ -117,6 +117,9 @@ public class GaoEvent extends UUIDEntity {
/// true 为登记时要求拍照
private Boolean requirePhoto;
+ /// true 为登记记录需要核销
+ private Boolean requireVerification;
+
/// 登记限制类型
private LimitType limitType;
diff --git a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoEventRecord.java b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoEventRecord.java
index 757a4cd..964dffc 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/entity/GaoEventRecord.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/entity/GaoEventRecord.java
@@ -18,6 +18,23 @@ import java.util.List;
@EqualsAndHashCode(callSuper = true)
public class GaoEventRecord extends UUIDEntity {
+ ///
+ /// 登记记录核销状态
+ ///
+ /// @author Codex
+ /// @since 2026-08-29
+ public enum VerificationStatus {
+
+ /// 该事件不需要核销
+ NOT_REQUIRED,
+
+ /// 等待核销
+ PENDING,
+
+ /// 已核销
+ VERIFIED
+ }
+
///
/// 登记事件记录附件类型
///
@@ -49,6 +66,15 @@ public class GaoEventRecord extends UUIDEntity {
/// 本次登记提交的整数业务数值
private Long numberValue;
+ /// 核销状态
+ private VerificationStatus verificationStatus;
+
+ /// 核销用户 ID
+ private String verifierUserId;
+
+ /// 核销时间
+ private Long verifiedAt;
+
/// 备注
private String remark;
@@ -70,6 +96,9 @@ public class GaoEventRecord extends UUIDEntity {
@Transient
private User operator;
+ @Transient
+ private User verifier;
+
@Transient
private List attachmentList;
diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoEventRecordMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoEventRecordMapper.java
index 5e7a644..6527854 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoEventRecordMapper.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoEventRecordMapper.java
@@ -44,6 +44,14 @@ public interface GaoEventRecordMapper extends BaseMapper
/// @param earnedPointValue 获得积分总和
void updateEarnedPointValue(@Param("id") String id, @Param("earnedPointValue") Long earnedPointValue);
+ /// 原子更新登记记录核销状态
+ ///
+ /// @param id 登记记录 ID
+ /// @param verifierUserId 核销用户 ID
+ /// @param verifiedAt 核销时间
+ /// @return 更新行数
+ int verify(@Param("id") String id, @Param("verifierUserId") String verifierUserId, @Param("verifiedAt") Long verifiedAt);
+
/// 按门店和登记日期统计登记记录数
///
/// @param storeId 门店 ID
diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/GaoEventRecordService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoEventRecordService.java
index 6d3744a..3cb8326 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/service/GaoEventRecordService.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoEventRecordService.java
@@ -24,6 +24,11 @@ public interface GaoEventRecordService extends BaseService listByCustomerId(String customerId);
+ /// 核销登记事件记录
+ ///
+ /// @param id 登记记录 ID
+ void verify(String id);
+
default void createBatch(List recordList) {
for (GaoEventRecord record : TimiJava.safeIterable(recordList)) {
create(record);
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 a3f45e7..d070e4d 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
@@ -157,17 +157,18 @@ public class GaoCustomerServiceImplement extends AbstractEntityService recordList) {
+ Set usedTempFileIdSet = new HashSet<>();
for (GaoEventRecord record : TimiJava.safeIterable(recordList)) {
+ TimiException.required(record, "not found record");
+ prepareBatchAttachments(record, usedTempFileIdSet);
create(record);
}
}
+ private void prepareBatchAttachments(GaoEventRecord record, Set usedTempFileIdSet) {
+ for (Attachment attachment : TimiJava.safeIterable(record.getAttachmentList())) {
+ if (attachment == null || TimiJava.isEmpty(attachment.getTempFileId()) || usedTempFileIdSet.add(attachment.getTempFileId())) {
+ continue;
+ }
+ Attachment clone = attachmentService.clone(attachment.getTempFileId());
+ TimiException.required(clone.getId(), "登记照片临时附件复制失败");
+ attachment.setTempFileId(clone.getId());
+ }
+ }
+
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void update(GaoEventRecord record) {
@@ -190,6 +238,7 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService attachmentList) {
+ if (!Boolean.TRUE.equals(event.getRequirePhoto())) {
+ return;
+ }
+ boolean hasPhoto = false;
+ for (Attachment attachment : TimiJava.safeIterable(attachmentList)) {
+ if (attachment != null && (attachment.getAttachType() == null || GaoEventRecord.AttachType.PHOTO.name().equalsIgnoreCase(attachment.getAttachType()))) {
+ hasPhoto = true;
+ break;
+ }
+ }
+ TimiException.requiredTrue(hasPhoto, "该事件必须上传照片");
+ }
+
private void verifyImmutableRecordFields(GaoEventRecord request, GaoEventRecord dbRecord) {
TimiException.requiredTrue(request.getCustomerId() == null || request.getCustomerId().equals(dbRecord.getCustomerId()), "登记记录 customerId 创建后不可修改");
TimiException.requiredTrue(request.getEventId() == null || request.getEventId().equals(dbRecord.getEventId()), "登记记录 eventId 创建后不可修改");
diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoEventServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoEventServiceImplement.java
index 9a42fb4..ac4a5b9 100644
--- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoEventServiceImplement.java
+++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoEventServiceImplement.java
@@ -69,6 +69,7 @@ public class GaoEventServiceImplement extends AbstractEntityService eventIdList;
+ /// 核销状态,为空查询全部状态
+ private GaoEventRecord.VerificationStatus verificationStatus;
+
/// 关键词,匹配客户、登记事件、备注、登记人
private String keyword;
diff --git a/src/main/resources/db/migration/timiserver/V45__add_gao_event_verification.sql b/src/main/resources/db/migration/timiserver/V45__add_gao_event_verification.sql
new file mode 100644
index 0000000..c29d0b2
--- /dev/null
+++ b/src/main/resources/db/migration/timiserver/V45__add_gao_event_verification.sql
@@ -0,0 +1,8 @@
+ALTER TABLE `gao_event`
+ ADD COLUMN `require_verification` BIT(1) NOT NULL DEFAULT b'0' COMMENT 'true 为登记记录需要核销' AFTER `require_photo`;
+
+ALTER TABLE `gao_event_record`
+ ADD COLUMN `verification_status` VARCHAR(32) NOT NULL DEFAULT 'NOT_REQUIRED' COMMENT '核销状态,NOT_REQUIRED 无需核销,PENDING 待核销,VERIFIED 已核销' AFTER `number_value`,
+ ADD COLUMN `verifier_user_id` VARCHAR(36) NULL COMMENT '核销用户 ID' AFTER `verification_status`,
+ ADD COLUMN `verified_at` BIGINT NULL COMMENT '核销时间,毫秒' AFTER `verifier_user_id`,
+ ADD KEY `idx_gao_event_record_store_verification` (`store_id`, `verification_status`, `deleted_at`, `registered_at`);
diff --git a/src/main/resources/mapper/timi-server/gao/GaoEventRecordMapper.xml b/src/main/resources/mapper/timi-server/gao/GaoEventRecordMapper.xml
index c20aca6..1a1b425 100644
--- a/src/main/resources/mapper/timi-server/gao/GaoEventRecordMapper.xml
+++ b/src/main/resources/mapper/timi-server/gao/GaoEventRecordMapper.xml
@@ -59,6 +59,19 @@
AND `deleted_at` IS NULL
+
+ UPDATE `gao_event_record`
+ SET
+ `verification_status` = 'VERIFIED',
+ `verifier_user_id` = #{verifierUserId},
+ `verified_at` = #{verifiedAt},
+ `updated_at` = ROUND(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000)
+ WHERE
+ `id` = #{id}
+ AND `verification_status` = 'PENDING'
+ AND `deleted_at` IS NULL
+
+