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 5f892de..ea3673c 100644 --- a/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java @@ -28,6 +28,15 @@ import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepThreeVali import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepThreeValidationResult; import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepFourValidationRequest; import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepFourValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepOneValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepOneValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepThreeValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepFourValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepFourValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorWordPreviewResult; import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService; import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepOneService; import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepTwoService; @@ -40,6 +49,10 @@ import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepOneService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepTwoService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepThreeService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepFourService; +import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepOneService; +import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepTwoService; +import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepThreeService; +import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepFourService; import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService; import com.sztzjy.linkCommerce.util.ResultEntity; import io.swagger.annotations.Api; @@ -47,6 +60,7 @@ import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; @@ -91,6 +105,18 @@ public class StudentTrainingAnswerController { @Autowired private ProductDevelopmentFactorsStepFourService productDevelopmentFactorsStepFourService; + @Autowired + private ConsumerBehaviorStepOneService consumerBehaviorStepOneService; + + @Autowired + private ConsumerBehaviorStepTwoService consumerBehaviorStepTwoService; + + @Autowired + private ConsumerBehaviorStepThreeService consumerBehaviorStepThreeService; + + @Autowired + private ConsumerBehaviorStepFourService consumerBehaviorStepFourService; + @GetMapping("/{taskKey}") @ApiOperation("查询当前学生指定实训任务答案") public ResultEntity detail(@PathVariable String taskKey, @@ -251,6 +277,61 @@ public class StudentTrainingAnswerController { catch (ServiceException e) { return new ResultEntity<>(e.getCode(), e.getMessage()); } } + @PostMapping("/consumer-behavior/step-1/validate") + @ApiOperation("消费者需求与行为第一步校验") + public ResultEntity validateConsumerBehaviorStepOne( + @RequestBody ConsumerBehaviorStepOneValidationRequest answer, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "校验通过", consumerBehaviorStepOneService.validate(answer, TokenProvider.getJWTUser(request))); + } catch (ServiceException e) { + return new ResultEntity<>(e.getCode(), e.getMessage()); + } + } + + @PostMapping("/consumer-behavior/step-2/validate") + @ApiOperation("消费者需求与行为第二步校验") + public ResultEntity validateConsumerBehaviorStepTwo( + @RequestBody ConsumerBehaviorStepTwoValidationRequest answer, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "校验通过", consumerBehaviorStepTwoService.validate(answer, TokenProvider.getJWTUser(request))); + } catch (ServiceException e) { + return new ResultEntity<>(e.getCode(), e.getMessage()); + } + } + + @PostMapping("/consumer-behavior/step-3/validate") + @ApiOperation("消费者需求与行为第三步校验") + public ResultEntity validateConsumerBehaviorStepThree( + @RequestBody ConsumerBehaviorStepThreeValidationRequest answer, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "校验通过", consumerBehaviorStepThreeService.validate(answer, TokenProvider.getJWTUser(request))); + } catch (ServiceException e) { + return new ResultEntity<>(e.getCode(), e.getMessage()); + } + } + + @PostMapping("/consumer-behavior/step-4/validate") + @ApiOperation("消费者需求与行为第四步校验") + public ResultEntity validateConsumerBehaviorStepFour( + @RequestBody ConsumerBehaviorStepFourValidationRequest answer, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "校验通过", consumerBehaviorStepFourService.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( + @RequestPart("file") MultipartFile file, HttpServletRequest request) { + try { + return new ResultEntity<>(HttpStatus.OK, "预览成功", consumerBehaviorStepThreeService.previewWord(file, 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/ConsumerBehaviorStepFourValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepFourValidationRequest.java new file mode 100644 index 0000000..f58cdcd --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepFourValidationRequest.java @@ -0,0 +1,20 @@ +package com.sztzjy.linkCommerce.entity.dto; + +import java.util.List; + +public class ConsumerBehaviorStepFourValidationRequest { + private List rows; + + public List getRows() { return rows; } + public void setRows(List rows) { this.rows = rows; } + + public static class ReportRow { + private String title; + private String content; + + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + public String getContent() { return content; } + public void setContent(String content) { this.content = content; } + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepFourValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepFourValidationResult.java new file mode 100644 index 0000000..78bdf0e --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepFourValidationResult.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ConsumerBehaviorStepFourValidationResult { + 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/entity/dto/ConsumerBehaviorStepOneValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepOneValidationRequest.java new file mode 100644 index 0000000..201c0a5 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepOneValidationRequest.java @@ -0,0 +1,23 @@ +package com.sztzjy.linkCommerce.entity.dto; + +import java.util.List; + +public class ConsumerBehaviorStepOneValidationRequest { + private List hypotheses; + + public List getHypotheses() { return hypotheses; } + public void setHypotheses(List hypotheses) { this.hypotheses = hypotheses; } + + public static class Hypothesis { + private String targetGroup; + private String keyFinding; + private String coreHypothesis; + + public String getTargetGroup() { return targetGroup; } + public void setTargetGroup(String targetGroup) { this.targetGroup = targetGroup; } + public String getKeyFinding() { return keyFinding; } + public void setKeyFinding(String keyFinding) { this.keyFinding = keyFinding; } + public String getCoreHypothesis() { return coreHypothesis; } + public void setCoreHypothesis(String coreHypothesis) { this.coreHypothesis = coreHypothesis; } + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepOneValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepOneValidationResult.java new file mode 100644 index 0000000..dbda3d8 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepOneValidationResult.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ConsumerBehaviorStepOneValidationResult { + 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/entity/dto/ConsumerBehaviorStepThreeValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepThreeValidationRequest.java new file mode 100644 index 0000000..fc76b61 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepThreeValidationRequest.java @@ -0,0 +1,29 @@ +package com.sztzjy.linkCommerce.entity.dto; + +import java.util.List; + +public class ConsumerBehaviorStepThreeValidationRequest { + private List questions; + private String importedDocumentUrl; + + public List getQuestions() { return questions; } + public void setQuestions(List questions) { this.questions = questions; } + public String getImportedDocumentUrl() { return importedDocumentUrl; } + public void setImportedDocumentUrl(String importedDocumentUrl) { this.importedDocumentUrl = importedDocumentUrl; } + + public static class Question { + private String section; + private String type; + private String title; + private String options; + + public String getSection() { return section; } + public void setSection(String section) { this.section = section; } + public String getType() { return type; } + public void setType(String type) { this.type = type; } + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + public String getOptions() { return options; } + public void setOptions(String options) { this.options = options; } + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepThreeValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepThreeValidationResult.java new file mode 100644 index 0000000..b59b7c6 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepThreeValidationResult.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ConsumerBehaviorStepThreeValidationResult { + 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/entity/dto/ConsumerBehaviorStepTwoValidationRequest.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationRequest.java new file mode 100644 index 0000000..bb2d24e --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationRequest.java @@ -0,0 +1,23 @@ +package com.sztzjy.linkCommerce.entity.dto; + +import java.util.List; + +public class ConsumerBehaviorStepTwoValidationRequest { + private List needs; + + public List getNeeds() { return needs; } + public void setNeeds(List needs) { this.needs = needs; } + + public static class KanoNeed { + private String feature; + private String kanoType; + private String featureDirection; + + public String getFeature() { return feature; } + public void setFeature(String feature) { this.feature = feature; } + public String getKanoType() { return kanoType; } + public void setKanoType(String kanoType) { this.kanoType = kanoType; } + public String getFeatureDirection() { return featureDirection; } + public void setFeatureDirection(String featureDirection) { this.featureDirection = featureDirection; } + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationResult.java new file mode 100644 index 0000000..e34f7e4 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorStepTwoValidationResult.java @@ -0,0 +1,11 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ConsumerBehaviorStepTwoValidationResult { + 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/entity/dto/ConsumerBehaviorWordPreviewResult.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorWordPreviewResult.java new file mode 100644 index 0000000..d203399 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/ConsumerBehaviorWordPreviewResult.java @@ -0,0 +1,8 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class ConsumerBehaviorWordPreviewResult { + private String content; + + public String getContent() { return content; } + public void setContent(String content) { this.content = content; } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepFourService.java b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepFourService.java new file mode 100644 index 0000000..fa2f9e5 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepFourService.java @@ -0,0 +1,9 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepFourValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepFourValidationResult; + +public interface ConsumerBehaviorStepFourService { + ConsumerBehaviorStepFourValidationResult validate(ConsumerBehaviorStepFourValidationRequest request, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepOneService.java b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepOneService.java new file mode 100644 index 0000000..1b3a287 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepOneService.java @@ -0,0 +1,9 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepOneValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepOneValidationResult; + +public interface ConsumerBehaviorStepOneService { + ConsumerBehaviorStepOneValidationResult validate(ConsumerBehaviorStepOneValidationRequest request, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepThreeService.java b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepThreeService.java new file mode 100644 index 0000000..c5430fc --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepThreeService.java @@ -0,0 +1,12 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepThreeValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorWordPreviewResult; +import org.springframework.web.multipart.MultipartFile; + +public interface ConsumerBehaviorStepThreeService { + ConsumerBehaviorStepThreeValidationResult validate(ConsumerBehaviorStepThreeValidationRequest request, JwtUser user); + ConsumerBehaviorWordPreviewResult previewWord(MultipartFile file, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepTwoService.java b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepTwoService.java new file mode 100644 index 0000000..3c8cadf --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/ConsumerBehaviorStepTwoService.java @@ -0,0 +1,9 @@ +package com.sztzjy.linkCommerce.service; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationResult; + +public interface ConsumerBehaviorStepTwoService { + ConsumerBehaviorStepTwoValidationResult validate(ConsumerBehaviorStepTwoValidationRequest request, JwtUser user); +} diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepFourServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepFourServiceImpl.java new file mode 100644 index 0000000..2721c29 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepFourServiceImpl.java @@ -0,0 +1,48 @@ +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.ConsumerBehaviorStepFourValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepFourValidationResult; +import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepFourService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ConsumerBehaviorStepFourServiceImpl implements ConsumerBehaviorStepFourService { + private static final int REQUIRED_REPORT_ROWS = 5; + + @Override + public ConsumerBehaviorStepFourValidationResult validate(ConsumerBehaviorStepFourValidationRequest request, JwtUser user) { + requireStudent(user); + List rows = request == null ? null : request.getRows(); + if (rows == null || rows.size() != REQUIRED_REPORT_ROWS) { + throw badRequest("问卷调研报告需填写 5 个报告模块"); + } + for (ConsumerBehaviorStepFourValidationRequest.ReportRow row : rows) { + if (row == null || StringUtils.isBlank(row.getTitle()) || StringUtils.isBlank(row.getContent())) { + throw badRequest("请完整填写每个报告模块的标题和内容"); + } + } + ConsumerBehaviorStepFourValidationResult result = new ConsumerBehaviorStepFourValidationResult(); + 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/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepOneServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepOneServiceImpl.java new file mode 100644 index 0000000..8711f0b --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepOneServiceImpl.java @@ -0,0 +1,44 @@ +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.ConsumerBehaviorStepOneValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepOneValidationResult; +import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepOneService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +@Service +public class ConsumerBehaviorStepOneServiceImpl implements ConsumerBehaviorStepOneService { + @Override + public ConsumerBehaviorStepOneValidationResult validate(ConsumerBehaviorStepOneValidationRequest request, JwtUser user) { + requireStudent(user); + if (request == null || request.getHypotheses() == null || request.getHypotheses().isEmpty()) { + throw badRequest("请至少填写一条目标人群与问卷核心假设"); + } + for (ConsumerBehaviorStepOneValidationRequest.Hypothesis hypothesis : request.getHypotheses()) { + if (hypothesis == null || StringUtils.isBlank(hypothesis.getTargetGroup()) + || StringUtils.isBlank(hypothesis.getKeyFinding()) || StringUtils.isBlank(hypothesis.getCoreHypothesis())) { + throw badRequest("请完整填写目标人群、实训8关键发现和问卷核心假设"); + } + } + ConsumerBehaviorStepOneValidationResult result = new ConsumerBehaviorStepOneValidationResult(); + 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/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepThreeServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepThreeServiceImpl.java new file mode 100644 index 0000000..486b255 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepThreeServiceImpl.java @@ -0,0 +1,120 @@ +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.ConsumerBehaviorStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepThreeValidationResult; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorWordPreviewResult; +import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepThreeService; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.apache.poi.xwpf.usermodel.XWPFTable; +import org.apache.poi.xwpf.usermodel.XWPFTableCell; +import org.apache.poi.xwpf.usermodel.XWPFTableRow; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +@Service +public class ConsumerBehaviorStepThreeServiceImpl implements ConsumerBehaviorStepThreeService { + private static final Set REQUIRED_SECTIONS = new LinkedHashSet<>(Arrays.asList("基本信息", "购买行为", "需求偏好", "开放建议")); + private static final Set QUESTION_TYPES = new LinkedHashSet<>(Arrays.asList("SINGLE", "MULTIPLE", "LIKERT", "TEXT")); + private static final long MAX_WORD_FILE_SIZE = 10L * 1024 * 1024; + private static final int MAX_PREVIEW_LENGTH = 30000; + + @Override + public ConsumerBehaviorStepThreeValidationResult validate(ConsumerBehaviorStepThreeValidationRequest request, JwtUser user) { + requireStudent(user); + if (request != null && StringUtils.isNotBlank(request.getImportedDocumentUrl())) { + return validResult(); + } + List questions = request == null ? null : request.getQuestions(); + if (questions == null || questions.isEmpty()) { + throw badRequest("请完整设计问卷,或导入 Word 问卷"); + } + Set completedSections = new LinkedHashSet<>(); + boolean hasLikert = false; + for (ConsumerBehaviorStepThreeValidationRequest.Question question : questions) { + if (question == null || StringUtils.isBlank(question.getTitle()) + || !REQUIRED_SECTIONS.contains(StringUtils.trimToEmpty(question.getSection())) + || !QUESTION_TYPES.contains(StringUtils.trimToEmpty(question.getType()))) { + throw badRequest("请完整填写每道问卷题目的分区、题型和内容"); + } + if (("SINGLE".equals(question.getType()) || "MULTIPLE".equals(question.getType())) && StringUtils.isBlank(question.getOptions())) { + throw badRequest("单选题和多选题请填写选项"); + } + completedSections.add(question.getSection()); + hasLikert = hasLikert || ("需求偏好".equals(question.getSection()) && "LIKERT".equals(question.getType())); + } + if (!completedSections.containsAll(REQUIRED_SECTIONS) || !hasLikert) { + throw badRequest("问卷需包含基本信息、购买行为、需求偏好、开放建议四部分,并在需求偏好中包含 Likert 五级量表"); + } + return validResult(); + } + + @Override + public ConsumerBehaviorWordPreviewResult previewWord(MultipartFile file, JwtUser user) { + requireStudent(user); + validateWordFile(file); + try (XWPFDocument document = new XWPFDocument(file.getInputStream())) { + StringBuilder content = new StringBuilder(); + document.getParagraphs().forEach(paragraph -> appendLine(content, paragraph.getText())); + for (XWPFTable table : document.getTables()) { + for (XWPFTableRow row : table.getRows()) { + StringBuilder rowContent = new StringBuilder(); + for (XWPFTableCell cell : row.getTableCells()) { + if (rowContent.length() > 0) rowContent.append(" | "); + rowContent.append(StringUtils.trimToEmpty(cell.getText()).replaceAll("\\s+", " ")); + } + appendLine(content, rowContent.toString()); + } + } + if (content.length() > MAX_PREVIEW_LENGTH) content.setLength(MAX_PREVIEW_LENGTH); + ConsumerBehaviorWordPreviewResult result = new ConsumerBehaviorWordPreviewResult(); + result.setContent(content.toString().trim()); + return result; + } catch (IOException e) { + throw badRequest("Word 文档解析失败,请确认文件未损坏"); + } + } + + private ConsumerBehaviorStepThreeValidationResult validResult() { + ConsumerBehaviorStepThreeValidationResult result = new ConsumerBehaviorStepThreeValidationResult(); + result.setValid(true); + result.setMessage("校验通过"); + return result; + } + + private void validateWordFile(MultipartFile file) { + String fileName = file == null ? "" : StringUtils.defaultString(file.getOriginalFilename()); + if (file == null || file.isEmpty()) throw badRequest("请上传 Word 问卷"); + if (!StringUtils.endsWithIgnoreCase(fileName, ".docx")) throw badRequest("仅支持 .docx 格式的 Word 问卷预览"); + if (file.getSize() > MAX_WORD_FILE_SIZE) throw badRequest("Word 问卷大小不能超过 10MB"); + } + + private void appendLine(StringBuilder content, String value) { + String line = StringUtils.trimToEmpty(value); + if (line.isEmpty() || content.length() >= MAX_PREVIEW_LENGTH) return; + if (content.length() > 0) content.append('\n'); + content.append(line); + } + + 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/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImpl.java new file mode 100644 index 0000000..78dd7cc --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImpl.java @@ -0,0 +1,54 @@ +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.ConsumerBehaviorStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationResult; +import com.sztzjy.linkCommerce.service.ConsumerBehaviorStepTwoService; +import org.apache.commons.lang3.StringUtils; +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 ConsumerBehaviorStepTwoServiceImpl implements ConsumerBehaviorStepTwoService { + private static final int MAX_NEED_COUNT = 20; + private static final Set KANO_TYPES = new LinkedHashSet<>(Arrays.asList("基本型", "期望型", "兴奋型", "无差异型", "反向型")); + + @Override + public ConsumerBehaviorStepTwoValidationResult validate(ConsumerBehaviorStepTwoValidationRequest request, JwtUser user) { + requireStudent(user); + if (request == null || request.getNeeds() == null || request.getNeeds().isEmpty()) { + throw badRequest("请至少填写一项KANO需求分类"); + } + if (request.getNeeds().size() > MAX_NEED_COUNT) { + throw badRequest("KANO需求分类最多填写20行"); + } + for (ConsumerBehaviorStepTwoValidationRequest.KanoNeed need : request.getNeeds()) { + if (need == null || StringUtils.isBlank(need.getFeature()) + || StringUtils.isBlank(need.getFeatureDirection()) || !KANO_TYPES.contains(StringUtils.trimToEmpty(need.getKanoType()))) { + throw badRequest("请完整填写功能、KANO类型和对应功能方向"); + } + } + ConsumerBehaviorStepTwoValidationResult result = new ConsumerBehaviorStepTwoValidationResult(); + 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/ConsumerBehaviorStepFourServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepFourServiceImplTest.java new file mode 100644 index 0000000..e0a8e43 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepFourServiceImplTest.java @@ -0,0 +1,64 @@ +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.ConsumerBehaviorStepFourValidationRequest; +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 ConsumerBehaviorStepFourServiceImplTest { + + @Test + void acceptsFiveCompletedReportModulesForStudent() { + ConsumerBehaviorStepFourServiceImpl service = new ConsumerBehaviorStepFourServiceImpl(); + + assertTrue(service.validate(validRequest(), student()).isValid()); + } + + @Test + void rejectsIncompleteReportRows() { + ConsumerBehaviorStepFourServiceImpl service = new ConsumerBehaviorStepFourServiceImpl(); + ConsumerBehaviorStepFourValidationRequest request = validRequest(); + request.getRows().get(2).setContent(" "); + + assertThrows(ServiceException.class, () -> service.validate(request, student())); + } + + @Test + void rejectsNonStudent() { + ConsumerBehaviorStepFourServiceImpl service = new ConsumerBehaviorStepFourServiceImpl(); + + assertThrows(ServiceException.class, () -> service.validate(validRequest(), teacher())); + } + + private ConsumerBehaviorStepFourValidationRequest validRequest() { + ConsumerBehaviorStepFourValidationRequest request = new ConsumerBehaviorStepFourValidationRequest(); + request.setRows(Arrays.asList(row("调研背景", "说明调研背景与目的"), row("调研方法", "说明样本与渠道"), row("决策因素", "分析购买决策因素"), row("群体差异", "分析不同群体差异"), row("结论建议", "提出产品建议"))); + return request; + } + + private ConsumerBehaviorStepFourValidationRequest.ReportRow row(String title, String content) { + ConsumerBehaviorStepFourValidationRequest.ReportRow row = new ConsumerBehaviorStepFourValidationRequest.ReportRow(); + row.setTitle(title); + row.setContent(content); + return row; + } + + private JwtUser student() { + JwtUser user = new JwtUser(); + user.setUserId("stu-1"); + user.setRoleId(4); + return user; + } + + private JwtUser teacher() { + JwtUser user = new JwtUser(); + user.setUserId("teacher-1"); + user.setRoleId(2); + return user; + } +} diff --git a/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepOneServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepOneServiceImplTest.java new file mode 100644 index 0000000..6d7159b --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepOneServiceImplTest.java @@ -0,0 +1,71 @@ +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.ConsumerBehaviorStepOneValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepOneValidationResult; +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 ConsumerBehaviorStepOneServiceImplTest { + + @Test + void acceptsStudentWithCompleteTargetHypotheses() { + ConsumerBehaviorStepOneServiceImpl service = new ConsumerBehaviorStepOneServiceImpl(); + + ConsumerBehaviorStepOneValidationResult result = service.validate(validRequest(), student()); + + assertTrue(result.isValid()); + } + + @Test + void rejectsIncompleteTargetHypothesis() { + ConsumerBehaviorStepOneServiceImpl service = new ConsumerBehaviorStepOneServiceImpl(); + ConsumerBehaviorStepOneValidationRequest request = validRequest(); + request.getHypotheses().get(1).setCoreHypothesis(" "); + + assertThrows(ServiceException.class, () -> service.validate(request, student())); + } + + @Test + void rejectsNonStudent() { + ConsumerBehaviorStepOneServiceImpl service = new ConsumerBehaviorStepOneServiceImpl(); + + assertThrows(ServiceException.class, () -> service.validate(validRequest(), teacher())); + } + + private ConsumerBehaviorStepOneValidationRequest validRequest() { + ConsumerBehaviorStepOneValidationRequest request = new ConsumerBehaviorStepOneValidationRequest(); + request.setHypotheses(Arrays.asList( + row("职场白领(25-35岁)", "高压工作、入睡困难、看重效率", "是否关注白噪声质量与智能场景联动"), + row("精致妈妈(28-38岁)", "关注宝宝睡眠、需要远程看护", "是否愿意为婴幼儿模式支付溢价"), + row("银发人群(50-65岁)", "睡眠浅易醒、担心操作复杂", "语音控制是否是刚需"))); + return request; + } + + private ConsumerBehaviorStepOneValidationRequest.Hypothesis row(String targetGroup, String keyFinding, String coreHypothesis) { + ConsumerBehaviorStepOneValidationRequest.Hypothesis row = new ConsumerBehaviorStepOneValidationRequest.Hypothesis(); + row.setTargetGroup(targetGroup); + row.setKeyFinding(keyFinding); + row.setCoreHypothesis(coreHypothesis); + return row; + } + + private JwtUser student() { + JwtUser user = new JwtUser(); + user.setUserId("stu-1"); + user.setRoleId(4); + return user; + } + + private JwtUser teacher() { + JwtUser user = new JwtUser(); + user.setUserId("teacher-1"); + user.setRoleId(2); + return user; + } +} diff --git a/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepThreeServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepThreeServiceImplTest.java new file mode 100644 index 0000000..ae933b0 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepThreeServiceImplTest.java @@ -0,0 +1,76 @@ +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.ConsumerBehaviorStepThreeValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepThreeValidationResult; +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 ConsumerBehaviorStepThreeServiceImplTest { + + @Test + void acceptsCompleteQuestionnaireForStudent() { + ConsumerBehaviorStepThreeServiceImpl service = new ConsumerBehaviorStepThreeServiceImpl(); + + ConsumerBehaviorStepThreeValidationResult result = service.validate(validRequest(), student()); + + assertTrue(result.isValid()); + } + + @Test + void rejectsQuestionnaireWithoutLikertOrOptions() { + ConsumerBehaviorStepThreeServiceImpl service = new ConsumerBehaviorStepThreeServiceImpl(); + ConsumerBehaviorStepThreeValidationRequest noLikert = validRequest(); + noLikert.getQuestions().get(2).setType("TEXT"); + assertThrows(ServiceException.class, () -> service.validate(noLikert, student())); + + ConsumerBehaviorStepThreeValidationRequest noOptions = validRequest(); + noOptions.getQuestions().get(0).setOptions(" "); + assertThrows(ServiceException.class, () -> service.validate(noOptions, student())); + } + + @Test + void rejectsNonStudent() { + ConsumerBehaviorStepThreeServiceImpl service = new ConsumerBehaviorStepThreeServiceImpl(); + + assertThrows(ServiceException.class, () -> service.validate(validRequest(), teacher())); + } + + private ConsumerBehaviorStepThreeValidationRequest validRequest() { + ConsumerBehaviorStepThreeValidationRequest request = new ConsumerBehaviorStepThreeValidationRequest(); + request.setQuestions(Arrays.asList( + question("基本信息", "SINGLE", "您的年龄处于以下哪个区间?", "18岁以下,18-25岁,26-35岁"), + question("购买行为", "MULTIPLE", "您通常通过什么渠道购买智能产品?", "电商平台,线下门店,社交平台"), + question("需求偏好", "LIKERT", "白噪声可定时关闭对您有多重要?", ""), + question("开放建议", "TEXT", "您希望智能助眠产品增加哪些功能?", ""))); + return request; + } + + private ConsumerBehaviorStepThreeValidationRequest.Question question(String section, String type, String title, String options) { + ConsumerBehaviorStepThreeValidationRequest.Question question = new ConsumerBehaviorStepThreeValidationRequest.Question(); + question.setSection(section); + question.setType(type); + question.setTitle(title); + question.setOptions(options); + return question; + } + + private JwtUser student() { + JwtUser user = new JwtUser(); + user.setUserId("stu-1"); + user.setRoleId(4); + return user; + } + + private JwtUser teacher() { + JwtUser user = new JwtUser(); + user.setUserId("teacher-1"); + user.setRoleId(2); + return user; + } +} diff --git a/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImplTest.java new file mode 100644 index 0000000..51a2ef6 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/ConsumerBehaviorStepTwoServiceImplTest.java @@ -0,0 +1,75 @@ +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.ConsumerBehaviorStepTwoValidationRequest; +import com.sztzjy.linkCommerce.entity.dto.ConsumerBehaviorStepTwoValidationResult; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ConsumerBehaviorStepTwoServiceImplTest { + + @Test + void acceptsCompleteKanoNeedsForStudent() { + ConsumerBehaviorStepTwoServiceImpl service = new ConsumerBehaviorStepTwoServiceImpl(); + + ConsumerBehaviorStepTwoValidationResult result = service.validate(validRequest(), student()); + + assertTrue(result.isValid()); + } + + @Test + void rejectsInvalidKanoTypeAndMoreThanTwentyRows() { + ConsumerBehaviorStepTwoServiceImpl service = new ConsumerBehaviorStepTwoServiceImpl(); + ConsumerBehaviorStepTwoValidationRequest invalidType = validRequest(); + invalidType.getNeeds().get(0).setKanoType("未知类型"); + assertThrows(ServiceException.class, () -> service.validate(invalidType, student())); + + ConsumerBehaviorStepTwoValidationRequest tooMany = new ConsumerBehaviorStepTwoValidationRequest(); + tooMany.setNeeds(Collections.nCopies(21, row("功能", "基本型", "功能方向"))); + assertThrows(ServiceException.class, () -> service.validate(tooMany, student())); + } + + @Test + void rejectsNonStudent() { + ConsumerBehaviorStepTwoServiceImpl service = new ConsumerBehaviorStepTwoServiceImpl(); + + assertThrows(ServiceException.class, () -> service.validate(validRequest(), teacher())); + } + + private ConsumerBehaviorStepTwoValidationRequest validRequest() { + ConsumerBehaviorStepTwoValidationRequest request = new ConsumerBehaviorStepTwoValidationRequest(); + request.setNeeds(Arrays.asList( + row("灯光亮度可无级调节", "期望型", "照明系统"), + row("根据时间自动调节灯光", "兴奋型", "智能场景"), + row("白噪声可定时关闭", "基本型", "音频系统"))); + return request; + } + + private ConsumerBehaviorStepTwoValidationRequest.KanoNeed row(String feature, String kanoType, String featureDirection) { + ConsumerBehaviorStepTwoValidationRequest.KanoNeed row = new ConsumerBehaviorStepTwoValidationRequest.KanoNeed(); + row.setFeature(feature); + row.setKanoType(kanoType); + row.setFeatureDirection(featureDirection); + return row; + } + + private JwtUser student() { + JwtUser user = new JwtUser(); + user.setUserId("stu-1"); + user.setRoleId(4); + return user; + } + + private JwtUser teacher() { + JwtUser user = new JwtUser(); + user.setUserId("teacher-1"); + user.setRoleId(2); + return user; + } +}