diff --git a/backend/src/main/java/com/xly/erp/module/mod/controller/ModuleController.java b/backend/src/main/java/com/xly/erp/module/mod/controller/ModuleController.java new file mode 100644 index 0000000..4c073fa --- /dev/null +++ b/backend/src/main/java/com/xly/erp/module/mod/controller/ModuleController.java @@ -0,0 +1,29 @@ +package com.xly.erp.module.mod.controller; + +import com.xly.erp.common.response.Result; +import com.xly.erp.module.mod.dto.CreateModuleDTO; +import com.xly.erp.module.mod.service.ModuleService; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +@RequestMapping("/api/mod") +public class ModuleController { + + private final ModuleService moduleService; + + public ModuleController(ModuleService moduleService) { + this.moduleService = moduleService; + } + + @PostMapping("/modules") + public Result> create(@Valid @RequestBody CreateModuleDTO dto) { + Integer id = moduleService.create(dto); + return Result.ok(Map.of("iIncrement", id)); + } +} diff --git a/backend/src/main/java/com/xly/erp/module/mod/dto/CreateModuleDTO.java b/backend/src/main/java/com/xly/erp/module/mod/dto/CreateModuleDTO.java index 2345a03..d9f982e 100644 --- a/backend/src/main/java/com/xly/erp/module/mod/dto/CreateModuleDTO.java +++ b/backend/src/main/java/com/xly/erp/module/mod/dto/CreateModuleDTO.java @@ -1,33 +1,42 @@ package com.xly.erp.module.mod.dto; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; public class CreateModuleDTO { + @JsonProperty("sDisplayType") @NotBlank private String sDisplayType; + @JsonProperty("sProcedureName") @NotBlank @Size(max = 100) private String sProcedureName; + @JsonProperty("sModuleType") @NotBlank @Size(max = 50) private String sModuleType; + @JsonProperty("sManageDeptEn") @NotBlank @Size(max = 50) private String sManageDeptEn; + @JsonProperty("bShowPermission") private Boolean bShowPermission; + @JsonProperty("sModuleNameZh") @NotBlank @Size(max = 100) private String sModuleNameZh; + @JsonProperty("iParentId") private Integer iParentId; + @JsonProperty("iSortOrder") private Integer iSortOrder; public String getSDisplayType() { return sDisplayType; } diff --git a/backend/src/test/java/com/xly/erp/module/mod/controller/ModuleControllerIT.java b/backend/src/test/java/com/xly/erp/module/mod/controller/ModuleControllerIT.java new file mode 100644 index 0000000..782a57a --- /dev/null +++ b/backend/src/test/java/com/xly/erp/module/mod/controller/ModuleControllerIT.java @@ -0,0 +1,92 @@ +package com.xly.erp.module.mod.controller; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.xly.erp.common.security.TestJwtHelper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ActiveProfiles; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +class ModuleControllerIT { + + @Autowired + private TestRestTemplate rest; + + @Autowired + private TestJwtHelper testJwtHelper; + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private ObjectMapper objectMapper; + + @LocalServerPort + private int port; + + @BeforeEach + @AfterEach + void cleanup() { + jdbcTemplate.update("DELETE FROM tModule WHERE sProcedureName LIKE 'sp_test_%'"); + } + + @Test + void postValidBody_with_jwt_returns200_andPersists() throws Exception { + String token = testJwtHelper.signFor("ADMIN001"); + HttpHeaders headers = jsonHeaders(); + headers.set("Authorization", "Bearer " + token); + + ResponseEntity resp = rest.exchange( + "http://localhost:" + port + "/api/mod/modules", + HttpMethod.POST, + new HttpEntity<>(validBody("sp_test_ctrl_ok", "正常路径"), headers), + String.class); + + assertThat(resp.getStatusCode().value()).isEqualTo(200); + JsonNode body = objectMapper.readTree(resp.getBody()); + assertThat(body.get("code").asInt()).isZero(); + int newId = body.get("data").get("iIncrement").asInt(); + assertThat(newId).isPositive(); + + Map row = jdbcTemplate.queryForMap( + "SELECT sProcedureName, sBrandsId, sCreatedBy FROM tModule WHERE iIncrement = ?", newId); + assertThat(row.get("sProcedureName")).isEqualTo("sp_test_ctrl_ok"); + assertThat(row.get("sBrandsId")).isEqualTo("XLY"); + assertThat(row.get("sCreatedBy")).isEqualTo("ADMIN001"); + } + + static HttpHeaders jsonHeaders() { + HttpHeaders h = new HttpHeaders(); + h.setContentType(MediaType.APPLICATION_JSON); + return h; + } + + static Map validBody(String procedureName, String nameZh) { + Map m = new HashMap<>(); + m.put("sDisplayType", "手机端"); + m.put("sProcedureName", procedureName); + m.put("sModuleType", "业务模块"); + m.put("sManageDeptEn", "IT"); + m.put("bShowPermission", false); + m.put("sModuleNameZh", nameZh); + return m; + } +}