Compare commits

..

2 Commits

Author SHA1 Message Date
6ef1488e5f feat(invite): 新增H5邀请链接配置与返回
在 AppConfig 中增加 inviteConfig 及 h5Link 字段;
服务层改造 getUserInviteCode 返回 InviteCodeRespVO 并填充 h5Link;
Controller 简化调用逻辑,统一走服务层组装 VO。
2025-12-24 22:02:08 +08:00
b9197c4275 feat(invite): 新增用户邀请码创建与查询接口 2025-12-24 21:36:27 +08:00
6 changed files with 136 additions and 3 deletions

View File

@@ -17,6 +17,8 @@ public class AppConfig {
private LLmConfig llmConfig = new LLmConfig(); private LLmConfig llmConfig = new LLmConfig();
private inviteConfig inviteConfig = new inviteConfig();
@Data @Data
public static class UserRegisterProperties { public static class UserRegisterProperties {
@@ -48,4 +50,8 @@ public class AppConfig {
private Integer maxMessageLength = 1000; private Integer maxMessageLength = 1000;
} }
@Data
public static class inviteConfig {
private String h5Link = "";
}
} }

View File

@@ -8,9 +8,13 @@ import com.yolo.keyborad.model.dto.AppleLoginReq;
import com.yolo.keyborad.model.dto.user.*; import com.yolo.keyborad.model.dto.user.*;
import com.yolo.keyborad.model.entity.KeyboardFeedback; import com.yolo.keyborad.model.entity.KeyboardFeedback;
import com.yolo.keyborad.model.entity.KeyboardUser; import com.yolo.keyborad.model.entity.KeyboardUser;
import com.yolo.keyborad.model.entity.KeyboardUserInviteCodes;
import com.yolo.keyborad.model.vo.user.InviteCodeRespVO;
import com.yolo.keyborad.model.vo.user.KeyboardUserInfoRespVO; import com.yolo.keyborad.model.vo.user.KeyboardUserInfoRespVO;
import com.yolo.keyborad.model.vo.user.KeyboardUserRespVO; import com.yolo.keyborad.model.vo.user.KeyboardUserRespVO;
import com.yolo.keyborad.service.IAppleService; import com.yolo.keyborad.service.IAppleService;
import com.yolo.keyborad.service.KeyboardFeedbackService;
import com.yolo.keyborad.service.KeyboardUserInviteCodesService;
import com.yolo.keyborad.service.UserService; import com.yolo.keyborad.service.UserService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@@ -41,8 +45,10 @@ public class UserController {
private UserService userService; private UserService userService;
@Resource @Resource
private com.yolo.keyborad.service.KeyboardFeedbackService feedbackService; private KeyboardFeedbackService feedbackService;
@Resource
private KeyboardUserInviteCodesService inviteCodesService;
/** /**
* 苹果登录 * 苹果登录
* *
@@ -133,4 +139,10 @@ public class UserController {
return ResultUtils.success(userService.bindInviteCode(bindInviteCodeDTO)); return ResultUtils.success(userService.bindInviteCode(bindInviteCodeDTO));
} }
@GetMapping("/inviteCode")
@Operation(summary = "查询邀请码", description = "查询用户自己的邀请码")
public BaseResponse<InviteCodeRespVO> getInviteCode() {
long userId = StpUtil.getLoginIdAsLong();
return ResultUtils.success( inviteCodesService.getUserInviteCode(userId));
}
} }

View File

@@ -0,0 +1,32 @@
package com.yolo.keyborad.model.vo.user;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* 邀请码响应VO
*/
@Data
@Schema(description = "邀请码信息")
public class InviteCodeRespVO {
@Schema(description = "邀请码")
private String code;
@Schema(description = "邀请码状态1=启用0=停用")
private Short status;
@Schema(description = "已使用次数")
private Integer usedCount;
@Schema(description = "最大可使用次数")
private Integer maxUses;
@Schema(description = "过期时间")
private Date expiresAt;
@Schema(description = "H5链接")
private String h5Link;
}

View File

@@ -2,6 +2,7 @@ package com.yolo.keyborad.service;
import com.yolo.keyborad.model.entity.KeyboardUserInviteCodes; import com.yolo.keyborad.model.entity.KeyboardUserInviteCodes;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.yolo.keyborad.model.vo.user.InviteCodeRespVO;
/* /*
* @author: ziin * @author: ziin
* @date: 2025/12/18 16:26 * @date: 2025/12/18 16:26
@@ -15,4 +16,18 @@ public interface KeyboardUserInviteCodesService extends IService<KeyboardUserInv
*/ */
KeyboardUserInviteCodes validateInviteCode(String code); KeyboardUserInviteCodes validateInviteCode(String code);
/**
* 获取用户的邀请码
* @param userId 用户ID
* @return 邀请码实体
*/
InviteCodeRespVO getUserInviteCode(Long userId);
/**
* 为用户创建邀请码
* @param userId 用户ID
* @return 创建的邀请码实体
*/
KeyboardUserInviteCodes createInviteCode(Long userId);
} }

View File

