feat(invite): 添加邀请码注册与验证功能
- 新增邀请码实体、Mapper、Service 及 XML 配置 - 注册接口支持填写邀请码并建立绑定关系 - 邀请码校验包含存在性、状态、过期及次数限制 - 补充相关错误码:INVITE_CODE_* 与 RECEIPT_ALREADY_PROCESSED
This commit is contained in:
@@ -62,6 +62,8 @@ public enum ErrorCode {
|
|||||||
INVITE_CODE_INVALID(50024, "邀请码无效"),
|
INVITE_CODE_INVALID(50024, "邀请码无效"),
|
||||||
INVITE_CODE_EXPIRED(50025, "邀请码已过期"),
|
INVITE_CODE_EXPIRED(50025, "邀请码已过期"),
|
||||||
INVITE_CODE_USED_UP(50026, "邀请码使用次数已达上限"),
|
INVITE_CODE_USED_UP(50026, "邀请码使用次数已达上限"),
|
||||||
|
INVITE_CODE_ALREADY_BOUND(50028, "您已绑定过邀请码,无法重复绑定"),
|
||||||
|
INVITE_CODE_CANNOT_BIND_SELF(50029, "不能绑定自己的邀请码"),
|
||||||
RECEIPT_ALREADY_PROCESSED(50027, "收据已处理");
|
RECEIPT_ALREADY_PROCESSED(50027, "收据已处理");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -103,8 +103,8 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
|||||||
"/apple/notification",
|
"/apple/notification",
|
||||||
"/apple/receipt",
|
"/apple/receipt",
|
||||||
"/apple/validate-receipt",
|
"/apple/validate-receipt",
|
||||||
"/user/inviteCode"
|
"/user/inviteCode",
|
||||||
|
"/user/bindInviteCode"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -142,4 +142,10 @@ public class UserController {
|
|||||||
return ResultUtils.success(respVO);
|
return ResultUtils.success(respVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/bindInviteCode")
|
||||||
|
@Operation(summary = "绑定邀请码", description = "用户填写邀请码进行绑定")
|
||||||
|
public BaseResponse<Boolean> bindInviteCode(@RequestBody BindInviteCodeDTO bindInviteCodeDTO) {
|
||||||
|
return ResultUtils.success(userService.bindInviteCode(bindInviteCodeDTO));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.yolo.keyborad.model.dto.user;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定邀请码请求
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2025/12/19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "绑定邀请码请求")
|
||||||
|
public class BindInviteCodeDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邀请码
|
||||||
|
*/
|
||||||
|
@Schema(description = "邀请码", required = true)
|
||||||
|
private String inviteCode;
|
||||||
|
}
|
||||||
@@ -28,4 +28,6 @@ public interface UserService extends IService<KeyboardUser> {
|
|||||||
|
|
||||||
Boolean resetPassWord(ResetPassWordDTO resetPassWordDTO);
|
Boolean resetPassWord(ResetPassWordDTO resetPassWordDTO);
|
||||||
|
|
||||||
|
Boolean bindInviteCode(BindInviteCodeDTO bindInviteCodeDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -350,4 +350,49 @@ public class UserServiceImpl extends ServiceImpl<KeyboardUserMapper, KeyboardUse
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Boolean bindInviteCode(BindInviteCodeDTO bindInviteCodeDTO) {
|
||||||
|
// 获取当前登录用户ID
|
||||||
|
long userId = StpUtil.getLoginIdAsLong();
|
||||||
|
|
||||||
|
// 检查用户是否已经绑定过邀请码
|
||||||
|
long existingBindCount = userInvitesService.count(
|
||||||
|
new LambdaQueryWrapper<KeyboardUserInvites>()
|
||||||
|
.eq(KeyboardUserInvites::getInviteeUserId, userId)
|
||||||
|
);
|
||||||
|
if (existingBindCount > 0) {
|
||||||
|
throw new BusinessException(ErrorCode.INVITE_CODE_ALREADY_BOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证邀请码
|
||||||
|
String inviteCodeStr = bindInviteCodeDTO.getInviteCode().trim();
|
||||||
|
KeyboardUserInviteCodes inviteCode = inviteCodesService.validateInviteCode(inviteCodeStr);
|
||||||
|
|
||||||
|
// 检查是否是绑定自己的邀请码
|
||||||
|
if (inviteCode.getOwnerUserId().equals(userId)) {
|
||||||
|
throw new BusinessException(ErrorCode.INVITE_CODE_CANNOT_BIND_SELF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建邀请关系绑定记录
|
||||||
|
KeyboardUserInvites userInvite = new KeyboardUserInvites();
|
||||||
|
userInvite.setInviterUserId(inviteCode.getOwnerUserId());
|
||||||
|
userInvite.setInviteeUserId(userId);
|
||||||
|
userInvite.setInviteCodeId(inviteCode.getId());
|
||||||
|
userInvite.setBindType((short) 1); // 1=手动填写邀请码
|
||||||
|
userInvite.setBoundAt(new Date());
|
||||||
|
userInvite.setBindIp(request.getRemoteAddr());
|
||||||
|
userInvite.setBindUserAgent(request.getHeader("User-Agent"));
|
||||||
|
userInvitesService.save(userInvite);
|
||||||
|
|
||||||
|
// 更新邀请码使用次数
|
||||||
|
inviteCode.setUsedCount(inviteCode.getUsedCount() + 1);
|
||||||
|
inviteCodesService.updateById(inviteCode);
|
||||||
|
|
||||||
|
log.info("User bound invite code, userId={}, inviteCodeId={}, inviterUserId={}",
|
||||||
|
userId, inviteCode.getId(), inviteCode.getOwnerUserId());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user