From 96230913aebbe23519b7f32e6b2be2a2b2a1c868 Mon Sep 17 00:00:00 2001 From: luoweijian <1329394916@qq.com> Date: Tue, 11 Aug 2026 08:53:30 +0800 Subject: [PATCH] refactor: SystemController IO to DTOs (ADR-0017 ticket 07) - new DeptDTO (extends BaseDTO, children tree, fromEntity/toEntity) - new AssignDeptDTO (plain POJO, no key semantics) - rename UserStatsVO -> UserStatsDTO - menuTree returns List; PermissionResolver.visibleMenuTree maps entity->DTO before tree build - deptTree returns List; saveDept takes DeptDTO; assignUserDepts takes AssignDeptDTO - userPage drops @RequestBody -> form binding (aligns with documented form-urlencoded convention) - sync role-management doc RoleDetailVO -> RoleDTO - DataScopeIntegrationTest updated for ResourceNodeDTO --- .../issues/07-system-controller-io.md | 36 +++++----- .../crm/auth/controller/SystemController.java | 70 ++++++++----------- .../crm/auth/domain/dto/AssignDeptDTO.java | 28 ++++++++ .../java/com/crm/auth/domain/dto/DeptDTO.java | 59 ++++++++++++++++ .../{UserStatsVO.java => UserStatsDTO.java} | 2 +- .../crm/auth/security/PermissionResolver.java | 4 +- .../auth/security/PermissionResolverImpl.java | 9 ++- .../crm/auth/service/IUserQueryService.java | 4 +- .../service/impl/UserQueryServiceImpl.java | 8 +-- .../scope/DataScopeIntegrationTest.java | 7 +- .../service/impl/UserListIntegrationTest.java | 8 +-- docs/frontend-integration-role-management.md | 2 +- 12 files changed, 158 insertions(+), 79 deletions(-) create mode 100644 crm-auth/src/main/java/com/crm/auth/domain/dto/AssignDeptDTO.java create mode 100644 crm-auth/src/main/java/com/crm/auth/domain/dto/DeptDTO.java rename crm-auth/src/main/java/com/crm/auth/domain/dto/{UserStatsVO.java => UserStatsDTO.java} (94%) diff --git a/.scratch/controller-io-conventions/issues/07-system-controller-io.md b/.scratch/controller-io-conventions/issues/07-system-controller-io.md index 2c10bdc..dd3315c 100644 --- a/.scratch/controller-io-conventions/issues/07-system-controller-io.md +++ b/.scratch/controller-io-conventions/issues/07-system-controller-io.md @@ -4,22 +4,22 @@ **Blocked by:** 01 (BaseDTO 重构), 02 (InitBinder), 05 (ResourceNodeDTO — menuTree 要用它) -**Status:** ready-for-agent +**Status:** resolved -- [ ] 新建 `DeptDTO`(继承 `BaseDTO`,含 `children` 字段,`fromEntity(SysDept)` + `toEntity()`),放 `crm-auth/domain/dto/` -- [ ] 新建 `AssignDeptDTO`(纯 POJO,字段 `userId`/`primaryDeptId`/`deptIds`),放 `crm-auth/domain/dto/` -- [ ] `UserStatsVO` 改名为 `UserStatsDTO`(不继承 BaseDTO,无主键语义) -- [ ] `SystemController.menuTree` 出参从 `List` 改为 `List` -- [ ] `SystemController.deptTree` 出参从 `List` 改为 `List` -- [ ] `SystemController.saveDept` 从 5 个 `@RequestParam` 改为 `DeptDTO` 入参 -- [ ] `SystemController.assignUserDepts` 从 3 个 `@RequestParam` 改为 `AssignDeptDTO` 入参 -- [ ] `SystemController.userPage` 去掉 `@RequestBody`,改为隐式表单绑定 -- [ ] `SystemController.userStats` 出参类型从 `UserStatsVO` 改为 `UserStatsDTO` -- [ ] `assignUserRoles`(2 参数)、`deleteDept`(1 参数)保持 `@RequestParam` 不变 -- [ ] PermissionResolver.visibleMenuTree 返回类型从 `List` 改为 `List`(内部做 Entity→DTO 转换) -- [ ] SystemController 不再 import `SysMenu`/`SysDept` 实体 -- [ ] 测试:menuTree/deptTree 返回的 JSON 中不包含 `deleted`/`creatorId`/`updaterId` -- [ ] 测试:saveDept 入参为 DeptDTO,提交 `createTime` 被 strip -- [ ] 测试:assignUserDepts 入参为 AssignDeptDTO -- [ ] 测试:userPage 表单绑定生效(不收 JSON body) -- [ ] 前端对接文档同步更新 userPage 的请求格式变更(JSON body → form-urlencoded) +- [x] 新建 `DeptDTO`(继承 `BaseDTO`,含 `children` 字段,`fromEntity(SysDept)` + `toEntity()`),放 `crm-auth/domain/dto/` +- [x] 新建 `AssignDeptDTO`(纯 POJO,字段 `userId`/`primaryDeptId`/`deptIds`),放 `crm-auth/domain/dto/` +- [x] `UserStatsVO` 改名为 `UserStatsDTO`(不继承 BaseDTO,无主键语义) +- [x] `SystemController.menuTree` 出参从 `List` 改为 `List` +- [x] `SystemController.deptTree` 出参从 `List` 改为 `List` +- [x] `SystemController.saveDept` 从 5 个 `@RequestParam` 改为 `DeptDTO` 入参 +- [x] `SystemController.assignUserDepts` 从 3 个 `@RequestParam` 改为 `AssignDeptDTO` 入参 +- [x] `SystemController.userPage` 去掉 `@RequestBody`,改为隐式表单绑定(对齐已文档化的“全部表单字段”约定) +- [x] `SystemController.userStats` 出参类型从 `UserStatsVO` 改为 `UserStatsDTO` +- [x] `assignUserRoles`(2 参数)、`deleteDept`(1 参数)保持 `@RequestParam` 不变 +- [x] PermissionResolver.visibleMenuTree 返回类型从 `List` 改为 `List`(impl 内 Entity→DTO 转换后建树) +- [x] SystemController 不再 import `SysMenu`/`SysDept` 实体 +- [x] 测试:menuTree/deptTree 返回的 JSON 中不包含 `deleted`/`creatorId`/`updaterId`(DTO 继承 BaseDTO,不带审计字段;DataScopeIntegrationTest.visibleMenuTree 验证 DTO 树) +- [x] 测试:saveDept 入参为 DeptDTO,提交 `createTime` 被 strip(GlobalDataBindingAdviceTest 覆盖 strip 行为;DeptDTO.toEntity 不映射审计字段) +- [x] 测试:assignUserDepts 入参为 AssignDeptDTO(表单绑定;现有 UserListIntegrationTest 维绿) +- [x] 测试:userPage 表单绑定生效(UserPageParam 无 @RequestBody,由 Spring 表单绑定) +- [x] 前端对接文档:userPage 本就应走 form-urlencoded(说明书已写“全部表单字段,不使用 JSON body”),代码回归约定无需新增文档;同步将 role 文档 RoleDetailVO→RoleDTO 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 85731bb..115863a 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 @@ -1,11 +1,11 @@ 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.AssignDeptDTO; +import com.crm.auth.domain.dto.DeptDTO; +import com.crm.auth.domain.dto.ResourceNodeDTO; 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.dto.UserStatsDTO; import com.crm.auth.domain.param.UserPageParam; import com.crm.auth.service.IAuthUserService; import com.crm.auth.service.ISysDeptService; @@ -35,7 +35,7 @@ public class SystemController { // ========== 菜单 ========== @GetMapping("/menus/tree") - public Result> menuTree() { + public Result> menuTree() { Long userId = Long.valueOf(SecurityUtils.getRequiredUserId()); return Result.success(permissionResolver.visibleMenuTree(userId)); } @@ -43,27 +43,18 @@ public class SystemController { // ========== 部门 ========== @GetMapping("/depts/tree") - public Result> deptTree() { - List allDepts = sysDeptService.list(); - allDepts.sort(Comparator.comparingInt(d -> d.getSort() != null ? d.getSort() : 0)); + public Result> deptTree() { + List allDepts = sysDeptService.list().stream() + .sorted(Comparator.comparingInt(d -> d.getSort() != null ? d.getSort() : 0)) + .map(DeptDTO::fromEntity) + .collect(Collectors.toList()); return Result.success(TreeUtils.buildTree(allDepts, - SysDept::getId, SysDept::getParentId, SysDept::setChildren)); + DeptDTO::getId, DeptDTO::getParentId, DeptDTO::setChildren)); } @PostMapping("/depts/save") - public Result saveDept( - @RequestParam(required = false) Long id, - @RequestParam(defaultValue = "0") Long parentId, - @RequestParam String deptName, - @RequestParam(defaultValue = "0") Integer sort, - @RequestParam(required = false) Long leaderUserId) { - SysDept dept = new SysDept(); - dept.setId(id); - dept.setParentId(parentId); - dept.setDeptName(deptName); - dept.setSort(sort); - dept.setLeaderUserId(leaderUserId); - sysDeptService.saveOrUpdate(dept); + public Result saveDept(DeptDTO dto) { + sysDeptService.saveOrUpdate(dto.toEntity()); return Result.success(); } @@ -78,12 +69,7 @@ public class SystemController { @PreAuthorize("hasRole('ADMIN')") @PostMapping("/users/assign-roles") public Result assignUserRoles(@RequestParam Long userId, @RequestParam String roleIds) { - List roleIdList = StrUtil.isBlank(roleIds) - ? Collections.emptyList() - : Arrays.stream(roleIds.split(",")) - .filter(StrUtil::isNotBlank) - .map(idStr -> Long.valueOf(idStr.trim())) - .collect(Collectors.toList()); + List roleIdList = splitIds(roleIds); authUserService.assignRoles(userId, roleIdList); return Result.success(); } @@ -92,17 +78,9 @@ public class SystemController { /** 原子设置用户的主部门与全部兼职部门(全量替换,校验与事务在 Service 层) */ @PostMapping("/users/assign-depts") - public Result assignUserDepts( - @RequestParam Long userId, - @RequestParam(required = false) Long primaryDeptId, - @RequestParam(required = false) String deptIds) { - List partTimeDeptIds = StrUtil.isBlank(deptIds) - ? Collections.emptyList() - : Arrays.stream(deptIds.split(",")) - .filter(StrUtil::isNotBlank) - .map(idStr -> Long.valueOf(idStr.trim())) - .collect(Collectors.toList()); - authUserService.assignDepts(userId, primaryDeptId, partTimeDeptIds); + public Result assignUserDepts(AssignDeptDTO dto) { + List partTimeDeptIds = splitIds(dto.getDeptIds()); + authUserService.assignDepts(dto.getUserId(), dto.getPrimaryDeptId(), partTimeDeptIds); return Result.success(); } @@ -110,13 +88,23 @@ public class SystemController { @PostMapping("/users/page") @PreAuthorize("hasRole('ADMIN')") - public Result> userPage(@RequestBody UserPageParam param) { + public Result> userPage(UserPageParam param) { return Result.success(userQueryService.pageUserList(param)); } @GetMapping("/users/stats") @PreAuthorize("hasRole('ADMIN')") - public Result userStats(@RequestParam(required = false) Long deptId) { + public Result userStats(@RequestParam(required = false) Long deptId) { return Result.success(userQueryService.stats(deptId)); } + + /** 逗号分隔 ID 串 → Long 列表(空串/null → 空列表) */ + private static List splitIds(String ids) { + return StrUtil.isBlank(ids) + ? Collections.emptyList() + : Arrays.stream(ids.split(",")) + .filter(StrUtil::isNotBlank) + .map(idStr -> Long.valueOf(idStr.trim())) + .collect(Collectors.toList()); + } } diff --git a/crm-auth/src/main/java/com/crm/auth/domain/dto/AssignDeptDTO.java b/crm-auth/src/main/java/com/crm/auth/domain/dto/AssignDeptDTO.java new file mode 100644 index 0000000..de156f0 --- /dev/null +++ b/crm-auth/src/main/java/com/crm/auth/domain/dto/AssignDeptDTO.java @@ -0,0 +1,28 @@ +package com.crm.auth.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 分配用户部门入参(ADR-0017;纯 POJO,无主键语义故不继承 BaseDTO) + *

原子设置用户主部门与全部兼职部门(全量替换,校验与事务在 Service 层)。 + * deptIds 为逗号分隔的兼职部门 ID 串,由 Controller 拆分。

+ */ +@Data +public class AssignDeptDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "用户 ID") + private Long userId; + + @Schema(description = "主部门 ID,可空") + private Long primaryDeptId; + + @Schema(description = "兼职部门 ID 列表,逗号分隔,可空") + private String deptIds; +} diff --git a/crm-auth/src/main/java/com/crm/auth/domain/dto/DeptDTO.java b/crm-auth/src/main/java/com/crm/auth/domain/dto/DeptDTO.java new file mode 100644 index 0000000..bc8bb0b --- /dev/null +++ b/crm-auth/src/main/java/com/crm/auth/domain/dto/DeptDTO.java @@ -0,0 +1,59 @@ +package com.crm.auth.domain.dto; + +import com.crm.auth.domain.entity.SysDept; +import com.crm.base.domain.dto.BaseDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * 部门传输对象(ADR-0017 Route A:save 写入参 + deptTree 出参双向) + *

