diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/BindInviteCodeExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/BindInviteCodeExe.java index 87dfc91b..2a50d356 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/BindInviteCodeExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/BindInviteCodeExe.java @@ -1,6 +1,7 @@ package com.red.circle.other.app.command.activity; import com.red.circle.component.redis.service.RedisService; +import com.red.circle.framework.dto.ResultResponse; import com.red.circle.other.app.command.user.InviteCodeService; import com.red.circle.other.app.dto.cmd.SpinsTaskProgressUpdateCmd; import com.red.circle.other.app.dto.cmd.activity.BindInviteCodeCmd; @@ -10,6 +11,7 @@ import com.red.circle.other.domain.model.user.UserProfile; import com.red.circle.other.infra.database.rds.entity.user.user.UserInviteUser; import com.red.circle.other.infra.database.rds.service.user.user.UserInviteUserService; import com.red.circle.other.infra.enums.user.InviteTypeEnum; +import com.red.circle.other.inner.endpoint.user.device.RegisterDeviceClient; import com.red.circle.tool.core.date.TimestampUtils; import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils; import com.red.circle.tool.core.sequence.IdWorkerUtils; @@ -41,6 +43,7 @@ public class BindInviteCodeExe { private final InviteCodeService inviteCodeService; private final RedisService redisService; private final SpinsUserTaskProgressService spinsUserTaskProgressService; + private final RegisterDeviceClient registerDeviceClient; /** * 执行绑定邀请码 @@ -56,7 +59,19 @@ public class BindInviteCodeExe { log.info("开始绑定邀请码, userId={}, inviteCode={}, inviteType={}", userId, inviteCode, inviteType); - // 1. 校验inviteType是否合法 + // 0. 每个设备只允许绑定一次 + String deviceId = getDeviceId(userId); + String deviceBindKey = "invite:device:bind:" + deviceId; + + // 检查该设备是否已经绑定过 + String boundUserId = redisService.getString(deviceBindKey); + if (StringUtils.isNotBlank(boundUserId)) { + log.warn("该设备已绑定过邀请码,不允许重复绑定, deviceId={}, boundUserId={}, currentUserId={}", + deviceId, boundUserId, userId); + throw new RuntimeException("This device has already bound an invitation code and cannot bind again"); + } + + // 1. 校验inviteType是否合法 if (!InviteTypeEnum.LOTTERY.getCode().equals(inviteType) && !InviteTypeEnum.REGISTER.getCode().equals(inviteType)) { throw new RuntimeException("Invalid invitation type, must be LOTTERY or REGISTER"); @@ -140,8 +155,11 @@ public class BindInviteCodeExe { userInviteUserService.save(inviteUser); - log.info("绑定邀请码成功, userId={}, inviterUserId={}, inviteCode={}, inviteType={}", - userId, inviterProfile.getId(), inviteCode, inviteType); + // 记录该设备已绑定(永久有效) + redisService.setString(deviceBindKey, userId.toString()); + + log.info("绑定邀请码成功, userId={}, inviterUserId={}, inviteCode={}, inviteType={}, deviceId={}", + userId, inviterProfile.getId(), inviteCode, inviteType, deviceId); // 增加用户每日邀请用户数量 int inviteCount = incrementDailyInviteCount(inviterProfile.getId()); @@ -167,6 +185,29 @@ public class BindInviteCodeExe { } } + /** + * 获取设备ID,如果没有则使用userId + * @param userId 用户ID + * @return 设备ID或用户ID + */ + private String getDeviceId(Long userId) { + try { + ResultResponse response = registerDeviceClient.getImeiByUserId(userId); + String imei = response != null ? response.getBody() : null; + + if (StringUtils.isNotBlank(imei)) { + log.info("获取到设备ID, userId={}, deviceId={}", userId, imei); + return imei; + } + } catch (Exception e) { + log.warn("获取设备ID失败, userId={}, error={}", userId, e.getMessage()); + } + + // 如果没有设备ID,使用userId + log.info("未获取到设备ID,使用userId作为设备标识, userId={}", userId); + return "USER_" + userId; + } + /** * 增加用户每日邀请用户数量 * @param userId 用户ID