diff --git a/src/main/java/com/yolo/keyborad/common/ErrorCode.java b/src/main/java/com/yolo/keyborad/common/ErrorCode.java index 39129c1..4cfd434 100644 --- a/src/main/java/com/yolo/keyborad/common/ErrorCode.java +++ b/src/main/java/com/yolo/keyborad/common/ErrorCode.java @@ -57,7 +57,12 @@ public enum ErrorCode { LACK_ORIGIN_TRANSACTION_ID_ERROR(50019, "缺少原始交易id"), UNKNOWN_PRODUCT_TYPE(50020, "未知商品类型"), PRODUCT_NOT_FOUND(50021, "商品不存在"), - NO_QUOTA_AND_NOT_VIP(50022, "免费次数已用完,请开通VIP"); + NO_QUOTA_AND_NOT_VIP(50022, "免费次数已用完,请开通VIP"), + INVITE_CODE_NOT_FOUND(50023, "邀请码不存在"), + INVITE_CODE_INVALID(50024, "邀请码无效"), + INVITE_CODE_EXPIRED(50025, "邀请码已过期"), + INVITE_CODE_USED_UP(50026, "邀请码使用次数已达上限"), + RECEIPT_ALREADY_PROCESSED(50027, "收据已处理"); /** * 状态码 diff --git a/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java b/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java index 0d4f7fb..a2645c1 100644 --- a/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java +++ b/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java @@ -102,7 +102,8 @@ public class SaTokenConfigure implements WebMvcConfigurer { "/purchase/handle", "/apple/notification", "/apple/receipt", - "/apple/validate-receipt" + "/apple/validate-receipt", + "/user/inviteCode" }; } diff --git a/src/main/java/com/yolo/keyborad/mapper/KeyboardUserInvitesMapper.java b/src/main/java/com/yolo/keyborad/mapper/KeyboardUserInvitesMapper.java new file mode 100644 index 0000000..c8fae89 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/mapper/KeyboardUserInvitesMapper.java @@ -0,0 +1,12 @@ +package com.yolo.keyborad.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yolo.keyborad.model.entity.KeyboardUserInvites; + +/* +* @author: ziin +* @date: 2025/12/19 13:26 +*/ + +public interface KeyboardUserInvitesMapper extends BaseMapper { +} \ No newline at end of file diff --git a/src/main/java/com/yolo/keyborad/model/dto/user/UserRegisterDTO.java b/src/main/java/com/yolo/keyborad/model/dto/user/UserRegisterDTO.java index e0ee6b3..11867aa 100644 --- a/src/main/java/com/yolo/keyborad/model/dto/user/UserRegisterDTO.java +++ b/src/main/java/com/yolo/keyborad/model/dto/user/UserRegisterDTO.java @@ -24,4 +24,7 @@ public class UserRegisterDTO { @Schema(description = "验证码") private String verifyCode; + + @Schema(description = "邀请码(可选)") + private String inviteCode; } diff --git a/src/main/java/com/yolo/keyborad/model/entity/KeyboardUserInvites.java b/src/main/java/com/yolo/keyborad/model/entity/KeyboardUserInvites.java new file mode 100644 index 0000000..4b95999 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/model/entity/KeyboardUserInvites.java @@ -0,0 +1,85 @@ +package com.yolo.keyborad.model.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Date; +import lombok.Data; + +/* +* @author: ziin +* @date: 2025/12/19 13:26 +*/ + +/** + * 用户邀请关系绑定台账表,记录新用户最终归属的邀请人 + */ +@Schema(description="用户邀请关系绑定台账表,记录新用户最终归属的邀请人") +@Data +@TableName(value = "keyboard_user_invites") +public class KeyboardUserInvites { + /** + * 邀请绑定记录主键ID + */ + @TableId(value = "id", type = IdType.AUTO) + @Schema(description="邀请绑定记录主键ID") + private Long id; + + /** + * 邀请人用户ID + */ + @TableField(value = "inviter_user_id") + @Schema(description="邀请人用户ID") + private Long inviterUserId; + + /** + * 被邀请人用户ID(新注册用户) + */ + @TableField(value = "invitee_user_id") + @Schema(description="被邀请人用户ID(新注册用户)") + private Long inviteeUserId; + + /** + * 使用的邀请码ID + */ + @TableField(value = "invite_code_id") + @Schema(description="使用的邀请码ID") + private Long inviteCodeId; + + /** + * 绑定时关联的点击Token(通过邀请链接自动绑定时使用) + */ + @TableField(value = "click_token") + @Schema(description="绑定时关联的点击Token(通过邀请链接自动绑定时使用)") + private String clickToken; + + /** + * 绑定方式:1=手动填写邀请码,2=邀请链接自动绑定,3=其他方式 + */ + @TableField(value = "bind_type") + @Schema(description="绑定方式:1=手动填写邀请码,2=邀请链接自动绑定,3=其他方式") + private Short bindType; + + /** + * 邀请关系绑定完成时间 + */ + @TableField(value = "bound_at") + @Schema(description="邀请关系绑定完成时间") + private Date boundAt; + + /** + * 绑定 iP + */ + @TableField(value = "bind_ip") + @Schema(description="绑定 iP") + private String bindIp; + + /** + * userAgent + */ + @TableField(value = "bind_user_agent") + @Schema(description="userAgent") + private String bindUserAgent; +} \ No newline at end of file diff --git a/src/main/java/com/yolo/keyborad/service/KeyboardUserInviteCodesService.java b/src/main/java/com/yolo/keyborad/service/KeyboardUserInviteCodesService.java index 12df1df..95151f3 100644 --- a/src/main/java/com/yolo/keyborad/service/KeyboardUserInviteCodesService.java +++ b/src/main/java/com/yolo/keyborad/service/KeyboardUserInviteCodesService.java @@ -23,4 +23,11 @@ public interface KeyboardUserInviteCodesService extends IService{ + + +} diff --git a/src/main/java/com/yolo/keyborad/service/impl/ApplePurchaseServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/ApplePurchaseServiceImpl.java index 584d88c..fa414d9 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/ApplePurchaseServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/ApplePurchaseServiceImpl.java @@ -94,7 +94,7 @@ public class ApplePurchaseServiceImpl implements ApplePurchaseService { .exists(); if (handled) { log.info("Apple purchase already handled, transactionId={}", validationResult.getTransactionId()); - return; + throw new BusinessException(ErrorCode.RECEIPT_ALREADY_PROCESSED); } // 4. 查询商品信息 diff --git a/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserInviteCodesServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserInviteCodesServiceImpl.java index 4256c23..f3e05ae 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserInviteCodesServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserInviteCodesServiceImpl.java @@ -1,6 +1,8 @@ package com.yolo.keyborad.service.impl; import cn.hutool.core.util.RandomUtil; +import com.yolo.keyborad.common.ErrorCode; +import com.yolo.keyborad.exception.BusinessException; import org.springframework.stereotype.Service; import org.springframework.beans.factory.annotation.Autowired; import java.util.Date; @@ -63,4 +65,34 @@ public class KeyboardUserInviteCodesServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("code", code); + KeyboardUserInviteCodes inviteCode = this.getOne(queryWrapper); + + // 邀请码不存在 + if (inviteCode == null) { + throw new BusinessException(ErrorCode.INVITE_CODE_NOT_FOUND); + } + + // 邀请码已停用 + if (inviteCode.getStatus() != 1) { + throw new BusinessException(ErrorCode.INVITE_CODE_INVALID); + } + + // 检查是否过期 + if (inviteCode.getExpiresAt() != null && inviteCode.getExpiresAt().before(new Date())) { + throw new BusinessException(ErrorCode.INVITE_CODE_EXPIRED); + } + + // 检查使用次数是否达到上限 + if (inviteCode.getMaxUses() != null && inviteCode.getUsedCount() >= inviteCode.getMaxUses()) { + throw new BusinessException(ErrorCode.INVITE_CODE_USED_UP); + } + + return inviteCode; + } } diff --git a/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserInvitesServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserInvitesServiceImpl.java new file mode 100644 index 0000000..bf8aee8 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserInvitesServiceImpl.java @@ -0,0 +1,18 @@ +package com.yolo.keyborad.service.impl; + +import org.springframework.stereotype.Service; +import org.springframework.beans.factory.annotation.Autowired; +import java.util.List; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yolo.keyborad.model.entity.KeyboardUserInvites; +import com.yolo.keyborad.mapper.KeyboardUserInvitesMapper; +import com.yolo.keyborad.service.KeyboardUserInvitesService; +/* +* @author: ziin +* @date: 2025/12/19 13:26 +*/ + +@Service +public class KeyboardUserInvitesServiceImpl extends ServiceImpl implements KeyboardUserInvitesService{ + +} diff --git a/src/main/java/com/yolo/keyborad/service/impl/UserServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/UserServiceImpl.java index 563c9f3..048fd99 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/UserServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/UserServiceImpl.java @@ -12,9 +12,7 @@ import com.yolo.keyborad.config.NacosAppConfigCenter; import com.yolo.keyborad.exception.BusinessException; import com.yolo.keyborad.mapper.KeyboardUserMapper; import com.yolo.keyborad.model.dto.user.*; -import com.yolo.keyborad.model.entity.KeyboardUser; -import com.yolo.keyborad.model.entity.KeyboardUserQuotaTotal; -import com.yolo.keyborad.model.entity.KeyboardUserWallet; +import com.yolo.keyborad.model.entity.*; import com.yolo.keyborad.model.vo.user.KeyboardUserRespVO; import com.yolo.keyborad.service.*; import jakarta.servlet.http.HttpServletRequest; @@ -65,6 +63,12 @@ public class UserServiceImpl extends ServiceImpl + + + + + + + + + + + + + + + + + + id, inviter_user_id, invitee_user_id, invite_code_id, click_token, bind_type, bound_at, + bind_ip, bind_user_agent + + \ No newline at end of file