You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
20 KiB
Java
379 lines
20 KiB
Java
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.TeachingClassStudent;
|
|
import com.sztzjy.linkCommerce.entity.TrainingTask;
|
|
import com.sztzjy.linkCommerce.mapper.StudentTrainingAnswerMapper;
|
|
import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper;
|
|
import com.sztzjy.linkCommerce.mapper.TrainingTaskMapper;
|
|
import com.sztzjy.linkCommerce.service.StudentTrainingAnswerService;
|
|
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 org.springframework.transaction.annotation.Transactional;
|
|
|
|
import java.util.Date;
|
|
import java.util.UUID;
|
|
|
|
@Service
|
|
public class StudentTrainingAnswerServiceImpl implements StudentTrainingAnswerService {
|
|
private static final String STATUS_NOT_STARTED = "NOT_STARTED";
|
|
private static final String STATUS_IN_PROGRESS = "IN_PROGRESS";
|
|
private static final String STATUS_COMPLETED = "COMPLETED";
|
|
private static final String ACTION_SAVE = "SAVE";
|
|
private static final String ACTION_SUBMIT = "SUBMIT";
|
|
private static final String ACTION_RESET = "RESET";
|
|
|
|
@Autowired
|
|
public StudentTrainingAnswerMapper studentTrainingAnswerMapper;
|
|
|
|
@Autowired
|
|
public TrainingTaskMapper trainingTaskMapper;
|
|
|
|
@Autowired
|
|
public TeachingClassStudentMapper teachingClassStudentMapper;
|
|
|
|
@Autowired(required = false)
|
|
public JdbcTemplate jdbcTemplate;
|
|
|
|
private boolean studentTrainingAnswerTableChecked = false;
|
|
|
|
@Override
|
|
public StudentTrainingAnswer get(String taskKey, String teachingClassId, JwtUser user) {
|
|
ensureStudentTrainingAnswerTable();
|
|
requireStudent(user);
|
|
requireNotDemo(user);
|
|
TrainingTask task = resolveTask(taskKey);
|
|
String resolvedTeachingClassId = resolveTeachingClassId(user.getUserId(), teachingClassId);
|
|
return studentTrainingAnswerMapper.selectByStudentClassAndTask(
|
|
user.getUserId(), resolvedTeachingClassId, task.getId());
|
|
}
|
|
|
|
@Override
|
|
@Transactional(rollbackFor = Exception.class)
|
|
public StudentTrainingAnswer save(String taskKey, StudentTrainingAnswer answer, JwtUser user) {
|
|
ensureStudentTrainingAnswerTable();
|
|
requireStudent(user);
|
|
requireNotDemo(user);
|
|
TrainingTask task = resolveTask(taskKey);
|
|
String resolvedTeachingClassId = resolveTeachingClassId(user.getUserId(),
|
|
answer == null ? null : answer.getTeachingClassId());
|
|
StudentTrainingAnswer existing = studentTrainingAnswerMapper.selectByStudentClassAndTask(
|
|
user.getUserId(), resolvedTeachingClassId, task.getId());
|
|
if (!isPersistAction(answer)) {
|
|
return existing;
|
|
}
|
|
|
|
StudentTrainingAnswer record = buildRecord(answer, existing, user.getUserId(), resolvedTeachingClassId, task);
|
|
if (existing == null) {
|
|
record.setId(UUID.randomUUID().toString());
|
|
record.setCreateTime(new Date());
|
|
record.setUpdateTime(new Date());
|
|
studentTrainingAnswerMapper.insertSelective(record);
|
|
} else {
|
|
record.setId(existing.getId());
|
|
record.setCreateTime(existing.getCreateTime());
|
|
record.setUpdateTime(new Date());
|
|
studentTrainingAnswerMapper.updateByPrimaryKeySelective(record);
|
|
}
|
|
StudentTrainingAnswer saved = studentTrainingAnswerMapper.selectByStudentClassAndTask(
|
|
user.getUserId(), resolvedTeachingClassId, task.getId());
|
|
syncDetailTables(saved);
|
|
return saved;
|
|
}
|
|
|
|
@Override
|
|
@Transactional(rollbackFor = Exception.class)
|
|
public void delete(String taskKey, String teachingClassId, JwtUser user) {
|
|
ensureStudentTrainingAnswerTable();
|
|
requireStudent(user);
|
|
requireNotDemo(user);
|
|
TrainingTask task = resolveTask(taskKey);
|
|
String resolvedTeachingClassId = resolveTeachingClassId(user.getUserId(), teachingClassId);
|
|
studentTrainingAnswerMapper.deleteByStudentClassAndTask(user.getUserId(), resolvedTeachingClassId, task.getId());
|
|
if (jdbcTemplate != null) {
|
|
jdbcTemplate.update("delete from student_training_step_answer where student_user_id = ? and teaching_class_id = ? and task_id = ?",
|
|
user.getUserId(), resolvedTeachingClassId, task.getId());
|
|
jdbcTemplate.update("delete from student_training_progress where student_user_id = ? and teaching_class_id = ? and task_id = ?",
|
|
user.getUserId(), resolvedTeachingClassId, task.getId());
|
|
}
|
|
}
|
|
|
|
private void requireStudent(JwtUser user) {
|
|
if (user == null || StringUtils.isBlank(user.getUserId())) {
|
|
throw new ServiceException(HttpStatus.UNAUTHORIZED, "Please login first");
|
|
}
|
|
if (user.getRoleId() != 4) {
|
|
throw new ServiceException(HttpStatus.FORBIDDEN, "Only students can submit training answers");
|
|
}
|
|
}
|
|
|
|
private TrainingTask resolveTask(String taskKey) {
|
|
String normalizedTaskKey = StringUtils.trimToEmpty(taskKey);
|
|
if (StringUtils.isBlank(normalizedTaskKey)) {
|
|
throw new ServiceException(HttpStatus.BAD_REQUEST, "Training task key is required");
|
|
}
|
|
TrainingTask task = trainingTaskMapper.selectByTaskKey(normalizedTaskKey);
|
|
if (task == null) {
|
|
throw new ServiceException(HttpStatus.BAD_REQUEST, "Training task does not exist");
|
|
}
|
|
return task;
|
|
}
|
|
|
|
private void requireNotDemo(JwtUser user) {
|
|
if (user != null && user.isDemoMode()) {
|
|
throw new ServiceException(HttpStatus.FORBIDDEN, "演示模式不保存数据");
|
|
}
|
|
}
|
|
|
|
private String resolveTeachingClassId(String studentUserId, String requestedTeachingClassId) {
|
|
String trimmedClassId = StringUtils.trimToNull(requestedTeachingClassId);
|
|
if (trimmedClassId != null) {
|
|
long count = teachingClassStudentMapper.countByStudentUserIdAndTeachingClassId(studentUserId, trimmedClassId);
|
|
if (count <= 0) {
|
|
throw new ServiceException(HttpStatus.BAD_REQUEST, "Student does not belong to this teaching class");
|
|
}
|
|
return trimmedClassId;
|
|
}
|
|
TeachingClassStudent member = teachingClassStudentMapper.selectActiveByStudentUserId(studentUserId);
|
|
if (member == null || StringUtils.isBlank(member.getTeachingClassId())) {
|
|
throw new ServiceException(HttpStatus.BAD_REQUEST, "Student has no active teaching class");
|
|
}
|
|
return member.getTeachingClassId();
|
|
}
|
|
|
|
private StudentTrainingAnswer buildRecord(StudentTrainingAnswer request,
|
|
StudentTrainingAnswer existing,
|
|
String studentUserId,
|
|
String teachingClassId,
|
|
TrainingTask task) {
|
|
StudentTrainingAnswer record = new StudentTrainingAnswer();
|
|
record.setStudentUserId(studentUserId);
|
|
record.setTeachingClassId(teachingClassId);
|
|
record.setTaskId(task.getId());
|
|
record.setTaskKey(task.getTaskKey());
|
|
record.setTaskName(task.getTaskName());
|
|
|
|
if (existing != null) {
|
|
record.setStep1Answer(existing.getStep1Answer());
|
|
record.setStep2Answer(existing.getStep2Answer());
|
|
record.setStep3Answer(existing.getStep3Answer());
|
|
record.setStep4Answer(existing.getStep4Answer());
|
|
record.setSubmitTime(existing.getSubmitTime());
|
|
}
|
|
|
|
if (isResetAction(request)) {
|
|
record.setStep1Answer("");
|
|
record.setStep2Answer("");
|
|
record.setStep3Answer("");
|
|
record.setStep4Answer("");
|
|
record.setCurrentStep(1);
|
|
record.setProgressStatus(STATUS_NOT_STARTED);
|
|
record.setSubmitted(Boolean.FALSE);
|
|
record.setSubmitTime(null);
|
|
return record;
|
|
}
|
|
|
|
if (request.getStep1Answer() != null) {
|
|
record.setStep1Answer(request.getStep1Answer());
|
|
}
|
|
if (request.getStep2Answer() != null) {
|
|
record.setStep2Answer(request.getStep2Answer());
|
|
}
|
|
if (request.getStep3Answer() != null) {
|
|
record.setStep3Answer(request.getStep3Answer());
|
|
}
|
|
if (request.getStep4Answer() != null) {
|
|
record.setStep4Answer(request.getStep4Answer());
|
|
}
|
|
|
|
boolean submitted = ACTION_SUBMIT.equals(StringUtils.upperCase(StringUtils.trimToEmpty(request.getSaveAction())));
|
|
record.setSubmitted(submitted);
|
|
record.setCurrentStep(submitted ? 4 : normalizeCurrentStepValue(request.getCurrentStep()));
|
|
record.setProgressStatus(submitted ? STATUS_COMPLETED : resolveProgressStatus(record));
|
|
if (submitted) {
|
|
record.setSubmitTime(new Date());
|
|
}
|
|
return record;
|
|
}
|
|
|
|
private Integer normalizeCurrentStepValue(Integer currentStep) {
|
|
if (currentStep == null || currentStep < 1) {
|
|
return 1;
|
|
}
|
|
if (currentStep > 4) {
|
|
return 4;
|
|
}
|
|
return currentStep;
|
|
}
|
|
|
|
private String resolveProgressStatus(StudentTrainingAnswer answer) {
|
|
if (StringUtils.isNotBlank(answer.getStep1Answer())
|
|
|| StringUtils.isNotBlank(answer.getStep2Answer())
|
|
|| StringUtils.isNotBlank(answer.getStep3Answer())
|
|
|| StringUtils.isNotBlank(answer.getStep4Answer())) {
|
|
return STATUS_IN_PROGRESS;
|
|
}
|
|
return STATUS_NOT_STARTED;
|
|
}
|
|
|
|
private boolean isResetAction(StudentTrainingAnswer answer) {
|
|
return answer != null && ACTION_RESET.equals(StringUtils.upperCase(StringUtils.trimToEmpty(answer.getSaveAction())));
|
|
}
|
|
|
|
private boolean isPersistAction(StudentTrainingAnswer answer) {
|
|
if (answer == null) {
|
|
return false;
|
|
}
|
|
String action = StringUtils.upperCase(StringUtils.trimToEmpty(answer.getSaveAction()));
|
|
return ACTION_SAVE.equals(action) || ACTION_SUBMIT.equals(action) || ACTION_RESET.equals(action);
|
|
}
|
|
|
|
private void ensureStudentTrainingAnswerTable() {
|
|
if (studentTrainingAnswerTableChecked || jdbcTemplate == null) {
|
|
return;
|
|
}
|
|
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS student_training_answer (" +
|
|
"id varchar(64) NOT NULL COMMENT 'primary id'," +
|
|
"student_user_id varchar(64) NOT NULL COMMENT 'student user id'," +
|
|
"teaching_class_id varchar(64) NOT NULL COMMENT 'teaching class id'," +
|
|
"task_id varchar(64) NOT NULL COMMENT 'training task id'," +
|
|
"task_key varchar(128) NOT NULL COMMENT 'training task key'," +
|
|
"task_name varchar(128) NOT NULL COMMENT 'training task name'," +
|
|
"step1_answer longtext NULL COMMENT 'step 1 answer json'," +
|
|
"step2_answer longtext NULL COMMENT 'step 2 answer json'," +
|
|
"step3_answer longtext NULL COMMENT 'step 3 answer json'," +
|
|
"step4_answer longtext NULL COMMENT 'step 4 answer json'," +
|
|
"current_step int DEFAULT 1 COMMENT 'current step'," +
|
|
"progress_status varchar(32) DEFAULT 'NOT_STARTED' COMMENT 'progress status'," +
|
|
"submitted bit(1) DEFAULT b'0' COMMENT 'submitted'," +
|
|
"ai_assessment_score int NULL COMMENT 'AI assessment score'," +
|
|
"submit_time datetime NULL COMMENT 'submit time'," +
|
|
"create_time datetime NULL COMMENT 'create time'," +
|
|
"update_time datetime NULL COMMENT 'update time'," +
|
|
"PRIMARY KEY (id)," +
|
|
"KEY idx_student_training_answer_task (task_id)," +
|
|
"KEY idx_student_training_answer_student (student_user_id)," +
|
|
"KEY idx_student_training_answer_class (teaching_class_id)" +
|
|
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='student training answer'");
|
|
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS student_training_progress (" +
|
|
"id varchar(64) NOT NULL COMMENT 'primary id'," +
|
|
"student_user_id varchar(64) NOT NULL COMMENT 'student user id'," +
|
|
"teaching_class_id varchar(64) NOT NULL COMMENT 'teaching class id'," +
|
|
"task_id varchar(64) NOT NULL COMMENT 'training task id'," +
|
|
"task_key varchar(128) NOT NULL COMMENT 'training task key'," +
|
|
"task_name varchar(128) NOT NULL COMMENT 'training task name'," +
|
|
"current_step int DEFAULT 1 COMMENT 'current step'," +
|
|
"progress_status varchar(32) DEFAULT 'NOT_STARTED' COMMENT 'progress status'," +
|
|
"submitted bit(1) DEFAULT b'0' COMMENT 'submitted'," +
|
|
"submit_time datetime NULL COMMENT 'submit time'," +
|
|
"create_time datetime NULL COMMENT 'create time'," +
|
|
"update_time datetime NULL COMMENT 'update time'," +
|
|
"PRIMARY KEY (id)," +
|
|
"UNIQUE KEY uk_student_training_progress (student_user_id, teaching_class_id, task_id)," +
|
|
"KEY idx_student_training_progress_task (task_id)," +
|
|
"KEY idx_student_training_progress_class (teaching_class_id)" +
|
|
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='student training progress'");
|
|
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS student_training_step_answer (" +
|
|
"id varchar(64) NOT NULL COMMENT 'primary id'," +
|
|
"progress_id varchar(64) NOT NULL COMMENT 'progress id'," +
|
|
"student_user_id varchar(64) NOT NULL COMMENT 'student user id'," +
|
|
"teaching_class_id varchar(64) NOT NULL COMMENT 'teaching class id'," +
|
|
"task_id varchar(64) NOT NULL COMMENT 'training task id'," +
|
|
"task_key varchar(128) NOT NULL COMMENT 'training task key'," +
|
|
"step_no int NOT NULL COMMENT 'step number'," +
|
|
"step_name varchar(128) NULL COMMENT 'step name'," +
|
|
"answer_json longtext NULL COMMENT 'step answer json'," +
|
|
"create_time datetime NULL COMMENT 'create time'," +
|
|
"update_time datetime NULL COMMENT 'update time'," +
|
|
"PRIMARY KEY (id)," +
|
|
"UNIQUE KEY uk_student_training_step_answer (student_user_id, teaching_class_id, task_id, step_no)," +
|
|
"KEY idx_student_training_step_answer_progress (progress_id)," +
|
|
"KEY idx_student_training_step_answer_task (task_id)," +
|
|
"KEY idx_student_training_step_answer_class (teaching_class_id)" +
|
|
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='student training step answer'");
|
|
jdbcTemplate.execute("ALTER TABLE student_training_answer CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
|
|
jdbcTemplate.execute("ALTER TABLE student_training_progress CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
|
|
jdbcTemplate.execute("ALTER TABLE student_training_step_answer CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
|
|
backfillDetailTables();
|
|
studentTrainingAnswerTableChecked = true;
|
|
}
|
|
|
|
private void syncDetailTables(StudentTrainingAnswer answer) {
|
|
if (jdbcTemplate == null || answer == null || StringUtils.isBlank(answer.getId())) {
|
|
return;
|
|
}
|
|
String progressId = "p-" + answer.getId();
|
|
jdbcTemplate.update("insert into student_training_progress " +
|
|
"(id, student_user_id, teaching_class_id, task_id, task_key, task_name, current_step, progress_status, submitted, submit_time, create_time, update_time) " +
|
|
"values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) " +
|
|
"on duplicate key update task_key = values(task_key), task_name = values(task_name), current_step = values(current_step), " +
|
|
"progress_status = values(progress_status), submitted = values(submitted), submit_time = values(submit_time), update_time = values(update_time)",
|
|
progressId,
|
|
answer.getStudentUserId(),
|
|
answer.getTeachingClassId(),
|
|
answer.getTaskId(),
|
|
answer.getTaskKey(),
|
|
answer.getTaskName(),
|
|
answer.getCurrentStep(),
|
|
answer.getProgressStatus(),
|
|
Boolean.TRUE.equals(answer.getSubmitted()),
|
|
answer.getSubmitTime(),
|
|
answer.getCreateTime(),
|
|
answer.getUpdateTime());
|
|
syncStepAnswer(answer, progressId, 1, answer.getStep1Answer());
|
|
syncStepAnswer(answer, progressId, 2, answer.getStep2Answer());
|
|
syncStepAnswer(answer, progressId, 3, answer.getStep3Answer());
|
|
syncStepAnswer(answer, progressId, 4, answer.getStep4Answer());
|
|
}
|
|
|
|
private void syncStepAnswer(StudentTrainingAnswer answer, String progressId, int stepNo, String answerJson) {
|
|
if (answerJson == null) {
|
|
return;
|
|
}
|
|
jdbcTemplate.update("insert into student_training_step_answer " +
|
|
"(id, progress_id, student_user_id, teaching_class_id, task_id, task_key, step_no, step_name, answer_json, create_time, update_time) " +
|
|
"values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) " +
|
|
"on duplicate key update progress_id = values(progress_id), task_key = values(task_key), step_name = values(step_name), " +
|
|
"answer_json = values(answer_json), update_time = values(update_time)",
|
|
"s" + stepNo + "-" + answer.getId(),
|
|
progressId,
|
|
answer.getStudentUserId(),
|
|
answer.getTeachingClassId(),
|
|
answer.getTaskId(),
|
|
answer.getTaskKey(),
|
|
stepNo,
|
|
"Step " + stepNo,
|
|
answerJson,
|
|
answer.getCreateTime(),
|
|
answer.getUpdateTime());
|
|
}
|
|
|
|
private void backfillDetailTables() {
|
|
jdbcTemplate.execute("insert into student_training_progress " +
|
|
"(id, student_user_id, teaching_class_id, task_id, task_key, task_name, current_step, progress_status, submitted, submit_time, create_time, update_time) " +
|
|
"select concat('p-', id), student_user_id, teaching_class_id, task_id, task_key, task_name, current_step, progress_status, submitted, submit_time, create_time, update_time " +
|
|
"from student_training_answer " +
|
|
"on duplicate key update task_key = values(task_key), task_name = values(task_name), current_step = values(current_step), " +
|
|
"progress_status = values(progress_status), submitted = values(submitted), submit_time = values(submit_time), update_time = values(update_time)");
|
|
backfillStep(1, "step1_answer");
|
|
backfillStep(2, "step2_answer");
|
|
backfillStep(3, "step3_answer");
|
|
backfillStep(4, "step4_answer");
|
|
}
|
|
|
|
private void backfillStep(int stepNo, String answerColumn) {
|
|
jdbcTemplate.execute("insert into student_training_step_answer " +
|
|
"(id, progress_id, student_user_id, teaching_class_id, task_id, task_key, step_no, step_name, answer_json, create_time, update_time) " +
|
|
"select concat('s" + stepNo + "-', id), concat('p-', id), student_user_id, teaching_class_id, task_id, task_key, " +
|
|
stepNo + ", 'Step " + stepNo + "', " + answerColumn + ", create_time, update_time " +
|
|
"from student_training_answer where " + answerColumn + " is not null " +
|
|
"on duplicate key update progress_id = values(progress_id), task_key = values(task_key), step_name = values(step_name), " +
|
|
"answer_json = values(answer_json), update_time = values(update_time)");
|
|
}
|
|
}
|