feat: validate target user market selection

main
chenyuan 3 weeks ago
parent 18e51aec03
commit 231d989843

@ -36,6 +36,8 @@ import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepThreeValidationRe
import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepThreeValidationResult; import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepThreeValidationResult;
import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepFourValidationRequest; import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepFourValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepFourValidationResult; import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepFourValidationResult;
import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepFiveValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepFiveValidationResult;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService;
import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepOneService; import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepOneService;
import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepTwoService; import com.sztzjy.linkCommerce.service.MarketOpportunitySelectionStepTwoService;
@ -52,6 +54,7 @@ import com.sztzjy.linkCommerce.service.TargetUserProfileStepOneService;
import com.sztzjy.linkCommerce.service.TargetUserProfileStepTwoService; import com.sztzjy.linkCommerce.service.TargetUserProfileStepTwoService;
import com.sztzjy.linkCommerce.service.TargetUserProfileStepThreeService; import com.sztzjy.linkCommerce.service.TargetUserProfileStepThreeService;
import com.sztzjy.linkCommerce.service.TargetUserProfileStepFourService; import com.sztzjy.linkCommerce.service.TargetUserProfileStepFourService;
import com.sztzjy.linkCommerce.service.TargetUserProfileStepFiveService;
import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService; import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService;
import com.sztzjy.linkCommerce.util.ResultEntity; import com.sztzjy.linkCommerce.util.ResultEntity;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
@ -115,6 +118,9 @@ public class StudentTrainingAnswerController {
@Autowired @Autowired
private TargetUserProfileStepFourService targetUserProfileStepFourService; private TargetUserProfileStepFourService targetUserProfileStepFourService;
@Autowired
private TargetUserProfileStepFiveService targetUserProfileStepFiveService;
@GetMapping("/{taskKey}") @GetMapping("/{taskKey}")
@ApiOperation("查询当前学生指定实训任务答案") @ApiOperation("查询当前学生指定实训任务答案")
public ResultEntity<StudentTrainingAnswer> detail(@PathVariable String taskKey, public ResultEntity<StudentTrainingAnswer> detail(@PathVariable String taskKey,
@ -319,6 +325,17 @@ public class StudentTrainingAnswerController {
} }
} }
@PostMapping("/target-user-profile/step-5/validate")
@ApiOperation("目标用户画像第五步校验")
public ResultEntity<TargetUserProfileStepFiveValidationResult> validateTargetUserProfileStepFive(
@RequestBody TargetUserProfileStepFiveValidationRequest answer, HttpServletRequest request) {
try {
return new ResultEntity<>(HttpStatus.OK, "校验通过", targetUserProfileStepFiveService.validate(answer, TokenProvider.getJWTUser(request)));
} catch (ServiceException e) {
return new ResultEntity<>(e.getCode(), e.getMessage());
}
}
@DeleteMapping("/{taskKey}") @DeleteMapping("/{taskKey}")
@ApiOperation("删除当前学生指定实训任务答案") @ApiOperation("删除当前学生指定实训任务答案")
public ResultEntity delete(@PathVariable String taskKey, public ResultEntity delete(@PathVariable String taskKey,

@ -0,0 +1,32 @@
package com.sztzjy.linkCommerce.entity.dto;
import java.util.List;
public class TargetUserProfileStepFiveValidationRequest {
private List<MarketSegment> segments;
private String marketSelection;
public List<MarketSegment> getSegments() { return segments; }
public void setSegments(List<MarketSegment> segments) { this.segments = segments; }
public String getMarketSelection() { return marketSelection; }
public void setMarketSelection(String marketSelection) { this.marketSelection = marketSelection; }
public static class MarketSegment {
private String market;
private String attractiveness;
private String painPoints;
private String behaviorCharacteristics;
private String productOpportunity;
public String getMarket() { return market; }
public void setMarket(String market) { this.market = market; }
public String getAttractiveness() { return attractiveness; }
public void setAttractiveness(String attractiveness) { this.attractiveness = attractiveness; }
public String getPainPoints() { return painPoints; }
public void setPainPoints(String painPoints) { this.painPoints = painPoints; }
public String getBehaviorCharacteristics() { return behaviorCharacteristics; }
public void setBehaviorCharacteristics(String behaviorCharacteristics) { this.behaviorCharacteristics = behaviorCharacteristics; }
public String getProductOpportunity() { return productOpportunity; }
public void setProductOpportunity(String productOpportunity) { this.productOpportunity = productOpportunity; }
}
}

@ -0,0 +1,11 @@
package com.sztzjy.linkCommerce.entity.dto;
public class TargetUserProfileStepFiveValidationResult {
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; }
}

@ -0,0 +1,9 @@
package com.sztzjy.linkCommerce.service;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepFiveValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepFiveValidationResult;
public interface TargetUserProfileStepFiveService {
TargetUserProfileStepFiveValidationResult validate(TargetUserProfileStepFiveValidationRequest request, JwtUser user);
}

@ -0,0 +1,60 @@
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.TargetUserProfileStepFiveValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.TargetUserProfileStepFiveValidationResult;
import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService;
import com.sztzjy.linkCommerce.service.TargetUserProfileStepFiveService;
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 TargetUserProfileStepFiveServiceImpl implements TargetUserProfileStepFiveService {
private static final String TASK_KEY = "target-user-profile";
private static final int MAX_SEGMENTS = 6;
private static final Set<String> ATTRACTIVENESS_OPTIONS = new LinkedHashSet<>(Arrays.asList("高", "中", "低"));
@Autowired
private StudentTrainingAnswerService studentTrainingAnswerService;
@Override
public TargetUserProfileStepFiveValidationResult validate(TargetUserProfileStepFiveValidationRequest request, JwtUser user) {
if (user == null || StringUtils.isBlank(user.getUserId())) {
throw new ServiceException(HttpStatus.UNAUTHORIZED, "请先登录后再校验");
}
if (user.getRoleId() != 4) {
throw new ServiceException(HttpStatus.FORBIDDEN, "仅学生可进行实训校验");
}
StudentTrainingAnswer savedAnswer = studentTrainingAnswerService.get(TASK_KEY, null, user);
String savedContent = savedAnswer == null ? "" : savedAnswer.getStep1Answer();
if (StringUtils.isBlank(savedContent) || !StringUtils.contains(savedContent, "keyUserRecords")
|| !StringUtils.contains(savedContent, "U01") || !StringUtils.contains(savedContent, "U02") || !StringUtils.contains(savedContent, "U03")) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "请先完成并保存第 4 步重点用户画像");
}
if (request == null || request.getSegments() == null || request.getSegments().isEmpty() || request.getSegments().size() > MAX_SEGMENTS) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "请完成细分市场分析表,最多可填写 6 行");
}
for (TargetUserProfileStepFiveValidationRequest.MarketSegment segment : request.getSegments()) {
if (segment == null || StringUtils.isBlank(segment.getMarket()) || !ATTRACTIVENESS_OPTIONS.contains(StringUtils.trim(segment.getAttractiveness()))
|| StringUtils.isBlank(segment.getPainPoints()) || StringUtils.isBlank(segment.getBehaviorCharacteristics())
|| StringUtils.isBlank(segment.getProductOpportunity())) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "请完整填写每个细分市场的吸引力、需求痛点、行为特征和产品机会");
}
}
if (StringUtils.isBlank(request.getMarketSelection())) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "请完成市场选择结论");
}
TargetUserProfileStepFiveValidationResult result = new TargetUserProfileStepFiveValidationResult();
result.setValid(true);
result.setMessage("校验通过");
return result;
}
}

