开启模块:工作流,会员管理,CRM系统
添加邀请码工具类 前端system.user页面添加邀请码字段 前端system.user页面添加生成邀请码按钮,使用create权限 数据库:system_user表添加invitioncode邀请码字段
This commit is contained in:
parent
bd93257a26
commit
fab87bf5d7
6
pom.xml
6
pom.xml
|
@ -15,13 +15,13 @@
|
|||
<!-- 各种 module 拓展 -->
|
||||
<module>yudao-module-system</module>
|
||||
<module>yudao-module-infra</module>
|
||||
<!-- <module>yudao-module-member</module>-->
|
||||
<!-- <module>yudao-module-bpm</module>-->
|
||||
<module>yudao-module-member</module>
|
||||
<module>yudao-module-bpm</module>
|
||||
<!-- <module>yudao-module-report</module>-->
|
||||
<!-- <module>yudao-module-mp</module>-->
|
||||
<!-- <module>yudao-module-pay</module>-->
|
||||
<!-- <module>yudao-module-mall</module>-->
|
||||
<!-- <module>yudao-module-crm</module>-->
|
||||
<module>yudao-module-crm</module>
|
||||
<!-- <module>yudao-module-erp</module>-->
|
||||
<!-- <module>yudao-module-ai</module>-->
|
||||
<!-- <module>yudao-module-iot</module>-->
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
package cn.iocoder.yudao.framework.common.util.invite;
|
||||
import java.util.Arrays;
|
||||
|
||||
// 邀请码工具类
|
||||
// 主要用于生成邀请码,以及校验邀请码是否正确
|
||||
// 邀请码的生成规则是:
|
||||
// 1. 邀请码的长度为 6 位
|
||||
public class InviteUtils {
|
||||
/**
|
||||
* 随机字符串
|
||||
*/
|
||||
private static final char[] CHARS = new char[] { 'F', 'L', 'G', 'W', '5', 'X', 'C', '3', '9', 'Z', 'M', '6', '7',
|
||||
'Y', 'R', 'T', '2', 'H', 'S', '8', 'D', 'V', 'E', 'J', '4', 'K', 'Q', 'P', 'U', 'A', 'N', 'B' };
|
||||
|
||||
private final static int CHARS_LENGTH = 32;
|
||||
/**
|
||||
* 邀请码长度
|
||||
*/
|
||||
private final static int CODE_LENGTH = 6;
|
||||
|
||||
/**
|
||||
* 随机数据
|
||||
*/
|
||||
private final static long SLAT = 1234561L;
|
||||
|
||||
/**
|
||||
* PRIME1 与 CHARS 的长度 L互质,可保证 ( id * PRIME1) % L 在 [0,L)上均匀分布
|
||||
*/
|
||||
private final static int PRIME1 = 3;
|
||||
|
||||
/**
|
||||
* PRIME2 与 CODE_LENGTH 互质,可保证 ( index * PRIME2) % CODE_LENGTH 在
|
||||
* [0,CODE_LENGTH)上均匀分布
|
||||
*/
|
||||
private final static int PRIME2 = 11;
|
||||
|
||||
/**
|
||||
* 生成邀请码
|
||||
*
|
||||
* @param id 唯一的id主键
|
||||
* @return code
|
||||
*/
|
||||
public static String generateInviteCode(Long id) {
|
||||
// 补位
|
||||
id = id * PRIME1 + SLAT;
|
||||
// 将 id 转换成32进制的值
|
||||
long[] b = new long[CODE_LENGTH];
|
||||
// 32进制数
|
||||
b[0] = id;
|
||||
for (int i = 0; i < CODE_LENGTH - 1; i++) {
|
||||
b[i + 1] = b[i] / CHARS_LENGTH;
|
||||
// 按位扩散
|
||||
b[i] = (b[i] + i * b[0]) % CHARS_LENGTH;
|
||||
}
|
||||
b[5] = (b[0] + b[1] + b[2] + b[3] + b[4]) * PRIME1 % CHARS_LENGTH;
|
||||
|
||||
// 进行混淆
|
||||
long[] codeIndexArray = new long[CODE_LENGTH];
|
||||
for (int i = 0; i < CODE_LENGTH; i++) {
|
||||
codeIndexArray[i] = b[i * PRIME2 % CODE_LENGTH];
|
||||
}
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
Arrays.stream(codeIndexArray).boxed().map(Long::intValue).map(t -> CHARS[t]).forEach(buffer::append);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将邀请码解密成原来的id
|
||||
*
|
||||
* @param code 邀请码
|
||||
* @return id
|
||||
*/
|
||||
public static Long deInviteCode(String code) {
|
||||
if (code.length() != CODE_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
// 将字符还原成对应数字
|
||||
long[] a = new long[CODE_LENGTH];
|
||||
for (int i = 0; i < CODE_LENGTH; i++) {
|
||||
char c = code.charAt(i);
|
||||
int index = findIndex(c);
|
||||
if (index == -1) {
|
||||
// 异常字符串
|
||||
return null;
|
||||
}
|
||||
a[i * PRIME2 % CODE_LENGTH] = index;
|
||||
}
|
||||
|
||||
long[] b = new long[CODE_LENGTH];
|
||||
for (int i = CODE_LENGTH - 2; i >= 0; i--) {
|
||||
b[i] = (a[i] - a[0] * i + CHARS_LENGTH * i) % CHARS_LENGTH;
|
||||
}
|
||||
|
||||
long res = 0;
|
||||
for (int i = CODE_LENGTH - 2; i >= 0; i--) {
|
||||
res += b[i];
|
||||
res *= (i > 0 ? CHARS_LENGTH : 1);
|
||||
}
|
||||
return (res - SLAT) / PRIME1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找对应字符的index
|
||||
*
|
||||
* @param c 字符
|
||||
* @return index
|
||||
*/
|
||||
private static int findIndex(char c) {
|
||||
for (int i = 0; i < CHARS_LENGTH; i++) {
|
||||
if (CHARS[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -86,4 +86,12 @@ public interface AdminUserApi {
|
|||
*/
|
||||
void validateUserList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 根据邀请码,获得用户
|
||||
*
|
||||
* @param invitationCode 邀请码
|
||||
* @return 用户
|
||||
*/
|
||||
AdminUserRespDTO getUserByInvitationCode(String invitationCode);
|
||||
|
||||
}
|
||||
|
|
|
@ -79,4 +79,11 @@ public class AdminUserApiImpl implements AdminUserApi {
|
|||
userService.validateUserList(ids);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public AdminUserRespDTO getUserByInvitationCode(String invitationCode) {
|
||||
AdminUserDO user = userService.getUserByInvitaCode(invitationCode);
|
||||
return BeanUtils.toBean(user, AdminUserRespDTO.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -169,4 +169,13 @@ public class UserController {
|
|||
return success(userService.importUserList(list, updateSupport));
|
||||
}
|
||||
|
||||
@PutMapping("/gen-invite-code")
|
||||
@Operation(summary = "生成邀请码")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:user:create')")
|
||||
public CommonResult<Boolean> generateInviteCode(@RequestParam("id") Long id) {
|
||||
userService.generateInviteCode(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ public class UserRespVO{
|
|||
@Schema(description = "备注", example = "我是一个用户")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "邀请码", example = "1234567")
|
||||
private String invitationCode;
|
||||
|
||||
@Schema(description = "部门ID", example = "我是一个用户")
|
||||
private Long deptId;
|
||||
@Schema(description = "部门名称", example = "IT 部")
|
||||
|
|
|
@ -93,4 +93,9 @@ public class AdminUserDO extends TenantBaseDO {
|
|||
*/
|
||||
private LocalDateTime loginDate;
|
||||
|
||||
/**
|
||||
* 邀请码
|
||||
*/
|
||||
private String invitationCode;
|
||||
|
||||
}
|
||||
|
|
|
@ -48,4 +48,7 @@ public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
|
|||
return selectList(AdminUserDO::getDeptId, deptIds);
|
||||
}
|
||||
|
||||
default AdminUserDO selectByInvitationCode(String invitationCode){
|
||||
return selectOne(AdminUserDO::getInvitationCode,invitationCode);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -216,4 +216,18 @@ public interface AdminUserService {
|
|||
*/
|
||||
boolean isPasswordMatch(String rawPassword, String encodedPassword);
|
||||
|
||||
/**
|
||||
* 获得指定邀请码的用户
|
||||
*
|
||||
* @param invitationCode 邀请码
|
||||
* @return 用户
|
||||
*/
|
||||
AdminUserDO getUserByInvitaCode(String invitationCode);
|
||||
|
||||
/**
|
||||
* 生成邀请码
|
||||
*
|
||||
* @param id 用户编号
|
||||
*/
|
||||
void generateInviteCode(Long id);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
|||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.invite.InviteUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
|
||||
|
@ -528,4 +529,33 @@ public class AdminUserServiceImpl implements AdminUserService {
|
|||
return passwordEncoder.encode(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邀请码对应的的用户
|
||||
*
|
||||
* @param invitationCode 用户编号数组
|
||||
* @return 用户信息
|
||||
*/
|
||||
@Override
|
||||
public AdminUserDO getUserByInvitaCode(String invitationCode) {
|
||||
return userMapper.selectByInvitationCode(invitationCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成邀请码
|
||||
*
|
||||
* @param id 用户编号
|
||||
*/
|
||||
@Override
|
||||
public void generateInviteCode(Long id) {
|
||||
// 校验用户存在
|
||||
AdminUserDO dd = validateUserExists(id);
|
||||
if(!StrUtil.isNotBlank(dd.getInvitationCode())) {
|
||||
// 更新状态
|
||||
AdminUserDO updateObj = new AdminUserDO();
|
||||
updateObj.setId(id);
|
||||
updateObj.setInvitationCode(InviteUtils.generateInviteCode(id));
|
||||
userMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@
|
|||
</dependency>
|
||||
|
||||
<!-- 会员中心。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-member-biz</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-member-biz</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据报表。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
|
@ -46,11 +46,11 @@
|
|||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- 工作流。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-bpm-biz</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-bpm-biz</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- 支付服务。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
|
@ -88,11 +88,11 @@
|
|||
<!-- </dependency>-->
|
||||
|
||||
<!-- CRM 相关模块。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>cn.iocoder.boot</groupId>-->
|
||||
<!-- <artifactId>yudao-module-crm-biz</artifactId>-->
|
||||
<!-- <version>${revision}</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-module-crm-biz</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ERP 相关模块。默认注释,保证编译速度 -->
|
||||
<!-- <dependency>-->
|
||||
|
|
|
@ -47,7 +47,7 @@ spring:
|
|||
primary: master
|
||||
datasource:
|
||||
master:
|
||||
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
|
||||
url: jdbc:mysql://192.168.111.130:3306/ruoyi?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
|
||||
# url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例
|
||||
# url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
|
||||
# url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
|
||||
|
@ -55,7 +55,7 @@ spring:
|
|||
# url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例
|
||||
# url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例
|
||||
# url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例
|
||||
username: root
|
||||
username: ruoyi
|
||||
password: 123456
|
||||
# username: sa # SQL Server 连接的示例
|
||||
# password: Yudao@2024 # SQL Server 连接的示例
|
||||
|
@ -65,7 +65,7 @@ spring:
|
|||
# password: Yudao@2024 # OpenGauss 连接的示例
|
||||
slave: # 模拟从库,可根据自己需要修改
|
||||
lazy: true # 开启懒加载,保证启动速度
|
||||
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
|
||||
url: jdbc:mysql://192.168.111.130:3306/ruoyi?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
|
||||
username: root
|
||||
password: 123456
|
||||
|
||||
|
|
Loading…
Reference in New Issue