feat: validate target user market selection
parent
18e51aec03
commit
231d989843
@ -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…
Reference in New Issue