diff --git a/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java b/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java index 6a7fad1..1061e88 100644 --- a/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java @@ -24,6 +24,8 @@ import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckR import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckResult; import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationRequest; import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepThreeValidationResult; import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepTwoService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepThreeService; @@ -34,6 +36,7 @@ import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepThreeService import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepFourService; import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepOneService; import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepTwoService; +import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepThreeService; import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService; import com.sztzjy.linkCommerce.util.ResultEntity; import io.swagger.annotations.Api; @@ -79,6 +82,9 @@ public class StudentTrainingAnswerController { @Autowired private ProductDevelopmentProcessStepTwoService productDevelopmentProcessStepTwoService; + @Autowired + private ProductDevelopmentProcessStepThreeService productDevelopmentProcessStepThreeService; + @GetMapping("/{taskKey}") @ApiOperation("查询当前学生指定实训任务答案") public ResultEntity detail(@PathVariable String taskKey, @@ -217,6 +223,17 @@ public class StudentTrainingAnswerController { } } + @PostMapping("/product-development-process/step-3/validate") + @ApiOperation("产品开发主要流程第三步校验") + public ResultEntity validateProductDevelopmentProcessStepThree( + @RequestBody ProductDevelopmentProcessStepThreeValidationRequest answer, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "校验通过", productDevelopmentProcessStepThreeService.validate(answer, TokenProvider.getJWTUser(request))); + } catch (ServiceException e) { + return new ResultEntity<>(e.getCode(), e.getMessage()); + } + } + @DeleteMapping("/{taskKey}") @ApiOperation("删除当前学生指定实训任务答案") public ResultEntity delete(@PathVariable String taskKey, diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentProcessStepThreeValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentProcessStepThreeValidationRequest.java new file mode 100644 index 0000000..3c2aac8 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentProcessStepThreeValidationRequest.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ProductDevelopmentProcessStepThreeValidationRequest { + private String ganttImageUrl; + private String ganttImageName; + + public String getGanttImageUrl() { return ganttImageUrl; } + public void setGanttImageUrl(String ganttImageUrl) { this.ganttImageUrl = ganttImageUrl; } + public String getGanttImageName() { return ganttImageName; } + public void setGanttImageName(String ganttImageName) { this.ganttImageName = ganttImageName; } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentProcessStepThreeValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentProcessStepThreeValidationResult.java new file mode 100644 index 0000000..1db8ced --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentProcessStepThreeValidationResult.java @@ -0,0 +1,10 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ProductDevelopmentProcessStepThreeValidationResult { + private boolean valid; + private String message; + public boolean isValid() { return valid; } + public void setValid(boolean valid) { this.valid = valid; } + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentProcessStepThreeService.java b/src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentProcessStepThreeService.java new file mode 100644 index 0000000..59d43e4 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentProcessStepThreeService.java @@ -0,0 +1,9 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepThreeValidationResult; + +public interface ProductDevelopmentProcessStepThreeService { + ProductDevelopmentProcessStepThreeValidationResult validate(ProductDevelopmentProcessStepThreeValidationRequest request, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentProcessStepThreeServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentProcessStepThreeServiceImpl.java new file mode 100644 index 0000000..28eacd7 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentProcessStepThreeServiceImpl.java @@ -0,0 +1,59 @@ +package com.sztzjy.linkCommerce.service.impl; + +import com.sztzjy.linkCommerce.config.exception.handler.ServiceException; +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.StudentTrainingAnswer; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepThreeValidationResult; +import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepThreeService; +import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.util.Locale; + +@Service +public class ProductDevelopmentProcessStepThreeServiceImpl implements ProductDevelopmentProcessStepThreeService { + private static final String TASK_KEY = "product-development-process"; + private final StudentTrainingAnswerService studentTrainingAnswerService; + + @Autowired + public ProductDevelopmentProcessStepThreeServiceImpl(StudentTrainingAnswerService studentTrainingAnswerService) { + this.studentTrainingAnswerService = studentTrainingAnswerService; + } + + @Override + public ProductDevelopmentProcessStepThreeValidationResult validate(ProductDevelopmentProcessStepThreeValidationRequest request, JwtUser user) { + requireStudent(user); + requireStepTwoCompleted(user); + String imageUrl = StringUtils.trimToEmpty(request == null ? null : request.getGanttImageUrl()); + String imageName = StringUtils.trimToEmpty(request == null ? null : request.getGanttImageName()); + if (imageUrl.isEmpty() || imageName.isEmpty() || !isImage(imageName)) { + throw new ServiceException(HttpStatus.BAD_REQUEST, "请上传甘特图图片(PNG、JPG、JPEG、WEBP 或 GIF)"); + } + ProductDevelopmentProcessStepThreeValidationResult result = new ProductDevelopmentProcessStepThreeValidationResult(); + result.setValid(true); + result.setMessage("校验通过"); + return result; + } + + private void requireStudent(JwtUser user) { + if (user == null || StringUtils.isBlank(user.getUserId())) throw new ServiceException(HttpStatus.UNAUTHORIZED, "请先登录后再校验"); + if (user.getRoleId() != 4) throw new ServiceException(HttpStatus.FORBIDDEN, "仅学生可进行实训校验"); + } + + private void requireStepTwoCompleted(JwtUser user) { + StudentTrainingAnswer answer = studentTrainingAnswerService.get(TASK_KEY, null, user); + if (answer == null || StringUtils.isBlank(answer.getStep2Answer())) { + throw new ServiceException(HttpStatus.BAD_REQUEST, "请先完成第二步项目排期"); + } + } + + private boolean isImage(String filename) { + String normalized = filename.toLowerCase(Locale.ROOT); + return normalized.endsWith(".png") || normalized.endsWith(".jpg") || normalized.endsWith(".jpeg") + || normalized.endsWith(".webp") || normalized.endsWith(".gif"); + } +} diff --git a/src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java b/src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java index 00f3ad8..0055d44 100644 --- a/src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java +++ b/src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java @@ -21,6 +21,8 @@ import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckR import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckResult; import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationRequest; import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepThreeValidationResult; import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepTwoService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepThreeService; @@ -30,6 +32,7 @@ import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepTwoService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepThreeService; import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepOneService; import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepTwoService; +import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepThreeService; import com.sztzjy.linkCommerce.util.ResultEntity; import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; @@ -195,6 +198,23 @@ class StudentTrainingAnswerControllerTest { verify(service).validate(any(ProductDevelopmentProcessStepTwoValidationRequest.class), any(JwtUser.class)); } + @Test + void validateProductDevelopmentProcessStepThreeUsesTheAuthenticatedStudentAndReturnsTheValidationResult() { + StudentTrainingAnswerController controller = new StudentTrainingAnswerController(); + ProductDevelopmentProcessStepThreeService service = mock(ProductDevelopmentProcessStepThreeService.class); + ReflectionTestUtils.setField(controller, "productDevelopmentProcessStepThreeService", service); + ProductDevelopmentProcessStepThreeValidationResult validation = new ProductDevelopmentProcessStepThreeValidationResult(); + validation.setValid(true); + when(service.validate(any(ProductDevelopmentProcessStepThreeValidationRequest.class), any(JwtUser.class))).thenReturn(validation); + + ResultEntity result = controller + .validateProductDevelopmentProcessStepThree(new ProductDevelopmentProcessStepThreeValidationRequest(), authenticatedStudentRequest()); + + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals(validation, result.getBody().getData()); + verify(service).validate(any(ProductDevelopmentProcessStepThreeValidationRequest.class), any(JwtUser.class)); + } + private HttpServletRequest authenticatedStudentRequest() { JwtUser user = new JwtUser(); user.setUserId("stu-1"); diff --git a/src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentProcessStepThreeServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentProcessStepThreeServiceImplTest.java new file mode 100644 index 0000000..631f6e3 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentProcessStepThreeServiceImplTest.java @@ -0,0 +1,56 @@ +package com.sztzjy.linkCommerce.service.impl; + +import com.sztzjy.linkCommerce.config.exception.handler.ServiceException; +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.StudentTrainingAnswer; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepThreeValidationResult; +import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ProductDevelopmentProcessStepThreeServiceImplTest { + @Test + void validateAcceptsAnImageAfterStepTwoIsSaved() { + StudentTrainingAnswerService answerService = answerServiceWithStepTwo(); + ProductDevelopmentProcessStepThreeServiceImpl service = new ProductDevelopmentProcessStepThreeServiceImpl(answerService); + + ProductDevelopmentProcessStepThreeValidationResult result = service.validate(request("gantt.png"), student()); + + assertTrue(result.isValid()); + } + + @Test + void validateRejectsNonImageOrMissingStepTwoAnswer() { + ProductDevelopmentProcessStepThreeServiceImpl service = new ProductDevelopmentProcessStepThreeServiceImpl(answerServiceWithStepTwo()); + assertThrows(ServiceException.class, () -> service.validate(request("gantt.xlsx"), student())); + + StudentTrainingAnswerService emptyAnswerService = mock(StudentTrainingAnswerService.class); + when(emptyAnswerService.get(anyString(), any(), any(JwtUser.class))).thenReturn(new StudentTrainingAnswer()); + ProductDevelopmentProcessStepThreeServiceImpl noStepTwoService = new ProductDevelopmentProcessStepThreeServiceImpl(emptyAnswerService); + assertThrows(ServiceException.class, () -> noStepTwoService.validate(request("gantt.png"), student())); + } + + private StudentTrainingAnswerService answerServiceWithStepTwo() { + StudentTrainingAnswerService answerService = mock(StudentTrainingAnswerService.class); + StudentTrainingAnswer answer = new StudentTrainingAnswer(); + answer.setStep2Answer("{\"items\":[{}]}"); + when(answerService.get(anyString(), any(), any(JwtUser.class))).thenReturn(answer); + return answerService; + } + + private ProductDevelopmentProcessStepThreeValidationRequest request(String imageName) { + ProductDevelopmentProcessStepThreeValidationRequest request = new ProductDevelopmentProcessStepThreeValidationRequest(); + request.setGanttImageUrl("/profile/upload/2026/gantt.png"); + request.setGanttImageName(imageName); + return request; + } + + private JwtUser student() { JwtUser user = new JwtUser(); user.setUserId("stu-1"); user.setRoleId(4); return user; } +}