feat: validate product development process step two

main
chenyuan 3 weeks ago
parent 763d0870e9
commit 9c5ef5bb9d

@ -22,6 +22,8 @@ import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepFourValid
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepFourValidationResult;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckResult;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationResult;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepTwoService;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepThreeService;
@ -31,6 +33,7 @@ import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepTwoService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepThreeService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepFourService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepOneService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepTwoService;
import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService;
import com.sztzjy.linkCommerce.util.ResultEntity;
import io.swagger.annotations.Api;
@ -73,6 +76,9 @@ public class StudentTrainingAnswerController {
@Autowired
private ProductDevelopmentProcessStepOneService productDevelopmentProcessStepOneService;
@Autowired
private ProductDevelopmentProcessStepTwoService productDevelopmentProcessStepTwoService;
@GetMapping("/{taskKey}")
@ApiOperation("查询当前学生指定实训任务答案")
public ResultEntity<StudentTrainingAnswer> detail(@PathVariable String taskKey,
@ -200,6 +206,17 @@ public class StudentTrainingAnswerController {
}
}
@PostMapping("/product-development-process/step-2/validate")
@ApiOperation("产品开发主要流程第二步校验")
public ResultEntity<ProductDevelopmentProcessStepTwoValidationResult> validateProductDevelopmentProcessStepTwo(
@RequestBody ProductDevelopmentProcessStepTwoValidationRequest answer, HttpServletRequest request) {
try {
return new ResultEntity<>(HttpStatus.OK, "校验通过", productDevelopmentProcessStepTwoService.validate(answer, TokenProvider.getJWTUser(request)));
} catch (ServiceException e) {
return new ResultEntity<>(e.getCode(), e.getMessage());
}
}
@DeleteMapping("/{taskKey}")
@ApiOperation("删除当前学生指定实训任务答案")
public ResultEntity delete(@PathVariable String taskKey,

@ -0,0 +1,29 @@
package com.sztzjy.linkCommerce.entity.dto;
import java.util.List;
public class ProductDevelopmentProcessStepTwoValidationRequest {
private List<Item> items;
public List<Item> getItems() { return items; }
public void setItems(List<Item> items) { this.items = items; }
public static class Item {
private String taskNo;
private String classification;
private String startDate;
private String endDate;
private String dependency;
public String getTaskNo() { return taskNo; }
public void setTaskNo(String taskNo) { this.taskNo = taskNo; }
public String getClassification() { return classification; }
public void setClassification(String classification) { this.classification = classification; }
public String getStartDate() { return startDate; }
public void setStartDate(String startDate) { this.startDate = startDate; }
public String getEndDate() { return endDate; }
public void setEndDate(String endDate) { this.endDate = endDate; }
public String getDependency() { return dependency; }
public void setDependency(String dependency) { this.dependency = dependency; }
}
}

@ -0,0 +1,11 @@
package com.sztzjy.linkCommerce.entity.dto;
public class ProductDevelopmentProcessStepTwoValidationResult {
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.ProductDevelopmentProcessStepTwoValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationResult;
public interface ProductDevelopmentProcessStepTwoService {
ProductDevelopmentProcessStepTwoValidationResult validate(ProductDevelopmentProcessStepTwoValidationRequest request, JwtUser user);
}

@ -0,0 +1,97 @@
package com.sztzjy.linkCommerce.service.impl;
import com.alibaba.fastjson.JSON;
import com.sztzjy.linkCommerce.config.exception.handler.ServiceException;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationResult;
import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepTwoService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Service
public class ProductDevelopmentProcessStepTwoServiceImpl implements ProductDevelopmentProcessStepTwoService {
private static final String TASK_KEY = "product-development-process";
private static final int STEP_NO = 1;
private static final String KEY_TASK = "关键任务";
private static final String NON_KEY_TASK = "非关键任务";
private static final Set<String> ALLOWED_CLASSIFICATIONS = new LinkedHashSet<>(Arrays.asList(KEY_TASK, NON_KEY_TASK));
private static final Set<String> TASK_NUMBERS = new LinkedHashSet<>(Arrays.asList(
"1.1", "1.2", "2.1", "2.2", "2.3", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6",
"4.1", "4.2", "4.3", "4.4", "5.1", "5.2", "5.3", "5.4"));
private final JdbcTemplate jdbcTemplate;
@Autowired
public ProductDevelopmentProcessStepTwoServiceImpl(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; }
@Override
public ProductDevelopmentProcessStepTwoValidationResult validate(ProductDevelopmentProcessStepTwoValidationRequest request, JwtUser user) {
requireStudent(user);
Map<String, String> standardAnswers = loadStandardAnswers();
validateItems(request == null ? null : request.getItems(), standardAnswers);
ProductDevelopmentProcessStepTwoValidationResult result = new ProductDevelopmentProcessStepTwoValidationResult();
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 void validateItems(List<ProductDevelopmentProcessStepTwoValidationRequest.Item> items, Map<String, String> standardAnswers) {
if (items == null || items.size() != TASK_NUMBERS.size()) throw new ServiceException(HttpStatus.BAD_REQUEST, "请完整填写全部任务的工期与项目依赖关系");
Set<String> submittedTasks = new LinkedHashSet<>();
for (ProductDevelopmentProcessStepTwoValidationRequest.Item item : items) {
String taskNo = item == null ? "" : StringUtils.trimToEmpty(item.getTaskNo());
String classification = item == null ? "" : StringUtils.trimToEmpty(item.getClassification());
String dependency = item == null ? "" : StringUtils.trimToEmpty(item.getDependency());
if (!TASK_NUMBERS.contains(taskNo) || !submittedTasks.add(taskNo) || !ALLOWED_CLASSIFICATIONS.contains(classification)) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "提交的任务数据不合法");
}
if (!classification.equals(standardAnswers.get(taskNo))) throw new ServiceException(HttpStatus.BAD_REQUEST, "请先完成并通过第一步关键任务判断");
if (dependency.isEmpty()) throw new ServiceException(HttpStatus.BAD_REQUEST, "请填写任务 " + taskNo + " 的项目依赖关系");
LocalDate startDate = parseDate(item.getStartDate(), taskNo, "开始时间");
LocalDate endDate = parseDate(item.getEndDate(), taskNo, "完成时间");
if (endDate.isBefore(startDate)) throw new ServiceException(HttpStatus.BAD_REQUEST, "任务 " + taskNo + " 的完成时间不能早于开始时间");
}
if (!submittedTasks.equals(TASK_NUMBERS)) throw new ServiceException(HttpStatus.BAD_REQUEST, "提交的任务数据不完整");
}
private LocalDate parseDate(String value, String taskNo, String label) {
try {
return LocalDate.parse(StringUtils.trimToEmpty(value));
} catch (DateTimeParseException e) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "请填写任务 " + taskNo + " 的" + label);
}
}
@SuppressWarnings("unchecked")
private Map<String, String> loadStandardAnswers() {
String answerJson = jdbcTemplate.queryForObject(
"SELECT answer_json FROM training_step_standard_answer WHERE task_key = ? AND step_no = ?",
String.class, TASK_KEY, STEP_NO);
Map<String, Object> raw = JSON.parseObject(answerJson, LinkedHashMap.class);
Map<String, String> answers = new LinkedHashMap<>();
for (String taskNo : TASK_NUMBERS) {
String classification = raw == null || raw.get(taskNo) == null ? "" : String.valueOf(raw.get(taskNo));
if (!ALLOWED_CLASSIFICATIONS.contains(classification)) throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, "第一步标准答案未正确配置");
answers.put(taskNo, classification);
}
if (raw == null || raw.size() != answers.size()) throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, "第一步标准答案未正确配置");
return answers;
}
}

