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 7d1e8f3..c13f79d 100644 --- a/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java @@ -41,6 +41,8 @@ import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepOneValidationRequ import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepOneValidationResult; import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepTwoValidationRequest; import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepTwoValidationResult; +import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationResult; import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService; import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepOneService; import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepTwoService; @@ -59,6 +61,7 @@ import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepThreeService; import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepFourService; import com.sztzjy.linkCommerce.service.FeatureConversionStepOneService; import com.sztzjy.linkCommerce.service.FeatureConversionStepTwoService; +import com.sztzjy.linkCommerce.service.FeatureConversionStepThreeService; import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService; import com.sztzjy.linkCommerce.util.ResultEntity; import io.swagger.annotations.Api; @@ -129,6 +132,9 @@ public class StudentTrainingAnswerController { @Autowired private FeatureConversionStepTwoService featureConversionStepTwoService; + @Autowired + private FeatureConversionStepThreeService featureConversionStepThreeService; + @GetMapping("/{taskKey}") @ApiOperation("查询当前学生指定实训任务答案") public ResultEntity detail(@PathVariable String taskKey, @@ -355,6 +361,17 @@ public class StudentTrainingAnswerController { } } + @PostMapping("/feature-conversion/step-3/validate") + @ApiOperation("需求转化为功能第三步校验") + public ResultEntity validateFeatureConversionStepThree( + @RequestBody FeatureConversionStepThreeValidationRequest answer, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "校验完成", featureConversionStepThreeService.validate(answer, TokenProvider.getJWTUser(request))); + } catch (ServiceException e) { + return new ResultEntity<>(e.getCode(), e.getMessage()); + } + } + @PostMapping(value = "/consumer-behavior/step-3/word-preview", consumes = "multipart/form-data") @ApiOperation("消费者需求与行为第三步Word预览") public ResultEntity previewConsumerBehaviorStepThreeWord( diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/FeatureConversionStepThreeValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/FeatureConversionStepThreeValidationRequest.java new file mode 100644 index 0000000..e8380f5 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/FeatureConversionStepThreeValidationRequest.java @@ -0,0 +1,37 @@ +package com.sztzjy.linkCommerce.entity.dto; + +import java.util.List; + +public class FeatureConversionStepThreeValidationRequest { + private List scoreRows; + private List rows; + + public List getScoreRows() { + return scoreRows; + } + + public void setScoreRows(List scoreRows) { + this.scoreRows = scoreRows; + } + + public List getRows() { + return rows; + } + + public void setRows(List rows) { + this.rows = rows; + } + + public static class PriorityRow { + private String name; + private String priority; + private String reason; + + public String getName() { return name; } + public void setName(String name) { this.name = name; } + public String getPriority() { return priority; } + public void setPriority(String priority) { this.priority = priority; } + public String getReason() { return reason; } + public void setReason(String reason) { this.reason = reason; } + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/FeatureConversionStepThreeValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/FeatureConversionStepThreeValidationResult.java new file mode 100644 index 0000000..13f5208 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/FeatureConversionStepThreeValidationResult.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class FeatureConversionStepThreeValidationResult { + 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/FeatureConversionStepThreeService.java b/src/main/java/com/sztzjy/linkCommerce/service/FeatureConversionStepThreeService.java new file mode 100644 index 0000000..b6817ae --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/FeatureConversionStepThreeService.java @@ -0,0 +1,9 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationResult; + +public interface FeatureConversionStepThreeService { + FeatureConversionStepThreeValidationResult validate(FeatureConversionStepThreeValidationRequest request, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/FeatureConversionStepThreeServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/FeatureConversionStepThreeServiceImpl.java new file mode 100644 index 0000000..dc1d054 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/FeatureConversionStepThreeServiceImpl.java @@ -0,0 +1,58 @@ +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.dto.FeatureConversionStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationResult; +import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepTwoValidationRequest; +import com.sztzjy.linkCommerce.service.FeatureConversionStepThreeService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; + +@Service +public class FeatureConversionStepThreeServiceImpl implements FeatureConversionStepThreeService { + private static final int MIN_ROWS = 8; + private static final int MAX_ROWS = 12; + private static final List PRIORITIES = Arrays.asList("P0", "P1", "P2", "P3"); + + @Override + public FeatureConversionStepThreeValidationResult validate(FeatureConversionStepThreeValidationRequest request, JwtUser user) { + requireStudent(user); + List scoreRows = request == null ? null : request.getScoreRows(); + List rows = request == null ? null : request.getRows(); + if (scoreRows == null || rows == null || scoreRows.size() < MIN_ROWS || scoreRows.size() > MAX_ROWS || scoreRows.size() != rows.size()) { + throw badRequest("功能优先级表必须与第二步 RICE 评分表保持一致,且为 8 至 12 行"); + } + for (int index = 0; index < rows.size(); index++) { + FeatureConversionStepTwoValidationRequest.RiceScoreRow scoreRow = scoreRows.get(index); + FeatureConversionStepThreeValidationRequest.PriorityRow row = rows.get(index); + if (scoreRow == null || row == null || StringUtils.isBlank(scoreRow.getName()) || !scoreRow.getName().equals(row.getName())) { + throw badRequest("功能名称和行数必须与第二步 RICE 评分表保持一致"); + } + if (!PRIORITIES.contains(row.getPriority()) || StringUtils.isBlank(row.getReason())) { + throw badRequest("请为每项功能选择 P0-P3 优先级并填写划分理由"); + } + } + FeatureConversionStepThreeValidationResult result = new FeatureConversionStepThreeValidationResult(); + 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 ServiceException badRequest(String message) { + return new ServiceException(HttpStatus.BAD_REQUEST, message); + } +} diff --git a/src/test/java/com/sztzjy/linkCommerce/service/impl/FeatureConversionStepThreeServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/FeatureConversionStepThreeServiceImplTest.java new file mode 100644 index 0000000..08ad2fb --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/FeatureConversionStepThreeServiceImplTest.java @@ -0,0 +1,69 @@ +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.dto.FeatureConversionStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepThreeValidationResult; +import com.sztzjy.linkCommerce.entity.dto.FeatureConversionStepTwoValidationRequest; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class FeatureConversionStepThreeServiceImplTest { + private final FeatureConversionStepThreeServiceImpl service = new FeatureConversionStepThreeServiceImpl(); + + @Test + void acceptsPriorityRowsSynchronizedWithRiceRows() { + FeatureConversionStepThreeValidationResult result = service.validate(request(), student()); + + assertTrue(result.isValid()); + } + + @Test + void rejectsPriorityNameNotSynchronizedWithRiceRows() { + FeatureConversionStepThreeValidationRequest request = request(); + request.getRows().get(0).setName("被篡改的功能名称"); + + assertThrows(ServiceException.class, () -> service.validate(request, student())); + } + + @Test + void rejectsBlankPriorityReason() { + FeatureConversionStepThreeValidationRequest request = request(); + request.getRows().get(0).setReason(" "); + + assertThrows(ServiceException.class, () -> service.validate(request, student())); + } + + private FeatureConversionStepThreeValidationRequest request() { + FeatureConversionStepThreeValidationRequest request = new FeatureConversionStepThreeValidationRequest(); + List scoreRows = new ArrayList<>(); + List rows = new ArrayList<>(); + for (int index = 0; index < 8; index++) { + String name = "功能定义" + (index + 1); + FeatureConversionStepTwoValidationRequest.RiceScoreRow scoreRow = new FeatureConversionStepTwoValidationRequest.RiceScoreRow(); + scoreRow.setName(name); + scoreRows.add(scoreRow); + + FeatureConversionStepThreeValidationRequest.PriorityRow row = new FeatureConversionStepThreeValidationRequest.PriorityRow(); + row.setName(name); + row.setPriority(index == 0 ? "P0" : "P1"); + row.setReason("结合 RICE 评分确定开发优先级"); + rows.add(row); + } + request.setScoreRows(scoreRows); + request.setRows(rows); + return request; + } + + private JwtUser student() { + JwtUser user = new JwtUser(); + user.setUserId("student-id"); + user.setRoleId(4); + return user; + } +}