Explorar el Código

feat: 实现按班级分配作业功能

- 新增 assignment_class 中间表及相关实体与 Mapper
- AssignmentDTO 新增 classIds 字段支持班级分配
- 普通作业与AI口语作业创建接口支持班级分配
- 新增 GET /api/class/{classId}/assignments 接口查询班级作业
- 添加事务注解确保数据一致性
wuzilong hace 3 meses
padre
commit
0558e48ddf

+ 16 - 1
src/main/java/com/njuzr/eaibackend/controller/ClassController.java

@@ -3,7 +3,9 @@ package com.njuzr.eaibackend.controller;
 import com.njuzr.eaibackend.dto.ClassDTO;
 import com.njuzr.eaibackend.exception.MyException;
 import com.njuzr.eaibackend.po.Class;
+import com.njuzr.eaibackend.service.AssignmentService;
 import com.njuzr.eaibackend.service.ClassService;
+import com.njuzr.eaibackend.vo.AssignmentVO;
 import com.njuzr.eaibackend.vo.BatchStudentImportResultVO;
 import com.njuzr.eaibackend.vo.ClassVO;
 import com.njuzr.eaibackend.vo.StudentInfoVO;
@@ -19,9 +21,11 @@ import java.util.List;
 @RequestMapping("/api/class")
 public class ClassController {
     private final ClassService classService;
+    private final AssignmentService assignmentService;
 
-    public ClassController(ClassService classService) {
+    public ClassController(ClassService classService, AssignmentService assignmentService) {
         this.classService = classService;
+        this.assignmentService = assignmentService;
     }
 
     /**
@@ -201,4 +205,15 @@ public class ClassController {
             return MyResponse.error(500, "服务器内部错误");
         }
     }
+
+    @GetMapping("/{classId}/assignments")
+    public MyResponse getClassAssignments(@PathVariable Long classId) {
+        try {
+            List<AssignmentVO> assignments = assignmentService.findAssignmentsByClassId(classId);
+            return MyResponse.success(assignments);
+        } catch (Exception e) {
+            log.error("查询班级作业失败: {}", e.getMessage(), e);
+            return MyResponse.error(500, "服务器内部错误");
+        }
+    }
 }

+ 3 - 1
src/main/java/com/njuzr/eaibackend/dto/AssignmentDTO.java

@@ -38,4 +38,6 @@ public class AssignmentDTO {
 
     private Integer engageNumber;
     private Integer correctNumber;
-}
+
+    private List<Long> classIds;
+}

+ 32 - 0
src/main/java/com/njuzr/eaibackend/mapper/AssignmentClassMapper.java

@@ -0,0 +1,32 @@
+package com.njuzr.eaibackend.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.njuzr.eaibackend.po.AssignmentClass;
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+@Mapper
+public interface AssignmentClassMapper extends BaseMapper<AssignmentClass> {
+
+    @Insert("<script>" +
+            "INSERT INTO assignment_class (assignment_id, class_id) VALUES " +
+            "<foreach collection='classIds' item='classId' separator=','>" +
+            "(#{assignmentId}, #{classId})" +
+            "</foreach>" +
+            "</script>")
+    void insertBatch(@Param("assignmentId") Long assignmentId, @Param("classIds") List<Long> classIds);
+
+    @Select("SELECT class_id FROM assignment_class WHERE assignment_id = #{assignmentId}")
+    List<Long> selectClassIdsByAssignmentId(@Param("assignmentId") Long assignmentId);
+
+    @Select("SELECT assignment_id FROM assignment_class WHERE class_id = #{classId}")
+    List<Long> selectAssignmentIdsByClassId(@Param("classId") Long classId);
+
+    @Delete("DELETE FROM assignment_class WHERE assignment_id = #{assignmentId}")
+    void deleteByAssignmentId(@Param("assignmentId") Long assignmentId);
+}

+ 15 - 0
src/main/java/com/njuzr/eaibackend/po/AssignmentClass.java

@@ -0,0 +1,15 @@
+package com.njuzr.eaibackend.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@Data
+@TableName("assignment_class")
+public class AssignmentClass {
+    @TableId(type = IdType.AUTO)
+    private Long id;
+    private Long assignmentId;
+    private Long classId;
+}

+ 3 - 1
src/main/java/com/njuzr/eaibackend/service/AssignmentService.java

@@ -68,4 +68,6 @@ public interface AssignmentService {
      * @return 学生作业状态列表
      */
     List<StudentAssignmentStatusVO> getStudentsAssignmentStatus(Long classId, Long assignmentId);
-}
+
+    List<AssignmentVO> findAssignmentsByClassId(Long classId);
+}