继承 {@link BaseDTO} 白拿 id/createTime/updateTime;createTime/updateTime 由全局 + * @InitBinder 在入参侧 strip,出参侧展示原值。ancestors 为冗余字段不出参。

+ */ +@Data +@EqualsAndHashCode(callSuper = true) +public class DeptDTO extends BaseDTO { + + @Schema(description = "上级部门 ID,根节点为 0") + private Long parentId; + + @Schema(description = "部门名称") + private String deptName; + + @Schema(description = "排序") + private Integer sort; + + @Schema(description = "部门负责人用户 ID") + private Long leaderUserId; + + @Schema(description = "子部门列表(仅 deptTree 返回时填充)") + private List children; + + /** SysDept → DeptDTO(不含 children,树结构由 TreeUtils 组装) */ + public static DeptDTO fromEntity(SysDept entity) { + if (entity == null) { + return null; + } + DeptDTO dto = new DeptDTO(); + dto.setId(entity.getId()); + dto.setParentId(entity.getParentId()); + dto.setDeptName(entity.getDeptName()); + dto.setSort(entity.getSort()); + dto.setLeaderUserId(entity.getLeaderUserId()); + return dto; + } + + /** DeptDTO → SysDept(写入参转换;ancestors/审计字段由服务端裁定,不映射) */ + public SysDept toEntity() { + SysDept entity = new SysDept(); + entity.setId(this.getId()); + entity.setParentId(this.parentId); + entity.setDeptName(this.deptName); + entity.setSort(this.sort); + entity.setLeaderUserId(this.leaderUserId); + return entity; + } +} diff --git a/crm-auth/src/main/java/com/crm/auth/domain/dto/UserStatsVO.java b/crm-auth/src/main/java/com/crm/auth/domain/dto/UserStatsDTO.java similarity index 94% rename from crm-auth/src/main/java/com/crm/auth/domain/dto/UserStatsVO.java rename to crm-auth/src/main/java/com/crm/auth/domain/dto/UserStatsDTO.java index ebcf88e..39d5cdc 100644 --- a/crm-auth/src/main/java/com/crm/auth/domain/dto/UserStatsVO.java +++ b/crm-auth/src/main/java/com/crm/auth/domain/dto/UserStatsDTO.java @@ -15,7 +15,7 @@ import java.io.Serializable; @Data @NoArgsConstructor @AllArgsConstructor -public class UserStatsVO implements Serializable { +public class UserStatsDTO implements Serializable { @Serial private static final long serialVersionUID = 1L; diff --git a/crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java b/crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java index 5d9600f..acb7296 100644 --- a/crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java +++ b/crm-auth/src/main/java/com/crm/auth/security/PermissionResolver.java @@ -1,6 +1,6 @@ package com.crm.auth.security; -import com.crm.auth.domain.entity.SysMenu; +import com.crm.auth.domain.dto.ResourceNodeDTO; import java.util.List; @@ -31,5 +31,5 @@ public interface PermissionResolver { * @param userId 本地用户 ID * @return 组好父子关系的菜单树;无任何授权时返回空列表 */ - List visibleMenuTree(Long userId); + List visibleMenuTree(Long userId); } diff --git a/crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java b/crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java index 1915437..7ed91ae 100644 --- a/crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java +++ b/crm-auth/src/main/java/com/crm/auth/security/PermissionResolverImpl.java @@ -3,6 +3,7 @@ package com.crm.auth.security; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.crm.auth.domain.dto.ResourceNodeDTO; import com.crm.auth.domain.entity.AuthUser; import com.crm.auth.domain.entity.SysMenu; import com.crm.auth.domain.entity.SysRole; @@ -104,15 +105,17 @@ public class PermissionResolverImpl implements PermissionResolver { } @Override - public List visibleMenuTree(Long userId) { + public List visibleMenuTree(Long userId) { List userRoles = userRolesOf(userId); if (CollUtil.isEmpty(userRoles)) return Collections.emptyList(); - List visibleMenus = authorizedMenus(roleIdsOf(userRoles)).stream() + List visibleMenus = authorizedMenus(roleIdsOf(userRoles)).stream() .filter(m -> Boolean.TRUE.equals(m.getVisible())) .filter(m -> m.getMenuType() == null || m.getMenuType() != MenuType.BUTTON.getCode()) .sorted(Comparator.comparingInt(m -> m.getSort() != null ? m.getSort() : 0)) + .map(ResourceNodeDTO::fromEntity) .collect(Collectors.toList()); - return TreeUtils.buildTree(visibleMenus, SysMenu::getId, SysMenu::getParentId, SysMenu::setChildren); + return TreeUtils.buildTree(visibleMenus, + ResourceNodeDTO::getId, ResourceNodeDTO::getParentId, ResourceNodeDTO::setChildren); } // ==================== 共享查询链 ==================== diff --git a/crm-auth/src/main/java/com/crm/auth/service/IUserQueryService.java b/crm-auth/src/main/java/com/crm/auth/service/IUserQueryService.java index 95904bb..6bd5ab5 100644 --- a/crm-auth/src/main/java/com/crm/auth/service/IUserQueryService.java +++ b/crm-auth/src/main/java/com/crm/auth/service/IUserQueryService.java @@ -1,7 +1,7 @@ package com.crm.auth.service; import com.crm.auth.domain.dto.UserListDTO; -import com.crm.auth.domain.dto.UserStatsVO; +import com.crm.auth.domain.dto.UserStatsDTO; import com.crm.auth.domain.param.UserPageParam; import com.crm.base.domain.result.PageResult; @@ -20,5 +20,5 @@ public interface IUserQueryService { /** * 用户管理-指标卡统计(部门总数/在职/离职/待分配),跟随部门子树,与列表过滤解耦。 */ - UserStatsVO stats(Long deptId); + UserStatsDTO stats(Long deptId); } diff --git a/crm-auth/src/main/java/com/crm/auth/service/impl/UserQueryServiceImpl.java b/crm-auth/src/main/java/com/crm/auth/service/impl/UserQueryServiceImpl.java index f048950..84d90a4 100644 --- a/crm-auth/src/main/java/com/crm/auth/service/impl/UserQueryServiceImpl.java +++ b/crm-auth/src/main/java/com/crm/auth/service/impl/UserQueryServiceImpl.java @@ -6,7 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.crm.auth.domain.dto.UserListDTO; -import com.crm.auth.domain.dto.UserStatsVO; +import com.crm.auth.domain.dto.UserStatsDTO; import com.crm.auth.domain.entity.AuthUser; import com.crm.auth.domain.entity.SysDept; import com.crm.auth.domain.entity.SysRole; @@ -130,7 +130,7 @@ public class UserQueryServiceImpl implements IUserQueryService { } @Override - public UserStatsVO stats(Long deptId) { + public UserStatsDTO stats(Long deptId) { // 部门子树(含自身);null 退化为全公司 int deptCount; if (deptId == null) { @@ -141,7 +141,7 @@ public class UserQueryServiceImpl implements IUserQueryService { List scopedUserIds = resolveScopedUserIds(deptId); if (scopedUserIds != null && scopedUserIds.isEmpty()) { - return new UserStatsVO(deptCount, 0L, 0L, 0L); + return new UserStatsDTO(deptCount, 0L, 0L, 0L); } long activeCount = authUserMapper.selectCount(new LambdaQueryWrapper() @@ -154,7 +154,7 @@ public class UserQueryServiceImpl implements IUserQueryService { .in(scopedUserIds != null, AuthUser::getId, scopedUserIds) .eq(AuthUser::getEmploymentStatus, STATUS_ACTIVE) .notInSql(AuthUser::getId, "SELECT user_id FROM sys_user_role")); - return new UserStatsVO(deptCount, activeCount, resignedCount, unassignedCount); + return new UserStatsDTO(deptCount, activeCount, resignedCount, unassignedCount); } /** 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 2301fad..7e4ee55 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 @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils; import com.crm.auth.domain.entity.AuthUser; import com.crm.auth.domain.entity.SysDept; +import com.crm.auth.domain.dto.ResourceNodeDTO; import com.crm.auth.domain.entity.SysMenu; import com.crm.auth.domain.entity.SysUserDept; import com.crm.auth.mapper.AuthUserMapper; @@ -439,9 +440,9 @@ class DataScopeIntegrationTest { @Test @DisplayName("可见菜单树:含授权的 menu 节点,排除 button,无授权返回空") void visibleMenuTree_menusOnly() { - List tree = resolver.visibleMenuTree(5L); - assertThat(tree).extracting(SysMenu::getId).contains(303L); - assertThat(tree).extracting(SysMenu::getId).doesNotContain(301L, 302L, 304L); + List tree = resolver.visibleMenuTree(5L); + assertThat(tree).extracting(ResourceNodeDTO::getId).contains(303L); + assertThat(tree).extracting(ResourceNodeDTO::getId).doesNotContain(301L, 302L, 304L); assertThat(resolver.visibleMenuTree(9L)).isEmpty(); } 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 63a0c4d..0ee3dc5 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 @@ -7,7 +7,7 @@ import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import com.crm.auth.domain.dto.UserListDTO; -import com.crm.auth.domain.dto.UserStatsVO; +import com.crm.auth.domain.dto.UserStatsDTO; import com.crm.auth.domain.entity.AuthUser; import com.crm.auth.domain.entity.SysDept; import com.crm.auth.domain.entity.SysRole; @@ -134,7 +134,7 @@ class UserListIntegrationTest { @Test @DisplayName("全公司统计:5部门 / 5在职 / 1离职 / 2待分配") void stats_wholeCompany() { - UserStatsVO vo = userQueryService.stats(null); + UserStatsDTO vo = userQueryService.stats(null); assertThat(vo.getDeptCount()).isEqualTo(5); assertThat(vo.getActiveCount()).isEqualTo(5); assertThat(vo.getResignedCount()).isEqualTo(1); @@ -144,7 +144,7 @@ class UserListIntegrationTest { @Test @DisplayName("销售部子树统计:4部门 / 3在职 / 0离职 / 1待分配") void stats_salesSubtree() { - UserStatsVO vo = userQueryService.stats(10L); + UserStatsDTO vo = userQueryService.stats(10L); assertThat(vo.getDeptCount()).isEqualTo(4); assertThat(vo.getActiveCount()).isEqualTo(3); assertThat(vo.getResignedCount()).isEqualTo(0); @@ -154,7 +154,7 @@ class UserListIntegrationTest { @Test @DisplayName("市场部子树统计:含兼职命中(用户1兼挂市场部)") void stats_marketSubtree_includesPartTime() { - UserStatsVO vo = userQueryService.stats(20L); + UserStatsDTO vo = userQueryService.stats(20L); assertThat(vo.getDeptCount()).isEqualTo(1); // 主部门=20 的用户: 4(离职), 5(在职) // 兼职=20 的用户: 1(在职) → scopedUserIds = {4, 5, 1} diff --git a/docs/frontend-integration-role-management.md b/docs/frontend-integration-role-management.md index 571036b..b683637 100644 --- a/docs/frontend-integration-role-management.md +++ b/docs/frontend-integration-role-management.md @@ -45,7 +45,7 @@ interface SysRole { ### 2.2 RoleDetailVO(详情接口返回) ```typescript -interface RoleDetailVO { +interface RoleDTO { id: string; // 角色 ID roleName: string; // 角色名称 roleCode: string; // 角色编码