feat: grade product development process step one

bugfix/ai-assessment-evidence-rescore
chenyuan 2 months ago
parent 50bf9265d5
commit 763d0870e9

@ -20,6 +20,8 @@ import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepThreeVali
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepThreeValidationResult; import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepThreeValidationResult;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepFourValidationRequest; import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepFourValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepFourValidationResult; 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.service.NewProductSurveyStepOneService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepTwoService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepTwoService;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepThreeService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepThreeService;
@ -28,6 +30,7 @@ import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepOneService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepTwoService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepTwoService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepThreeService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepThreeService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepFourService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepFourService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepOneService;
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;
@ -67,6 +70,9 @@ public class StudentTrainingAnswerController {
@Autowired @Autowired
private ProductDevelopmentFactorsStepFourService productDevelopmentFactorsStepFourService; private ProductDevelopmentFactorsStepFourService productDevelopmentFactorsStepFourService;
@Autowired
private ProductDevelopmentProcessStepOneService productDevelopmentProcessStepOneService;
@GetMapping("/{taskKey}") @GetMapping("/{taskKey}")
@ApiOperation("查询当前学生指定实训任务答案") @ApiOperation("查询当前学生指定实训任务答案")
public ResultEntity<StudentTrainingAnswer> detail(@PathVariable String taskKey, public ResultEntity<StudentTrainingAnswer> detail(@PathVariable String taskKey,
@ -183,6 +189,17 @@ public class StudentTrainingAnswerController {
catch (ServiceException e) { return new ResultEntity<>(e.getCode(), e.getMessage()); } catch (ServiceException e) { return new ResultEntity<>(e.getCode(), e.getMessage()); }
} }
@PostMapping("/product-development-process/step-1/check")
@ApiOperation("产品开发主要流程第一步判题")
public ResultEntity<ProductDevelopmentProcessStepOneCheckResult> checkProductDevelopmentProcessStepOne(
@RequestBody ProductDevelopmentProcessStepOneCheckRequest answer, HttpServletRequest request) {
try {
return new ResultEntity<>(HttpStatus.OK, "判题完成", productDevelopmentProcessStepOneService.check(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,20 @@
package com.sztzjy.linkCommerce.entity.dto;
import java.util.List;
public class ProductDevelopmentProcessStepOneCheckRequest {
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;
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; }
}
}

@ -0,0 +1,33 @@
package com.sztzjy.linkCommerce.entity.dto;
import java.util.ArrayList;
import java.util.List;
public class ProductDevelopmentProcessStepOneCheckResult {
private List<ItemResult> items = new ArrayList<>();
private int correctCount;
private int totalCount;
private boolean allCorrect;
public List<ItemResult> getItems() { return items; }
public void setItems(List<ItemResult> items) { this.items = items; }
public int getCorrectCount() { return correctCount; }
public void setCorrectCount(int correctCount) { this.correctCount = correctCount; }
public int getTotalCount() { return totalCount; }
public void setTotalCount(int totalCount) { this.totalCount = totalCount; }
public boolean isAllCorrect() { return allCorrect; }
public void setAllCorrect(boolean allCorrect) { this.allCorrect = allCorrect; }
public static class ItemResult {
private String taskNo;
private boolean correct;
private String message;
public String getTaskNo() { return taskNo; }
public void setTaskNo(String taskNo) { this.taskNo = taskNo; }
public boolean isCorrect() { return correct; }
public void setCorrect(boolean correct) { this.correct = correct; }
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.ProductDevelopmentProcessStepOneCheckRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckResult;
public interface ProductDevelopmentProcessStepOneService {
ProductDevelopmentProcessStepOneCheckResult check(ProductDevelopmentProcessStepOneCheckRequest request, JwtUser user);
}

@ -0,0 +1,148 @@
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.ProductDevelopmentProcessStepOneCheckRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckResult;
import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepOneService;
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 javax.annotation.PostConstruct;
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 ProductDevelopmentProcessStepOneServiceImpl implements ProductDevelopmentProcessStepOneService {
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 Map<String, String> DEFAULT_ANSWERS = createDefaultAnswers();
private final JdbcTemplate jdbcTemplate;
@Autowired
public ProductDevelopmentProcessStepOneServiceImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@PostConstruct
public void initializeStandardAnswers() {
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS training_step_standard_answer ("
+ "id varchar(64) NOT NULL COMMENT 'primary id',"
+ "task_key varchar(128) NOT NULL COMMENT 'training task key',"
+ "step_no int NOT NULL COMMENT 'step number',"
+ "answer_json longtext NOT NULL COMMENT 'standard answer json',"
+ "create_time datetime NULL COMMENT 'create time',"
+ "update_time datetime NULL COMMENT 'update time',"
+ "PRIMARY KEY (id),"
+ "UNIQUE KEY uk_training_step_standard_answer (task_key, step_no)"
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='training step standard answer'");
jdbcTemplate.update("INSERT IGNORE INTO training_step_standard_answer "
+ "(id, task_key, step_no, answer_json, create_time, update_time) VALUES (?, ?, ?, ?, NOW(), NOW())",
"product-development-process-step-1", TASK_KEY, STEP_NO, JSON.toJSONString(DEFAULT_ANSWERS));
}
@Override
public ProductDevelopmentProcessStepOneCheckResult check(ProductDevelopmentProcessStepOneCheckRequest request, JwtUser user) {
requireStudent(user);
Map<String, String> submitted = validateSubmittedItems(request == null ? null : request.getItems());
Map<String, String> standardAnswers = loadStandardAnswers();
ProductDevelopmentProcessStepOneCheckResult result = new ProductDevelopmentProcessStepOneCheckResult();
int correctCount = 0;
for (String taskNo : standardAnswers.keySet()) {
boolean correct = standardAnswers.get(taskNo).equals(submitted.get(taskNo));
ProductDevelopmentProcessStepOneCheckResult.ItemResult item = new ProductDevelopmentProcessStepOneCheckResult.ItemResult();
item.setTaskNo(taskNo);
item.setCorrect(correct);
item.setMessage(correct ? "分类正确" : "分类有误,请重新选择");
result.getItems().add(item);
if (correct) correctCount++;
}
result.setCorrectCount(correctCount);
result.setTotalCount(standardAnswers.size());
result.setAllCorrect(correctCount == standardAnswers.size());
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 Map<String, String> validateSubmittedItems(List<ProductDevelopmentProcessStepOneCheckRequest.Item> items) {
if (items == null || items.size() != DEFAULT_ANSWERS.size()) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "请完成全部任务分类后再判题");
}
Map<String, String> submitted = new LinkedHashMap<>();
for (ProductDevelopmentProcessStepOneCheckRequest.Item item : items) {
String taskNo = item == null ? null : StringUtils.trimToEmpty(item.getTaskNo());
String classification = item == null ? null : StringUtils.trimToEmpty(item.getClassification());
if (!DEFAULT_ANSWERS.containsKey(taskNo) || !ALLOWED_CLASSIFICATIONS.contains(classification) || submitted.put(taskNo, classification) != null) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "提交的任务分类数据不合法");
}
}
if (!submitted.keySet().equals(DEFAULT_ANSWERS.keySet())) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "提交的任务分类数据不完整");
}
return submitted;
}
@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 : DEFAULT_ANSWERS.keySet()) {
Object classification = raw == null ? null : raw.get(taskNo);
if (classification == null || !ALLOWED_CLASSIFICATIONS.contains(String.valueOf(classification))) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, "第一步标准答案未正确配置");
}
answers.put(taskNo, String.valueOf(classification));
}
if (raw == null || raw.size() != answers.size()) {
throw new ServiceException(HttpStatus.INTERNAL_SERVER_ERROR, "第一步标准答案未正确配置");
}
return answers;
}
private static Map<String, String> createDefaultAnswers() {
Map<String, String> answers = new LinkedHashMap<>();
answers.put("1.1", KEY_TASK);
answers.put("1.2", KEY_TASK);
answers.put("2.1", KEY_TASK);
answers.put("2.2", NON_KEY_TASK);
answers.put("2.3", KEY_TASK);
answers.put("3.1", KEY_TASK);
answers.put("3.2", KEY_TASK);
answers.put("3.3", NON_KEY_TASK);
answers.put("3.4", KEY_TASK);
answers.put("3.5", KEY_TASK);
answers.put("3.6", KEY_TASK);
answers.put("4.1", KEY_TASK);
answers.put("4.2", KEY_TASK);
answers.put("4.3", KEY_TASK);
answers.put("4.4", KEY_TASK);
answers.put("5.1", KEY_TASK);
answers.put("5.2", KEY_TASK);
answers.put("5.3", KEY_TASK);
answers.put("5.4", KEY_TASK);
return answers;
}
}

