From c9a5d5f3fdda4130584445946e1062fdd8ca91c3 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Fri, 7 Aug 2026 17:01:56 +0800 Subject: [PATCH] feat: validate industry demand analysis step four --- .../stu/StudentTrainingAnswerController.java | 17 +++++ ...mandAnalysisStepFourValidationRequest.java | 26 ++++++++ ...emandAnalysisStepFourValidationResult.java | 11 ++++ ...IndustryDemandAnalysisStepFourService.java | 9 +++ ...stryDemandAnalysisStepFourServiceImpl.java | 50 ++++++++++++++ .../StudentTrainingAnswerControllerTest.java | 20 ++++++ ...DemandAnalysisStepFourServiceImplTest.java | 65 +++++++++++++++++++ 7 files changed, 198 insertions(+) create mode 100644 src/main/java/com/sztzjy/linkCommerce/entity/dto/IndustryDemandAnalysisStepFourValidationRequest.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/entity/dto/IndustryDemandAnalysisStepFourValidationResult.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/service/IndustryDemandAnalysisStepFourService.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/service/impl/IndustryDemandAnalysisStepFourServiceImpl.java create mode 100644 src/test/java/com/sztzjy/linkCommerce/service/impl/IndustryDemandAnalysisStepFourServiceImplTest.java 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 24dd5fc..fd9b7b3 100644 --- a/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java @@ -10,6 +10,8 @@ import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepTwoValidatio import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepTwoValidationResult; import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepThreeValidationRequest; import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepThreeValidationResult; +import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepFourValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepFourValidationResult; import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepOneCheckRequest; import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepOneCheckResult; import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepTwoValidationRequest; @@ -38,6 +40,7 @@ import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService; import com.sztzjy.linkCommerce.service.IndustryDemandAnalysisStepOneService; import com.sztzjy.linkCommerce.service.IndustryDemandAnalysisStepTwoService; import com.sztzjy.linkCommerce.service.IndustryDemandAnalysisStepThreeService; +import com.sztzjy.linkCommerce.service.IndustryDemandAnalysisStepFourService; import com.sztzjy.linkCommerce.util.ResultEntity; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -63,6 +66,9 @@ public class StudentTrainingAnswerController { @Autowired private IndustryDemandAnalysisStepThreeService industryDemandAnalysisStepThreeService; + @Autowired + private IndustryDemandAnalysisStepFourService industryDemandAnalysisStepFourService; + @Autowired private NewProductSurveyStepOneService newProductSurveyStepOneService; @@ -144,6 +150,17 @@ public class StudentTrainingAnswerController { } } + @PostMapping("/industry-demand-analysis/step-4/validate") + @ApiOperation("行业需求分析第四步校验") + public ResultEntity validateIndustryDemandAnalysisStepFour( + @RequestBody IndustryDemandAnalysisStepFourValidationRequest answer, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "校验通过", industryDemandAnalysisStepFourService.validate(answer, TokenProvider.getJWTUser(request))); + } catch (ServiceException e) { + return new ResultEntity<>(e.getCode(), e.getMessage()); + } + } + @PostMapping("/new-product-survey/step-1/check") @ApiOperation("新产品调查与分析第一步判题") public ResultEntity checkNewProductSurveyStepOne( diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/IndustryDemandAnalysisStepFourValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/IndustryDemandAnalysisStepFourValidationRequest.java new file mode 100644 index 0000000..de063b0 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/IndustryDemandAnalysisStepFourValidationRequest.java @@ -0,0 +1,26 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class IndustryDemandAnalysisStepFourValidationRequest { + private String overallAssessment; + private String marketDecision; + private String decisionReason; + private String riskOne; + private String riskTwo; + private String otherRisks; + private String summary; + + public String getOverallAssessment() { return overallAssessment; } + public void setOverallAssessment(String overallAssessment) { this.overallAssessment = overallAssessment; } + public String getMarketDecision() { return marketDecision; } + public void setMarketDecision(String marketDecision) { this.marketDecision = marketDecision; } + public String getDecisionReason() { return decisionReason; } + public void setDecisionReason(String decisionReason) { this.decisionReason = decisionReason; } + public String getRiskOne() { return riskOne; } + public void setRiskOne(String riskOne) { this.riskOne = riskOne; } + public String getRiskTwo() { return riskTwo; } + public void setRiskTwo(String riskTwo) { this.riskTwo = riskTwo; } + public String getOtherRisks() { return otherRisks; } + public void setOtherRisks(String otherRisks) { this.otherRisks = otherRisks; } + public String getSummary() { return summary; } + public void setSummary(String summary) { this.summary = summary; } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/IndustryDemandAnalysisStepFourValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/IndustryDemandAnalysisStepFourValidationResult.java new file mode 100644 index 0000000..2d3671b --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/IndustryDemandAnalysisStepFourValidationResult.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class IndustryDemandAnalysisStepFourValidationResult { + 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/IndustryDemandAnalysisStepFourService.java b/src/main/java/com/sztzjy/linkCommerce/service/IndustryDemandAnalysisStepFourService.java new file mode 100644 index 0000000..4a373f0 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/IndustryDemandAnalysisStepFourService.java @@ -0,0 +1,9 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepFourValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepFourValidationResult; + +public interface IndustryDemandAnalysisStepFourService { + IndustryDemandAnalysisStepFourValidationResult validate(IndustryDemandAnalysisStepFourValidationRequest request, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/IndustryDemandAnalysisStepFourServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/IndustryDemandAnalysisStepFourServiceImpl.java new file mode 100644 index 0000000..2d6c5a0 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/IndustryDemandAnalysisStepFourServiceImpl.java @@ -0,0 +1,50 @@ +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.IndustryDemandAnalysisStepFourValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepFourValidationResult; +import com.sztzjy.linkCommerce.service.IndustryDemandAnalysisStepFourService; +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.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +@Service +public class IndustryDemandAnalysisStepFourServiceImpl implements IndustryDemandAnalysisStepFourService { + private static final String TASK_KEY = "industry-demand-analysis"; + private static final Set ASSESSMENTS = new LinkedHashSet<>(Arrays.asList("高度友好", "较为友好", "中性", "存在风险", "风险较高")); + private static final Set DECISIONS = new LinkedHashSet<>(Arrays.asList("建议进入", "谨慎进入", "建议暂缓")); + + @Autowired + private StudentTrainingAnswerService studentTrainingAnswerService; + + @Override + public IndustryDemandAnalysisStepFourValidationResult validate(IndustryDemandAnalysisStepFourValidationRequest request, JwtUser user) { + requireStudent(user); + StudentTrainingAnswer savedAnswer = studentTrainingAnswerService.get(TASK_KEY, null, user); + if (savedAnswer == null || StringUtils.isBlank(savedAnswer.getStep1Answer()) || StringUtils.isBlank(savedAnswer.getStep2Answer()) || StringUtils.isBlank(savedAnswer.getStep3Answer())) { + throw new ServiceException(HttpStatus.BAD_REQUEST, "请先完成并保存前 3 步的 PEST 分析"); + } + if (request == null || !ASSESSMENTS.contains(StringUtils.trimToEmpty(request.getOverallAssessment()))) throw badRequest("请选择总体 PEST 环境评估等级"); + if (!DECISIONS.contains(StringUtils.trimToEmpty(request.getMarketDecision())) || StringUtils.isBlank(request.getDecisionReason())) throw badRequest("请选择市场进入结论并说明理由"); + if (StringUtils.isBlank(request.getRiskOne()) || StringUtils.isBlank(request.getRiskTwo())) throw badRequest("请至少填写 2 个核心风险点"); + if (StringUtils.isBlank(request.getSummary())) throw badRequest("请总结 PEST 环境评估结论"); + IndustryDemandAnalysisStepFourValidationResult result = new IndustryDemandAnalysisStepFourValidationResult(); + result.setValid(true); + result.setMessage("校验通过"); + return result; + } + + private ServiceException badRequest(String message) { return new ServiceException(HttpStatus.BAD_REQUEST, message); } + 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, "仅学生可进行实训校验"); + } +} 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 bfdc3e2..f5e20c4 100644 --- a/src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java +++ b/src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java @@ -9,6 +9,8 @@ import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepTwoValidatio import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepTwoValidationResult; import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepThreeValidationRequest; import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepThreeValidationResult; +import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepFourValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepFourValidationResult; import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepOneCheckRequest; import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepOneCheckResult; import com.sztzjy.linkCommerce.entity.dto.NewProductSurveyStepTwoValidationRequest; @@ -27,6 +29,7 @@ import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService; import com.sztzjy.linkCommerce.service.IndustryDemandAnalysisStepOneService; import com.sztzjy.linkCommerce.service.IndustryDemandAnalysisStepTwoService; import com.sztzjy.linkCommerce.service.IndustryDemandAnalysisStepThreeService; +import com.sztzjy.linkCommerce.service.IndustryDemandAnalysisStepFourService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepTwoService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepThreeService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepFourService; @@ -100,6 +103,23 @@ class StudentTrainingAnswerControllerTest { verify(service).validate(any(IndustryDemandAnalysisStepThreeValidationRequest.class), any(JwtUser.class)); } + @Test + void validateIndustryDemandAnalysisStepFourUsesTheAuthenticatedStudentAndReturnsTheValidationResult() { + StudentTrainingAnswerController controller = new StudentTrainingAnswerController(); + IndustryDemandAnalysisStepFourService service = mock(IndustryDemandAnalysisStepFourService.class); + ReflectionTestUtils.setField(controller, "industryDemandAnalysisStepFourService", service); + IndustryDemandAnalysisStepFourValidationResult validation = new IndustryDemandAnalysisStepFourValidationResult(); + validation.setValid(true); + when(service.validate(any(IndustryDemandAnalysisStepFourValidationRequest.class), any(JwtUser.class))).thenReturn(validation); + + ResultEntity result = controller + .validateIndustryDemandAnalysisStepFour(new IndustryDemandAnalysisStepFourValidationRequest(), authenticatedStudentRequest()); + + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals(validation, result.getBody().getData()); + verify(service).validate(any(IndustryDemandAnalysisStepFourValidationRequest.class), any(JwtUser.class)); + } + @Test void checkStepOneUsesTheAuthenticatedStudentAndReturnsTheGrade() { StudentTrainingAnswerController controller = new StudentTrainingAnswerController(); diff --git a/src/test/java/com/sztzjy/linkCommerce/service/impl/IndustryDemandAnalysisStepFourServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/IndustryDemandAnalysisStepFourServiceImplTest.java new file mode 100644 index 0000000..a3562c5 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/IndustryDemandAnalysisStepFourServiceImplTest.java @@ -0,0 +1,65 @@ +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.IndustryDemandAnalysisStepFourValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.IndustryDemandAnalysisStepFourValidationResult; +import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService; +import org.junit.jupiter.api.Test; +import org.springframework.test.util.ReflectionTestUtils; + +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 IndustryDemandAnalysisStepFourServiceImplTest { + @Test + void validateAcceptsCompleteConclusionAfterFirstThreeStepsAreSaved() { + IndustryDemandAnalysisStepFourServiceImpl service = serviceWithFirstThreeSteps(); + IndustryDemandAnalysisStepFourValidationResult result = service.validate(completedRequest(), student()); + assertTrue(result.isValid()); + } + + @Test + void validateRejectsMissingCoreRiskAndMissingPrerequisiteAnswers() { + IndustryDemandAnalysisStepFourServiceImpl service = serviceWithFirstThreeSteps(); + IndustryDemandAnalysisStepFourValidationRequest missingRisk = completedRequest(); + missingRisk.setRiskTwo(" "); + assertThrows(ServiceException.class, () -> service.validate(missingRisk, student())); + + IndustryDemandAnalysisStepFourServiceImpl noPrerequisiteService = new IndustryDemandAnalysisStepFourServiceImpl(); + StudentTrainingAnswerService answerService = mock(StudentTrainingAnswerService.class); + ReflectionTestUtils.setField(noPrerequisiteService, "studentTrainingAnswerService", answerService); + when(answerService.get(anyString(), any(), any(JwtUser.class))).thenReturn(new StudentTrainingAnswer()); + assertThrows(ServiceException.class, () -> noPrerequisiteService.validate(completedRequest(), student())); + } + + private IndustryDemandAnalysisStepFourServiceImpl serviceWithFirstThreeSteps() { + IndustryDemandAnalysisStepFourServiceImpl service = new IndustryDemandAnalysisStepFourServiceImpl(); + StudentTrainingAnswerService answerService = mock(StudentTrainingAnswerService.class); + StudentTrainingAnswer savedAnswer = new StudentTrainingAnswer(); + savedAnswer.setStep1Answer("{\"pest\":{}}"); + savedAnswer.setStep2Answer("{\"supplements\":{}}"); + savedAnswer.setStep3Answer("{\"analysis\":{}}"); + when(answerService.get(anyString(), any(), any(JwtUser.class))).thenReturn(savedAnswer); + ReflectionTestUtils.setField(service, "studentTrainingAnswerService", answerService); + return service; + } + + private IndustryDemandAnalysisStepFourValidationRequest completedRequest() { + IndustryDemandAnalysisStepFourValidationRequest request = new IndustryDemandAnalysisStepFourValidationRequest(); + request.setOverallAssessment("较为友好"); + request.setMarketDecision("谨慎进入"); + request.setDecisionReason("市场需求增长,但需要控制合规和成本风险。"); + request.setRiskOne("数据合规风险"); + request.setRiskTwo("供应链成本波动风险"); + request.setSummary("整体环境较为友好,建议在风险控制措施到位后谨慎进入。"); + return request; + } + + private JwtUser student() { JwtUser user = new JwtUser(); user.setUserId("stu-1"); user.setRoleId(4); return user; } +}