fix(产品需求): 完善产品需求的诸多细节。

This commit is contained in:
dk
2026-05-09 18:01:42 +08:00
parent 604bf61981
commit 4f6b209c3d
6 changed files with 78 additions and 6 deletions

View File

@@ -21,6 +21,8 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static com.njcn.rdms.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 项目管理")
@@ -67,6 +69,13 @@ public class ProjectController {
return success(BeanUtils.toBean(pageResult, ProjectRespVO.class));
}
@GetMapping("/list-by-product")
@Operation(summary = "根据产品编号获取该产品下的全部项目")
@Parameter(name = "productId", description = "产品编号", required = true, example = "1024")
public CommonResult<List<ProjectRespVO>> getProjectListByProductId(@RequestParam("productId") Long productId) {
return success(projectService.getProjectListByProductId(productId));
}
@GetMapping("/overview-summary")
@Operation(summary = "获取项目入口页概览统计")
public CommonResult<ProjectOverviewSummaryRespVO> getProjectOverviewSummary() {

View File

@@ -72,6 +72,12 @@ public interface ProjectMapper extends BaseMapperX<ProjectDO> {
.orderByDesc(ProjectDO::getProjectCode));
}
default List<ProjectDO> selectListByProductId(Long productId) {
return selectList(new LambdaQueryWrapperX<ProjectDO>()
.eq(ProjectDO::getProductId, productId)
.orderByDesc(BaseDO::getCreateTime));
}
default int updateStatusByIdAndStatus(Long id, String fromStatus, String toStatus, String lastStatusReason) {
ProjectDO update = new ProjectDO();
update.setStatusCode(toStatus);

View File

@@ -228,9 +228,15 @@ public class ProductRequirementServiceImpl implements ProductRequirementService
rootIds.add(rootId);
}
// 第三步:查询根需求详情并按创建时间倒排
// 第三步:查询根需求详情并按排序值升序、创建时间倒排
List<ProductRequirementDO> rootRequirements = requirementMapper.selectBatchIds(rootIds);
rootRequirements.sort((a, b) -> b.getCreateTime().compareTo(a.getCreateTime()));
rootRequirements.sort((a, b) -> {
int sortCompare = Integer.compare(a.getSort() != null ? a.getSort() : 0, b.getSort() != null ? b.getSort() : 0);
if (sortCompare != 0) {
return sortCompare;
}
return b.getCreateTime().compareTo(a.getCreateTime());
});
// 第四步:对根节点列表进行内存分页
int pageNo = pageReqVO.getPageNo() != null ? pageReqVO.getPageNo() : 1;

View File

@@ -10,6 +10,8 @@ import com.njcn.rdms.module.project.controller.admin.project.vo.project.ProjectS
import com.njcn.rdms.module.project.controller.admin.project.vo.project.ProjectStatusActionReqVO;
import com.njcn.rdms.module.project.dal.dataobject.project.ProjectDO;
import java.util.List;
/**
* 项目 Service 接口
*/
@@ -23,6 +25,8 @@ public interface ProjectService {
ProjectRespVO getProjectDetail(Long id);
List<ProjectRespVO> getProjectListByProductId(Long productId);
ProjectContextRespVO getProjectContext(Long id);
PageResult<ProjectDO> getProjectPage(ProjectPageReqVO pageReqVO);

View File

@@ -177,10 +177,15 @@ public class ProjectServiceImpl implements ProjectService {
@Override
public ProjectRespVO getProjectDetail(Long id) {
ProjectDO project = validateProjectExists(id);
ProjectRespVO respVO = BeanUtils.toBean(project, ProjectRespVO.class);
respVO.setProductName(getProductName(project.getProductId()));
respVO.setManagerUserNickname(getManagerNickname(project.getManagerUserId()));
return respVO;
return buildProjectRespVO(project);
}
@Override
public List<ProjectRespVO> getProjectListByProductId(Long productId) {
validateProductUsable(productId);
return projectMapper.selectListByProductId(productId).stream()
.map(this::buildProjectRespVO)
.collect(Collectors.toList());
}
@Override
@@ -666,6 +671,16 @@ public class ProjectServiceImpl implements ProjectService {
return currentProject;
}
/**
* 构建项目响应对象,补齐产品名和负责人昵称,避免前端再做二次查询。
*/
private ProjectRespVO buildProjectRespVO(ProjectDO project) {
ProjectRespVO respVO = BeanUtils.toBean(project, ProjectRespVO.class);
respVO.setProductName(getProductName(project.getProductId()));
respVO.setManagerUserNickname(getManagerNickname(project.getManagerUserId()));
return respVO;
}
private ProjectContextRespVO buildProjectContextWithoutMenus(ProjectDO project, boolean guestFlag) {
ProjectContextRespVO respVO = new ProjectContextRespVO();
respVO.setCurrentProject(buildCurrentProject(project));

View File

@@ -114,6 +114,38 @@ class ProjectServiceImplTest extends BaseMockitoUnitTest {
assertEquals("张三", result.getManagerUserNickname());
}
@Test
void getProjectListByProductId_shouldReturnProjectsUnderCurrentProduct() {
Long productId = 1001L;
ProductDO product = new ProductDO();
product.setId(productId);
product.setName("统一交付平台");
ProjectDO project1 = createProject(3001L, productId, "项目A", 2001L, "pending");
ProjectDO project2 = createProject(3002L, productId, "项目B", 2002L, "active");
AdminUserRespDTO manager1 = new AdminUserRespDTO();
manager1.setId(2001L);
manager1.setNickname("张三");
AdminUserRespDTO manager2 = new AdminUserRespDTO();
manager2.setId(2002L);
manager2.setNickname("李四");
when(productMapper.selectById(productId)).thenReturn(product);
when(projectMapper.selectListByProductId(productId)).thenReturn(List.of(project1, project2));
when(adminUserApi.getUser(2001L)).thenReturn(success(manager1));
when(adminUserApi.getUser(2002L)).thenReturn(success(manager2));
List<ProjectRespVO> result = projectService.getProjectListByProductId(productId);
assertEquals(2, result.size());
assertEquals(productId, result.get(0).getProductId());
assertEquals("统一交付平台", result.get(0).getProductName());
assertEquals("张三", result.get(0).getManagerUserNickname());
assertEquals("李四", result.get(1).getManagerUserNickname());
}
@Test
void createProject_withManualCode_shouldInsertPendingProjectInitManagerAndWriteAudit() {
ProjectSaveReqVO reqVO = createReqVO("CNPJ-MANUAL", 1001L, "合同交付项目", 2001L);