diff --git a/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/DashboardController.java b/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/DashboardController.java index 4ad0ddbfa9..418972b52e 100644 --- a/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/DashboardController.java +++ b/backend/services/dashboard/src/main/java/io/metersphere/dashboard/controller/DashboardController.java @@ -36,14 +36,14 @@ public class DashboardController { return dashboardService.getLayout(organizationId, SessionUtils.getUserId()); } - @PostMapping("/CREATE_BY_ME") + @PostMapping("/create_by_me") @Operation(summary = "我创建的") @CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization") public OverViewCountDTO createByMeCount(@Validated @RequestBody DashboardFrontPageRequest request) { return dashboardService.createByMeCount(request, SessionUtils.getUserId()); } - @PostMapping("/PROJECT_VIEW") + @PostMapping("/project_view") @Operation(summary = "概览") @CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization") public OverViewCountDTO projectViewCount(@Validated @RequestBody DashboardFrontPageRequest request) { diff --git a/backend/services/dashboard/src/main/java/io/metersphere/dashboard/service/DashboardService.java b/backend/services/dashboard/src/main/java/io/metersphere/dashboard/service/DashboardService.java index b3ca423ec4..452792d861 100644 --- a/backend/services/dashboard/src/main/java/io/metersphere/dashboard/service/DashboardService.java +++ b/backend/services/dashboard/src/main/java/io/metersphere/dashboard/service/DashboardService.java @@ -4,6 +4,7 @@ import io.metersphere.api.mapper.ExtApiDefinitionMapper; import io.metersphere.api.mapper.ExtApiScenarioMapper; import io.metersphere.api.mapper.ExtApiTestCaseMapper; import io.metersphere.bug.mapper.ExtBugMapper; +import io.metersphere.dashboard.constants.DashboardUserLayoutKeys; import io.metersphere.dashboard.dto.LayoutDTO; import io.metersphere.dashboard.dto.NameArrayDTO; import io.metersphere.dashboard.request.DashboardFrontPageRequest; @@ -14,15 +15,18 @@ import io.metersphere.plan.mapper.ExtTestPlanMapper; import io.metersphere.project.domain.Project; import io.metersphere.project.dto.ProjectCountDTO; import io.metersphere.project.mapper.ExtProjectMapper; +import io.metersphere.project.mapper.ExtProjectMemberMapper; import io.metersphere.project.service.ProjectService; import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.util.JSON; import io.metersphere.system.domain.UserLayout; import io.metersphere.system.domain.UserLayoutExample; +import io.metersphere.system.dto.user.ProjectUserMemberDTO; import io.metersphere.system.mapper.UserLayoutMapper; import io.metersphere.system.uid.IDGenerator; import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -56,6 +60,8 @@ public class DashboardService { @Resource private ExtProjectMapper extProjectMapper; @Resource + private ExtProjectMemberMapper extProjectMemberMapper; + @Resource private ProjectService projectService; @Resource private UserLayoutMapper userLayoutMapper; @@ -87,9 +93,7 @@ public class DashboardService { private OverViewCountDTO getModuleCountMap(Map> permissionModuleProjectIdMap, List projects, Long toStartTime, Long toEndTime, String userId) { Map map = new HashMap<>(); List xaxis = new ArrayList<>(); - //TODO: 返回数量顺序, List nameArrayDTOList = new ArrayList<>(); - //功能用例 Map caseProjectCount = new HashMap<>(); Set caseProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.FUNCTIONAL_CASE_READ); @@ -162,7 +166,7 @@ public class DashboardService { List projectBugCount = extBugMapper.projectBugCount(bugProjectIds, toStartTime, toEndTime, userId); int bugCount = projectBugCount.stream().mapToInt(ProjectCountDTO::getCount).sum(); map.put(BUG_COUNT, bugCount); - xaxis.add(TEST_PLAN); + xaxis.add(BUG_COUNT); bugProjectCount = projectBugCount.stream().collect(Collectors.toMap(ProjectCountDTO::getProjectId, t -> t)); } @@ -226,14 +230,24 @@ public class DashboardService { } public OverViewCountDTO projectViewCount(DashboardFrontPageRequest request, String userId) { - List userProject = projectService.getUserProject(request.getOrganizationId(), userId); - List collect = userProject.stream().filter(t -> request.getProjectIds().contains(t.getId())).toList(); + List collect = getHasPermissionProjects(request, userId); Map> permissionModuleProjectIdMap = dashboardProjectService.getModuleProjectIds(collect); Long toStartTime = request.getToStartTime(); Long toEndTime = request.getToEndTime(); return getModuleCountMap(permissionModuleProjectIdMap, collect, toStartTime, toEndTime, null); } + private List getHasPermissionProjects(DashboardFrontPageRequest request, String userId) { + List userProject = projectService.getUserProject(request.getOrganizationId(), userId); + List collect; + if (CollectionUtils.isNotEmpty(request.getProjectIds())) { + collect = userProject.stream().filter(t -> request.getProjectIds().contains(t.getId())).toList(); + } else { + collect = userProject; + } + return collect; + } + public List editLayout(String organizationId, String userId, List layoutDTO) { UserLayoutExample userLayoutExample = new UserLayoutExample(); @@ -258,9 +272,93 @@ public class DashboardService { UserLayoutExample userLayoutExample = new UserLayoutExample(); userLayoutExample.createCriteria().andUserIdEqualTo(userId).andOrgIdEqualTo(organizationId); List userLayouts = userLayoutMapper.selectByExampleWithBLOBs(userLayoutExample); + if (CollectionUtils.isEmpty(userLayouts)) { + return getDefaultLayoutDTOS(organizationId); + } + UserLayout userLayout = userLayouts.getFirst(); byte[] configuration = userLayout.getConfiguration(); String layoutDTOStr = new String(configuration); - return JSON.parseArray(layoutDTOStr, LayoutDTO.class); + List layoutDTOS = JSON.parseArray(layoutDTOStr, LayoutDTO.class); + + //重新查询排除项目禁用的或者用户已经移除某个项目的项目或者成员 + List allProjectIds = new ArrayList<>(); + List allHandleUsers = new ArrayList<>(); + for (LayoutDTO layoutDTO : layoutDTOS) { + allProjectIds.addAll(layoutDTO.getProjectIds()); + allHandleUsers.addAll(layoutDTO.getHandleUsers()); + } + List projectIds = allProjectIds.stream().distinct().toList(); + List getUserProjectIdName = extProjectMapper.getUserProjectIdName(null, projectIds, userId); + + Map projectMap = getUserProjectIdName.stream().collect(Collectors.toMap(Project::getId, t -> t)); + List handleUsers = allHandleUsers.stream().distinct().toList(); + List orgProjectMemberList = extProjectMemberMapper.getOrgProjectMemberList(organizationId, handleUsers); + + //重新填充填充返回的项目id 和 用户id + rebuildProjectOrUser(layoutDTOS, getUserProjectIdName, projectMap, orgProjectMemberList); + return layoutDTOS; + } + + /** + * 获取默认布局 + * + * @param organizationId 组织ID + * @return List + */ + private static List getDefaultLayoutDTOS(String organizationId) { + List layoutDTOS = new ArrayList<>(); + LayoutDTO projectLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.PROJECT_VIEW, "workbench.homePage.projectOverview", 0, new ArrayList<>()); + layoutDTOS.add(projectLayoutDTO); + LayoutDTO createByMeLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.CREATE_BY_ME, "workbench,homePage.createdByMe", 1, new ArrayList<>()); + layoutDTOS.add(createByMeLayoutDTO); + LayoutDTO projectMemberLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.PROJECT_MEMBER_VIEW, "workbench,homePage.staffOverview", 2, List.of(organizationId)); + layoutDTOS.add(projectMemberLayoutDTO); + return layoutDTOS; + } + + /** + * 构建默认布局内容 + * + * @param layoutKey 布局卡片的key + * @param label 布局卡片页面显示的label + * @param pos 布局卡片 排序 + * @param projectIds 布局卡片所选的项目ids + * @return LayoutDTO + */ + private static LayoutDTO buildDefaultLayoutDTO(DashboardUserLayoutKeys layoutKey, String label, int pos, List projectIds) { + LayoutDTO layoutDTO = new LayoutDTO(); + layoutDTO.setId(UUID.randomUUID().toString()); + layoutDTO.setKey(layoutKey.toString()); + layoutDTO.setLabel(label); + layoutDTO.setPos(pos); + layoutDTO.setFullScreen(true); + layoutDTO.setProjectIds(projectIds); + layoutDTO.setHandleUsers(new ArrayList<>()); + return layoutDTO; + } + + /** + * 过滤用户在当前项目是否有移除或者项目是否被禁用以及用户是否被删除禁用 + * + * @param layoutDTOS 获取的所有布局卡片 + * @param getUserProjectIdName 用户有任意权限的项目 + * @param projectMap 用户有任意权限的项目Map + * @param orgProjectMemberList 组织下所有的项目人员 + */ + private static void rebuildProjectOrUser(List layoutDTOS, List getUserProjectIdName, Map projectMap, List orgProjectMemberList) { + for (LayoutDTO layoutDTO : layoutDTOS) { + if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.PROJECT_VIEW.toString()) || StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.CREATE_BY_ME.toString())) { + List list = getUserProjectIdName.stream().filter(t -> layoutDTO.getProjectIds().contains(t.getId())).toList(); + layoutDTO.setProjectIds(list.stream().map(Project::getId).toList()); + } else if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.PROJECT_MEMBER_VIEW.toString())) { + List list = orgProjectMemberList.stream().filter(t -> layoutDTO.getHandleUsers().contains(t.getId())).toList(); + layoutDTO.setHandleUsers(list.stream().map(ProjectUserMemberDTO::getId).toList()); + } else { + if (CollectionUtils.isNotEmpty(layoutDTO.getProjectIds()) && projectMap.get(layoutDTO.getProjectIds().getFirst()) == null) { + layoutDTO.setProjectIds(List.of(getUserProjectIdName.get(0).getId())); + } + } + } } } diff --git a/backend/services/dashboard/src/test/java/io/metersphere/dashboard/controller/DashboardFrontPageControllerTests.java b/backend/services/dashboard/src/test/java/io/metersphere/dashboard/controller/DashboardFrontPageControllerTests.java index 935f5e96a9..ef205de88a 100644 --- a/backend/services/dashboard/src/test/java/io/metersphere/dashboard/controller/DashboardFrontPageControllerTests.java +++ b/backend/services/dashboard/src/test/java/io/metersphere/dashboard/controller/DashboardFrontPageControllerTests.java @@ -6,6 +6,12 @@ import io.metersphere.dashboard.dto.LayoutDTO; import io.metersphere.dashboard.request.DashboardFrontPageRequest; import io.metersphere.dashboard.response.OverViewCountDTO; import io.metersphere.dashboard.service.DashboardService; +import io.metersphere.project.domain.Project; +import io.metersphere.project.domain.ProjectExample; +import io.metersphere.project.dto.ProjectUserDTO; +import io.metersphere.project.mapper.ProjectMapper; +import io.metersphere.project.request.ProjectMemberRequest; +import io.metersphere.project.service.ProjectMemberService; import io.metersphere.sdk.util.JSON; import io.metersphere.system.base.BaseTest; import io.metersphere.system.controller.handler.ResultHolder; @@ -30,13 +36,18 @@ public class DashboardFrontPageControllerTests extends BaseTest { @Resource private DashboardService dashboardService; + @Resource + private ProjectMapper projectMapper; + + @Resource + private ProjectMemberService projectMemberService; private static final String EDIT_LAYOUT = "/dashboard/layout/edit/"; private static final String GET_LAYOUT = "/dashboard/layout/get/"; - private static final String CREATE_BY_ME = "/dashboard/CREATE_BY_ME"; - private static final String PROJECT_VIEW = "/dashboard/PROJECT_VIEW"; + private static final String CREATE_BY_ME = "/dashboard/create_by_me"; + private static final String PROJECT_VIEW = "/dashboard/project_view"; @Test @@ -88,7 +99,55 @@ public class DashboardFrontPageControllerTests extends BaseTest { @Test @Order(2) public void testLayout() throws Exception { + MvcResult mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT+DEFAULT_ORGANIZATION_ID); + String contentAsString = mvcResultGrt.getResponse().getContentAsString(StandardCharsets.UTF_8); + ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class); + List layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class); + Assertions.assertEquals(3, layoutDTOS.size()); + + ProjectExample projectExample = new ProjectExample(); + projectExample.createCriteria().andOrganizationIdEqualTo(DEFAULT_ORGANIZATION_ID); + List projects = projectMapper.selectByExample(projectExample); + + ProjectMemberRequest projectMemberRequest = new ProjectMemberRequest(); + projectMemberRequest.setProjectId(DEFAULT_PROJECT_ID); + projectMemberRequest.setCurrent(1); + projectMemberRequest.setPageSize(5); + List projectUserDTOS = projectMemberService.listMember(projectMemberRequest); + List layoutDTO = new ArrayList<>(); + LayoutDTO layoutDTOa = new LayoutDTO(); + layoutDTOa.setId(UUID.randomUUID().toString()); + layoutDTOa.setPos(3); + layoutDTOa.setKey(DashboardUserLayoutKeys.PROJECT_VIEW.toString()); + layoutDTOa.setLabel("项目概览"); + layoutDTOa.setProjectIds(new ArrayList<>()); + layoutDTOa.setHandleUsers(new ArrayList<>()); + layoutDTOa.setFullScreen(false); + layoutDTO.add(layoutDTOa); + + LayoutDTO layoutDTOb = new LayoutDTO(); + layoutDTOb.setId(UUID.randomUUID().toString()); + layoutDTOb.setPos(4); + layoutDTOb.setKey(DashboardUserLayoutKeys.CREATE_BY_ME.toString()); + layoutDTOb.setLabel("我的创建"); + layoutDTOb.setProjectIds(projects.stream().map(Project::getId).toList()); + layoutDTOb.setHandleUsers(new ArrayList<>()); + layoutDTOb.setFullScreen(false); + layoutDTO.add(layoutDTOb); + + List userIds = projectUserDTOS.stream().map(ProjectUserDTO::getId).toList(); + + LayoutDTO layoutDTOc = new LayoutDTO(); + layoutDTOc.setId(UUID.randomUUID().toString()); + layoutDTOc.setPos(4); + layoutDTOc.setKey(DashboardUserLayoutKeys.PROJECT_MEMBER_VIEW.toString()); + layoutDTOc.setLabel("人员概览"); + layoutDTOc.setProjectIds(List.of(DEFAULT_PROJECT_ID)); + layoutDTOc.setHandleUsers(userIds); + layoutDTOc.setFullScreen(false); + layoutDTO.add(layoutDTOc); + LayoutDTO layoutDTO1 = new LayoutDTO(); layoutDTO1.setId(UUID.randomUUID().toString()); layoutDTO1.setPos(1); @@ -99,12 +158,12 @@ public class DashboardFrontPageControllerTests extends BaseTest { layoutDTO1.setFullScreen(false); layoutDTO.add(layoutDTO1); MvcResult mvcResult = this.requestPostWithOkAndReturn(EDIT_LAYOUT+DEFAULT_ORGANIZATION_ID, layoutDTO); - String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); - ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class); - List layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class); + contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); + resultHolder = JSON.parseObject(contentAsString, ResultHolder.class); + layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class); Assertions.assertNotNull(layoutDTOS); - MvcResult mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT+DEFAULT_ORGANIZATION_ID); + mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT+DEFAULT_ORGANIZATION_ID); contentAsString = mvcResultGrt.getResponse().getContentAsString(StandardCharsets.UTF_8); resultHolder = JSON.parseObject(contentAsString, ResultHolder.class); layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class); @@ -115,16 +174,17 @@ public class DashboardFrontPageControllerTests extends BaseTest { layoutDTO2.setPos(2); layoutDTO2.setKey(DashboardUserLayoutKeys.ASSOCIATE_CASE_COUNT.toString()); layoutDTO2.setLabel("关联用例数量"); - layoutDTO2.setProjectIds(new ArrayList<>()); + layoutDTO2.setProjectIds(List.of(DEFAULT_PROJECT_ID)); layoutDTO2.setHandleUsers(new ArrayList<>()); layoutDTO2.setFullScreen(false); layoutDTO.add(layoutDTO1); - mvcResult = this.requestPostWithOkAndReturn(EDIT_LAYOUT+DEFAULT_ORGANIZATION_ID, layoutDTO); contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); resultHolder = JSON.parseObject(contentAsString, ResultHolder.class); layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class); Assertions.assertNotNull(layoutDTOS); + + } } diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMapper.java b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMapper.java index c8d685513a..dfe1afd227 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMapper.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMapper.java @@ -34,4 +34,14 @@ public interface ExtProjectMapper { List getProjectNameModule(@Param("organizationId") String organizationId, @Param("ids") ListprojectIds); + /** + * 获取用户在所选项目中仍然有任意权限的项目 + * @param organizationId 组织id + * @param projectIds 所选项目ids + * @param userId 用户 + * @return List + */ + List getUserProjectIdName(@Param("organizationId") String organizationId, @Param("ids") ListprojectIds, @Param("userId") String userId); + + } diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMapper.xml b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMapper.xml index 0ba0d6e748..9f0b991747 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMapper.xml +++ b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMapper.xml @@ -133,4 +133,26 @@ + + \ No newline at end of file diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMemberMapper.java b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMemberMapper.java index 331220ef3d..330e160730 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMemberMapper.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMemberMapper.java @@ -2,6 +2,7 @@ package io.metersphere.project.mapper; import io.metersphere.project.request.ProjectMemberRequest; import io.metersphere.system.dto.CommentUserInfo; +import io.metersphere.system.dto.user.ProjectUserMemberDTO; import io.metersphere.system.dto.user.UserExtendDTO; import org.apache.ibatis.annotations.Param; @@ -35,4 +36,13 @@ public interface ExtProjectMemberMapper { * @return 用户集合信息 */ List getCommentAtUserInfoByParam(@Param("projectId") String projectId, @Param("keyword") String keyword); + + /** + * 获取组织下所有有项目权限的成员 + * @param organizationId 组织ID + * @param userIds 用户过滤 + * @return List + */ + List getOrgProjectMemberList(@Param("organizationId") String organizationId, @Param("userIds") ListuserIds ); + } diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMemberMapper.xml b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMemberMapper.xml index 216f6cf5e5..59f4395ab0 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMemberMapper.xml +++ b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtProjectMemberMapper.xml @@ -60,4 +60,18 @@ + + + \ No newline at end of file diff --git a/backend/services/system-setting/src/main/java/io/metersphere/system/dto/user/ProjectUserMemberDTO.java b/backend/services/system-setting/src/main/java/io/metersphere/system/dto/user/ProjectUserMemberDTO.java new file mode 100644 index 0000000000..e3ceaf8822 --- /dev/null +++ b/backend/services/system-setting/src/main/java/io/metersphere/system/dto/user/ProjectUserMemberDTO.java @@ -0,0 +1,17 @@ +package io.metersphere.system.dto.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class ProjectUserMemberDTO { + + @Schema(description = "用户id") + private String id; + @Schema(description = "项目id") + private String projectId; + @Schema(description = "用户名称") + private String name; +}