diff --git a/pom.xml b/pom.xml
index 142869ff97..8659a524d2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,13 +15,13 @@
yudao-module-system
yudao-module-infra
-
-
+ yudao-module-member
+ yudao-module-bpm
-
+ yudao-module-crm
diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/invite/InviteUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/invite/InviteUtils.java
new file mode 100644
index 0000000000..a5d04b0a87
--- /dev/null
+++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/invite/InviteUtils.java
@@ -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;
+ }
+}
+
diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java
index 507fb4b3e7..db5e95bccd 100644
--- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java
+++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApi.java
@@ -86,4 +86,12 @@ public interface AdminUserApi {
*/
void validateUserList(Collection ids);
+ /**
+ * 根据邀请码,获得用户
+ *
+ * @param invitationCode 邀请码
+ * @return 用户
+ */
+ AdminUserRespDTO getUserByInvitationCode(String invitationCode);
+
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java
index 6af7bcd422..752122cce3 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java
@@ -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);
+ }
+
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
index 1015bc0736..8802133046 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
@@ -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 generateInviteCode(@RequestParam("id") Long id) {
+ userService.generateInviteCode(id);
+ return success(true);
+ }
+
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java
index 2837318f9a..760f2bbfd4 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserRespVO.java
@@ -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 部")
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java
index 2f07a3015a..e4a98f2944 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java
@@ -93,4 +93,9 @@ public class AdminUserDO extends TenantBaseDO {
*/
private LocalDateTime loginDate;
+ /**
+ * 邀请码
+ */
+ private String invitationCode;
+
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java
index c0c9be8e42..ed4bcc6f2c 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/AdminUserMapper.java
@@ -48,4 +48,7 @@ public interface AdminUserMapper extends BaseMapperX {
return selectList(AdminUserDO::getDeptId, deptIds);
}
+ default AdminUserDO selectByInvitationCode(String invitationCode){
+ return selectOne(AdminUserDO::getInvitationCode,invitationCode);
+ };
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java
index 15564408d7..84c8238717 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java
@@ -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);
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
index 09e7b61e1f..cf902f6d12 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
@@ -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);
+ }
+
+ }
}
diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml
index efd53c84a5..6ac577f9e0 100644
--- a/yudao-server/pom.xml
+++ b/yudao-server/pom.xml
@@ -33,11 +33,11 @@
-
-
-
-
-
+
+ cn.iocoder.boot
+ yudao-module-member-biz
+ ${revision}
+
@@ -46,11 +46,11 @@
-
-
-
-
-
+
+ cn.iocoder.boot
+ yudao-module-bpm-biz
+ ${revision}
+
@@ -88,11 +88,11 @@
-
-
-
-
-
+
+ cn.iocoder.boot
+ yudao-module-crm-biz
+ ${revision}
+
diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml
index 60564f094b..d5ac4323f7 100644
--- a/yudao-server/src/main/resources/application-local.yaml
+++ b/yudao-server/src/main/resources/application-local.yaml
@@ -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