feat: grade product development process step one
parent
50bf9265d5
commit
763d0870e9
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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…
Reference in New Issue