You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1277 lines
106 KiB
1277 lines
106 KiB
diff --git a/crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java b/crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java
|
|
index 189453e..a13cefb 100644
|
|
--- a/crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/config/DataInitializer.java
|
|
@@ -1,15 +1,23 @@
|
|
package com.crm.auth.config;
|
|
|
|
-import com.crm.auth.domain.entity.*;
|
|
-import com.crm.auth.mapper.*;
|
|
-import com.crm.auth.service.ISysRoleService;
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
+import com.crm.auth.domain.entity.SysMenu;
|
|
+import com.crm.auth.domain.entity.SysRole;
|
|
+import com.crm.auth.domain.entity.SysRoleMenu;
|
|
+import com.crm.auth.mapper.SysMenuMapper;
|
|
+import com.crm.auth.mapper.SysRoleMapper;
|
|
+import com.crm.auth.mapper.SysRoleMenuMapper;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.boot.CommandLineRunner;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
+import java.util.List;
|
|
+
|
|
/**
|
|
- * 绯荤粺鏁版嵁鍒濆鍖栵細棣栨鍚姩鏃惰嫢鏉冮檺琛ㄤ负绌猴紝鎻掑叆榛樿绠$悊鍛樿鑹层€佽彍鍗曘€佽鑹?鐢ㄦ埛缁戝畾銆?+ * 绯荤粺鏁版嵁鍒濆鍖栵紙骞傜瓑锛夛細姣忔鍚姩閫愰」妫€鏌ワ紝鍙ˉ缂虹殑銆?+ * <p>鍒涘缓鍐呯疆绠$悊鍛樿鑹层€佺郴缁熺鐞嗚彍鍗曘€佽鑹茬鐞?button 鏉冮檺鐐癸紝
|
|
+ * 骞跺皢鍏ㄩ儴璧勬簮鍒嗛厤缁欑鐞嗗憳瑙掕壊锛圓DR-0012锛夈€?/p>
|
|
*/
|
|
@Slf4j
|
|
@Component
|
|
@@ -19,41 +27,87 @@ public class DataInitializer implements CommandLineRunner {
|
|
private final SysRoleMapper sysRoleMapper;
|
|
private final SysMenuMapper sysMenuMapper;
|
|
private final SysRoleMenuMapper sysRoleMenuMapper;
|
|
- private final SysUserRoleMapper sysUserRoleMapper;
|
|
|
|
@Override
|
|
public void run(String... args) {
|
|
- if (sysRoleMapper.selectCount(null) > 0) {
|
|
- log.info("鏉冮檺鏁版嵁宸插瓨鍦紝璺宠繃鍒濆鍖?);
|
|
- return;
|
|
+ log.info("鎵ц鏉冮檺鏁版嵁鍒濆鍖栨鏌?..");
|
|
+
|
|
+ // ---- 鍐呯疆瑙掕壊锛欰DMIN ----
|
|
+ SysRole adminRole = sysRoleMapper.selectOne(
|
|
+ new LambdaQueryWrapper<SysRole>().eq(SysRole::getRoleCode, "ROLE_ADMIN"));
|
|
+ if (adminRole == null) {
|
|
+ adminRole = new SysRole();
|
|
+ adminRole.setRoleName("绠$悊鍛?);
|
|
+ adminRole.setRoleCode("ROLE_ADMIN");
|
|
+ adminRole.setDataScope(4);
|
|
+ adminRole.setSort(0);
|
|
+ adminRole.setBuiltin(true);
|
|
+ sysRoleMapper.insert(adminRole);
|
|
+ log.info("鍒涘缓鍐呯疆瑙掕壊锛歿}", adminRole.getRoleCode());
|
|
+ } else if (!Boolean.TRUE.equals(adminRole.getBuiltin())) {
|
|
+ adminRole.setBuiltin(true);
|
|
+ sysRoleMapper.updateById(adminRole);
|
|
+ log.info("琛ヨ鍐呯疆瑙掕壊鏍囪锛歿}", adminRole.getRoleCode());
|
|
+ }
|
|
+
|
|
+ // ---- 涓€绾х洰褰曪細绯荤粺绠$悊 ----
|
|
+ SysMenu sysManage = findMenu("绯荤粺绠$悊", 0L);
|
|
+ if (sysManage == null) {
|
|
+ sysManage = insertMenu("绯荤粺绠$悊", 0L, 1, null, null, 0);
|
|
+ }
|
|
+
|
|
+ // ---- 浜岀骇鑿滃崟 ----
|
|
+ SysMenu roleManage = findMenu("瑙掕壊绠$悊", sysManage.getId());
|
|
+ if (roleManage == null) {
|
|
+ roleManage = insertMenu("瑙掕壊绠$悊", sysManage.getId(), 2,
|
|
+ "/system/role", "system/role/index", 1);
|
|
+ }
|
|
+ SysMenu menuManage = findMenu("鑿滃崟绠$悊", sysManage.getId());
|
|
+ if (menuManage == null) {
|
|
+ menuManage = insertMenu("鑿滃崟绠$悊", sysManage.getId(), 2,
|
|
+ "/system/menu", "system/menu/index", 2);
|
|
+ }
|
|
+ SysMenu deptManage = findMenu("閮ㄩ棬绠$悊", sysManage.getId());
|
|
+ if (deptManage == null) {
|
|
+ deptManage = insertMenu("閮ㄩ棬绠$悊", sysManage.getId(), 2,
|
|
+ "/system/dept", "system/dept/index", 3);
|
|
+ }
|
|
+
|
|
+ // ---- 瑙掕壊绠$悊 button 鏉冮檺鐐癸紙ADR-0012锛?----
|
|
+ insertButtonIfAbsent("瑙掕壊鍒楄〃", roleManage.getId(), "crm:role:list", "/api/roles/page", 1);
|
|
+ insertButtonIfAbsent("瑙掕壊璇︽儏", roleManage.getId(), "crm:role:detail", "/api/roles/detail", 2);
|
|
+ insertButtonIfAbsent("瑙掕壊淇濆瓨", roleManage.getId(), "crm:role:save", "/api/roles/saveOrUpdate", 3);
|
|
+ insertButtonIfAbsent("瑙掕壊鍒犻櫎", roleManage.getId(), "crm:role:delete", "/api/roles/delete", 4);
|
|
+ insertButtonIfAbsent("鏉冮檺鍒嗛厤", roleManage.getId(), "crm:role:assign", "/api/roles/assign-resources", 5);
|
|
+
|
|
+ // ---- 瑙掕壊-鑿滃崟缁戝畾锛堢鐞嗗憳鎷ユ湁鎵€鏈夎彍鍗曞拰鏉冮檺鐐癸級 ----
|
|
+ bindIfAbsent(adminRole.getId(), sysManage.getId());
|
|
+ bindIfAbsent(adminRole.getId(), roleManage.getId());
|
|
+ bindIfAbsent(adminRole.getId(), menuManage.getId());
|
|
+ bindIfAbsent(adminRole.getId(), deptManage.getId());
|
|
+ // 缁戝畾瑙掕壊绠$悊涓嬬殑鍏ㄩ儴 button 鏉冮檺鐐?+ List<SysMenu> roleButtons = sysMenuMapper.selectList(
|
|
+ new LambdaQueryWrapper<SysMenu>()
|
|
+ .eq(SysMenu::getParentId, roleManage.getId())
|
|
+ .eq(SysMenu::getMenuType, 3));
|
|
+ for (SysMenu btn : roleButtons) {
|
|
+ bindIfAbsent(adminRole.getId(), btn.getId());
|
|
}
|
|
- log.info("棣栨鍚姩锛屽垵濮嬪寲榛樿鏉冮檺鏁版嵁...");
|
|
-
|
|
- // ---- 瑙掕壊 ----
|
|
- SysRole adminRole = new SysRole();
|
|
- adminRole.setRoleName("绠$悊鍛?);
|
|
- adminRole.setRoleCode("ROLE_ADMIN");
|
|
- adminRole.setDataScope(4); // 鍏ㄩ儴鏁版嵁
|
|
- adminRole.setSort(0);
|
|
- sysRoleMapper.insert(adminRole);
|
|
-
|
|
- // ---- 鑿滃崟 ----
|
|
- // 涓€绾х洰褰?- SysMenu sysManage = menu("绯荤粺绠$悊", 0L, 1, null, null, 0);
|
|
- SysMenu roleManage = menu("瑙掕壊绠$悊", sysManage.getId(), 2, "/system/role", "system/role/index", 1);
|
|
- SysMenu menuManage = menu("鑿滃崟绠$悊", sysManage.getId(), 2, "/system/menu", "system/menu/index", 2);
|
|
- SysMenu deptManage = menu("閮ㄩ棬绠$悊", sysManage.getId(), 2, "/system/dept", "system/dept/index", 3);
|
|
-
|
|
- // ---- 瑙掕壊-鑿滃崟缁戝畾锛堢鐞嗗憳鎷ユ湁鎵€鏈夎彍鍗曪級 ----
|
|
- bind(adminRole.getId(), sysManage.getId());
|
|
- bind(adminRole.getId(), roleManage.getId());
|
|
- bind(adminRole.getId(), menuManage.getId());
|
|
- bind(adminRole.getId(), deptManage.getId());
|
|
-
|
|
- log.info("榛樿鏉冮檺鏁版嵁鍒濆鍖栧畬鎴?);
|
|
+
|
|
+ log.info("鏉冮檺鏁版嵁鍒濆鍖栨鏌ュ畬鎴?);
|
|
+ }
|
|
+
|
|
+ // ==================== 骞傜瓑杈呭姪鏂规硶 ====================
|
|
+
|
|
+ private SysMenu findMenu(String name, Long parentId) {
|
|
+ return sysMenuMapper.selectOne(
|
|
+ new LambdaQueryWrapper<SysMenu>()
|
|
+ .eq(SysMenu::getMenuName, name)
|
|
+ .eq(SysMenu::getParentId, parentId));
|
|
}
|
|
|
|
- private SysMenu menu(String name, Long parentId, int type, String path, String component, int sort) {
|
|
+ private SysMenu insertMenu(String name, Long parentId, int type,
|
|
+ String path, String component, int sort) {
|
|
SysMenu m = new SysMenu();
|
|
m.setParentId(parentId);
|
|
m.setMenuName(name);
|
|
@@ -63,10 +117,39 @@ public class DataInitializer implements CommandLineRunner {
|
|
m.setSort(sort);
|
|
m.setVisible(true);
|
|
sysMenuMapper.insert(m);
|
|
+ log.info("鍒涘缓鑿滃崟鑺傜偣锛歿} (type={})", name, type);
|
|
return m;
|
|
}
|
|
|
|
- private void bind(Long roleId, Long menuId) {
|
|
+ private void insertButtonIfAbsent(String name, Long parentId,
|
|
+ String perms, String apiUrl, int sort) {
|
|
+ Long count = sysMenuMapper.selectCount(
|
|
+ new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getPerms, perms));
|
|
+ if (count > 0) {
|
|
+ return;
|
|
+ }
|
|
+ SysMenu btn = new SysMenu();
|
|
+ btn.setParentId(parentId);
|
|
+ btn.setMenuName(name);
|
|
+ btn.setMenuType(3);
|
|
+ btn.setSort(sort);
|
|
+ btn.setVisible(true);
|
|
+ btn.setPerms(perms);
|
|
+ btn.setDenyBehavior("hide");
|
|
+ btn.setApiUrl(apiUrl);
|
|
+ btn.setStatus("enabled");
|
|
+ sysMenuMapper.insert(btn);
|
|
+ log.info("鍒涘缓鏉冮檺鐐癸細{} -> {}", name, perms);
|
|
+ }
|
|
+
|
|
+ private void bindIfAbsent(Long roleId, Long menuId) {
|
|
+ Long count = sysRoleMenuMapper.selectCount(
|
|
+ new LambdaQueryWrapper<SysRoleMenu>()
|
|
+ .eq(SysRoleMenu::getRoleId, roleId)
|
|
+ .eq(SysRoleMenu::getMenuId, menuId));
|
|
+ if (count > 0) {
|
|
+ return;
|
|
+ }
|
|
SysRoleMenu rm = new SysRoleMenu();
|
|
rm.setRoleId(roleId);
|
|
rm.setMenuId(menuId);
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java b/crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java
|
|
index 4f1f19c..4f4f17c 100644
|
|
--- a/crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/constant/AuthConstants.java
|
|
@@ -51,4 +51,13 @@ public interface AuthConstants {
|
|
|
|
/** 闈炴湰缁勭粐鎴愬憳锛堢粍缁囧噯鍏ユ牎楠屾湭閫氳繃锛?*/
|
|
int CODE_NOT_ORG_MEMBER = 61008;
|
|
+
|
|
+ /** 瑙掕壊鍙傛暟闈炴硶锛堢紪鐮佷负绌恒€佹暟鎹寖鍥磋秺鐣岀瓑锛?*/
|
|
+ int CODE_ROLE_INVALID = 61010;
|
|
+
|
|
+ /** 瑙掕壊缂栫爜宸插瓨鍦?*/
|
|
+ int CODE_ROLE_CODE_DUPLICATE = 61011;
|
|
+
|
|
+ /** 鍐呯疆瑙掕壊淇濇姢锛堢姝㈠垹闄ゆ垨鏀圭紪鐮侊級 */
|
|
+ int CODE_BUILTIN_ROLE_PROTECTED = 61012;
|
|
}
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/controller/AuthController.java b/crm-auth/src/main/java/com/crm/auth/controller/AuthController.java
|
|
index c14454f..34a50e7 100644
|
|
--- a/crm-auth/src/main/java/com/crm/auth/controller/AuthController.java
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/controller/AuthController.java
|
|
@@ -27,20 +27,20 @@ public class AuthController {
|
|
|
|
private final IAuthService authService;
|
|
|
|
- @Operation(summary = "閽夐拤鎵爜鐧诲綍")
|
|
+ @Operation(summary = "閽夐拤鐧诲綍锛堟壂鐮?鍏嶇櫥閫氱敤锛? , tags = "鐧诲綍")
|
|
@PostMapping("/login/dingtalk")
|
|
public Result<LoginResultDTO> loginByDingTalk(@RequestParam String authCode) {
|
|
return Result.success(authService.login(IdentityTypeEnum.DINGTALK, authCode));
|
|
}
|
|
|
|
- @Operation(summary = "娉ㄩ攢")
|
|
+ @Operation(summary = "娉ㄩ攢" , tags = "鐧诲綍")
|
|
@PostMapping("/logout")
|
|
public Result<Void> logout(HttpServletRequest request) {
|
|
authService.logout(resolveToken(request));
|
|
return Result.success();
|
|
}
|
|
|
|
- @Operation(summary = "鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅")
|
|
+ @Operation(summary = "鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅" , tags = "鐧诲綍")
|
|
@GetMapping("/me")
|
|
public Result<UserInfoDTO> me() {
|
|
return Result.success(authService.getCurrentUserInfo());
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/controller/ResourceController.java b/crm-auth/src/main/java/com/crm/auth/controller/ResourceController.java
|
|
index ee26018..9951b59 100644
|
|
--- a/crm-auth/src/main/java/com/crm/auth/controller/ResourceController.java
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/controller/ResourceController.java
|
|
@@ -4,6 +4,7 @@ import com.crm.auth.domain.dto.ResourceNode;
|
|
import com.crm.auth.service.IResourceService;
|
|
import com.crm.base.domain.result.Result;
|
|
import com.crm.file.domain.dto.FileInfoDTO;
|
|
+import io.swagger.v3.oas.annotations.Operation;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.springframework.security.access.prepost.PreAuthorize;
|
|
import org.springframework.web.bind.annotation.*;
|
|
@@ -25,18 +26,21 @@ public class ResourceController {
|
|
|
|
/** 鍏ㄩ噺璧勬簮鏍戯紙鎵佸钩鏁扮粍锛屽墠绔寜 parentId 缁勬爲锛?*/
|
|
@GetMapping("/list")
|
|
+ @Operation(summary = "鑾峰彇鏉冮檺璧勬簮鏍? , tags = "鏉冮檺鐐圭鐞?)
|
|
public Result<List<ResourceNode>> listAll() {
|
|
return Result.success(resourceService.listAll());
|
|
}
|
|
|
|
/** 鏂板鎴栫紪杈戣妭鐐癸紙鍚牎楠岋級 */
|
|
@PostMapping("/saveOrUpdate")
|
|
+ @Operation(summary = "鏂板缂栬緫涓€绾ц彍鍗?浜岀骇鑿滃崟/鏉冮檺鐐? , tags = "鏉冮檺鐐圭鐞?)
|
|
public Result<ResourceNode> saveOrUpdate(ResourceNode node) {
|
|
return Result.success(resourceService.save(node));
|
|
}
|
|
|
|
/** 鍒犻櫎鑺傜偣锛堝惈瀛愯妭鐐规鏌?+ 绾ц仈娓呯悊锛?*/
|
|
@PostMapping("/delete")
|
|
+ @Operation(summary = "鍒犻櫎涓€绾ц彍鍗?浜岀骇鑿滃崟/鏉冮檺鐐? , tags = "鏉冮檺鐐圭鐞?)
|
|
public Result<Void> delete(@RequestParam Long id) {
|
|
resourceService.delete(id);
|
|
return Result.success();
|
|
@@ -44,6 +48,7 @@ public class ResourceController {
|
|
|
|
/** 鍥炬爣涓婁紶锛堟牸寮?澶у皬鏍¢獙锛?*/
|
|
@PostMapping("/icon/upload")
|
|
+ @Operation(summary = "涓婁紶鍥炬爣" , tags = "鏉冮檺鐐圭鐞?)
|
|
public Result<FileInfoDTO> uploadIcon(@RequestParam("file") MultipartFile file) {
|
|
return Result.success(resourceService.uploadIcon(file));
|
|
}
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/controller/RoleController.java b/crm-auth/src/main/java/com/crm/auth/controller/RoleController.java
|
|
new file mode 100644
|
|
index 0000000..fc5178d
|
|
--- /dev/null
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/controller/RoleController.java
|
|
@@ -0,0 +1,97 @@
|
|
+package com.crm.auth.controller;
|
|
+
|
|
+import cn.hutool.core.util.StrUtil;
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
+import com.crm.auth.domain.dto.RoleDetailVO;
|
|
+import com.crm.auth.domain.entity.SysRole;
|
|
+import com.crm.auth.service.ISysRoleService;
|
|
+import com.crm.base.domain.result.PageResult;
|
|
+import com.crm.base.domain.result.Result;
|
|
+import io.swagger.v3.oas.annotations.Operation;
|
|
+import lombok.RequiredArgsConstructor;
|
|
+import org.springframework.security.access.prepost.PreAuthorize;
|
|
+import org.springframework.web.bind.annotation.*;
|
|
+
|
|
+import java.util.Arrays;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.stream.Collectors;
|
|
+
|
|
+/**
|
|
+ * 瑙掕壊绠$悊绔帴鍙o紙ADR-0012锛?+ * <p>閬靛惊鍏ㄥ眬鎺ュ彛濂戠害锛氶潪涓ユ牸 RESTful锛屽啓鎿嶄綔 POST + 鍔ㄤ綔鍚庣紑锛岃〃鍗曞瓧娈垫敹鍙?/p>
|
|
+ * <p>鏉冮檺鎺у埗锛氱函 hasAuthority锛屾潈闄愮爜鐢辨暟鎹垵濮嬪寲鍣ㄧ瀛愬寲鍒版潈闄愯祫婧愭爲</p>
|
|
+ */
|
|
+@RestController
|
|
+@RequestMapping("/api/roles")
|
|
+@RequiredArgsConstructor
|
|
+public class RoleController {
|
|
+
|
|
+ private final ISysRoleService sysRoleService;
|
|
+
|
|
+ @PostMapping("/page")
|
|
+ @PreAuthorize("hasAuthority('crm:role:list')")
|
|
+ @Operation(summary = "鍒嗛〉鏌ヨ瑙掕壊", tags = "瑙掕壊绠$悊")
|
|
+ public Result<PageResult<SysRole>> page(
|
|
+ @RequestParam(defaultValue = "1") Long current,
|
|
+ @RequestParam(defaultValue = "10") Long size,
|
|
+ @RequestParam(required = false) String keyword) {
|
|
+ Page<SysRole> page = new Page<>(current, size);
|
|
+ sysRoleService.lambdaQuery()
|
|
+ .like(StrUtil.isNotBlank(keyword), SysRole::getRoleName, keyword)
|
|
+ .page(page);
|
|
+ return Result.success(new PageResult<>(page));
|
|
+ }
|
|
+
|
|
+ @PostMapping("/saveOrUpdate")
|
|
+ @PreAuthorize("hasAuthority('crm:role:save')")
|
|
+ @Operation(summary = "鏂板鎴栫紪杈戣鑹?, tags = "瑙掕壊绠$悊")
|
|
+ public Result<Void> saveOrUpdate(
|
|
+ @RequestParam(required = false) Long id,
|
|
+ @RequestParam String roleName,
|
|
+ @RequestParam String roleCode,
|
|
+ @RequestParam(defaultValue = "1") Integer dataScope,
|
|
+ @RequestParam(defaultValue = "0") Integer sort,
|
|
+ @RequestParam(required = false) String remark) {
|
|
+ SysRole role = new SysRole();
|
|
+ role.setId(id);
|
|
+ role.setRoleName(roleName);
|
|
+ role.setRoleCode(roleCode);
|
|
+ role.setDataScope(dataScope);
|
|
+ role.setSort(sort);
|
|
+ role.setRemark(remark);
|
|
+ sysRoleService.saveRole(role);
|
|
+ return Result.success();
|
|
+ }
|
|
+
|
|
+ @GetMapping("/detail")
|
|
+ @PreAuthorize("hasAuthority('crm:role:detail')")
|
|
+ @Operation(summary = "瑙掕壊璇︽儏锛堝惈鎺堟潈璧勬簮闆嗗悎锛?, tags = "瑙掕壊绠$悊")
|
|
+ public Result<RoleDetailVO> detail(@RequestParam Long roleId) {
|
|
+ return Result.success(sysRoleService.getRoleDetail(roleId));
|
|
+ }
|
|
+
|
|
+ @PostMapping("/assign-resources")
|
|
+ @PreAuthorize("hasAuthority('crm:role:assign')")
|
|
+ @Operation(summary = "鍒嗛厤瑙掕壊鏉冮檺璧勬簮锛堢鍏堣ˉ鍏?鍏ㄩ噺鏇挎崲锛?, tags = "瑙掕壊绠$悊")
|
|
+ public Result<Void> assignResources(
|
|
+ @RequestParam Long roleId,
|
|
+ @RequestParam String resourceIds) {
|
|
+ List<Long> menuIdList = StrUtil.isBlank(resourceIds)
|
|
+ ? Collections.emptyList()
|
|
+ : Arrays.stream(resourceIds.split(","))
|
|
+ .filter(StrUtil::isNotBlank)
|
|
+ .map(idStr -> Long.valueOf(idStr.trim()))
|
|
+ .collect(Collectors.toList());
|
|
+ sysRoleService.assignResources(roleId, menuIdList);
|
|
+ return Result.success();
|
|
+ }
|
|
+
|
|
+ @PostMapping("/delete")
|
|
+ @PreAuthorize("hasAuthority('crm:role:delete')")
|
|
+ @Operation(summary = "鍒犻櫎瑙掕壊锛堢骇鑱旀竻鐞嗗叧鑱旇〃锛?, tags = "瑙掕壊绠$悊")
|
|
+ public Result<Void> delete(@RequestParam Long id) {
|
|
+ sysRoleService.deleteRoleCascade(id);
|
|
+ return Result.success();
|
|
+ }
|
|
+}
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/controller/SystemController.java b/crm-auth/src/main/java/com/crm/auth/controller/SystemController.java
|
|
index 790bf34..5535bcc 100644
|
|
--- a/crm-auth/src/main/java/com/crm/auth/controller/SystemController.java
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/controller/SystemController.java
|
|
@@ -6,12 +6,9 @@ import com.crm.auth.domain.dto.UserListDTO;
|
|
import com.crm.auth.domain.dto.UserStatsVO;
|
|
import com.crm.auth.domain.entity.SysDept;
|
|
import com.crm.auth.domain.entity.SysMenu;
|
|
-import com.crm.auth.domain.entity.SysRole;
|
|
import com.crm.auth.domain.param.UserPageParam;
|
|
import com.crm.auth.service.IAuthUserService;
|
|
import com.crm.auth.service.ISysDeptService;
|
|
-import com.crm.auth.service.ISysMenuService;
|
|
-import com.crm.auth.service.ISysRoleService;
|
|
import com.crm.auth.security.PermissionResolver;
|
|
import com.crm.base.domain.result.PageResult;
|
|
import com.crm.base.domain.result.Result;
|
|
@@ -29,8 +26,6 @@ import java.util.stream.Collectors;
|
|
@RequiredArgsConstructor
|
|
public class SystemController {
|
|
|
|
- private final ISysRoleService sysRoleService;
|
|
- private final ISysMenuService sysMenuService;
|
|
private final ISysDeptService sysDeptService;
|
|
private final IAuthUserService authUserService;
|
|
private final PermissionResolver permissionResolver;
|
|
@@ -43,62 +38,6 @@ public class SystemController {
|
|
return Result.success(permissionResolver.visibleMenuTree(userId));
|
|
}
|
|
|
|
- // ========== 瑙掕壊 ==========
|
|
-
|
|
- @PostMapping("/roles/page")
|
|
- public Result<PageResult<SysRole>> rolePage(
|
|
- @RequestParam(defaultValue = "1") Long current,
|
|
- @RequestParam(defaultValue = "10") Long size,
|
|
- @RequestParam(required = false) String keyword) {
|
|
- Page<SysRole> page = new Page<>(current, size);
|
|
- sysRoleService.lambdaQuery()
|
|
- .like(StrUtil.isNotBlank(keyword), SysRole::getRoleName, keyword)
|
|
- .page(page);
|
|
- return Result.success(new PageResult<>(page));
|
|
- }
|
|
-
|
|
- @PostMapping("/roles/save")
|
|
- public Result<Void> saveRole(
|
|
- @RequestParam(required = false) Long id,
|
|
- @RequestParam String roleName,
|
|
- @RequestParam String roleCode,
|
|
- @RequestParam(defaultValue = "1") Integer dataScope,
|
|
- @RequestParam(defaultValue = "0") Integer sort,
|
|
- @RequestParam(required = false) String remark) {
|
|
- SysRole role = new SysRole();
|
|
- role.setId(id);
|
|
- role.setRoleName(roleName);
|
|
- role.setRoleCode(roleCode);
|
|
- role.setDataScope(dataScope);
|
|
- role.setSort(sort);
|
|
- role.setRemark(remark);
|
|
- sysRoleService.saveOrUpdate(role);
|
|
- return Result.success();
|
|
- }
|
|
-
|
|
- @PostMapping("/roles/delete")
|
|
- public Result<Void> deleteRole(@RequestParam Long id) {
|
|
- sysRoleService.deleteRoleCascade(id);
|
|
- return Result.success();
|
|
- }
|
|
-
|
|
- @PostMapping("/roles/assign-menus")
|
|
- public Result<Void> assignRoleMenus(@RequestParam Long roleId, @RequestParam String menuIds) {
|
|
- List<Long> menuIdList = StrUtil.isBlank(menuIds)
|
|
- ? Collections.emptyList()
|
|
- : Arrays.stream(menuIds.split(","))
|
|
- .filter(StrUtil::isNotBlank)
|
|
- .map(idStr -> Long.valueOf(idStr.trim()))
|
|
- .collect(Collectors.toList());
|
|
- sysRoleService.assignMenus(roleId, menuIdList);
|
|
- return Result.success();
|
|
- }
|
|
-
|
|
- @GetMapping("/roles/menus")
|
|
- public Result<List<Long>> roleMenus(@RequestParam Long roleId) {
|
|
- return Result.success(sysMenuService.getMenuIdsByRoleId(roleId));
|
|
- }
|
|
-
|
|
// ========== 閮ㄩ棬 ==========
|
|
|
|
@GetMapping("/depts/tree")
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDetailVO.java b/crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDetailVO.java
|
|
new file mode 100644
|
|
index 0000000..4365cbd
|
|
--- /dev/null
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDetailVO.java
|
|
@@ -0,0 +1,60 @@
|
|
+package com.crm.auth.domain.dto;
|
|
+
|
|
+import com.crm.auth.domain.entity.SysRole;
|
|
+import io.swagger.v3.oas.annotations.media.Schema;
|
|
+import lombok.Data;
|
|
+
|
|
+import java.io.Serial;
|
|
+import java.io.Serializable;
|
|
+import java.util.List;
|
|
+
|
|
+/**
|
|
+ * 瑙掕壊璇︽儏 DTO锛圓DR-0012锛?+ * <p>瑙掕壊绠$悊璇︽儏鎺ュ彛鐨勮緭鍑鸿浇浣擄紱resourceIds 涓哄凡琛ュ叏绁栧厛鐨勫畬鏁存巿鏉冮泦鍚堬紙ADR-0005锛?/p>
|
|
+ */
|
|
+@Data
|
|
+public class RoleDetailVO implements Serializable {
|
|
+
|
|
+ @Serial
|
|
+ private static final long serialVersionUID = 1L;
|
|
+
|
|
+ @Schema(description = "瑙掕壊 ID")
|
|
+ private Long id;
|
|
+
|
|
+ @Schema(description = "瑙掕壊鍚嶇О")
|
|
+ private String roleName;
|
|
+
|
|
+ @Schema(description = "瑙掕壊缂栫爜")
|
|
+ private String roleCode;
|
|
+
|
|
+ @Schema(description = "鏁版嵁鑼冨洿 1=鏈汉 2=鏈儴闂?3=鏈儴闂ㄥ強瀛愰儴闂?4=鍏ㄩ儴")
|
|
+ private Integer dataScope;
|
|
+
|
|
+ @Schema(description = "鎺掑簭")
|
|
+ private Integer sort;
|
|
+
|
|
+ @Schema(description = "澶囨敞")
|
|
+ private String remark;
|
|
+
|
|
+ @Schema(description = "鏄惁鍐呯疆瑙掕壊")
|
|
+ private Boolean builtin;
|
|
+
|
|
+ @Schema(description = "宸茶ˉ鍏ㄧ鍏堢殑瀹屾暣鎺堟潈闆嗗悎锛堝瓨鍌ㄦ€侊級")
|
|
+ private List<Long> resourceIds;
|
|
+
|
|
+ /** SysRole 鈫?RoleDetailVO 鍩烘湰瀛楁鏄犲皠锛堜笉鍚?resourceIds锛?*/
|
|
+ public static RoleDetailVO fromEntity(SysRole entity) {
|
|
+ if (entity == null) {
|
|
+ return null;
|
|
+ }
|
|
+ RoleDetailVO vo = new RoleDetailVO();
|
|
+ vo.setId(entity.getId());
|
|
+ vo.setRoleName(entity.getRoleName());
|
|
+ vo.setRoleCode(entity.getRoleCode());
|
|
+ vo.setDataScope(entity.getDataScope());
|
|
+ vo.setSort(entity.getSort());
|
|
+ vo.setRemark(entity.getRemark());
|
|
+ vo.setBuiltin(entity.getBuiltin());
|
|
+ return vo;
|
|
+ }
|
|
+}
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java b/crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java
|
|
index 819e2f2..adb2d31 100644
|
|
--- a/crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java
|
|
@@ -33,4 +33,8 @@ public class SysRole extends BaseEntity {
|
|
@Comment("澶囨敞")
|
|
@Column(columnDefinition = "varchar(200) comment '澶囨敞'")
|
|
private String remark;
|
|
+
|
|
+ @Comment("鍐呯疆瑙掕壊鏍囪锛宼rue=绯荤粺鍐呯疆涓嶅彲鍒犻櫎涓嶅彲鏀圭紪鐮?)
|
|
+ @Column(columnDefinition = "boolean default false")
|
|
+ private Boolean builtin;
|
|
}
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/service/ISysMenuService.java b/crm-auth/src/main/java/com/crm/auth/service/ISysMenuService.java
|
|
index af633c1..272a9c4 100644
|
|
--- a/crm-auth/src/main/java/com/crm/auth/service/ISysMenuService.java
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/service/ISysMenuService.java
|
|
@@ -3,10 +3,17 @@ package com.crm.auth.service;
|
|
import com.crm.auth.domain.entity.SysMenu;
|
|
import com.crm.base.service.IBaseService;
|
|
|
|
-import java.util.List;
|
|
+import java.util.Collection;
|
|
+import java.util.Set;
|
|
|
|
public interface ISysMenuService extends IBaseService<SysMenu> {
|
|
|
|
- /** 鑾峰彇鏌愯鑹茬殑鑿滃崟ID鍒楄〃 */
|
|
- List<Long> getMenuIdsByRoleId(Long roleId);
|
|
+ /**
|
|
+ * 娌?parentId 鍚戜笂閬嶅巻锛岃ˉ鍏ㄧ粰瀹氳妭鐐归泦鍚堢殑鍏ㄩ儴绁栧厛 catalog/menu ID锛圓DR-0005锛夈€?+ * <p>鎵归噺鏌ュ叏琛ㄦ瀯寤?ID鈫抪arentId 鏄犲皠锛屽唴瀛橀亶鍘嗭紝閬垮厤閫愯妭鐐规煡 DB銆?/p>
|
|
+ *
|
|
+ * @param menuIds 鐢ㄦ埛鍕鹃€夌殑璧勬簮鑺傜偣 ID锛堝彲鑳戒笉鍚鍏堬級
|
|
+ * @return 鍖呭惈鍏ㄩ儴绁栧厛鐨勫畬鏁撮泦鍚堬紙杈撳叆 ID + 绁栧厛 ID锛夛紝瀛樺偍鎬?+ */
|
|
+ Set<Long> getAncestorIds(Collection<Long> menuIds);
|
|
}
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java b/crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java
|
|
index 8735b8d..c50ee13 100644
|
|
--- a/crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/service/ISysRoleService.java
|
|
@@ -1,5 +1,6 @@
|
|
package com.crm.auth.service;
|
|
|
|
+import com.crm.auth.domain.dto.RoleDetailVO;
|
|
import com.crm.auth.domain.entity.SysRole;
|
|
import com.crm.base.service.IBaseService;
|
|
|
|
@@ -8,12 +9,29 @@ import java.util.List;
|
|
public interface ISysRoleService extends IBaseService<SysRole> {
|
|
|
|
/**
|
|
- * 鍒嗛厤瑙掕壊鐨勮彍鍗曟潈闄愶紙鍏ㄩ噺鏇挎崲锛屼簨鍔′繚鎶わ級
|
|
+ * 淇濆瓨瑙掕壊锛堝甫鏍¢獙锛歳oleCode 鍞竴銆佸唴缃鑹蹭繚鎶ゃ€乨ataScope 鑼冨洿銆佺璁?builtin锛? *
|
|
- * @param roleId 瑙掕壊 ID
|
|
- * @param menuIds 鑿滃崟 ID 鍒楄〃
|
|
+ * @param role 瑙掕壊淇℃伅锛坕d 涓虹┖鏃舵柊澧炪€侀潪绌烘椂缂栬緫锛?+ * @return 淇濆瓨鍚庣殑瑙掕壊锛堝惈 ID锛? */
|
|
- void assignMenus(Long roleId, List<Long> menuIds);
|
|
+ SysRole saveRole(SysRole role);
|
|
+
|
|
+ /**
|
|
+ * 鑾峰彇瑙掕壊璇︽儏锛堝熀鏈俊鎭?+ 宸叉巿鏉冭祫婧?ID 闆嗗悎锛?+ *
|
|
+ * @param roleId 瑙掕壊 ID
|
|
+ * @return RoleDetailVO锛屽惈 resourceIds锛堜粠 sys_role_menu 鏌ュ嚭鐨勫畬鏁存巿鏉冮泦鍚堬級
|
|
+ */
|
|
+ RoleDetailVO getRoleDetail(Long roleId);
|
|
+
|
|
+ /**
|
|
+ * 鍒嗛厤瑙掕壊鏉冮檺璧勬簮锛堢鍏堣ˉ鍏?+ 鍏ㄩ噺鏇挎崲锛屼簨鍔′繚鎶わ級
|
|
+ * <p>鍓嶇鍙紶鍕鹃€夌殑鍙跺瓙鑺傜偣锛屽悗绔皟鐢?ISysMenuService.getAncestorIds 琛ュ叏绁栧厛鍚庡叏閲忓啓鍏?sys_role_menu</p>
|
|
+ *
|
|
+ * @param roleId 瑙掕壊 ID
|
|
+ * @param resourceIds 鍓嶇鍕鹃€夌殑璧勬簮鑺傜偣 ID锛堝彲鑳戒笉鍚鍏堬級
|
|
+ */
|
|
+ void assignResources(Long roleId, List<Long> resourceIds);
|
|
|
|
/**
|
|
* 鍒犻櫎瑙掕壊骞剁骇鑱旀竻鐞嗚鑹?鑿滃崟鍏宠仈锛堜簨鍔′繚鎶わ級
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/service/impl/SysMenuServiceImpl.java b/crm-auth/src/main/java/com/crm/auth/service/impl/SysMenuServiceImpl.java
|
|
index 6cb99a6..db54cd2 100644
|
|
--- a/crm-auth/src/main/java/com/crm/auth/service/impl/SysMenuServiceImpl.java
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/service/impl/SysMenuServiceImpl.java
|
|
@@ -1,32 +1,42 @@
|
|
package com.crm.auth.service.impl;
|
|
|
|
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.crm.auth.domain.entity.SysMenu;
|
|
-import com.crm.auth.domain.entity.SysRoleMenu;
|
|
import com.crm.auth.mapper.SysMenuMapper;
|
|
-import com.crm.auth.mapper.SysRoleMenuMapper;
|
|
import com.crm.auth.service.ISysMenuService;
|
|
import com.crm.base.service.impl.BaseServiceImpl;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
-import java.util.Collections;
|
|
-import java.util.List;
|
|
+import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class SysMenuServiceImpl extends BaseServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {
|
|
|
|
- private final SysRoleMenuMapper sysRoleMenuMapper;
|
|
-
|
|
@Override
|
|
- public List<Long> getMenuIdsByRoleId(Long roleId) {
|
|
- List<SysRoleMenu> list = sysRoleMenuMapper.selectList(
|
|
- new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
|
|
- if (list == null || list.isEmpty()) {
|
|
- return Collections.emptyList();
|
|
+ public Set<Long> getAncestorIds(Collection<Long> menuIds) {
|
|
+ if (menuIds == null || menuIds.isEmpty()) {
|
|
+ return Collections.emptySet();
|
|
+ }
|
|
+ // 鎵归噺鏌ュ叏琛紝鏋勫缓 ID鈫抪arentId 鏄犲皠
|
|
+ List<SysMenu> allMenus = list();
|
|
+ Map<Long, Long> parentIdMap = allMenus.stream()
|
|
+ .collect(Collectors.toMap(SysMenu::getId, SysMenu::getParentId, (a, b) -> a));
|
|
+
|
|
+ // 瀵规瘡涓緭鍏ヨ妭鐐癸紝娌?parentId 鍚戜笂閬嶅巻鏀堕泦绁栧厛
|
|
+ Set<Long> result = new LinkedHashSet<>(menuIds);
|
|
+ for (Long menuId : menuIds) {
|
|
+ Long current = menuId;
|
|
+ while (current != null) {
|
|
+ Long parent = parentIdMap.get(current);
|
|
+ if (parent == null || parent == 0L || result.contains(parent)) {
|
|
+ break;
|
|
+ }
|
|
+ result.add(parent);
|
|
+ current = parent;
|
|
+ }
|
|
}
|
|
- return list.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
|
|
+ return result;
|
|
}
|
|
}
|
|
diff --git a/crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java b/crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java
|
|
index f8423c8..95e2a87 100644
|
|
--- a/crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java
|
|
+++ b/crm-auth/src/main/java/com/crm/auth/service/impl/SysRoleServiceImpl.java
|
|
@@ -1,47 +1,135 @@
|
|
package com.crm.auth.service.impl;
|
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
+import com.crm.auth.constant.AuthConstants;
|
|
+import com.crm.auth.domain.dto.RoleDetailVO;
|
|
import com.crm.auth.domain.entity.SysRole;
|
|
import com.crm.auth.domain.entity.SysRoleMenu;
|
|
+import com.crm.auth.domain.entity.SysUserRole;
|
|
import com.crm.auth.mapper.SysRoleMapper;
|
|
import com.crm.auth.mapper.SysRoleMenuMapper;
|
|
+import com.crm.auth.mapper.SysUserRoleMapper;
|
|
+import com.crm.auth.service.ISysMenuService;
|
|
import com.crm.auth.service.ISysRoleService;
|
|
+import com.crm.base.domain.exception.BusinessErrorException;
|
|
import com.crm.base.service.impl.BaseServiceImpl;
|
|
import lombok.RequiredArgsConstructor;
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
import java.util.List;
|
|
+import java.util.Set;
|
|
|
|
+import static com.crm.auth.constant.AuthConstants.*;
|
|
+
|
|
+@Slf4j
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {
|
|
|
|
private final SysRoleMenuMapper sysRoleMenuMapper;
|
|
+ private final SysUserRoleMapper sysUserRoleMapper;
|
|
+ private final ISysMenuService sysMenuService;
|
|
+
|
|
+ @Override
|
|
+ public SysRole saveRole(SysRole role) {
|
|
+ // 鍩烘湰闈炵┖鏍¢獙
|
|
+ if (StrUtil.isBlank(role.getRoleName())) {
|
|
+ throw new BusinessErrorException(CODE_ROLE_INVALID, "瑙掕壊鍚嶇О涓嶈兘涓虹┖");
|
|
+ }
|
|
+ if (StrUtil.isBlank(role.getRoleCode())) {
|
|
+ throw new BusinessErrorException(CODE_ROLE_INVALID, "瑙掕壊缂栫爜涓嶈兘涓虹┖");
|
|
+ }
|
|
+
|
|
+ // dataScope 鑼冨洿鏍¢獙
|
|
+ if (role.getDataScope() != null && (role.getDataScope() < 1 || role.getDataScope() > 4)) {
|
|
+ throw new BusinessErrorException(CODE_ROLE_INVALID, "鏁版嵁鑼冨洿蹇呴』鍦?1-4 鑼冨洿鍐?);
|
|
+ }
|
|
+
|
|
+ // 鍐呯疆瑙掕壊淇濇姢锛氫笉鍏佽閫氳繃鎺ュ彛鍒涘缓鍐呯疆瑙掕壊锛堟棤璁烘柊寤鸿繕鏄紪杈戜笉瀛樺湪鐨勮褰曪級
|
|
+ SysRole existing = role.getId() != null ? baseMapper.selectById(role.getId()) : null;
|
|
+ if (Boolean.TRUE.equals(role.getBuiltin())
|
|
+ && (existing == null || !Boolean.TRUE.equals(existing.getBuiltin()))) {
|
|
+ throw new BusinessErrorException(CODE_BUILTIN_ROLE_PROTECTED, "涓嶅厑璁搁€氳繃鎺ュ彛鍒涘缓鍐呯疆瑙掕壊");
|
|
+ }
|
|
+ if (role.getId() == null) {
|
|
+ role.setBuiltin(false);
|
|
+ } else if (existing != null && Boolean.TRUE.equals(existing.getBuiltin())
|
|
+ && !existing.getRoleCode().equals(role.getRoleCode())) {
|
|
+ // 缂栬緫锛氬唴缃鑹茬姝㈡敼 roleCode
|
|
+ throw new BusinessErrorException(CODE_BUILTIN_ROLE_PROTECTED, "鍐呯疆瑙掕壊鐨勭紪鐮佷笉鍙慨鏀?);
|
|
+ }
|
|
+
|
|
+ // roleCode 鍞竴鎬ф牎楠?+ Long count = baseMapper.selectCount(
|
|
+ new LambdaQueryWrapper<SysRole>()
|
|
+ .eq(SysRole::getRoleCode, role.getRoleCode())
|
|
+ .ne(role.getId() != null, SysRole::getId, role.getId()));
|
|
+ if (count != null && count > 0) {
|
|
+ throw new BusinessErrorException(CODE_ROLE_CODE_DUPLICATE,
|
|
+ "瑙掕壊缂栫爜宸插瓨鍦細" + role.getRoleCode());
|
|
+ }
|
|
+
|
|
+ saveOrUpdate(role);
|
|
+ log.info("淇濆瓨瑙掕壊锛歩d={}, roleCode={}", role.getId(), role.getRoleCode());
|
|
+ return role;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public RoleDetailVO getRoleDetail(Long roleId) {
|
|
+ SysRole role = baseMapper.selectById(roleId);
|
|
+ if (role == null) {
|
|
+ throw new BusinessErrorException(CODE_ROLE_INVALID, "瑙掕壊涓嶅瓨鍦細" + roleId);
|
|
+ }
|
|
+ RoleDetailVO vo = RoleDetailVO.fromEntity(role);
|
|
+ // 鏌?sys_role_menu 寰楀埌瀹屾暣鎺堟潈闆嗗悎锛堝瓨鍌ㄦ€侊紝宸插惈绁栧厛锛?+ List<SysRoleMenu> bindings = sysRoleMenuMapper.selectList(
|
|
+ new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
|
|
+ List<Long> resourceIds = bindings.stream()
|
|
+ .map(SysRoleMenu::getMenuId)
|
|
+ .toList();
|
|
+ vo.setResourceIds(resourceIds);
|
|
+ return vo;
|
|
+ }
|
|
|
|
@Override
|
|
@Transactional(rollbackFor = Exception.class)
|
|
- public void assignMenus(Long roleId, List<Long> menuIds) {
|
|
- // 鍏堝垹鍚庢彃锛堝叏閲忔浛鎹級
|
|
+ public void assignResources(Long roleId, List<Long> resourceIds) {
|
|
+ // 绁栧厛琛ュ叏锛氬墠绔彧浼犲嬀閫夌殑鍙跺瓙鑺傜偣锛屽悗绔ˉ鍏ㄥ叏閮ㄧ鍏?catalog/menu ID
|
|
+ Set<Long> completeIds = sysMenuService.getAncestorIds(resourceIds);
|
|
+ log.info("鍒嗛厤瑙掕壊璧勬簮锛歳oleId={}, 杈撳叆 {} 涓?-> 琛ュ叏鍚?{} 涓?, roleId,
|
|
+ resourceIds != null ? resourceIds.size() : 0, completeIds.size());
|
|
+
|
|
+ // 鍏堝垹鍚庢彃锛堝叏閲忔浛鎹?sys_role_menu锛? sysRoleMenuMapper.delete(
|
|
new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
|
|
- if (menuIds != null && !menuIds.isEmpty()) {
|
|
- for (Long menuId : menuIds) {
|
|
- SysRoleMenu rm = new SysRoleMenu();
|
|
- rm.setRoleId(roleId);
|
|
- rm.setMenuId(menuId);
|
|
- sysRoleMenuMapper.insert(rm);
|
|
- }
|
|
+ for (Long menuId : completeIds) {
|
|
+ SysRoleMenu rm = new SysRoleMenu();
|
|
+ rm.setRoleId(roleId);
|
|
+ rm.setMenuId(menuId);
|
|
+ sysRoleMenuMapper.insert(rm);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
@Transactional(rollbackFor = Exception.class)
|
|
public void deleteRoleCascade(Long roleId) {
|
|
+ // 鍐呯疆瑙掕壊淇濇姢锛歜uiltin=true 鐨勮鑹叉嫆缁濆垹闄?+ SysRole role = baseMapper.selectById(roleId);
|
|
+ if (role != null && Boolean.TRUE.equals(role.getBuiltin())) {
|
|
+ throw new BusinessErrorException(CODE_BUILTIN_ROLE_PROTECTED, "鍐呯疆瑙掕壊涓嶅厑璁稿垹闄?);
|
|
+ }
|
|
// 绾ц仈娓呯悊瑙掕壊-鑿滃崟鍏宠仈
|
|
sysRoleMenuMapper.delete(
|
|
new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
|
|
+ // 绾ц仈娓呯悊鐢ㄦ埛-瑙掕壊鍏宠仈
|
|
+ sysUserRoleMapper.delete(
|
|
+ new LambdaQueryWrapper<SysUserRole>()
|
|
+ .eq(SysUserRole::getRoleId, roleId));
|
|
// 鍒犻櫎瑙掕壊
|
|
removeById(roleId);
|
|
+ log.info("鍒犻櫎瑙掕壊鍙婄骇鑱斿叧鑱旓細roleId={}", roleId);
|
|
}
|
|
}
|
|
diff --git a/crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java b/crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java
|
|
index 565ced7..2301fad 100644
|
|
--- a/crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java
|
|
+++ b/crm-auth/src/test/java/com/crm/auth/security/scope/DataScopeIntegrationTest.java
|
|
@@ -460,7 +460,8 @@ class DataScopeIntegrationTest {
|
|
create table sys_role (
|
|
id bigint primary key, creator_id varchar(50), create_time datetime,
|
|
updater_id varchar(50), update_time datetime, deleted tinyint not null default 0,
|
|
- role_name varchar(50), role_code varchar(50), data_scope tinyint, sort int, remark varchar(200))
|
|
+ role_name varchar(50), role_code varchar(50), data_scope tinyint, sort int, remark varchar(200),
|
|
+ builtin boolean default false)
|
|
""",
|
|
"""
|
|
create table sys_user_role (
|
|
diff --git a/crm-auth/src/test/java/com/crm/auth/service/impl/SysMenuServiceImplTest.java b/crm-auth/src/test/java/com/crm/auth/service/impl/SysMenuServiceImplTest.java
|
|
new file mode 100644
|
|
index 0000000..805dea1
|
|
--- /dev/null
|
|
+++ b/crm-auth/src/test/java/com/crm/auth/service/impl/SysMenuServiceImplTest.java
|
|
@@ -0,0 +1,127 @@
|
|
+package com.crm.auth.service.impl;
|
|
+
|
|
+import com.crm.auth.domain.entity.SysMenu;
|
|
+import org.junit.jupiter.api.DisplayName;
|
|
+import org.junit.jupiter.api.Test;
|
|
+import org.junit.jupiter.api.extension.ExtendWith;
|
|
+import org.mockito.InjectMocks;
|
|
+import org.mockito.Spy;
|
|
+import org.mockito.junit.jupiter.MockitoExtension;
|
|
+
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.Set;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.mockito.Mockito.doReturn;
|
|
+
|
|
+/**
|
|
+ * {@link SysMenuServiceImpl} 鍗曞厓娴嬭瘯锛氳鐩栫鍏堣ˉ鍏ㄩ€昏緫锛圓DR-0005锛?+ */
|
|
+@ExtendWith(MockitoExtension.class)
|
|
+class SysMenuServiceImplTest {
|
|
+
|
|
+ @Spy
|
|
+ @InjectMocks
|
|
+ private SysMenuServiceImpl sysMenuService;
|
|
+
|
|
+ // ==================== 绁栧厛琛ュ叏 ====================
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鍗曢摼鍚戜笂閬嶅巻 -> 浼犲叆鍙跺瓙 button锛岃繑鍥?button+menu+catalog 瀹屾暣閾?)
|
|
+ void singleChainAncestorCompletion() {
|
|
+ SysMenu catalog = buildMenu(1L, 0L, "绯荤粺绠$悊", 1);
|
|
+ SysMenu menu = buildMenu(10L, 1L, "瑙掕壊绠$悊", 2);
|
|
+ SysMenu button = buildMenu(100L, 10L, "瑙掕壊鍒楄〃", 3);
|
|
+ doReturn(List.of(catalog, menu, button)).when(sysMenuService).list();
|
|
+
|
|
+ Set<Long> result = sysMenuService.getAncestorIds(Set.of(100L));
|
|
+
|
|
+ assertThat(result).containsExactlyInAnyOrder(100L, 10L, 1L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("澶氶摼姹囧悎 -> 涓ゆ潯鐙珛閾剧殑鍙跺瓙锛岃繑鍥炰袱鏉¢摼鍏ㄩ儴绁栧厛鐨勫苟闆?)
|
|
+ void multipleChainsAncestorCompletion() {
|
|
+ // 閾?锛氱郴缁熺鐞?1) -> 瑙掕壊绠$悊(10) -> 瑙掕壊鍒楄〃(100)
|
|
+ // 閾?锛氬鎴风鐞?2) -> 瀹㈡埛鍒楄〃(20) -> 鏂板瀹㈡埛(200)
|
|
+ SysMenu catalog1 = buildMenu(1L, 0L, "绯荤粺绠$悊", 1);
|
|
+ SysMenu menu1 = buildMenu(10L, 1L, "瑙掕壊绠$悊", 2);
|
|
+ SysMenu button1 = buildMenu(100L, 10L, "瑙掕壊鍒楄〃", 3);
|
|
+
|
|
+ SysMenu catalog2 = buildMenu(2L, 0L, "瀹㈡埛绠$悊", 1);
|
|
+ SysMenu menu2 = buildMenu(20L, 2L, "瀹㈡埛鍒楄〃", 2);
|
|
+ SysMenu button2 = buildMenu(200L, 20L, "鏂板瀹㈡埛", 3);
|
|
+
|
|
+ doReturn(List.of(catalog1, menu1, button1, catalog2, menu2, button2))
|
|
+ .when(sysMenuService).list();
|
|
+
|
|
+ Set<Long> result = sysMenuService.getAncestorIds(Set.of(100L, 200L));
|
|
+
|
|
+ assertThat(result).containsExactlyInAnyOrder(100L, 10L, 1L, 200L, 20L, 2L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鏍硅妭鐐?-> parentId=0 鐨?catalog锛岃繑鍥炲畠鑷繁锛堟棤绁栧厛鍙ˉ锛?)
|
|
+ void rootNodeNoAncestor() {
|
|
+ SysMenu catalog = buildMenu(1L, 0L, "绯荤粺绠$悊", 1);
|
|
+ SysMenu menu = buildMenu(10L, 1L, "瑙掕壊绠$悊", 2);
|
|
+ doReturn(List.of(catalog, menu)).when(sysMenuService).list();
|
|
+
|
|
+ Set<Long> result = sysMenuService.getAncestorIds(Set.of(1L));
|
|
+
|
|
+ assertThat(result).containsExactly(1L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("绌鸿緭鍏?-> 浼犲叆绌洪泦鍚堬紝杩斿洖绌洪泦鍚?)
|
|
+ void emptyInputReturnsEmpty() {
|
|
+ Set<Long> result = sysMenuService.getAncestorIds(Collections.emptySet());
|
|
+
|
|
+ assertThat(result).isEmpty();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("null 杈撳叆 -> 浼犲叆 null锛岃繑鍥炵┖闆嗗悎")
|
|
+ void nullInputReturnsEmpty() {
|
|
+ Set<Long> result = sysMenuService.getAncestorIds(null);
|
|
+
|
|
+ assertThat(result).isEmpty();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("宸插惈绁栧厛 -> 浼犲叆瀹屾暣闆嗗悎锛岃繑鍥炵浉鍚岄泦鍚堬紙骞傜瓑涓嶉噸澶嶏級")
|
|
+ void alreadyCompleteSetIsIdempotent() {
|
|
+ SysMenu catalog = buildMenu(1L, 0L, "绯荤粺绠$悊", 1);
|
|
+ SysMenu menu = buildMenu(10L, 1L, "瑙掕壊绠$悊", 2);
|
|
+ SysMenu button = buildMenu(100L, 10L, "瑙掕壊鍒楄〃", 3);
|
|
+ doReturn(List.of(catalog, menu, button)).when(sysMenuService).list();
|
|
+
|
|
+ Set<Long> result = sysMenuService.getAncestorIds(Set.of(100L, 10L, 1L));
|
|
+
|
|
+ assertThat(result).containsExactlyInAnyOrder(100L, 10L, 1L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("杈撳叆鍚笉瀛樺湪浜?DB 鐨?ID -> 璇?ID 淇濈暀鍦ㄧ粨鏋滀腑锛屼絾涓嶄骇鐢熺鍏?)
|
|
+ void nonExistentIdKeptButNoAncestors() {
|
|
+ SysMenu catalog = buildMenu(1L, 0L, "绯荤粺绠$悊", 1);
|
|
+ SysMenu menu = buildMenu(10L, 1L, "瑙掕壊绠$悊", 2);
|
|
+ doReturn(List.of(catalog, menu)).when(sysMenuService).list();
|
|
+
|
|
+ Set<Long> result = sysMenuService.getAncestorIds(Set.of(10L, 999L));
|
|
+
|
|
+ assertThat(result).containsExactlyInAnyOrder(10L, 1L, 999L);
|
|
+ }
|
|
+
|
|
+ // ==================== 妗╂暟鎹?====================
|
|
+
|
|
+ private SysMenu buildMenu(Long id, Long parentId, String name, int type) {
|
|
+ SysMenu m = new SysMenu();
|
|
+ m.setId(id);
|
|
+ m.setParentId(parentId);
|
|
+ m.setMenuName(name);
|
|
+ m.setMenuType(type);
|
|
+ return m;
|
|
+ }
|
|
+}
|
|
diff --git a/crm-auth/src/test/java/com/crm/auth/service/impl/SysRoleServiceImplTest.java b/crm-auth/src/test/java/com/crm/auth/service/impl/SysRoleServiceImplTest.java
|
|
new file mode 100644
|
|
index 0000000..70c49b9
|
|
--- /dev/null
|
|
+++ b/crm-auth/src/test/java/com/crm/auth/service/impl/SysRoleServiceImplTest.java
|
|
@@ -0,0 +1,300 @@
|
|
+package com.crm.auth.service.impl;
|
|
+
|
|
+import com.crm.auth.domain.dto.RoleDetailVO;
|
|
+import com.crm.auth.domain.entity.SysRole;
|
|
+import com.crm.auth.domain.entity.SysRoleMenu;
|
|
+import com.crm.auth.domain.entity.SysUserRole;
|
|
+import com.crm.auth.mapper.SysRoleMapper;
|
|
+import com.crm.auth.mapper.SysRoleMenuMapper;
|
|
+import com.crm.auth.mapper.SysUserRoleMapper;
|
|
+import com.crm.auth.service.ISysMenuService;
|
|
+import com.crm.base.domain.exception.BusinessErrorException;
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
+import org.junit.jupiter.api.DisplayName;
|
|
+import org.junit.jupiter.api.Test;
|
|
+import org.junit.jupiter.api.extension.ExtendWith;
|
|
+import org.mockito.ArgumentCaptor;
|
|
+import org.mockito.InjectMocks;
|
|
+import org.mockito.Mock;
|
|
+import org.mockito.junit.jupiter.MockitoExtension;
|
|
+import org.mockito.junit.jupiter.MockitoSettings;
|
|
+import org.mockito.quality.Strictness;
|
|
+import org.springframework.test.util.ReflectionTestUtils;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Set;
|
|
+
|
|
+import static org.assertj.core.api.Assertions.assertThat;
|
|
+import static org.assertj.core.api.Assertions.assertThatCode;
|
|
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
+import static org.mockito.Mockito.atLeastOnce;
|
|
+import static org.mockito.Mockito.verify;
|
|
+import static org.mockito.Mockito.when;
|
|
+
|
|
+/**
|
|
+ * {@link SysRoleServiceImpl} 鍗曞厓娴嬭瘯锛氳鐩?saveRole 鏍¢獙瑙勫垯锛圓DR-0012锛?+ */
|
|
+@ExtendWith(MockitoExtension.class)
|
|
+@MockitoSettings(strictness = Strictness.LENIENT)
|
|
+class SysRoleServiceImplTest {
|
|
+
|
|
+ @Mock
|
|
+ private SysRoleMapper sysRoleMapper;
|
|
+ @Mock
|
|
+ private SysRoleMenuMapper sysRoleMenuMapper;
|
|
+ @Mock
|
|
+ private SysUserRoleMapper sysUserRoleMapper;
|
|
+ @Mock
|
|
+ private ISysMenuService sysMenuService;
|
|
+
|
|
+ @InjectMocks
|
|
+ private SysRoleServiceImpl sysRoleService;
|
|
+
|
|
+ @BeforeEach
|
|
+ void setUp() {
|
|
+ // ServiceImpl 鐨?baseMapper 瀛楁鍦ㄧ埗绫伙紝@InjectMocks 鍙兘涓嶆敞鍏ワ紝鎵嬪姩璁剧疆
|
|
+ ReflectionTestUtils.setField(sysRoleService, "baseMapper", sysRoleMapper);
|
|
+ }
|
|
+
|
|
+ // ==================== roleCode 鍞竴鎬?====================
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鍒涘缓瑙掕壊 -> roleCode 宸插瓨鍦?-> 鎷掔粷")
|
|
+ void createRole_duplicateCode_rejected() {
|
|
+ SysRole role = buildRole(null, "閿€鍞?, "ROLE_SALES", 1);
|
|
+ when(sysRoleMapper.selectCount(any())).thenReturn(1L);
|
|
+
|
|
+ assertThatThrownBy(() -> sysRoleService.saveRole(role))
|
|
+ .isInstanceOf(BusinessErrorException.class)
|
|
+ .hasMessageContaining("瑙掕壊缂栫爜宸插瓨鍦?);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("缂栬緫瑙掕壊 -> roleCode 涓嶅彉锛堝悓 id锛?-> 閫氳繃")
|
|
+ void editRole_sameCodeSameId_passes() {
|
|
+ SysRole role = buildRole(1L, "閿€鍞?, "ROLE_SALES", 1);
|
|
+ when(sysRoleMapper.selectById(1L)).thenReturn(role);
|
|
+ when(sysRoleMapper.selectCount(any())).thenReturn(0L);
|
|
+ when(sysRoleMapper.updateById(any(SysRole.class))).thenReturn(1);
|
|
+
|
|
+ assertThatCode(() -> sysRoleService.saveRole(role))
|
|
+ .doesNotThrowAnyException();
|
|
+ }
|
|
+
|
|
+ // ==================== 鍐呯疆瑙掕壊淇濇姢 ====================
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("缂栬緫鍐呯疆瑙掕壊 -> 淇敼 roleCode -> 鎷掔粷")
|
|
+ void editBuiltinRole_changeCode_rejected() {
|
|
+ SysRole existing = buildRole(1L, "绠$悊鍛?, "ROLE_ADMIN", 4);
|
|
+ existing.setBuiltin(true);
|
|
+ SysRole input = buildRole(1L, "绠$悊鍛?, "ROLE_SUPER", 4);
|
|
+ when(sysRoleMapper.selectById(1L)).thenReturn(existing);
|
|
+
|
|
+ assertThatThrownBy(() -> sysRoleService.saveRole(input))
|
|
+ .isInstanceOf(BusinessErrorException.class)
|
|
+ .hasMessageContaining("鍐呯疆瑙掕壊鐨勭紪鐮佷笉鍙慨鏀?);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("缂栬緫鍐呯疆瑙掕壊 -> roleCode 涓嶅彉 -> 閫氳繃")
|
|
+ void editBuiltinRole_sameCode_passes() {
|
|
+ SysRole existing = buildRole(1L, "绠$悊鍛?, "ROLE_ADMIN", 4);
|
|
+ existing.setBuiltin(true);
|
|
+ SysRole input = buildRole(1L, "绠$悊鍛樻敼", "ROLE_ADMIN", 4);
|
|
+ when(sysRoleMapper.selectById(1L)).thenReturn(existing);
|
|
+ when(sysRoleMapper.selectCount(any())).thenReturn(0L);
|
|
+ when(sysRoleMapper.updateById(any(SysRole.class))).thenReturn(1);
|
|
+
|
|
+ assertThatCode(() -> sysRoleService.saveRole(input))
|
|
+ .doesNotThrowAnyException();
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鍒涘缓瑙掕壊 -> 璁剧疆 builtin=true -> 鎷掔粷")
|
|
+ void createRole_setBuiltin_rejected() {
|
|
+ SysRole role = buildRole(null, "鍋囩鐞嗗憳", "ROLE_FAKE", 4);
|
|
+ role.setBuiltin(true);
|
|
+
|
|
+ assertThatThrownBy(() -> sysRoleService.saveRole(role))
|
|
+ .isInstanceOf(BusinessErrorException.class)
|
|
+ .hasMessageContaining("涓嶅厑璁搁€氳繃鎺ュ彛鍒涘缓鍐呯疆瑙掕壊");
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("缂栬緫涓嶅瓨鍦ㄧ殑 id -> 璁剧疆 builtin=true -> 鎷掔粷锛堥槻姝?saveOrUpdate 鐨?insert 缁曡繃锛?)
|
|
+ void editNonExistentRole_setBuiltin_rejected() {
|
|
+ SysRole role = buildRole(999L, "鍋囩鐞嗗憳", "ROLE_FAKE", 4);
|
|
+ role.setBuiltin(true);
|
|
+ when(sysRoleMapper.selectById(999L)).thenReturn(null);
|
|
+
|
|
+ assertThatThrownBy(() -> sysRoleService.saveRole(role))
|
|
+ .isInstanceOf(BusinessErrorException.class)
|
|
+ .hasMessageContaining("涓嶅厑璁搁€氳繃鎺ュ彛鍒涘缓鍐呯疆瑙掕壊");
|
|
+ }
|
|
+
|
|
+ // ==================== dataScope 鑼冨洿鏍¢獙 ====================
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鍒涘缓瑙掕壊 -> dataScope=0锛堣秺鐣岋級 -> 鎷掔粷")
|
|
+ void createRole_dataScopeTooLow_rejected() {
|
|
+ SysRole role = buildRole(null, "閿€鍞?, "ROLE_SALES", 0);
|
|
+
|
|
+ assertThatThrownBy(() -> sysRoleService.saveRole(role))
|
|
+ .isInstanceOf(BusinessErrorException.class)
|
|
+ .hasMessageContaining("鏁版嵁鑼冨洿蹇呴』鍦?1-4 鑼冨洿鍐?);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鍒涘缓瑙掕壊 -> dataScope=5锛堣秺鐣岋級 -> 鎷掔粷")
|
|
+ void createRole_dataScopeTooHigh_rejected() {
|
|
+ SysRole role = buildRole(null, "閿€鍞?, "ROLE_SALES", 5);
|
|
+
|
|
+ assertThatThrownBy(() -> sysRoleService.saveRole(role))
|
|
+ .isInstanceOf(BusinessErrorException.class)
|
|
+ .hasMessageContaining("鏁版嵁鑼冨洿蹇呴』鍦?1-4 鑼冨洿鍐?);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鍒涘缓瑙掕壊 -> dataScope=3锛堝悎娉曪級 -> 閫氳繃")
|
|
+ void createRole_validDataScope_passes() {
|
|
+ SysRole role = buildRole(null, "閿€鍞?, "ROLE_SALES", 3);
|
|
+ when(sysRoleMapper.selectCount(any())).thenReturn(0L);
|
|
+ when(sysRoleMapper.insert(any(SysRole.class))).thenReturn(1);
|
|
+
|
|
+ assertThatCode(() -> sysRoleService.saveRole(role))
|
|
+ .doesNotThrowAnyException();
|
|
+ }
|
|
+
|
|
+ // ==================== 鍩烘湰闈炵┖鏍¢獙 ====================
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鍒涘缓瑙掕壊 -> roleName 涓虹┖ -> 鎷掔粷")
|
|
+ void createRole_blankName_rejected() {
|
|
+ SysRole role = buildRole(null, "", "ROLE_SALES", 1);
|
|
+
|
|
+ assertThatThrownBy(() -> sysRoleService.saveRole(role))
|
|
+ .isInstanceOf(BusinessErrorException.class)
|
|
+ .hasMessageContaining("瑙掕壊鍚嶇О涓嶈兘涓虹┖");
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鍒涘缓瑙掕壊 -> roleCode 涓虹┖ -> 鎷掔粷")
|
|
+ void createRole_blankCode_rejected() {
|
|
+ SysRole role = buildRole(null, "閿€鍞?, "", 1);
|
|
+
|
|
+ assertThatThrownBy(() -> sysRoleService.saveRole(role))
|
|
+ .isInstanceOf(BusinessErrorException.class)
|
|
+ .hasMessageContaining("瑙掕壊缂栫爜涓嶈兘涓虹┖");
|
|
+ }
|
|
+
|
|
+ // ==================== 鏉冮檺鍒嗛厤锛堢鍏堣ˉ鍏級 ====================
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("assignResources -> 璋冪敤绁栧厛琛ュ叏 -> 鍐欏叆鐨?menuIds 鍖呭惈绁栧厛")
|
|
+ void assignResources_ancestorCompletion_writesAllIds() {
|
|
+ // 杈撳叆鍙紶鍙跺瓙鑺傜偣 100L锛岀鍏堣ˉ鍏ㄥ悗搴斿寘鍚?100L + 10L + 1L
|
|
+ when(sysMenuService.getAncestorIds(List.of(100L)))
|
|
+ .thenReturn(Set.of(100L, 10L, 1L));
|
|
+ when(sysRoleMenuMapper.delete(any())).thenReturn(1);
|
|
+ when(sysRoleMenuMapper.insert(any(SysRoleMenu.class))).thenReturn(1);
|
|
+
|
|
+ sysRoleService.assignResources(1L, List.of(100L));
|
|
+
|
|
+ // 鐢?ArgumentCaptor 鎹曡幏鍐欏叆鐨?SysRoleMenu锛岄獙璇?menuId 闆嗗悎鍖呭惈绁栧厛
|
|
+ ArgumentCaptor<SysRoleMenu> captor = ArgumentCaptor.forClass(SysRoleMenu.class);
|
|
+ verify(sysRoleMenuMapper, atLeastOnce()).insert(captor.capture());
|
|
+ List<Long> writtenMenuIds = captor.getAllValues().stream()
|
|
+ .map(SysRoleMenu::getMenuId).toList();
|
|
+ assertThat(writtenMenuIds).containsExactlyInAnyOrder(100L, 10L, 1L);
|
|
+ assertThat(captor.getAllValues()).allSatisfy(rm ->
|
|
+ assertThat(rm.getRoleId()).isEqualTo(1L));
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("assignResources -> 鍏堝垹鍚庢彃鍏ㄩ噺鏇挎崲 sys_role_menu")
|
|
+ void assignResources_fullReplacement() {
|
|
+ when(sysMenuService.getAncestorIds(List.of(200L)))
|
|
+ .thenReturn(Set.of(200L));
|
|
+ when(sysRoleMenuMapper.delete(any())).thenReturn(1);
|
|
+ when(sysRoleMenuMapper.insert(any(SysRoleMenu.class))).thenReturn(1);
|
|
+
|
|
+ sysRoleService.assignResources(1L, List.of(200L));
|
|
+
|
|
+ // 楠岃瘉鍐欏叆鐨?menuId 闆嗗悎浠呬负琛ュ叏鍚庣殑 {200L}
|
|
+ ArgumentCaptor<SysRoleMenu> captor = ArgumentCaptor.forClass(SysRoleMenu.class);
|
|
+ verify(sysRoleMenuMapper, atLeastOnce()).insert(captor.capture());
|
|
+ assertThat(captor.getAllValues()).hasSize(1);
|
|
+ assertThat(captor.getAllValues().get(0).getMenuId()).isEqualTo(200L);
|
|
+ }
|
|
+
|
|
+ // ==================== 瑙掕壊璇︽儏 ====================
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("getRoleDetail -> 杩斿洖 RoleDetailVO 鍚熀鏈俊鎭拰 resourceIds")
|
|
+ void getRoleDetail_returnsVO() {
|
|
+ SysRole role = buildRole(1L, "閿€鍞?, "ROLE_SALES", 1);
|
|
+ when(sysRoleMapper.selectById(1L)).thenReturn(role);
|
|
+ SysRoleMenu rm1 = new SysRoleMenu();
|
|
+ rm1.setMenuId(100L);
|
|
+ SysRoleMenu rm2 = new SysRoleMenu();
|
|
+ rm2.setMenuId(200L);
|
|
+ when(sysRoleMenuMapper.selectList(any())).thenReturn(List.of(rm1, rm2));
|
|
+
|
|
+ RoleDetailVO vo = sysRoleService.getRoleDetail(1L);
|
|
+
|
|
+ assertThat(vo).isNotNull();
|
|
+ assertThat(vo.getRoleName()).isEqualTo("閿€鍞?);
|
|
+ assertThat(vo.getRoleCode()).isEqualTo("ROLE_SALES");
|
|
+ assertThat(vo.getResourceIds()).containsExactly(100L, 200L);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("getRoleDetail -> 瑙掕壊涓嶅瓨鍦?-> 鎷掔粷")
|
|
+ void getRoleDetail_notFound_rejected() {
|
|
+ when(sysRoleMapper.selectById(999L)).thenReturn(null);
|
|
+
|
|
+ assertThatThrownBy(() -> sysRoleService.getRoleDetail(999L))
|
|
+ .isInstanceOf(BusinessErrorException.class)
|
|
+ .hasMessageContaining("瑙掕壊涓嶅瓨鍦?);
|
|
+ }
|
|
+
|
|
+ // ==================== 瑙掕壊鍒犻櫎锛堢骇鑱旀竻鐞嗭級 ====================
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鍒犻櫎鍐呯疆瑙掕壊 -> builtin=true -> 鎷掔粷")
|
|
+ void deleteBuiltinRole_rejected() {
|
|
+ SysRole role = buildRole(1L, "绠$悊鍛?, "ROLE_ADMIN", 4);
|
|
+ role.setBuiltin(true);
|
|
+ when(sysRoleMapper.selectById(1L)).thenReturn(role);
|
|
+
|
|
+ assertThatThrownBy(() -> sysRoleService.deleteRoleCascade(1L))
|
|
+ .isInstanceOf(BusinessErrorException.class)
|
|
+ .hasMessageContaining("鍐呯疆瑙掕壊涓嶅厑璁稿垹闄?);
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ @DisplayName("鍒犻櫎鏅€氳鑹?-> builtin=false -> 閫氳繃骞舵竻鐞?sys_role_menu + sys_user_role")
|
|
+ void deleteNormalRole_passes() {
|
|
+ SysRole role = buildRole(2L, "閿€鍞?, "ROLE_SALES", 1);
|
|
+ when(sysRoleMapper.selectById(2L)).thenReturn(role);
|
|
+ when(sysRoleMenuMapper.delete(any())).thenReturn(1);
|
|
+ when(sysUserRoleMapper.delete(any())).thenReturn(1);
|
|
+
|
|
+ assertThatCode(() -> sysRoleService.deleteRoleCascade(2L))
|
|
+ .doesNotThrowAnyException();
|
|
+ }
|
|
+
|
|
+ // ==================== 妗╂暟鎹?====================
|
|
+
|
|
+ private SysRole buildRole(Long id, String name, String code, int dataScope) {
|
|
+ SysRole role = new SysRole();
|
|
+ role.setId(id);
|
|
+ role.setRoleName(name);
|
|
+ role.setRoleCode(code);
|
|
+ role.setDataScope(dataScope);
|
|
+ role.setSort(0);
|
|
+ return role;
|
|
+ }
|
|
+}
|
|
diff --git a/crm-auth/src/test/java/com/crm/auth/service/impl/UserListIntegrationTest.java b/crm-auth/src/test/java/com/crm/auth/service/impl/UserListIntegrationTest.java
|
|
index 2e0c173..be66a5e 100644
|
|
--- a/crm-auth/src/test/java/com/crm/auth/service/impl/UserListIntegrationTest.java
|
|
+++ b/crm-auth/src/test/java/com/crm/auth/service/impl/UserListIntegrationTest.java
|
|
@@ -332,7 +332,8 @@ class UserListIntegrationTest {
|
|
create table sys_role (
|
|
id bigint primary key, creator_id varchar(50), create_time datetime,
|
|
updater_id varchar(50), update_time datetime, deleted tinyint not null default 0,
|
|
- role_name varchar(50), role_code varchar(50), data_scope tinyint, sort int, remark varchar(200))
|
|
+ role_name varchar(50), role_code varchar(50), data_scope tinyint, sort int, remark varchar(200),
|
|
+ builtin boolean default false)
|
|
""",
|
|
"""
|
|
create table sys_user_role (
|
|
|