|
|
|
|
@ -36,6 +36,7 @@ import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.UUID;
|
|
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
@ -67,6 +68,9 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
|
|
|
|
|
|
|
|
|
|
private boolean trainingTaskTableChecked = false;
|
|
|
|
|
private boolean trainingTaskClassConfigTableChecked = false;
|
|
|
|
|
private volatile boolean defaultTasksInitialized = false;
|
|
|
|
|
private final Object defaultTasksInitializationLock = new Object();
|
|
|
|
|
private final Set<String> initializedStudentClassTaskIds = ConcurrentHashMap.newKeySet();
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List<TrainingTask> list(String projectName, String taskName, Boolean enabledOnly) {
|
|
|
|
|
@ -186,19 +190,27 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
|
|
|
|
|
@Override
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public void ensureDefaultTasks(String operatorId) {
|
|
|
|
|
ensureTrainingTaskTable();
|
|
|
|
|
ensureTrainingTaskClassConfigTable();
|
|
|
|
|
int sort = 1;
|
|
|
|
|
for (TrainingTask task : defaultTasks()) {
|
|
|
|
|
TrainingTask existing = trainingTaskMapper.selectByTaskKey(task.getTaskKey());
|
|
|
|
|
if (existing == null) {
|
|
|
|
|
task.setSort(sort);
|
|
|
|
|
create(task, operatorId);
|
|
|
|
|
if (defaultTasksInitialized) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
synchronized (defaultTasksInitializationLock) {
|
|
|
|
|
if (defaultTasksInitialized) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ensureTrainingTaskTable();
|
|
|
|
|
ensureTrainingTaskClassConfigTable();
|
|
|
|
|
int sort = 1;
|
|
|
|
|
for (TrainingTask task : defaultTasks()) {
|
|
|
|
|
TrainingTask existing = trainingTaskMapper.selectByTaskKey(task.getTaskKey());
|
|
|
|
|
if (existing == null) {
|
|
|
|
|
task.setSort(sort);
|
|
|
|
|
create(task, operatorId);
|
|
|
|
|
}
|
|
|
|
|
sort++;
|
|
|
|
|
}
|
|
|
|
|
sort++;
|
|
|
|
|
ensureTaskAllocationClassIndex();
|
|
|
|
|
defaultTasksInitialized = true;
|
|
|
|
|
}
|
|
|
|
|
// 班级任务在对应班级首次读取时按需初始化。不要在学生读取单个任务时遍历所有教学班,
|
|
|
|
|
// 否则班级数量增加会把每次页面切换的查询放大为全量写入检查。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
@ -304,7 +316,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
|
|
|
|
|
|| (requiresExplicitPublication(normalizedTaskKey) && publishedTaskKeys == null)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
ensureClassTasksInitialized(teachingClassId, trainingTaskMapper.selectList(null, null, null), null);
|
|
|
|
|
ensureStudentClassTasksInitialized(teachingClassId);
|
|
|
|
|
TrainingTaskClassConfig classTask = trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey(teachingClassId, normalizedTaskKey);
|
|
|
|
|
if (classTask != null) {
|
|
|
|
|
return Boolean.TRUE.equals(classTask.getEnabled()) ? toTask(classTask) : null;
|
|
|
|
|
@ -334,7 +346,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
|
|
|
|
|
.filter(task -> !requiresExplicitPublication(task.getTaskKey()))
|
|
|
|
|
.collect(Collectors.toList()), enabledOnly);
|
|
|
|
|
}
|
|
|
|
|
List<TrainingTaskClassConfig> classTasks = ensureClassTasksInitialized(teachingClassId, defaults, null);
|
|
|
|
|
List<TrainingTaskClassConfig> classTasks = readStudentClassTasks(teachingClassId, defaults);
|
|
|
|
|
List<TrainingTask> tasks = filterEnabled(toTasks(classTasks), enabledOnly);
|
|
|
|
|
Set<String> publishedTaskKeys = getPublishedTaskKeys(teachingClassId);
|
|
|
|
|
if (publishedTaskKeys == null) {
|
|
|
|
|
@ -476,6 +488,23 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
|
|
|
|
|
return new ArrayList<>(existingByKey.values());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ensureStudentClassTasksInitialized(String teachingClassId) {
|
|
|
|
|
if (StringUtils.isBlank(teachingClassId) || initializedStudentClassTaskIds.contains(teachingClassId)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ensureClassTasksInitialized(teachingClassId, trainingTaskMapper.selectList(null, null, null), null);
|
|
|
|
|
initializedStudentClassTaskIds.add(teachingClassId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<TrainingTaskClassConfig> readStudentClassTasks(String teachingClassId, List<TrainingTask> defaults) {
|
|
|
|
|
if (initializedStudentClassTaskIds.contains(teachingClassId)) {
|
|
|
|
|
return trainingTaskClassConfigMapper.selectListByTeachingClass(teachingClassId, null);
|
|
|
|
|
}
|
|
|
|
|
List<TrainingTaskClassConfig> classTasks = ensureClassTasksInitialized(teachingClassId, defaults, null);
|
|
|
|
|
initializedStudentClassTaskIds.add(teachingClassId);
|
|
|
|
|
return classTasks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void synchronizeClassTaskDefaults(TrainingTask previousTask, TrainingTask updatedTask) {
|
|
|
|
|
if (schoolClassMapper == null || trainingTaskClassConfigMapper == null
|
|
|
|
|
|| previousTask == null || updatedTask == null) {
|
|
|
|
|
@ -687,6 +716,14 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
|
|
|
|
|
trainingTaskClassConfigTableChecked = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ensureTaskAllocationClassIndex() {
|
|
|
|
|
if (jdbcTemplate == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
jdbcTemplate.execute("CREATE INDEX IF NOT EXISTS idx_task_allocation_class_disabled_module "
|
|
|
|
|
+ "ON task_allocation (class_id, disabled_status, module)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TrainingTask buildTask(TrainingTaskImportDTO row, int rowNumber, List<String> errors) {
|
|
|
|
|
String projectName = StringUtils.trimToEmpty(row.getProjectName());
|
|
|
|
|
String taskKey = StringUtils.trimToEmpty(row.getTaskKey());
|
|
|
|
|
|