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 5d79e4d..1065cf1 100644 --- a/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java @@ -39,6 +39,8 @@ import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepFourValidationResu import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorWordPreviewResult; import com.sztzjy.linkCommerce.entity.dto.ConsumerScenarioStepOneValidationRequest; import com.sztzjy.linkCommerce.entity.dto.ConsumerScenarioStepOneValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ConsumerScenarioStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerScenarioStepTwoValidationResult; import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService; import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepOneService; import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepTwoService; @@ -56,6 +58,7 @@ import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepTwoService; import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepThreeService; import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepFourService; import com.sztzjy.linkCommerce.service.ConsumerScenarioStepOneService; +import com.sztzjy.linkCommerce.service.ConsumerScenarioStepTwoService; import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService; import com.sztzjy.linkCommerce.util.ResultEntity; import io.swagger.annotations.Api; @@ -123,6 +126,9 @@ public class StudentTrainingAnswerController { @Autowired private ConsumerScenarioStepOneService consumerScenarioStepOneService; + @Autowired + private ConsumerScenarioStepTwoService consumerScenarioStepTwoService; + @GetMapping("/{taskKey}") @ApiOperation("查询当前学生指定实训任务答案") public ResultEntity detail(@PathVariable String taskKey, @@ -338,6 +344,17 @@ public class StudentTrainingAnswerController { } } + @PostMapping("/consumer-scenario/step-2/validate") + @ApiOperation("消费场景解构第二步校验") + public ResultEntity validateConsumerScenarioStepTwo( + @RequestBody ConsumerScenarioStepTwoValidationRequest answer, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "校验完成", consumerScenarioStepTwoService.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/ConsumerScenarioStepTwoValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerScenarioStepTwoValidationRequest.java new file mode 100644 index 0000000..bad4441 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerScenarioStepTwoValidationRequest.java @@ -0,0 +1,34 @@ +package com.sztzjy.linkCommerce.entity.dto; + +import java.util.List; + +public class ConsumerScenarioStepTwoValidationRequest { + private List rows; + + public List getRows() { + return rows; + } + + public void setRows(List rows) { + this.rows = rows; + } + + public static class JourneyAnalysisRow { + private String stageId; + private String behaviorDescription; + private String keyTouchpoints; + private String emotionExperience; + private String decisionFactors; + + public String getStageId() { return stageId; } + public void setStageId(String stageId) { this.stageId = stageId; } + public String getBehaviorDescription() { return behaviorDescription; } + public void setBehaviorDescription(String behaviorDescription) { this.behaviorDescription = behaviorDescription; } + public String getKeyTouchpoints() { return keyTouchpoints; } + public void setKeyTouchpoints(String keyTouchpoints) { this.keyTouchpoints = keyTouchpoints; } + public String getEmotionExperience() { return emotionExperience; } + public void setEmotionExperience(String emotionExperience) { this.emotionExperience = emotionExperience; } + public String getDecisionFactors() { return decisionFactors; } + public void setDecisionFactors(String decisionFactors) { this.decisionFactors = decisionFactors; } + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerScenarioStepTwoValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerScenarioStepTwoValidationResult.java new file mode 100644 index 0000000..7a0beeb --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerScenarioStepTwoValidationResult.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ConsumerScenarioStepTwoValidationResult { + 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/ConsumerScenarioStepTwoService.java b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerScenarioStepTwoService.java new file mode 100644 index 0000000..cbb7d29 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerScenarioStepTwoService.java @@ -0,0 +1,9 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ConsumerScenarioStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerScenarioStepTwoValidationResult; + +public interface ConsumerScenarioStepTwoService { + ConsumerScenarioStepTwoValidationResult validate(ConsumerScenarioStepTwoValidationRequest request, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerScenarioStepTwoServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerScenarioStepTwoServiceImpl.java new file mode 100644 index 0000000..4c05c29 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerScenarioStepTwoServiceImpl.java @@ -0,0 +1,55 @@ +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.ConsumerScenarioStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerScenarioStepTwoValidationResult; +import com.sztzjy.linkCommerce.service.ConsumerScenarioStepTwoService; +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 ConsumerScenarioStepTwoServiceImpl implements ConsumerScenarioStepTwoService { + private static final List STAGE_IDS = Arrays.asList( + "problem-awareness", "information-search", "evaluation-decision", "purchase-conversion", "post-purchase" + ); + private static final List EMOTIONS = Arrays.asList("负面", "中性", "正面"); + + @Override + public ConsumerScenarioStepTwoValidationResult validate(ConsumerScenarioStepTwoValidationRequest request, JwtUser user) { + requireStudent(user); + List rows = request == null ? null : request.getRows(); + if (rows == null || rows.size() != STAGE_IDS.size() || rows.stream().anyMatch(row -> row == null) + || rows.stream().map(ConsumerScenarioStepTwoValidationRequest.JourneyAnalysisRow::getStageId).distinct().count() != STAGE_IDS.size() + || rows.stream().anyMatch(row -> !STAGE_IDS.contains(row.getStageId()))) { + throw badRequest("请完整填写五个购买旅程阶段的分析"); + } + for (ConsumerScenarioStepTwoValidationRequest.JourneyAnalysisRow row : rows) { + if (StringUtils.isBlank(row.getBehaviorDescription()) || StringUtils.isBlank(row.getKeyTouchpoints()) + || StringUtils.isBlank(row.getDecisionFactors()) || !EMOTIONS.contains(row.getEmotionExperience())) { + throw badRequest("请完整填写用户行为、关键触点、情感体验和关键决策因素"); + } + } + ConsumerScenarioStepTwoValidationResult result = new ConsumerScenarioStepTwoValidationResult(); + 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/ConsumerScenarioStepTwoServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerScenarioStepTwoServiceImplTest.java new file mode 100644 index 0000000..109d0bd --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerScenarioStepTwoServiceImplTest.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.dto.ConsumerScenarioStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerScenarioStepTwoValidationResult; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ConsumerScenarioStepTwoServiceImplTest { + @Test + void acceptsFiveCompleteJourneyRows() { + ConsumerScenarioStepTwoValidationResult result = new ConsumerScenarioStepTwoServiceImpl().validate(request(), student()); + + assertTrue(result.isValid()); + } + + @Test + void rejectsIncompleteJourneyRows() { + ConsumerScenarioStepTwoValidationRequest request = request(); + request.getRows().get(2).setDecisionFactors(" "); + + assertThrows(ServiceException.class, () -> new ConsumerScenarioStepTwoServiceImpl().validate(request, student())); + } + + @Test + void rejectsInvalidEmotion() { + ConsumerScenarioStepTwoValidationRequest request = request(); + request.getRows().get(0).setEmotionExperience("高兴"); + + assertThrows(ServiceException.class, () -> new ConsumerScenarioStepTwoServiceImpl().validate(request, student())); + } + + private ConsumerScenarioStepTwoValidationRequest request() { + ConsumerScenarioStepTwoValidationRequest request = new ConsumerScenarioStepTwoValidationRequest(); + request.setRows(Arrays.asList( + row("problem-awareness", "失眠后搜索助眠方案", "短视频与电商搜索页", "负面", "白噪声质量与智能联动"), + row("information-search", "浏览测评和产品详情", "达人测评、详情页", "中性", "参数、口碑与价格"), + row("evaluation-decision", "对比多个品牌", "对比页、评价区", "正面", "性能、价格与售后"), + row("purchase-conversion", "使用优惠完成下单", "直播间、支付页", "正面", "优惠与物流承诺"), + row("post-purchase", "安装使用并分享反馈", "App、售后与社区", "正面", "体验、服务与更新"))); + return request; + } + + private ConsumerScenarioStepTwoValidationRequest.JourneyAnalysisRow row(String stageId, String behavior, String touchpoints, String emotion, String factors) { + ConsumerScenarioStepTwoValidationRequest.JourneyAnalysisRow row = new ConsumerScenarioStepTwoValidationRequest.JourneyAnalysisRow(); + row.setStageId(stageId); + row.setBehaviorDescription(behavior); + row.setKeyTouchpoints(touchpoints); + row.setEmotionExperience(emotion); + row.setDecisionFactors(factors); + return row; + } + + private JwtUser student() { + JwtUser user = new JwtUser(); + user.setUserId("stu-1"); + user.setRoleId(4); + return user; + } +}