From c7c6940e50dc144436a2f9e9fd1e664ca0830876 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Mon, 3 Aug 2026 09:49:51 +0800 Subject: [PATCH] feat: gate comprehensive training task publication --- .../service/impl/TrainingTaskServiceImpl.java | 23 +++- .../stu/TaskAllocationControllerTest.java | 4 +- .../impl/TrainingTaskServiceImplTest.java | 101 +++++++++++++++++- 3 files changed, 120 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImpl.java index 2338ddc..100f29c 100644 --- a/src/main/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImpl.java +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImpl.java @@ -42,6 +42,7 @@ import java.util.stream.Collectors; @Service public class TrainingTaskServiceImpl implements TrainingTaskService { private static final Pattern SPLIT_PATTERN = Pattern.compile("[;;||]"); + private static final String COMPREHENSIVE_CASE_TRAINING_TASK_KEY = "comprehensive-case-training"; @Autowired public TrainingTaskMapper trainingTaskMapper; @@ -291,9 +292,13 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { ensureDefaultTasks(null); String normalizedTaskKey = StringUtils.trimToEmpty(taskKey); TrainingTask defaultTask = trainingTaskMapper.selectByTaskKey(normalizedTaskKey); + if (StringUtils.isBlank(teachingClassId) && requiresExplicitPublication(normalizedTaskKey)) { + return null; + } if (StringUtils.isNotBlank(teachingClassId)) { Set publishedTaskKeys = getPublishedTaskKeys(teachingClassId); - if (publishedTaskKeys != null && !publishedTaskKeys.contains(normalizedTaskKey)) { + if ((publishedTaskKeys != null && !publishedTaskKeys.contains(normalizedTaskKey)) + || (requiresExplicitPublication(normalizedTaskKey) && publishedTaskKeys == null)) { return null; } ensureClassTasksInitialized(teachingClassId, trainingTaskMapper.selectList(null, null, null), null); @@ -301,6 +306,9 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { if (classTask != null) { return Boolean.TRUE.equals(classTask.getEnabled()) ? toTask(classTask) : null; } + if (requiresExplicitPublication(normalizedTaskKey)) { + return null; + } } return defaultTask; } @@ -319,19 +327,27 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { ensureDefaultTasks(null); List defaults = trainingTaskMapper.selectList(null, null, null); if (StringUtils.isBlank(teachingClassId)) { - return filterEnabled(sortTasks(defaults), enabledOnly); + return filterEnabled(sortTasks(defaults).stream() + .filter(task -> !requiresExplicitPublication(task.getTaskKey())) + .collect(Collectors.toList()), enabledOnly); } List classTasks = ensureClassTasksInitialized(teachingClassId, defaults, null); List tasks = filterEnabled(toTasks(classTasks), enabledOnly); Set publishedTaskKeys = getPublishedTaskKeys(teachingClassId); if (publishedTaskKeys == null) { - return tasks; + return tasks.stream() + .filter(task -> !requiresExplicitPublication(task.getTaskKey())) + .collect(Collectors.toList()); } return tasks.stream() .filter(task -> publishedTaskKeys.contains(task.getTaskKey())) .collect(Collectors.toList()); } + private boolean requiresExplicitPublication(String taskKey) { + return COMPREHENSIVE_CASE_TRAINING_TASK_KEY.equals(StringUtils.trimToEmpty(taskKey)); + } + /** * @return null when this teaching class has never been configured (default: all tasks), * otherwise the explicitly published task keys, which may be empty. @@ -844,6 +860,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { private List defaultTasks() { List tasks = new ArrayList<>(); + addDefault(tasks, "综合实训", COMPREHENSIVE_CASE_TRAINING_TASK_KEY, "综合案例实训"); addDefault(tasks, "互联网产品开发基础认知", "new-product-survey", "新产品调查与分析"); addDefault(tasks, "互联网产品开发基础认知", "product-development-factors", "产品开发关键因素"); addDefault(tasks, "互联网产品开发基础认知", "product-development-process", "产品开发主要流程"); diff --git a/src/test/java/com/sztzjy/linkCommerce/controller/stu/TaskAllocationControllerTest.java b/src/test/java/com/sztzjy/linkCommerce/controller/stu/TaskAllocationControllerTest.java index 3b7630f..5b51770 100644 --- a/src/test/java/com/sztzjy/linkCommerce/controller/stu/TaskAllocationControllerTest.java +++ b/src/test/java/com/sztzjy/linkCommerce/controller/stu/TaskAllocationControllerTest.java @@ -65,7 +65,7 @@ class TaskAllocationControllerTest { schoolClass.setClassType("TEACHING"); when(controller.schoolClassMapper.selectByPrimaryKey("teaching-1")).thenReturn(schoolClass); TaskAllocation allocation = new TaskAllocation(); - allocation.setModule("任务A"); + allocation.setModule("comprehensive-case-training"); allocation.setSort(1); ResultEntity result = controller.updateTaskAllocationByClassId(Collections.singletonList(allocation), "teaching-1", "school-1", "teacher-1"); @@ -78,7 +78,7 @@ class TaskAllocationControllerTest { assertNotNull(inserted.get(0).getId()); assertEquals(TaskAllocation.PUBLICATION_MARKER, inserted.get(0).getModule()); assertEquals((byte) 1, inserted.get(0).getDisabledStatus()); - assertEquals("任务A", inserted.get(1).getModule()); + assertEquals("comprehensive-case-training", inserted.get(1).getModule()); assertEquals((byte) 0, inserted.get(1).getDisabledStatus()); assertEquals("teaching-1", inserted.get(1).getClassId()); assertEquals("school-1", inserted.get(1).getSchoolId()); diff --git a/src/test/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImplTest.java b/src/test/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImplTest.java index 3f8f3d0..7055fd6 100644 --- a/src/test/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImplTest.java +++ b/src/test/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImplTest.java @@ -2,11 +2,13 @@ package com.sztzjy.linkCommerce.service.impl; import com.sztzjy.linkCommerce.config.security.JwtUser; import com.sztzjy.linkCommerce.entity.SchoolClass; +import com.sztzjy.linkCommerce.entity.TaskAllocation; import com.sztzjy.linkCommerce.entity.TeachingClassStudent; import com.sztzjy.linkCommerce.entity.TrainingTask; import com.sztzjy.linkCommerce.entity.TrainingTaskClassConfig; import com.sztzjy.linkCommerce.entity.importDto.TrainingTaskImportDTO; import com.sztzjy.linkCommerce.mapper.SchoolClassMapper; +import com.sztzjy.linkCommerce.mapper.TaskAllocationMapper; import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper; import com.sztzjy.linkCommerce.mapper.TrainingTaskClassConfigMapper; import com.sztzjy.linkCommerce.mapper.TrainingTaskMapper; @@ -220,9 +222,11 @@ class TrainingTaskServiceImplTest { service.ensureDefaultTasks("system"); ArgumentCaptor captor = ArgumentCaptor.forClass(TrainingTask.class); - verify(service.trainingTaskMapper, times(22)).insertSelective(captor.capture()); + verify(service.trainingTaskMapper, times(23)).insertSelective(captor.capture()); assertFalse(captor.getAllValues().stream().anyMatch(task -> "new-product-survey".equals(task.getTaskKey()))); - assertEquals("product-development-factors", captor.getAllValues().get(0).getTaskKey()); + assertEquals("comprehensive-case-training", captor.getAllValues().get(0).getTaskKey()); + assertEquals("综合实训", captor.getAllValues().get(0).getProjectName()); + assertEquals("综合案例实训", captor.getAllValues().get(0).getTaskName()); } @Test @@ -510,7 +514,7 @@ class TrainingTaskServiceImplTest { service.saveClassTask("class-1", "new-product-survey", payload, "teacher-1"); ArgumentCaptor captor = ArgumentCaptor.forClass(TrainingTaskClassConfig.class); - verify(service.trainingTaskClassConfigMapper, times(24)).insertSelective(captor.capture()); + verify(service.trainingTaskClassConfigMapper, times(25)).insertSelective(captor.capture()); TrainingTaskClassConfig savedOverride = captor.getAllValues().stream() .filter(config -> "new-product-survey".equals(config.getTaskKey())) .filter(config -> "Class Name".equals(config.getTaskName())) @@ -601,6 +605,97 @@ class TrainingTaskServiceImplTest { assertEquals(0, result.size()); } + @Test + void studentListHidesComprehensiveTrainingUntilTheClassHasPublishedIt() { + TrainingTaskServiceImpl service = studentTaskService("class-1"); + TrainingTask legacy = storedTask("task-1", "new-product-survey"); + TrainingTask comprehensive = comprehensiveTrainingTask(); + when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); + when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) + .thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), + overrideTask("config-2", "class-1", "comprehensive-case-training"))); + when(service.taskAllocationMapper.selectByExample(any())).thenReturn(Collections.emptyList()); + + List result = service.listForStudent("stu-1", true); + + assertEquals(List.of("new-product-survey"), result.stream() + .map(TrainingTask::getTaskKey) + .collect(java.util.stream.Collectors.toList())); + } + + @Test + void studentTaskLookupHidesComprehensiveTrainingUntilTheClassHasPublishedIt() { + TrainingTaskServiceImpl service = studentTaskService("class-1"); + TrainingTask comprehensive = comprehensiveTrainingTask(); + when(service.trainingTaskMapper.selectByTaskKey("comprehensive-case-training")).thenReturn(comprehensive); + when(service.taskAllocationMapper.selectByExample(any())).thenReturn(Collections.emptyList()); + + TrainingTask result = service.getStudentTaskByTaskKey("comprehensive-case-training", "stu-1"); + + assertNull(result); + } + + @Test + void studentTaskLookupReturnsComprehensiveTrainingWhenPublishedAndEnabledForTheClass() { + TrainingTaskServiceImpl service = studentTaskService("class-1"); + TrainingTask comprehensive = comprehensiveTrainingTask(); + when(service.trainingTaskMapper.selectByTaskKey("comprehensive-case-training")).thenReturn(comprehensive); + when(service.trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey("class-1", "comprehensive-case-training")) + .thenReturn(overrideTask("config-1", "class-1", "comprehensive-case-training")); + when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( + taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), + taskAllocation("comprehensive-case-training", (byte) 0))); + + TrainingTask result = service.getStudentTaskByTaskKey("comprehensive-case-training", "stu-1"); + + assertEquals("comprehensive-case-training", result.getTaskKey()); + } + + @Test + void studentTaskLookupHidesPublishedComprehensiveTrainingWhenItsClassTaskIsDisabled() { + TrainingTaskServiceImpl service = studentTaskService("class-1"); + TrainingTask comprehensive = comprehensiveTrainingTask(); + when(service.trainingTaskMapper.selectByTaskKey("comprehensive-case-training")).thenReturn(comprehensive); + TrainingTaskClassConfig disabled = overrideTask("config-1", "class-1", "comprehensive-case-training"); + disabled.setEnabled(Boolean.FALSE); + when(service.trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey("class-1", "comprehensive-case-training")) + .thenReturn(disabled); + when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( + taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), + taskAllocation("comprehensive-case-training", (byte) 0))); + + TrainingTask result = service.getStudentTaskByTaskKey("comprehensive-case-training", "stu-1"); + + assertNull(result); + } + + private TrainingTaskServiceImpl studentTaskService(String teachingClassId) { + TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); + service.trainingTaskMapper = mock(TrainingTaskMapper.class); + service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); + service.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class); + service.taskAllocationMapper = mock(TaskAllocationMapper.class); + TeachingClassStudent membership = new TeachingClassStudent(); + membership.setTeachingClassId(teachingClassId); + when(service.teachingClassStudentMapper.selectActiveByStudentUserId("stu-1")).thenReturn(membership); + return service; + } + + private TrainingTask comprehensiveTrainingTask() { + TrainingTask task = storedTask("task-comprehensive", "comprehensive-case-training"); + task.setProjectName("综合实训"); + task.setTaskName("综合案例实训"); + task.setSort(1); + return task; + } + + private TaskAllocation taskAllocation(String module, byte disabledStatus) { + TaskAllocation allocation = new TaskAllocation(); + allocation.setModule(module); + allocation.setDisabledStatus(disabledStatus); + return allocation; + } + private TrainingTask storedTask(String id, String taskKey) { TrainingTask task = new TrainingTask(); task.setId(id);