+ 9 - 0
src/main/java/com/njuzr/eaibackend/service/impl/AiSpeakingAssignmentServiceImpl.java

@@ -47,7 +47,12 @@ public class AiSpeakingAssignmentServiceImpl extends ServiceImpl<AiSpeakingAssig
 
     @Autowired
     MongoTemplate mongoTemplate;
+
+    @Autowired
+    AssignmentClassMapper assignmentClassMapper;
+
     @Override
+    @Transactional
     public void createSpeakingAssignment(MyUserDetails user, Long courseId, AiSpeakingAssignmentDTO aiSpeakingAssignmentDTO) {
         Course course = courseMapper.selectById(courseId);
         if (course == null)
@@ -81,6 +86,10 @@ public class AiSpeakingAssignmentServiceImpl extends ServiceImpl<AiSpeakingAssig
                 aiSpeakingAssignment.setSurveyLinks(ConvertUtil.listToString(aiSpeakingAssignmentDTO.getSurveyLinks()));
             }
             baseMapper.insert(aiSpeakingAssignment);
+
+            if (aiSpeakingAssignmentDTO.getClassIds() != null && !aiSpeakingAssignmentDTO.getClassIds().isEmpty()) {
+                assignmentClassMapper.insertBatch(assignmentId, aiSpeakingAssignmentDTO.getClassIds());
+            }
         } catch (Exception e) {
             log.error(e.getMessage());
             throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "创建作业失败");

+ 39 - 1
src/main/java/com/njuzr/eaibackend/service/impl/AssignmentServiceImpl.java

@@ -53,6 +53,10 @@ public class AssignmentServiceImpl implements AssignmentService {
     private final ClassService classService;
     private final OssUtil ossUtil;
 
+    private final AssignmentClassMapper assignmentClassMapper;
+
+    private final ClassMapper classMapper;
+
     private final FileUtil fileUtil = new FileUtil();
 
     private final TextAnalysisService textAnalysisService;
@@ -65,7 +69,9 @@ public class AssignmentServiceImpl implements AssignmentService {
                                  CourseServiceImpl courseServiceImpl,
                                  CourseStudentMapper courseStudentMapper,
                                  ClassService classService,
-                                 TextAnalysisService textAnalysisService) {
+                                 TextAnalysisService textAnalysisService,
+                                 AssignmentClassMapper assignmentClassMapper,
+                                 ClassMapper classMapper) {
         this.assignmentMapper = assignmentMapper;
         this.courseMapper = courseMapper;
         this.studentAssignmentMapper = studentAssignmentMapper;
@@ -73,9 +79,12 @@ public class AssignmentServiceImpl implements AssignmentService {
         this.ossUtil = ossUtil;
         this.textAnalysisService = textAnalysisService;
         this.classService = classService;
+        this.assignmentClassMapper = assignmentClassMapper;
+        this.classMapper = classMapper;
     }
 
     @Override
+    @Transactional
     public AssignmentVO createAssignment(MyUserDetails user, Long courseId, AssignmentDTO assignmentDTO) {
         Course course = courseMapper.selectById(courseId);
         if (course == null)
@@ -110,6 +119,11 @@ public class AssignmentServiceImpl implements AssignmentService {
             log.error(e.getMessage());
             throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "创建作业失败");
         }
+
+        if (assignmentDTO.getClassIds() != null && !assignmentDTO.getClassIds().isEmpty()) {
+            assignmentClassMapper.insertBatch(target.getAssignmentId(), assignmentDTO.getClassIds());
+        }
+
         return convertToVO(target);
     }
 
@@ -626,4 +640,28 @@ public class AssignmentServiceImpl implements AssignmentService {
                 })
                 .collect(Collectors.toList());
     }
+
+    @Override
+    public List<AssignmentVO> findAssignmentsByClassId(Long classId) {
+        Class cls = classMapper.selectById(classId);
+        if (cls == null) {
+            throw MyException.create(HttpStatus.NOT_FOUND, "班级不存在");
+        }
+
+        QueryWrapper<Assignment> wrapper = new QueryWrapper<>();
+        wrapper.eq("course_id", cls.getCourseId());
+        List<Assignment> allAssignments = assignmentMapper.selectList(wrapper);
+
+        List<Assignment> result = new ArrayList<>();
+        for (Assignment assignment : allAssignments) {
+            List<Long> relatedClassIds = assignmentClassMapper.selectClassIdsByAssignmentId(assignment.getAssignmentId());
+            if (relatedClassIds.isEmpty()) {
+                result.add(assignment);
+            } else if (relatedClassIds.contains(classId)) {
+                result.add(assignment);
+            }
+        }
+
+        return result.stream().map(this::convertToVO).collect(Collectors.toList());
+    }
 }