@@ -1,8 +1,12 @@
package com.yolo.keyborad.service.impl; package com.yolo.keyborad.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import com.yolo.keyborad.common.ErrorCode; import com.yolo.keyborad.common.ErrorCode;
import com.yolo.keyborad.config.AppConfig;
import com.yolo.keyborad.config.NacosAppConfigCenter;
import com.yolo.keyborad.exception.BusinessException; import com.yolo.keyborad.exception.BusinessException;
import com.yolo.keyborad.model.vo.user.InviteCodeRespVO;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date; import java.util.Date;
@@ -20,6 +24,68 @@ import com.yolo.keyborad.service.KeyboardUserInviteCodesService;
@Service @Service
public class KeyboardUserInviteCodesServiceImpl extends ServiceImpl<KeyboardUserInviteCodesMapper, KeyboardUserInviteCodes> implements KeyboardUserInviteCodesService{ public class KeyboardUserInviteCodesServiceImpl extends ServiceImpl<KeyboardUserInviteCodesMapper, KeyboardUserInviteCodes> implements KeyboardUserInviteCodesService{
private final NacosAppConfigCenter.DynamicAppConfig cfgHolder;
public KeyboardUserInviteCodesServiceImpl(NacosAppConfigCenter.DynamicAppConfig cfgHolder) {
this.cfgHolder = cfgHolder;
}
@Override
public InviteCodeRespVO getUserInviteCode(Long userId) {
QueryWrapper<KeyboardUserInviteCodes> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("owner_user_id", userId);
KeyboardUserInviteCodes one = this.getOne(queryWrapper);
if (one == null) {
one = createInviteCode(userId);
}
InviteCodeRespVO inviteCodeRespVO = BeanUtil.copyProperties(one, InviteCodeRespVO.class);
AppConfig appConfig = cfgHolder.getRef().get();
inviteCodeRespVO.setH5Link(appConfig.getInviteConfig().getH5Link());
return inviteCodeRespVO;
}
@Override
public KeyboardUserInviteCodes createInviteCode(Long userId) {
// 生成唯一的邀请码
String code;
int maxRetries = 10;
int retryCount = 0;
do {
// 生成8位字母数字组合的邀请码
code = RandomUtil.randomString(8).toUpperCase();
// 检查邀请码是否已存在
QueryWrapper<KeyboardUserInviteCodes> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("code", code);
KeyboardUserInviteCodes existingCode = this.getOne(queryWrapper);
if (existingCode == null) {
break;
}
retryCount++;
} while (retryCount < maxRetries);
// 创建邀请码实体
KeyboardUserInviteCodes inviteCode = new KeyboardUserInviteCodes();
inviteCode.setCode(code);
inviteCode.setOwnerUserId(userId);
inviteCode.setStatus((short) 1); // 启用状态
inviteCode.setCreatedAt(new Date());
inviteCode.setExpiresAt(null); // 永久有效
inviteCode.setMaxUses(null); // 不限次数
inviteCode.setUsedCount(0); // 初始使用次数为0
// 保存到数据库
this.save(inviteCode);
InviteCodeRespVO inviteCodeRespVO = BeanUtil.copyProperties(inviteCode, InviteCodeRespVO.class);
return inviteCode;
}
@Override @Override
public KeyboardUserInviteCodes validateInviteCode(String code) { public KeyboardUserInviteCodes validateInviteCode(String code) {
// 查询邀请码 // 查询邀请码

View File

@@ -103,7 +103,6 @@ public class UserServiceImpl extends ServiceImpl<KeyboardUserMapper, KeyboardUse
wallet.setCreatedAt(new Date()); wallet.setCreatedAt(new Date());
wallet.setUpdatedAt(new Date()); wallet.setUpdatedAt(new Date());
walletService.save(wallet); walletService.save(wallet);
// 初始化用户免费使用次数配额 // 初始化用户免费使用次数配额
KeyboardUserQuotaTotal quotaTotal = new KeyboardUserQuotaTotal(); KeyboardUserQuotaTotal quotaTotal = new KeyboardUserQuotaTotal();
quotaTotal.setUserId(keyboardUser.getId()); quotaTotal.setUserId(keyboardUser.getId());
@@ -114,6 +113,8 @@ public class UserServiceImpl extends ServiceImpl<KeyboardUserMapper, KeyboardUse
quotaTotal.setUpdatedAt(new Date()); quotaTotal.setUpdatedAt(new Date());
quotaTotalService.save(quotaTotal); quotaTotalService.save(quotaTotal);
inviteCodesService.createInviteCode(keyboardUser.getId());
log.info("User registered with Apple Sign-In, userId={}, freeQuota={}", log.info("User registered with Apple Sign-In, userId={}, freeQuota={}",
keyboardUser.getId(), appConfig.getUserRegisterProperties().getFreeTrialQuota()); keyboardUser.getId(), appConfig.getUserRegisterProperties().getFreeTrialQuota());
@@ -252,6 +253,7 @@ public class UserServiceImpl extends ServiceImpl<KeyboardUserMapper, KeyboardUse
quotaTotal.setCreatedAt(new Date()); quotaTotal.setCreatedAt(new Date());
quotaTotal.setUpdatedAt(new Date()); quotaTotal.setUpdatedAt(new Date());
quotaTotalService.save(quotaTotal); quotaTotalService.save(quotaTotal);
inviteCodesService.createInviteCode(keyboardUser.getId());
// 处理邀请码绑定 // 处理邀请码绑定
if (userRegisterDTO.getInviteCode() != null && !userRegisterDTO.getInviteCode().trim().isEmpty()) { if (userRegisterDTO.getInviteCode() != null && !userRegisterDTO.getInviteCode().trim().isEmpty()) {