From eb0d89611430a327791acfa5331b17941f29f664 Mon Sep 17 00:00:00 2001 From: wkc <978997012@qq.com> Date: Sun, 29 Mar 2026 09:47:43 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=8E=86=E5=8F=B2=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=AF=BC=E5=85=A5=E6=8E=A5=E5=8F=A3=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CcdiProjectController.java | 26 ++++++++++++++ .../dto/CcdiProjectImportHistoryDTO.java | 36 +++++++++++++++++++ .../vo/CcdiProjectHistoryListItemVO.java | 32 +++++++++++++++++ .../project/service/ICcdiProjectService.java | 21 +++++++++++ .../service/impl/CcdiProjectServiceImpl.java | 18 ++++++++++ .../CcdiProjectControllerContractTest.java | 16 +++++++++ .../controller/CcdiProjectControllerTest.java | 27 ++++++++++++++ ...3-29-project-import-history-plan-record.md | 7 ++++ 8 files changed, 183 insertions(+) create mode 100644 ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectImportHistoryDTO.java create mode 100644 ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectHistoryListItemVO.java diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectController.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectController.java index b9e61bf7..7c419956 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectController.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectController.java @@ -6,8 +6,10 @@ import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.PageDomain; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableSupport; +import com.ruoyi.ccdi.project.domain.dto.CcdiProjectImportHistoryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectQueryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectSaveDTO; +import com.ruoyi.ccdi.project.domain.vo.CcdiProjectHistoryListItemVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectStatusCountsVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO; import com.ruoyi.ccdi.project.service.ICcdiProjectService; @@ -19,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; + /** * 纪检初核项目管理Controller * @@ -100,6 +104,28 @@ public class CcdiProjectController extends BaseController { return getDataTable(result.getRecords(), result.getTotal()); } + /** + * 查询历史项目列表 + */ + @GetMapping("/history") + @Operation(summary = "查询历史项目列表") + @PreAuthorize("@ss.hasPermi('ccdi:project:list')") + public AjaxResult listHistoryProjects(CcdiProjectQueryDTO queryDTO) { + List result = projectService.listHistoryProjects(queryDTO); + return AjaxResult.success(result); + } + + /** + * 从历史项目导入 + */ + @PostMapping("/import") + @Operation(summary = "导入历史项目") + @PreAuthorize("@ss.hasPermi('ccdi:project:add')") + public AjaxResult importFromHistory(@Validated @RequestBody CcdiProjectImportHistoryDTO dto) { + CcdiProjectVO vo = projectService.importFromHistory(dto, SecurityUtils.getUsername()); + return AjaxResult.success("项目创建成功", vo); + } + /** * 查询项目状态统计 */ diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectImportHistoryDTO.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectImportHistoryDTO.java new file mode 100644 index 00000000..ee72e9dd --- /dev/null +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectImportHistoryDTO.java @@ -0,0 +1,36 @@ +package com.ruoyi.ccdi.project.domain.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import java.util.List; + +/** + * 历史项目导入DTO + * + * @author ruoyi + */ +@Data +public class CcdiProjectImportHistoryDTO { + + /** 新项目名称 */ + @NotBlank(message = "项目名称不能为空") + @Length(max = 200, message = "项目名称长度不能超过200个字符") + private String projectName; + + /** 项目描述 */ + @Length(max = 500, message = "项目描述长度不能超过500个字符") + private String description; + + /** 来源项目ID列表 */ + @NotEmpty(message = "来源项目不能为空") + private List sourceProjectIds; + + /** 流水起始日期 */ + private String startDate; + + /** 流水结束日期 */ + private String endDate; +} diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectHistoryListItemVO.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectHistoryListItemVO.java new file mode 100644 index 00000000..0d1efcc7 --- /dev/null +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectHistoryListItemVO.java @@ -0,0 +1,32 @@ +package com.ruoyi.ccdi.project.domain.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * 历史项目列表项VO + * + * @author ruoyi + */ +@Data +public class CcdiProjectHistoryListItemVO { + + /** 项目ID */ + private Long projectId; + + /** 项目名称 */ + private String projectName; + + /** 项目描述 */ + private String description; + + /** 项目状态 */ + private String status; + + /** 是否归档 */ + private Integer isArchived; + + /** 创建时间 */ + private Date createTime; +} diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectService.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectService.java index 31bfd841..fba89dba 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectService.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectService.java @@ -1,11 +1,15 @@ package com.ruoyi.ccdi.project.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.ccdi.project.domain.dto.CcdiProjectImportHistoryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectQueryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectSaveDTO; +import com.ruoyi.ccdi.project.domain.vo.CcdiProjectHistoryListItemVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectStatusCountsVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO; +import java.util.List; + /** * 项目Service接口 * @@ -53,6 +57,23 @@ public interface ICcdiProjectService { */ Page selectProjectPage(Page page, CcdiProjectQueryDTO queryDTO); + /** + * 查询历史项目列表 + * + * @param queryDTO 查询条件 + * @return 历史项目列表 + */ + List listHistoryProjects(CcdiProjectQueryDTO queryDTO); + + /** + * 从历史项目导入 + * + * @param dto 导入参数 + * @param operator 操作人 + * @return 新建项目 + */ + CcdiProjectVO importFromHistory(CcdiProjectImportHistoryDTO dto, String operator); + /** * 查询各状态的项目总数(不受搜索条件影响) * diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java index cbe83348..b32cc572 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java @@ -4,8 +4,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.ccdi.project.constants.CcdiProjectStatusConstants; import com.ruoyi.ccdi.project.domain.CcdiProject; +import com.ruoyi.ccdi.project.domain.dto.CcdiProjectImportHistoryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectQueryDTO; import com.ruoyi.ccdi.project.domain.dto.CcdiProjectSaveDTO; +import com.ruoyi.ccdi.project.domain.vo.CcdiProjectHistoryListItemVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectStatusCountsVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO; import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper; @@ -21,7 +23,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; +import java.util.Collections; import java.util.Date; +import java.util.List; import java.util.Objects; /** @@ -114,6 +118,20 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService { return projectMapper.selectProjectPage(page, queryDTO); } + @Override + public List listHistoryProjects(CcdiProjectQueryDTO queryDTO) { + return Collections.emptyList(); + } + + @Override + public CcdiProjectVO importFromHistory(CcdiProjectImportHistoryDTO dto, String operator) { + CcdiProjectSaveDTO saveDTO = new CcdiProjectSaveDTO(); + saveDTO.setProjectName(dto.getProjectName()); + saveDTO.setDescription(dto.getDescription()); + saveDTO.setConfigType("default"); + return createProject(saveDTO); + } + @Override public CcdiProjectStatusCountsVO getStatusCounts() { CcdiProjectStatusCountsVO vo = new CcdiProjectStatusCountsVO(); diff --git a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectControllerContractTest.java b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectControllerContractTest.java index 10d51227..fb746a2f 100644 --- a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectControllerContractTest.java +++ b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectControllerContractTest.java @@ -1,8 +1,11 @@ package com.ruoyi.ccdi.project.controller; +import com.ruoyi.ccdi.project.domain.dto.CcdiProjectImportHistoryDTO; +import com.ruoyi.ccdi.project.domain.dto.CcdiProjectQueryDTO; import io.swagger.v3.oas.annotations.Operation; import org.junit.jupiter.api.Test; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -30,4 +33,17 @@ class CcdiProjectControllerContractTest { assertNotNull(operation); assertEquals("归档项目", operation.summary()); } + + @Test + void shouldExposeHistoryImportEndpointContracts() throws Exception { + Method history = CcdiProjectController.class.getMethod("listHistoryProjects", CcdiProjectQueryDTO.class); + GetMapping historyMapping = history.getAnnotation(GetMapping.class); + assertNotNull(historyMapping); + assertEquals("/history", historyMapping.value()[0]); + + Method importing = CcdiProjectController.class.getMethod("importFromHistory", CcdiProjectImportHistoryDTO.class); + PostMapping importMapping = importing.getAnnotation(PostMapping.class); + assertNotNull(importMapping); + assertEquals("/import", importMapping.value()[0]); + } } diff --git a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectControllerTest.java b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectControllerTest.java index 2baa70f2..a0b7d296 100644 --- a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectControllerTest.java +++ b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectControllerTest.java @@ -1,5 +1,7 @@ package com.ruoyi.ccdi.project.controller; +import com.ruoyi.ccdi.project.domain.dto.CcdiProjectImportHistoryDTO; +import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO; import com.ruoyi.ccdi.project.service.ICcdiProjectService; import com.ruoyi.common.core.domain.AjaxResult; import io.swagger.v3.oas.annotations.Operation; @@ -16,7 +18,10 @@ import java.lang.reflect.Method; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) @@ -52,4 +57,26 @@ class CcdiProjectControllerTest { assertNotNull(operation); assertEquals("归档项目", operation.summary()); } + + @Test + void shouldImportFromHistoryAndReturnCreatedProject() { + CcdiProjectImportHistoryDTO dto = new CcdiProjectImportHistoryDTO(); + dto.setProjectName("新建项目"); + + CcdiProjectVO project = new CcdiProjectVO(); + project.setProjectId(88L); + project.setProjectName("新建项目"); + when(projectService.importFromHistory(eq(dto), eq("tester"))).thenReturn(project); + + try (MockedStatic mocked = mockStatic(com.ruoyi.common.utils.SecurityUtils.class)) { + mocked.when(com.ruoyi.common.utils.SecurityUtils::getUsername).thenReturn("tester"); + + AjaxResult result = controller.importFromHistory(dto); + + assertEquals(200, result.get("code")); + assertEquals("项目创建成功", result.get("msg")); + assertSame(project, result.get("data")); + verify(projectService).importFromHistory(dto, "tester"); + } + } } diff --git a/docs/reports/implementation/2026-03-29-project-import-history-plan-record.md b/docs/reports/implementation/2026-03-29-project-import-history-plan-record.md index b03d7749..0ecf5010 100644 --- a/docs/reports/implementation/2026-03-29-project-import-history-plan-record.md +++ b/docs/reports/implementation/2026-03-29-project-import-history-plan-record.md @@ -27,3 +27,10 @@ - 调整 `CcdiBankStatementMapper.xml` 详情查询,补充 `fur.source_project_name` 查询痕迹,为后续历史导入来源展示预留字段 - 新增 `CcdiBankStatementMapperXmlTest` 断言,先验证缺少来源字段时失败,再验证补齐后通过 - 验证命令:`mvn -pl ccdi-project -am -Dtest=CcdiBankStatementMapperXmlTest -Dsurefire.failIfNoSpecifiedTests=false test` + +### 2026-03-29 Task 2 后端接口契约落地 + +- 新增 `CcdiProjectImportHistoryDTO` 与 `CcdiProjectHistoryListItemVO`,明确历史导入入参与历史项目列表返回结构 +- 扩展 `ICcdiProjectService`、`CcdiProjectController` 与 `CcdiProjectServiceImpl`,补齐 `/ccdi/project/history` 和 `/ccdi/project/import` 最小接口骨架 +- 新增控制器契约测试与导入返回结构测试,锁定真实接口路径和“项目创建成功”返回数据 +- 验证命令:`mvn -pl ccdi-project -am -Dtest=CcdiProjectControllerContractTest,CcdiProjectControllerTest -Dsurefire.failIfNoSpecifiedTests=false test`