CourseServiceImpl.java 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. package com.njuzr.eaibackend.service.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  3. import com.baomidou.mybatisplus.core.metadata.IPage;
  4. import com.baomidou.mybatisplus.core.toolkit.StringUtils;
  5. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  6. import com.njuzr.eaibackend.dto.course.CourseDTO;
  7. import com.njuzr.eaibackend.dto.course.CourseQueryDTO;
  8. import com.njuzr.eaibackend.dto.course.CourseUpdateDTO;
  9. import com.njuzr.eaibackend.dto.course.EnrollDTO;
  10. import com.njuzr.eaibackend.enums.AssignmentCompletionStatus;
  11. import com.njuzr.eaibackend.enums.ClassStudentState;
  12. import com.njuzr.eaibackend.enums.Role;
  13. import com.njuzr.eaibackend.exception.MyException;
  14. import com.njuzr.eaibackend.mapper.*;
  15. import com.njuzr.eaibackend.po.*;
  16. import com.njuzr.eaibackend.po.Class;
  17. import com.njuzr.eaibackend.service.CourseService;
  18. import com.njuzr.eaibackend.utils.ConvertUtil;
  19. import com.njuzr.eaibackend.utils.ModelMapperUtil;
  20. import com.njuzr.eaibackend.utils.PageMapperUtil;
  21. import com.njuzr.eaibackend.vo.*;
  22. import lombok.extern.slf4j.Slf4j;
  23. import org.springframework.beans.BeanUtils;
  24. import org.springframework.beans.factory.annotation.Autowired;
  25. import org.springframework.cache.annotation.CacheEvict;
  26. import org.springframework.http.HttpStatus;
  27. import org.springframework.stereotype.Service;
  28. import org.springframework.transaction.annotation.Transactional;
  29. import java.time.LocalDate;
  30. import java.time.format.DateTimeFormatter;
  31. import java.util.*;
  32. import java.util.stream.Collectors;
  33. /**
  34. * @author: Leonezhurui
  35. * @Date: 2024/3/5 - 22:09
  36. * @Package: EAI-Backend
  37. */
  38. @Slf4j
  39. @Service
  40. public class CourseServiceImpl implements CourseService {
  41. private final CourseMapper courseMapper;
  42. private final UserMapper userMapper;
  43. private final CourseStudentMapper courseStudentMapper;
  44. private final AssignmentMapper assignmentMapper;
  45. private final StudentAssignmentMapper studentAssignmentMapper;
  46. private final ClassStudentMapper classStudentMapper;
  47. private final ClassMapper classMapper;
  48. @Autowired
  49. public CourseServiceImpl(CourseMapper courseMapper, UserMapper userMapper, CourseStudentMapper courseStudentMapper, AssignmentMapper assignmentMapper, StudentAssignmentMapper studentAssignmentMapper, ClassStudentMapper classStudentMapper, ClassMapper classMapper) {
  50. this.courseMapper = courseMapper;
  51. this.userMapper = userMapper;
  52. this.courseStudentMapper = courseStudentMapper;
  53. this.assignmentMapper = assignmentMapper;
  54. this.studentAssignmentMapper = studentAssignmentMapper;
  55. this.classStudentMapper = classStudentMapper;
  56. this.classMapper = classMapper;
  57. }
  58. @Override
  59. @CacheEvict(value = "coursesPages", allEntries = true)
  60. public CourseVO createCourse(CourseDTO courseDTO) {
  61. // 类型转换
  62. Course targetCourse = convertToPO(courseDTO);
  63. targetCourse.setCreateTime(new Date());
  64. // 插入数据库
  65. int status = courseMapper.insert(targetCourse);
  66. if (status == 0) {
  67. log.error("创建课程失败,数据库插入错误!");
  68. throw new MyException(HttpStatus.INTERNAL_SERVER_ERROR.value(), HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()+":"+"创建课程错误");
  69. }
  70. return convertToVO(targetCourse);
  71. }
  72. @Override
  73. // @Cacheable(value = "coursePages", key = "#page.getCurrent() + '_' + #page.getSize() + '_' + #courseQueryDTO.isEmpty()", unless = "#page.getSize() <= 1 || !#courseQueryDTO.isEmpty()")
  74. public IPage<CourseVO> findCoursesPage(Page<Course> page, CourseQueryDTO courseQueryDTO) {
  75. log.info("课程信息从数据库查询: {}", courseQueryDTO.toString());
  76. QueryWrapper<Course> wrapper = getCourseQueryWrapper(courseQueryDTO);
  77. IPage<Course> courses = courseMapper.selectPage(page, wrapper);
  78. return PageMapperUtil.convert(courses, this::convertToVO);
  79. }
  80. /**
  81. * 设置查询条件
  82. * @param courseQueryDTO
  83. * @return
  84. */
  85. private static QueryWrapper<Course> getCourseQueryWrapper(CourseQueryDTO courseQueryDTO) {
  86. QueryWrapper<Course> wrapper = new QueryWrapper<>();
  87. if (courseQueryDTO.getCourseId() != null) { // courseId直接判断是否相等
  88. wrapper.eq("course_id", courseQueryDTO.getCourseId());
  89. }
  90. // 兼容两种id的查询方式
  91. if(courseQueryDTO.getTeacherId() != null && courseQueryDTO.getTeacherPid() != null){
  92. wrapper.and(wq -> wq
  93. .eq(courseQueryDTO.getTeacherPid() != null,
  94. "teacher_portal_id", courseQueryDTO.getTeacherPid())
  95. .or()
  96. .eq(courseQueryDTO.getTeacherId() != null,
  97. "teacher_ids", courseQueryDTO.getTeacherId().toString())
  98. );
  99. } else {
  100. if (courseQueryDTO.getTeacherPid() != null ) { // courseId直接判断是否相等
  101. System.out.println(courseQueryDTO.getTeacherPid());
  102. wrapper.eq("teacher_portal_id", courseQueryDTO.getTeacherPid());
  103. }
  104. if(courseQueryDTO.getTeacherId() != null){
  105. System.out.println(courseQueryDTO.getTeacherPid());
  106. wrapper.eq("teacher_ids", courseQueryDTO.getTeacherId());
  107. }
  108. }
  109. // if (courseQueryDTO.getTeacherId() != null) { // 模糊匹配teacherIds中是否包含这个字段
  110. // wrapper.apply("FIND_IN_SET({0}, teacher_ids) > 0", courseQueryDTO.getTeacherId());
  111. // // wrapper.like("teacher_ids", "%" + courseQueryDTO.getTeacherId() + "%"); // 模糊匹配
  112. // }
  113. if (courseQueryDTO.getCourseName() != null) { // 模糊匹配课程名字
  114. wrapper.like("course_name", courseQueryDTO.getCourseName());
  115. }
  116. if (courseQueryDTO.getStudentId() != null) { // 联表查询学生所选课程
  117. // 使用安全的参数绑定方式
  118. wrapper.apply("course_id IN (SELECT course_id FROM course_student WHERE student_id = {0})", courseQueryDTO.getStudentId());
  119. }
  120. if (courseQueryDTO.getSemester() != null && !courseQueryDTO.getSemester().trim().isEmpty()) { // 课程时间过滤,转换成具体日期
  121. String semester = courseQueryDTO.getSemester();
  122. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  123. LocalDate startDate, endDate;
  124. // 解析输入字符串获取学年和学期
  125. try {
  126. String[] parts = semester.split("学年第");
  127. String[] years = parts[0].split("-");
  128. int yearStart = Integer.parseInt(years[0]);
  129. int semesterType = parts[1].startsWith("一") ? 1 : 2;
  130. // 根据学期计算开始和结束日期
  131. if (semesterType == 1) {
  132. startDate = LocalDate.of(yearStart, 9, 1);
  133. endDate = LocalDate.of(yearStart + 1, 3, 1);
  134. } else {
  135. startDate = LocalDate.of(yearStart + 1, 3, 1);
  136. endDate = LocalDate.of(yearStart + 1, 9, 1);
  137. }
  138. } catch (Exception e) {
  139. log.error(e.getMessage());
  140. throw MyException.create(HttpStatus.BAD_REQUEST, "学期字符串解析错误");
  141. }
  142. wrapper.ge("start_time", startDate.format(formatter))
  143. .le("end_time", endDate.format(formatter));
  144. }
  145. return wrapper;
  146. }
  147. /**
  148. * 更新课程信息
  149. * @param courseUpdateDTO
  150. */
  151. @Override
  152. @CacheEvict(value = "coursePages", allEntries = true)
  153. public CourseVO updateCourse(Long userId, Long courseId, CourseUpdateDTO courseUpdateDTO) {
  154. User targetUser = userMapper.selectById(userId);
  155. Course targetCourse = courseMapper.selectById(courseId);
  156. if (targetCourse == null)
  157. throw MyException.create(HttpStatus.BAD_REQUEST, "课程不存在");
  158. // 兼容两种id的权限判断方式
  159. if (targetUser.getRole() != Role.ADMIN && !Objects.equals(targetCourse.getTeacherPid(), targetUser.getPid()) && !targetCourse.getTeacherIds().contains(String.valueOf(userId)))
  160. throw MyException.create(HttpStatus.BAD_REQUEST, "无权限更新");
  161. Course opeCourse = convertToPO(courseUpdateDTO);
  162. opeCourse.setCourseId(courseId);
  163. try {
  164. int code = courseMapper.updateById(opeCourse);
  165. if (code == 0) {
  166. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "更新课程失败");
  167. }
  168. } catch (Exception e) {
  169. log.error(e.getMessage());
  170. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "更新课程失败");
  171. }
  172. return convertToVO(courseMapper.selectById(courseId));
  173. }
  174. /**
  175. * 门户更新课程信息
  176. * @param userPid
  177. * @param courseId
  178. * @param courseUpdateDTO
  179. * @return
  180. */
  181. @Override
  182. @CacheEvict(value = "coursePages", allEntries = true)
  183. public CourseVO updateCourseByPortal(Long userId, Long userPid, Long courseId, CourseUpdateDTO courseUpdateDTO) {
  184. User targetUser;
  185. if (userPid == null){
  186. targetUser = userMapper.selectById(userId);
  187. } else {
  188. QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  189. queryWrapper.eq("pid", userPid);
  190. targetUser = userMapper.selectOne(queryWrapper);
  191. }
  192. Course targetCourse = courseMapper.selectById(courseId);
  193. if (targetCourse == null)
  194. throw MyException.create(HttpStatus.BAD_REQUEST, "课程不存在");
  195. if (targetUser.getRole() != Role.ADMIN) {
  196. List<String> teacherIds = Collections.singletonList(Optional.ofNullable(targetCourse.getTeacherIds())
  197. .orElse(Collections.emptyList().toString()));
  198. String userIdStr = String.valueOf(targetUser.getId());
  199. boolean hasTeacherId = teacherIds.contains(userIdStr);
  200. boolean pidMatches = Objects.equals(targetCourse.getTeacherPid(), targetUser.getPid());
  201. if (!hasTeacherId && !pidMatches) {
  202. throw MyException.create(HttpStatus.BAD_REQUEST, "无权限更新");
  203. }
  204. }
  205. Course opeCourse = convertToPO(courseUpdateDTO);
  206. opeCourse.setCourseId(courseId);
  207. try {
  208. int code = courseMapper.updateById(opeCourse);
  209. if (code == 0) {
  210. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "更新课程失败");
  211. }
  212. } catch (Exception e) {
  213. log.error(e.getMessage());
  214. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "更新课程失败");
  215. }
  216. return convertToVO(courseMapper.selectById(courseId));
  217. }
  218. /**
  219. * 删除课程
  220. * @param user
  221. * @param courseId
  222. */
  223. @Override
  224. @Transactional
  225. @CacheEvict(value = "coursePages", allEntries = true)
  226. public void deleteById(MyUserDetails user, Long courseId) {
  227. Course course = courseMapper.selectById(courseId);
  228. if (course == null) {
  229. throw MyException.create(HttpStatus.BAD_REQUEST, "课程不存在");
  230. }
  231. if (user.getRole() != Role.ADMIN) {
  232. List<String> teacherIds = Collections.singletonList(Optional.ofNullable(course.getTeacherIds())
  233. .orElse(Collections.emptyList().toString()));
  234. String userIdStr = String.valueOf(user.getId());
  235. boolean hasTeacherId = teacherIds.contains(userIdStr);
  236. boolean pidMatches = Objects.equals(course.getTeacherPid(), user.getPid());
  237. if (!hasTeacherId && !pidMatches) {
  238. throw MyException.create(HttpStatus.BAD_REQUEST, "无权限创建");
  239. }
  240. }
  241. try {
  242. // 首先找到选了该课程的所有学生
  243. List<User> students = courseStudentMapper.selectStudentsByCourseId(courseId);
  244. // 所有学生执行退课操作
  245. for(User student : students) {
  246. dropCourse(student.getId(), courseId);
  247. }
  248. // 删除该课程下的所有assignment信息
  249. QueryWrapper<Assignment> wrapper = new QueryWrapper<>();
  250. wrapper.eq("course_id", courseId);
  251. List<Assignment> assignments = assignmentMapper.selectList(wrapper);
  252. for(Assignment assignment : assignments) {
  253. assignmentMapper.deleteById(assignment.getAssignmentId());
  254. }
  255. // 删除课程信息
  256. int code = courseMapper.deleteById(courseId);
  257. if (code == 0) {
  258. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "删除课程失败");
  259. }
  260. } catch (Exception e) {
  261. log.error(e.getMessage());
  262. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "删除课程失败");
  263. }
  264. }
  265. /**
  266. * 学生选课。给course_student表添加记录。
  267. * @param enrollDTO
  268. */
  269. /**
  270. @Override
  271. @Transactional
  272. public void enroll(EnrollDTO enrollDTO) {
  273. Course target = courseMapper.selectById(enrollDTO.getCourseId());
  274. if (target == null)
  275. throw MyException.create(HttpStatus.BAD_REQUEST, "课程不存在");
  276. if (!target.getEnrollCode().equals(enrollDTO.getEnrollCode()))
  277. throw MyException.create(HttpStatus.BAD_REQUEST, "选课码错误");
  278. Enrollment enrollment = ModelMapperUtil.map(enrollDTO, Enrollment.class);
  279. courseStudentMapper.insert(enrollment);
  280. Long studentId = enrollDTO.getStudentId();
  281. Long courseId = enrollDTO.getCourseId();
  282. ClassStudent classStudent = classStudentMapper.findClassStudentByStudentAndCourse(studentId, courseId);
  283. if (classStudent == null) {
  284. log.warn("未找到学生 {} 在课程 {} 中的班级记录", studentId, courseId);
  285. throw MyException.create(HttpStatus.BAD_REQUEST, "老师未将学生添加到课程班级,无法选课");
  286. }
  287. int result = classStudentMapper.updateStateById(classStudent.getId(), 1);
  288. if (result > 0) {
  289. log.info("成功更新学生 {} 在课程 {} 中的加入状态", studentId, courseId);
  290. return;
  291. }
  292. log.error("更新学生 {} 在课程 {} 中的加入状态失败", studentId, courseId);
  293. throw MyException.create(HttpStatus.BAD_REQUEST, "失败");
  294. }
  295. */
  296. /**
  297. * 获取某课程的所有选课学生信息
  298. * @param page
  299. * @param teacherId
  300. * @param courseId
  301. * @return
  302. */
  303. @Override
  304. public IPage<UserVO> getEnrollmentsByCourse(Page<User> page, Long teacherId, Long courseId) {
  305. Course target = courseMapper.selectById(courseId);
  306. if (target == null) throw MyException.create(HttpStatus.BAD_REQUEST, "课程不存在");
  307. if (!target.getTeacherIds().contains(String.valueOf(teacherId)))
  308. throw MyException.create(HttpStatus.BAD_REQUEST, "无权限查看");
  309. Page<User> students = courseStudentMapper.selectStudentsByCourseId(page, courseId);
  310. return PageMapperUtil.convert(students, student -> ModelMapperUtil.map(student, UserVO.class));
  311. }
  312. @Override
  313. public IPage<CourseVO> getEnrollmentsByStudent(Page<Course> page, Long studentId) {
  314. User student = userMapper.selectById(studentId);
  315. if (student == null) throw MyException.create(HttpStatus.BAD_REQUEST, "用户不存在");
  316. Page<Course> courses = courseStudentMapper.selectCoursesByStudentId(page, studentId);
  317. return PageMapperUtil.convert(courses, this::convertToVO);
  318. }
  319. /**
  320. * 学生退课
  321. * @param studentId
  322. * @param courseId
  323. */
  324. @Override
  325. @Transactional
  326. public void dropCourse(Long studentId, Long courseId) {
  327. // 首先找到该课程的所有作业信息
  328. QueryWrapper<Assignment> wrapper = new QueryWrapper<>();
  329. wrapper.eq("course_id", courseId);
  330. List<Assignment> assignments = assignmentMapper.selectList(wrapper);
  331. // 删除学生的所有作业记录
  332. for(Assignment assignment : assignments) {
  333. // 修改对应参与数量和批改数量
  334. Engagement engage = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignment.getAssignmentId());
  335. if(engage.getStatus() == AssignmentCompletionStatus.CORRECTED || engage.getStatus() == AssignmentCompletionStatus.PUBLISHED){
  336. assignment.setCorrectNumber(assignment.getCorrectNumber() - 1);
  337. }
  338. assignment.setEngageNumber(assignment.getEngageNumber() - 1);
  339. assignmentMapper.updateById(assignment);
  340. studentAssignmentMapper.delete(studentId, assignment.getAssignmentId());
  341. }
  342. // 学生退课
  343. int code = courseStudentMapper.dropCourse(studentId, courseId);
  344. if (code == 0) {
  345. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "退课失败");
  346. }
  347. }
  348. /**
  349. * 将DTO转换成PO
  350. * @param courseDTO
  351. * @return
  352. */
  353. private Course convertToPO(CourseDTO courseDTO) {
  354. Course course = new Course();
  355. BeanUtils.copyProperties(courseDTO, course);
  356. if(courseDTO.getTeacherIds() != null){
  357. course.setTeacherIds(ConvertUtil.listToString(courseDTO.getTeacherIds()));
  358. }
  359. if (courseDTO.getCourseImages() != null)
  360. course.setCourseImages(ConvertUtil.listToString(courseDTO.getCourseImages()));
  361. return course;
  362. }
  363. private Course convertToPO(CourseUpdateDTO updateDTO) {
  364. Course course = new Course();
  365. BeanUtils.copyProperties(updateDTO, course);
  366. if (updateDTO.getTeacherIds() != null)
  367. course.setTeacherIds(ConvertUtil.listToString(updateDTO.getTeacherIds()));
  368. if (updateDTO.getCourseImages() != null)
  369. course.setCourseImages(ConvertUtil.listToString(updateDTO.getCourseImages()));
  370. return course;
  371. }
  372. /**
  373. * 通过班级码选课
  374. * @param enrollDTO 包含学生ID和课程ID
  375. */
  376. @Override
  377. @Transactional
  378. public void enrollByClassCode(EnrollDTO enrollDTO) {
  379. // 获取班级码
  380. String classCode = enrollDTO.getEnrollCode();
  381. Long studentId = enrollDTO.getStudentId();
  382. Long courseId = enrollDTO.getCourseId();
  383. // 根据班级码查询班级信息
  384. QueryWrapper<Class> classWrapper = new QueryWrapper<>();
  385. classWrapper.eq("class_code", classCode);
  386. Class targetClass = classMapper.selectOne(classWrapper);
  387. if (targetClass == null) {
  388. throw MyException.create(HttpStatus.BAD_REQUEST, "班级码不存在");
  389. }
  390. // 验证班级是否属于指定课程
  391. if (!targetClass.getCourseId().equals(courseId)) {
  392. throw MyException.create(HttpStatus.BAD_REQUEST, "班级码与课程不匹配");
  393. }
  394. Long classId = targetClass.getClassId();
  395. // 检查学生是否已经加入了该课程下的其他班级
  396. QueryWrapper<ClassStudent> csWrapper = new QueryWrapper<>();
  397. csWrapper.inSql("class_id", "SELECT class_id FROM class WHERE course_id = " + courseId);
  398. csWrapper.inSql("official_number", "SELECT official_number FROM users WHERE id = " + studentId);
  399. ClassStudent existingClassStudent = classStudentMapper.selectOne(csWrapper);
  400. if (existingClassStudent != null) {
  401. throw MyException.create(HttpStatus.BAD_REQUEST, "学生已经加入了该课程下的一个班级");
  402. }
  403. // 检查学生是否已经选过该课程
  404. QueryWrapper<Enrollment> enrollmentWrapper = new QueryWrapper<>();
  405. enrollmentWrapper.eq("student_id", studentId);
  406. enrollmentWrapper.eq("course_id", courseId);
  407. Enrollment existingEnrollment = courseStudentMapper.selectOne(enrollmentWrapper);
  408. if (existingEnrollment == null) {
  409. // 创建新的选课记录
  410. Enrollment enrollment = new Enrollment();
  411. enrollment.setStudentId(studentId);
  412. enrollment.setCourseId(courseId);
  413. int status = courseStudentMapper.insert(enrollment);
  414. if (status == 0) {
  415. log.error("选课失败,数据库插入错误!");
  416. throw new MyException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "选课错误");
  417. }
  418. }
  419. // 将学生加入班级
  420. ClassStudent classStudent = new ClassStudent();
  421. classStudent.setClassId(classId);
  422. classStudent.setState(ClassStudentState.JOINED); // 已加入状态
  423. // 获取学生信息
  424. User student = userMapper.selectById(studentId);
  425. if (student != null) {
  426. classStudent.setOfficialNumber(student.getOfficialNumber());
  427. classStudent.setStuName(student.getName());
  428. }
  429. int csStatus = classStudentMapper.insert(classStudent);
  430. if (csStatus == 0) {
  431. log.error("加入班级失败,数据库插入错误!");
  432. throw new MyException(HttpStatus.INTERNAL_SERVER_ERROR.value(), "加入班级错误");
  433. }
  434. // 更新班级人数
  435. classMapper.increaseStuNumber(classId, 1);
  436. }
  437. /**
  438. * 将PO转换成VO
  439. * @param course
  440. * @return
  441. */
  442. private CourseVO convertToVO(Course course) {
  443. CourseVO res = new CourseVO();
  444. BeanUtils.copyProperties(course, res);
  445. if(course.getCourseImages() != null)
  446. res.setCourseImages(ConvertUtil.stringToList(course.getCourseImages(), String::valueOf));
  447. // 组装教师名字
  448. List<String> teacherNames = new ArrayList<>();
  449. // 1.getTeacherIds
  450. if(StringUtils.isNotBlank(course.getTeacherIds())){
  451. res.setTeacherIds(ConvertUtil.stringToList(course.getTeacherIds(), Long::valueOf));
  452. for (Long teacherId : res.getTeacherIds()) {
  453. teacherNames.add(userMapper.selectNameById(teacherId));
  454. }
  455. if (course.getCourseImages() != null) {
  456. res.setCourseImages(ConvertUtil.stringToList(course.getCourseImages(), String::valueOf));
  457. }
  458. }
  459. // 2. getTeacherPid
  460. if(StringUtils.isBlank(course.getTeacherIds()) && StringUtils.isNotBlank(course.getTeacherPid())){
  461. res.setTeacherPid(Long.valueOf(course.getTeacherPid()));
  462. teacherNames.add(userMapper.selectNameByPid(Long.valueOf(course.getTeacherPid())));
  463. }
  464. res.setTeacherNames(teacherNames);
  465. return res;
  466. }
  467. @Override
  468. public StudentCourseHomeworkVO getStudentCourseAssignments(Long studentId, Long courseId) {
  469. // 1. 验证学生是否存在
  470. User student = userMapper.selectById(studentId);
  471. if (student == null) {
  472. throw new RuntimeException("学生不存在");
  473. }
  474. // 2. 验证课程是否存在
  475. Course course = courseMapper.selectById(courseId);
  476. if (course == null) {
  477. throw new RuntimeException("课程不存在");
  478. }
  479. // 3. 查询该课程下的所有作业
  480. List<Assignment> courseAssignments = assignmentMapper.selectByCourseId(courseId);
  481. if (courseAssignments.isEmpty()) {
  482. StudentCourseHomeworkVO result = new StudentCourseHomeworkVO();
  483. result.setStudentId(studentId);
  484. result.setOfficialNumber(student.getOfficialNumber());
  485. result.setStuName(student.getName());
  486. return result;
  487. }
  488. // 4. 查询学生在该课程下的所有作业提交情况
  489. List<Long> assignmentIds = courseAssignments.stream()
  490. .map(Assignment::getAssignmentId)
  491. .collect(Collectors.toList());
  492. List<StudentAssignment> studentAssignments = studentAssignmentMapper.findByStudentIdAndAssignmentIds(studentId, assignmentIds);
  493. // 5. 构建作业ID到提交情况的映射
  494. Map<Long, StudentAssignment> assignmentMap = studentAssignments.stream()
  495. .collect(Collectors.toMap(
  496. StudentAssignment::getAssignmentId,
  497. item -> item
  498. ));
  499. // 6. 组装作业列表
  500. List<StudentCourseAssignmentVO> assignmentVOs = courseAssignments.stream()
  501. .map(assignment -> {
  502. StudentCourseAssignmentVO vo = new StudentCourseAssignmentVO();
  503. vo.setAssignmentId(assignment.getAssignmentId());
  504. vo.setAssignmentName(assignment.getAssignmentName());
  505. // 处理作业状态和分数
  506. StudentAssignment studentAssignment = assignmentMap.get(assignment.getAssignmentId());
  507. if (studentAssignment == null) {
  508. vo.setStatus(AssignmentCompletionStatus.NOT_SUBMITTED);
  509. vo.setScore(0);
  510. } else {
  511. vo.setStatus(AssignmentCompletionStatus.fromValue(studentAssignment.getStatus()));
  512. vo.setScore(studentAssignment.getScore() != null ?
  513. studentAssignment.getScore().intValue() : 0);
  514. }
  515. return vo;
  516. })
  517. .collect(Collectors.toList());
  518. // 7. 组装返回结果
  519. StudentCourseHomeworkVO result = new StudentCourseHomeworkVO();
  520. result.setStudentId(studentId);
  521. result.setOfficialNumber(student.getOfficialNumber());
  522. result.setStuName(student.getName());
  523. result.setAssignments(assignmentVOs);
  524. return result;
  525. }
  526. }