@ -0,0 +1,72 @@
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.TargetUserProfileStepFiveValidationRequest;
import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Arrays;
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 TargetUserProfileStepFiveServiceImplTest {
@Test
void validatesCompleteMarketSegmentsAfterPortraitsAreSaved() {
assertTrue(serviceWithPortraitHistory().validate(request(), student()).isValid());
}
@Test
void rejectsIncompleteSegmentAndMissingPortraitHistory() {
TargetUserProfileStepFiveValidationRequest incomplete = request();
incomplete.getSegments().get(0).setAttractiveness("");
assertThrows(ServiceException.class, () -> serviceWithPortraitHistory().validate(incomplete, student()));
TargetUserProfileStepFiveServiceImpl service = new TargetUserProfileStepFiveServiceImpl();
StudentTrainingAnswerService answers = mock(StudentTrainingAnswerService.class);
when(answers.get(anyString(), any(), any(JwtUser.class))).thenReturn(new StudentTrainingAnswer());
ReflectionTestUtils.setField(service, "studentTrainingAnswerService", answers);
assertThrows(ServiceException.class, () -> service.validate(request(), student()));
}
private TargetUserProfileStepFiveServiceImpl serviceWithPortraitHistory() {
TargetUserProfileStepFiveServiceImpl service = new TargetUserProfileStepFiveServiceImpl();
StudentTrainingAnswerService answers = mock(StudentTrainingAnswerService.class);
StudentTrainingAnswer answer = new StudentTrainingAnswer();
answer.setStep1Answer("{\"keyUserRecords\":[{\"code\":\"U01\"},{\"code\":\"U02\"},{\"code\":\"U03\"}]}");
when(answers.get(anyString(), any(), any(JwtUser.class))).thenReturn(answer);
ReflectionTestUtils.setField(service, "studentTrainingAnswerService", answers);
return service;
}
private TargetUserProfileStepFiveValidationRequest request() {
TargetUserProfileStepFiveValidationRequest request = new TargetUserProfileStepFiveValidationRequest();
request.setSegments(Arrays.asList(segment("职场白领"), segment("精致妈妈")));
request.setMarketSelection("优先服务有明确助眠需求的职场白领,并开发便捷的智能助眠产品。");
return request;
}
private TargetUserProfileStepFiveValidationRequest.MarketSegment segment(String market) {
TargetUserProfileStepFiveValidationRequest.MarketSegment segment = new TargetUserProfileStepFiveValidationRequest.MarketSegment();
segment.setMarket(market);
segment.setAttractiveness("高");
segment.setPainPoints("睡眠质量差,需要便捷的改善方案");
segment.setBehaviorCharacteristics("愿意尝试智能设备,并会关注健康数据");
segment.setProductOpportunity("提供智能灯光、睡眠内容和数据报告的一体化产品");
return segment;
}
private JwtUser student() {
JwtUser user = new JwtUser();
user.setUserId("stu-1");
user.setRoleId(4);
return user;
}
}
Loading…
Cancel
Save