@ -17,6 +17,8 @@ import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepTwoValida
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepTwoValidationResult; import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepTwoValidationResult;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepThreeValidationRequest; import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepThreeValidationRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentFactorsStepThreeValidationResult; 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.service.NewProductSurveyStepOneService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepOneService;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepTwoService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepTwoService;
import com.sztzjy.linkCommerce.service.NewProductSurveyStepThreeService; import com.sztzjy.linkCommerce.service.NewProductSurveyStepThreeService;
@ -24,6 +26,7 @@ import com.sztzjy.linkCommerce.service.NewProductSurveyStepFourService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepOneService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepOneService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepTwoService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepTwoService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepThreeService; import com.sztzjy.linkCommerce.service.ProductDevelopmentFactorsStepThreeService;
import com.sztzjy.linkCommerce.service.ProductDevelopmentProcessStepOneService;
import com.sztzjy.linkCommerce.util.ResultEntity; import com.sztzjy.linkCommerce.util.ResultEntity;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -155,6 +158,23 @@ class StudentTrainingAnswerControllerTest {
verify(service).validate(any(ProductDevelopmentFactorsStepThreeValidationRequest.class), any(JwtUser.class)); verify(service).validate(any(ProductDevelopmentFactorsStepThreeValidationRequest.class), any(JwtUser.class));
} }
@Test
void checkProductDevelopmentProcessStepOneUsesTheAuthenticatedStudentAndReturnsTheGrade() {
StudentTrainingAnswerController controller = new StudentTrainingAnswerController();
ProductDevelopmentProcessStepOneService service = mock(ProductDevelopmentProcessStepOneService.class);
ReflectionTestUtils.setField(controller, "productDevelopmentProcessStepOneService", service);
ProductDevelopmentProcessStepOneCheckResult grade = new ProductDevelopmentProcessStepOneCheckResult();
grade.setAllCorrect(true);
when(service.check(any(ProductDevelopmentProcessStepOneCheckRequest.class), any(JwtUser.class))).thenReturn(grade);
ResultEntity<ProductDevelopmentProcessStepOneCheckResult> result = controller
.checkProductDevelopmentProcessStepOne(new ProductDevelopmentProcessStepOneCheckRequest(), authenticatedStudentRequest());
assertEquals(HttpStatus.OK, result.getStatusCode());
assertEquals(grade, result.getBody().getData());
verify(service).check(any(ProductDevelopmentProcessStepOneCheckRequest.class), any(JwtUser.class));
}
private HttpServletRequest authenticatedStudentRequest() { private HttpServletRequest authenticatedStudentRequest() {
JwtUser user = new JwtUser(); JwtUser user = new JwtUser();
user.setUserId("stu-1"); user.setUserId("stu-1");

@ -0,0 +1,100 @@
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.ProductDevelopmentProcessStepOneCheckRequest;
import com.sztzjy.linkCommerce.entity.dto.ProductDevelopmentProcessStepOneCheckResult;
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.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
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.contains;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class ProductDevelopmentProcessStepOneServiceImplTest {
@Test
void checkReturnsPerTaskFeedbackWithoutReturningTheAnswers() {
ProductDevelopmentProcessStepOneServiceImpl service = new ProductDevelopmentProcessStepOneServiceImpl(standardAnswerJdbcTemplate());
ProductDevelopmentProcessStepOneCheckResult result = service.check(requestWithClassification("2.2", "关键任务"), student());
assertEquals(18, result.getCorrectCount());
assertEquals(19, result.getTotalCount());
assertFalse(result.isAllCorrect());
assertTrue(result.getItems().get(0).isCorrect());
assertFalse(result.getItems().get(3).isCorrect());
assertEquals("分类有误,请重新选择", result.getItems().get(3).getMessage());
assertFalse(JSON.toJSONString(result).contains("correctClassification"));
}
@Test
void checkRejectsIncompleteAnswersInvalidClassificationAndNonStudents() {
ProductDevelopmentProcessStepOneServiceImpl service = new ProductDevelopmentProcessStepOneServiceImpl(standardAnswerJdbcTemplate());
assertThrows(ServiceException.class, () -> service.check(request(Arrays.asList(item("1.1", "关键任务"))), student()));
assertThrows(ServiceException.class, () -> service.check(requestWithClassification("2.2", "未知任务"), student()));
assertThrows(ServiceException.class, () -> service.check(requestWithClassification("2.2", "非关键任务"), teacher()));
}
@Test
void initializationKeepsAnyExistingStandardAnswer() {
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
ProductDevelopmentProcessStepOneServiceImpl service = new ProductDevelopmentProcessStepOneServiceImpl(jdbcTemplate);
service.initializeStandardAnswers();
verify(jdbcTemplate).execute(contains("CREATE TABLE IF NOT EXISTS training_step_standard_answer"));
verify(jdbcTemplate).update(startsWith("INSERT IGNORE INTO training_step_standard_answer"), any(), any(), any(), any());
}
private JdbcTemplate standardAnswerJdbcTemplate() {
JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class);
Map<String, String> answers = new LinkedHashMap<>();
for (ProductDevelopmentProcessStepOneCheckRequest.Item item : defaultAnswers()) answers.put(item.getTaskNo(), item.getClassification());
when(jdbcTemplate.queryForObject(any(String.class), any(Class.class), any(), any())).thenReturn(JSON.toJSONString(answers));
return jdbcTemplate;
}
private ProductDevelopmentProcessStepOneCheckRequest requestWithClassification(String taskNo, String classification) {
List<ProductDevelopmentProcessStepOneCheckRequest.Item> items = defaultAnswers();
items.stream().filter(item -> taskNo.equals(item.getTaskNo())).findFirst().orElseThrow(IllegalStateException::new).setClassification(classification);
return request(items);
}
private ProductDevelopmentProcessStepOneCheckRequest request(List<ProductDevelopmentProcessStepOneCheckRequest.Item> items) {
ProductDevelopmentProcessStepOneCheckRequest request = new ProductDevelopmentProcessStepOneCheckRequest();
request.setItems(items);
return request;
}
private List<ProductDevelopmentProcessStepOneCheckRequest.Item> defaultAnswers() {
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 ProductDevelopmentProcessStepOneCheckRequest.Item item(String taskNo, String classification) {
ProductDevelopmentProcessStepOneCheckRequest.Item item = new ProductDevelopmentProcessStepOneCheckRequest.Item();
item.setTaskNo(taskNo);
item.setClassification(classification);
return item;
}
private JwtUser student() { JwtUser user = new JwtUser(); user.setUserId("stu-1"); user.setRoleId(4); return user; }
private JwtUser teacher() { JwtUser user = student(); user.setRoleId(3); return user; }
}
Loading…
Cancel
Save