@ -19,6 +19,8 @@ import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepThreeVali
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepThreeValidationResult;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckResult;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationResult;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepTwoService;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepThreeService;
@ -27,6 +29,7 @@ import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepOneService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepTwoService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepThreeService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepOneService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepTwoService;
import com.sztzjy.linkCommerce.util.ResultEntity;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
@ -175,6 +178,23 @@ class StudentTrainingAnswerControllerTest {
verify(service).check(any(ProductDevelopmentProcessStepOneCheckRequest.class), any(JwtUser.class));
}
@Test
void validateProductDevelopmentProcessStepTwoUsesTheAuthenticatedStudentAndReturnsTheValidationResult() {
StudentTrainingAnswerController controller = new StudentTrainingAnswerController();
ProductDevelopmentProcessStepTwoService service = mock(ProductDevelopmentProcessStepTwoService.class);
ReflectionTestUtils.setField(controller, "productDevelopmentProcessStepTwoService", service);
ProductDevelopmentProcessStepTwoValidationResult validation = new ProductDevelopmentProcessStepTwoValidationResult();
validation.setValid(true);
when(service.validate(any(ProductDevelopmentProcessStepTwoValidationRequest.class), any(JwtUser.class))).thenReturn(validation);
ResultEntity<ProductDevelopmentProcessStepTwoValidationResult> result = controller
.validateProductDevelopmentProcessStepTwo(new ProductDevelopmentProcessStepTwoValidationRequest(), authenticatedStudentRequest());
assertEquals(HttpStatus.OK, result.getStatusCode());
assertEquals(validation, result.getBody().getData());
verify(service).validate(any(ProductDevelopmentProcessStepTwoValidationRequest.class), any(JwtUser.class));
}
private HttpServletRequest authenticatedStudentRequest() {
JwtUser user = new JwtUser();
user.setUserId("stu-1");

@ -0,0 +1,81 @@
package com.sztzjy.linkCommerce.service.impl;
import com.alibaba.fastjson.JSON;
import com.sztzjy.linkCommerce.config.exception.handler.ServiceException;
import com.sztzjy.linkCommerce.config.security.JwtUser;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepTwoValidationResult;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
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.Mockito.mock;
import static org.mockito.Mockito.when;
class ProductDevelopmentProcessStepTwoServiceImplTest {
@Test
void validateAcceptsAllTasksWithAValidSchedule() {
ProductDevelopmentProcessStepTwoServiceImpl service = new ProductDevelopmentProcessStepTwoServiceImpl(standardAnswerJdbcTemplate());
ProductDevelopmentProcessStepTwoValidationResult result = service.validate(request(defaultItems()), student());
assertTrue(result.isValid());
}
@Test
void validateRejectsMissingDependencyInvertedDatesAndWrongFirstStepClassification() {
ProductDevelopmentProcessStepTwoServiceImpl service = new ProductDevelopmentProcessStepTwoServiceImpl(standardAnswerJdbcTemplate());
List<ProductDevelopmentProcessStepTwoValidationRequest.Item> missingDependency = defaultItems();
missingDependency.get(0).setDependency("");
assertThrows(ServiceException.class, () -> service.validate(request(missingDependency), student()));
List<ProductDevelopmentProcessStepTwoValidationRequest.Item> invertedDates = defaultItems();
invertedDates.get(0).setEndDate("2026-01-01");
assertThrows(ServiceException.class, () -> service.validate(request(invertedDates), student()));
List<ProductDevelopmentProcessStepTwoValidationRequest.Item> wrongClassification = defaultItems();
wrongClassification.get(3).setClassification("关键任务");
assertThrows(ServiceException.class, () -> service.validate(request(wrongClassification), student()));
}
private JdbcTemplate standardAnswerJdbcTemplate() {
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
Map<String, String> answers = new LinkedHashMap<>();
for (ProductDevelopmentProcessStepTwoValidationRequest.Item item : defaultItems()) answers.put(item.getTaskNo(), item.getClassification());
when(jdbcTemplate.queryForObject(any(String.class), any(Class.class), any(), any())).thenReturn(JSON.toJSONString(answers));
return jdbcTemplate;
}
private ProductDevelopmentProcessStepTwoValidationRequest request(List<ProductDevelopmentProcessStepTwoValidationRequest.Item> items) {
ProductDevelopmentProcessStepTwoValidationRequest request = new ProductDevelopmentProcessStepTwoValidationRequest();
request.setItems(items);
return request;
}
private List<ProductDevelopmentProcessStepTwoValidationRequest.Item> defaultItems() {
return Arrays.asList(
item("1.1", "关键任务"), item("1.2", "关键任务"), item("2.1", "关键任务"), item("2.2", "非关键任务"), item("2.3", "关键任务"),
item("3.1", "关键任务"), item("3.2", "关键任务"), item("3.3", "非关键任务"), item("3.4", "关键任务"), item("3.5", "关键任务"), item("3.6", "关键任务"),
item("4.1", "关键任务"), item("4.2", "关键任务"), item("4.3", "关键任务"), item("4.4", "关键任务"),
item("5.1", "关键任务"), item("5.2", "关键任务"), item("5.3", "关键任务"), item("5.4", "关键任务"));
}
private ProductDevelopmentProcessStepTwoValidationRequest.Item item(String taskNo, String classification) {
ProductDevelopmentProcessStepTwoValidationRequest.Item item = new ProductDevelopmentProcessStepTwoValidationRequest.Item();
item.setTaskNo(taskNo);
item.setClassification(classification);
item.setStartDate("2026-02-01");
item.setEndDate("2026-02-02");
item.setDependency("无");
return item;
}
private JwtUser student() { JwtUser user = new JwtUser(); user.setUserId("stu-1"); user.setRoleId(4); return user; }
}
Loading…
Cancel
Save