From 0cab423604e9bbcaefb518dde5e58d2765c47e4c Mon Sep 17 00:00:00 2001 From: ziin Date: Mon, 29 Dec 2025 15:43:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(user-invite-codes):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E5=90=8D=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=B9=B6=E6=96=B0=E5=A2=9E=E4=BB=A3=E7=90=86=E9=82=80=E8=AF=B7?= =?UTF-8?q?=E7=A0=81=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修正 owenrSystemUserId → ownerSystemUserId 拼写错误; 新增 UserInviteCodeApi 及实现,为代理租户自动生成 6 位唯一邀请码。 --- .../api/invitecode/UserInviteCodeApiImpl.java | 55 ++++++++++++ .../vo/KeyboardUserInviteCodesPageReqVO.java | 2 +- .../vo/KeyboardUserInviteCodesRespVO.java | 2 +- .../vo/KeyboardUserInviteCodesSaveReqVO.java | 2 +- .../KeyboardUserInviteCodesDO.java | 4 +- .../KeyboardUserInviteCodesMapper.java | 2 +- .../themes/KeyboardThemesServiceImpl.java | 89 ++++++++++++++++--- .../api/invitecode/UserInviteCodeApi.java | 19 ++++ .../service/tenant/TenantServiceImpl.java | 8 ++ 9 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 keyboard-server/src/main/java/com/yolo/keyboard/api/invitecode/UserInviteCodeApiImpl.java create mode 100644 yolo-module-system/src/main/java/com/yolo/keyboard/module/system/api/invitecode/UserInviteCodeApi.java diff --git a/keyboard-server/src/main/java/com/yolo/keyboard/api/invitecode/UserInviteCodeApiImpl.java b/keyboard-server/src/main/java/com/yolo/keyboard/api/invitecode/UserInviteCodeApiImpl.java new file mode 100644 index 0000000..74c1df7 --- /dev/null +++ b/keyboard-server/src/main/java/com/yolo/keyboard/api/invitecode/UserInviteCodeApiImpl.java @@ -0,0 +1,55 @@ +package com.yolo.keyboard.api.invitecode; + +import cn.hutool.core.util.RandomUtil; +import com.yolo.keyboard.dal.dataobject.userinvitecodes.KeyboardUserInviteCodesDO; +import com.yolo.keyboard.dal.mysql.userinvitecodes.KeyboardUserInviteCodesMapper; +import com.yolo.keyboard.module.system.api.invitecode.UserInviteCodeApi; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +/** + * 用户邀请码 API 实现类 + * + * @author ziin + */ +@Service +public class UserInviteCodeApiImpl implements UserInviteCodeApi { + + @Resource + private KeyboardUserInviteCodesMapper userInviteCodesMapper; + + @Override + public String createInviteCodeForAgent(Long userId, Long tenantId) { + String inviteCode = generateUniqueInviteCode(); + KeyboardUserInviteCodesDO inviteCodeDO = KeyboardUserInviteCodesDO.builder() + .code(inviteCode) + .ownerSystemUserId(userId) + .ownerTenantId(tenantId) + .status((short) 1) + .createdAt(LocalDateTime.now()) + .usedCount(0) + .inviteType("AGENT") + .build(); + userInviteCodesMapper.insert(inviteCodeDO); + return inviteCode; + } + + /** + * 生成唯一的6位邀请码(字母和数字混合) + */ + private String generateUniqueInviteCode() { + String code; + int maxAttempts = 100; + int attempt = 0; + do { + code = RandomUtil.randomString("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 6); + attempt++; + if (attempt >= maxAttempts) { + throw new RuntimeException("无法生成唯一的邀请码,请稍后重试"); + } + } while (userInviteCodesMapper.selectOne(KeyboardUserInviteCodesDO::getCode, code) != null); + return code; + } +} diff --git a/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesPageReqVO.java b/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesPageReqVO.java index dc6ae7e..7c9505e 100644 --- a/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesPageReqVO.java +++ b/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesPageReqVO.java @@ -41,7 +41,7 @@ public class KeyboardUserInviteCodesPageReqVO extends PageParam { private Long ownerTenantId; @Schema(description = "邀请码所属系统用户", example = "772") - private Long owenrSystemUserId; + private Long ownerSystemUserId; @Schema(description = "邀请码类型", example = "1") private String inviteType; diff --git a/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesRespVO.java b/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesRespVO.java index 76819c6..aeeb7a1 100644 --- a/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesRespVO.java +++ b/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesRespVO.java @@ -54,7 +54,7 @@ public class KeyboardUserInviteCodesRespVO { @Schema(description = "邀请码所属系统用户", example = "772") @ExcelProperty("邀请码所属系统用户") - private Long owenrSystemUserId; + private Long ownerSystemUserId; @Schema(description = "邀请码类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @ExcelProperty("邀请码类型") diff --git a/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesSaveReqVO.java b/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesSaveReqVO.java index 6bee6fa..f080ea0 100644 --- a/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesSaveReqVO.java +++ b/keyboard-server/src/main/java/com/yolo/keyboard/controller/admin/userinvitecodes/vo/KeyboardUserInviteCodesSaveReqVO.java @@ -47,7 +47,7 @@ public class KeyboardUserInviteCodesSaveReqVO { private Long ownerTenantId; @Schema(description = "邀请码所属系统用户", example = "772") - private Long owenrSystemUserId; + private Long ownerSystemUserId; @Schema(description = "邀请码类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotEmpty(message = "邀请码类型不能为空") diff --git a/keyboard-server/src/main/java/com/yolo/keyboard/dal/dataobject/userinvitecodes/KeyboardUserInviteCodesDO.java b/keyboard-server/src/main/java/com/yolo/keyboard/dal/dataobject/userinvitecodes/KeyboardUserInviteCodesDO.java index 5c60a18..510ca83 100644 --- a/keyboard-server/src/main/java/com/yolo/keyboard/dal/dataobject/userinvitecodes/KeyboardUserInviteCodesDO.java +++ b/keyboard-server/src/main/java/com/yolo/keyboard/dal/dataobject/userinvitecodes/KeyboardUserInviteCodesDO.java @@ -14,7 +14,7 @@ import com.yolo.keyboard.framework.mybatis.core.dataobject.BaseDO; * @author ziin */ @TableName("keyboard_user_invite_codes") -@KeySequence("keyboard_user_invite_codes_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@KeySequence("invite_codes_id_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @ToString(callSuper = true) @Builder @@ -67,7 +67,7 @@ public class KeyboardUserInviteCodesDO { /** * 邀请码所属系统用户 */ - private Long owenrSystemUserId; + private Long ownerSystemUserId; /** * 邀请码类型 */ diff --git a/keyboard-server/src/main/java/com/yolo/keyboard/dal/mysql/userinvitecodes/KeyboardUserInviteCodesMapper.java b/keyboard-server/src/main/java/com/yolo/keyboard/dal/mysql/userinvitecodes/KeyboardUserInviteCodesMapper.java index 45777c1..b7fdcc3 100644 --- a/keyboard-server/src/main/java/com/yolo/keyboard/dal/mysql/userinvitecodes/KeyboardUserInviteCodesMapper.java +++ b/keyboard-server/src/main/java/com/yolo/keyboard/dal/mysql/userinvitecodes/KeyboardUserInviteCodesMapper.java @@ -28,7 +28,7 @@ public interface KeyboardUserInviteCodesMapper extends BaseMapperX redisTemplate; + @Override public Long createThemes(KeyboardThemesSaveReqVO createReqVO) { // 插入 KeyboardThemesDO themes = BeanUtils.toBean(createReqVO, KeyboardThemesDO.class); themesMapper.insert(themes); + // 同步更新 Redis 缓存 + refreshThemeStyleCache(themes.getThemeStyle()); + // 返回 return themes.getId(); } @@ -47,25 +54,57 @@ public class KeyboardThemesServiceImpl implements KeyboardThemesService { @Override public void updateThemes(KeyboardThemesSaveReqVO updateReqVO) { // 校验存在 + KeyboardThemesDO oldTheme = themesMapper.selectById(updateReqVO.getId()); validateThemesExists(updateReqVO.getId()); + // 更新 KeyboardThemesDO updateObj = BeanUtils.toBean(updateReqVO, KeyboardThemesDO.class); themesMapper.updateById(updateObj); + + // 同步更新 Redis 缓存(如果风格变更,需要刷新新旧两个风格的缓存) + refreshThemeStyleCache(updateReqVO.getThemeStyle()); + if (oldTheme != null && oldTheme.getThemeStyle() != null + && !oldTheme.getThemeStyle().equals(updateReqVO.getThemeStyle())) { + refreshThemeStyleCache(oldTheme.getThemeStyle()); + } } @Override public void deleteThemes(Long id) { // 校验存在 + KeyboardThemesDO theme = themesMapper.selectById(id); validateThemesExists(id); + // 删除 themesMapper.deleteById(id); + + // 同步更新 Redis 缓存 + if (theme != null && theme.getThemeStyle() != null) { + refreshThemeStyleCache(theme.getThemeStyle()); + } } @Override - public void deleteThemesListByIds(List ids) { + public void deleteThemesListByIds(List ids) { + // 获取要删除的主题列表,记录其风格 + List themes = themesMapper.selectBatchIds(ids); + Set styleIds = new HashSet<>(); + if (CollUtil.isNotEmpty(themes)) { + for (KeyboardThemesDO theme : themes) { + if (theme.getThemeStyle() != null) { + styleIds.add(theme.getThemeStyle()); + } + } + } + // 删除 themesMapper.deleteByIds(ids); + + // 同步更新 Redis 缓存 + for (Long styleId : styleIds) { + refreshThemeStyleCache(styleId); } + } private void validateThemesExists(Long id) { @@ -84,4 +123,32 @@ public class KeyboardThemesServiceImpl implements KeyboardThemesService { return themesMapper.selectPage(pageReqVO); } + /** + * 刷新主题风格缓存 + * + * @param styleId 风格ID + */ + private void refreshThemeStyleCache(Long styleId) { + if (styleId == null) { + return; + } + + // 1. 刷新指定风格的缓存 + String styleKey = THEME_STYLE_KEY_PREFIX + styleId; + List themesByStyle = themesMapper.selectList(KeyboardThemesDO::getThemeStyle, styleId); + if (CollUtil.isNotEmpty(themesByStyle)) { + redisTemplate.opsForValue().set(styleKey, themesByStyle); + } else { + redisTemplate.delete(styleKey); + } + + // 2. 刷新全部主题缓存(theme:style:all) + List allThemes = themesMapper.selectList(); + if (CollUtil.isNotEmpty(allThemes)) { + redisTemplate.opsForValue().set(THEME_STYLE_ALL_KEY, allThemes); + } else { + redisTemplate.delete(THEME_STYLE_ALL_KEY); + } + } + } \ No newline at end of file diff --git a/yolo-module-system/src/main/java/com/yolo/keyboard/module/system/api/invitecode/UserInviteCodeApi.java b/yolo-module-system/src/main/java/com/yolo/keyboard/module/system/api/invitecode/UserInviteCodeApi.java new file mode 100644 index 0000000..1029e89 --- /dev/null +++ b/yolo-module-system/src/main/java/com/yolo/keyboard/module/system/api/invitecode/UserInviteCodeApi.java @@ -0,0 +1,19 @@ +package com.yolo.keyboard.module.system.api.invitecode; + +/** + * 用户邀请码 API 接口 + * + * @author ziin + */ +public interface UserInviteCodeApi { + + /** + * 为代理租户创建邀请码 + * + * @param userId 系统用户ID + * @param tenantId 租户ID + * @return 生成的邀请码 + */ + String createInviteCodeForAgent(Long userId, Long tenantId); + +} diff --git a/yolo-module-system/src/main/java/com/yolo/keyboard/module/system/service/tenant/TenantServiceImpl.java b/yolo-module-system/src/main/java/com/yolo/keyboard/module/system/service/tenant/TenantServiceImpl.java index 1f3250e..311ce47 100644 --- a/yolo-module-system/src/main/java/com/yolo/keyboard/module/system/service/tenant/TenantServiceImpl.java +++ b/yolo-module-system/src/main/java/com/yolo/keyboard/module/system/service/tenant/TenantServiceImpl.java @@ -21,6 +21,7 @@ import com.yolo.keyboard.module.system.dal.dataobject.permission.RoleDO; import com.yolo.keyboard.module.system.dal.dataobject.tenant.TenantDO; import com.yolo.keyboard.module.system.dal.dataobject.tenant.TenantPackageDO; import com.yolo.keyboard.module.system.dal.mysql.tenant.TenantMapper; +import com.yolo.keyboard.module.system.api.invitecode.UserInviteCodeApi; import com.yolo.keyboard.module.system.enums.permission.RoleCodeEnum; import com.yolo.keyboard.module.system.enums.permission.RoleTypeEnum; import com.yolo.keyboard.module.system.service.permission.MenuService; @@ -75,6 +76,9 @@ public class TenantServiceImpl implements TenantService { @Resource private PermissionService permissionService; + @Autowired(required = false) + private UserInviteCodeApi userInviteCodeApi; + @Override public List getTenantIdList() { List tenants = tenantMapper.selectList(); @@ -135,6 +139,10 @@ public class TenantServiceImpl implements TenantService { Long userId = createUser(roleId, createReqVO); // 修改租户的管理员 tenantMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(userId)); + // 为代理租户创建邀请码 + if ("代理".equals(createReqVO.getTenantType()) && userInviteCodeApi != null) { + userInviteCodeApi.createInviteCodeForAgent(userId, tenant.getId()); + } }); return tenant.getId(); }