From 0aac26f13b9af5be1bd175c2ec884b5c67ee4fb7 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Wed, 12 Aug 2026 01:01:31 +0800 Subject: [PATCH] feat: validate value proposition canvas --- .../stu/StudentTrainingAnswerController.java | 17 ++++++ ...uePositioningStepTwoValidationRequest.java | 40 +++++++++++++ ...luePositioningStepTwoValidationResult.java | 11 ++++ ...ProductValuePositioningStepTwoService.java | 9 +++ ...uctValuePositioningStepTwoServiceImpl.java | 41 +++++++++++++ ...aluePositioningStepTwoServiceImplTest.java | 57 +++++++++++++++++++ 6 files changed, 175 insertions(+) create mode 100644 src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductValuePositioningStepTwoValidationRequest.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductValuePositioningStepTwoValidationResult.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/service/ProductValuePositioningStepTwoService.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/service/impl/ProductValuePositioningStepTwoServiceImpl.java create mode 100644 src/test/java/com/sztzjy/linkCommerce/service/impl/ProductValuePositioningStepTwoServiceImplTest.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 045620f..0318a80 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.ProductValuePositioningStepOneValidationRequest; import com.sztzjy.linkCommerce.entity.dto.ProductValuePositioningStepOneValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ProductValuePositioningStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductValuePositioningStepTwoValidationResult; 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.ProductValuePositioningStepOneService; +import com.sztzjy.linkCommerce.service.ProductValuePositioningStepTwoService; 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 ProductValuePositioningStepOneService productValuePositioningStepOneService; + @Autowired + private ProductValuePositioningStepTwoService productValuePositioningStepTwoService; + @GetMapping("/{taskKey}") @ApiOperation("查询当前学生指定实训任务答案") public ResultEntity detail(@PathVariable String taskKey, @@ -338,6 +344,17 @@ public class StudentTrainingAnswerController { } } + @PostMapping("/product-value-positioning/step-2/validate") + @ApiOperation("产品价值主张及定位第二步校验") + public ResultEntity validateProductValuePositioningStepTwo( + @RequestBody ProductValuePositioningStepTwoValidationRequest answer, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "校验完成", productValuePositioningStepTwoService.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/ProductValuePositioningStepTwoValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductValuePositioningStepTwoValidationRequest.java new file mode 100644 index 0000000..f4014ee --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductValuePositioningStepTwoValidationRequest.java @@ -0,0 +1,40 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ProductValuePositioningStepTwoValidationRequest { + private CustomerProfile customerProfile; + private ValueMap valueMap; + private String canvasUrl; + + public CustomerProfile getCustomerProfile() { return customerProfile; } + public void setCustomerProfile(CustomerProfile customerProfile) { this.customerProfile = customerProfile; } + public ValueMap getValueMap() { return valueMap; } + public void setValueMap(ValueMap valueMap) { this.valueMap = valueMap; } + public String getCanvasUrl() { return canvasUrl; } + public void setCanvasUrl(String canvasUrl) { this.canvasUrl = canvasUrl; } + + public static class CustomerProfile { + private String jobs; + private String pains; + private String gains; + + public String getJobs() { return jobs; } + public void setJobs(String jobs) { this.jobs = jobs; } + public String getPains() { return pains; } + public void setPains(String pains) { this.pains = pains; } + public String getGains() { return gains; } + public void setGains(String gains) { this.gains = gains; } + } + + public static class ValueMap { + private String products; + private String painRelievers; + private String gainCreators; + + public String getProducts() { return products; } + public void setProducts(String products) { this.products = products; } + public String getPainRelievers() { return painRelievers; } + public void setPainRelievers(String painRelievers) { this.painRelievers = painRelievers; } + public String getGainCreators() { return gainCreators; } + public void setGainCreators(String gainCreators) { this.gainCreators = gainCreators; } + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductValuePositioningStepTwoValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductValuePositioningStepTwoValidationResult.java new file mode 100644 index 0000000..37e7c91 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductValuePositioningStepTwoValidationResult.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ProductValuePositioningStepTwoValidationResult { + 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/ProductValuePositioningStepTwoService.java b/src/main/java/com/sztzjy/linkCommerce/service/ProductValuePositioningStepTwoService.java new file mode 100644 index 0000000..e5192ca --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/ProductValuePositioningStepTwoService.java @@ -0,0 +1,9 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ProductValuePositioningStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductValuePositioningStepTwoValidationResult; + +public interface ProductValuePositioningStepTwoService { + ProductValuePositioningStepTwoValidationResult validate(ProductValuePositioningStepTwoValidationRequest request, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductValuePositioningStepTwoServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductValuePositioningStepTwoServiceImpl.java new file mode 100644 index 0000000..c015deb --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductValuePositioningStepTwoServiceImpl.java @@ -0,0 +1,41 @@ +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.ProductValuePositioningStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductValuePositioningStepTwoValidationResult; +import com.sztzjy.linkCommerce.service.ProductValuePositioningStepTwoService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +@Service +public class ProductValuePositioningStepTwoServiceImpl implements ProductValuePositioningStepTwoService { + @Override + public ProductValuePositioningStepTwoValidationResult validate(ProductValuePositioningStepTwoValidationRequest request, JwtUser user) { + requireStudent(user); + ProductValuePositioningStepTwoValidationRequest.CustomerProfile profile = request == null ? null : request.getCustomerProfile(); + ProductValuePositioningStepTwoValidationRequest.ValueMap valueMap = request == null ? null : request.getValueMap(); + if (profile == null || valueMap == null + || StringUtils.isBlank(profile.getJobs()) || StringUtils.isBlank(profile.getPains()) || StringUtils.isBlank(profile.getGains()) + || StringUtils.isBlank(valueMap.getProducts()) || StringUtils.isBlank(valueMap.getPainRelievers()) || StringUtils.isBlank(valueMap.getGainCreators()) + || StringUtils.isBlank(request.getCanvasUrl())) { + throw badRequest("请完整填写用户档案、产品价值地图并上传产品价值主张画布"); + } + ProductValuePositioningStepTwoValidationResult result = new ProductValuePositioningStepTwoValidationResult(); + 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/ProductValuePositioningStepTwoServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/ProductValuePositioningStepTwoServiceImplTest.java new file mode 100644 index 0000000..056d795 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/ProductValuePositioningStepTwoServiceImplTest.java @@ -0,0 +1,57 @@ +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.ProductValuePositioningStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ProductValuePositioningStepTwoValidationResult; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ProductValuePositioningStepTwoServiceImplTest { + private final ProductValuePositioningStepTwoServiceImpl service = new ProductValuePositioningStepTwoServiceImpl(); + + @Test + void acceptsCompleteValuePropositionCanvas() { + ProductValuePositioningStepTwoValidationResult result = service.validate(request(), student()); + assertTrue(result.isValid()); + } + + @Test + void rejectsBlankPainReliever() { + ProductValuePositioningStepTwoValidationRequest request = request(); + request.getValueMap().setPainRelievers(" "); + assertThrows(ServiceException.class, () -> service.validate(request, student())); + } + + @Test + void rejectsMissingCanvas() { + ProductValuePositioningStepTwoValidationRequest request = request(); + request.setCanvasUrl(""); + assertThrows(ServiceException.class, () -> service.validate(request, student())); + } + + private ProductValuePositioningStepTwoValidationRequest request() { + ProductValuePositioningStepTwoValidationRequest.CustomerProfile profile = new ProductValuePositioningStepTwoValidationRequest.CustomerProfile(); + profile.setJobs("完成高质量睡眠"); + profile.setPains("入睡困难"); + profile.setGains("温和唤醒"); + ProductValuePositioningStepTwoValidationRequest.ValueMap valueMap = new ProductValuePositioningStepTwoValidationRequest.ValueMap(); + valueMap.setProducts("智能助眠灯"); + valueMap.setPainRelievers("节律光缓解入睡困难"); + valueMap.setGainCreators("睡眠报告创造额外收益"); + ProductValuePositioningStepTwoValidationRequest request = new ProductValuePositioningStepTwoValidationRequest(); + request.setCustomerProfile(profile); + request.setValueMap(valueMap); + request.setCanvasUrl("/uploads/value-canvas.png"); + return request; + } + + private JwtUser student() { + JwtUser user = new JwtUser(); + user.setUserId("student-id"); + user.setRoleId(4); + return user; + } +}