AssignmentServiceImpl.java 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. package com.njuzr.eaibackend.service.impl;
  2. import com.alibaba.fastjson2.JSONObject;
  3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4. import com.baomidou.mybatisplus.core.metadata.IPage;
  5. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  6. import com.njuzr.eaibackend.dto.AssignmentDTO;
  7. import com.njuzr.eaibackend.dto.AssignmentQueryDTO;
  8. import com.njuzr.eaibackend.dto.AssignmentUpdateDTO;
  9. import com.njuzr.eaibackend.dto.CorrectDTO;
  10. import com.njuzr.eaibackend.enums.AssignmentCompletionStatus;
  11. import com.njuzr.eaibackend.enums.AssignmentStatus;
  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.AssignmentService;
  18. import com.njuzr.eaibackend.service.ClassService;
  19. import com.njuzr.eaibackend.service.TextAnalysisService;
  20. import com.njuzr.eaibackend.utils.*;
  21. import com.njuzr.eaibackend.vo.*;
  22. import lombok.extern.slf4j.Slf4j;
  23. import org.springframework.beans.BeanUtils;
  24. import org.springframework.cache.annotation.CacheEvict;
  25. import org.springframework.http.HttpStatus;
  26. import org.springframework.stereotype.Service;
  27. import org.springframework.transaction.annotation.Transactional;
  28. import java.time.LocalDateTime;
  29. import java.util.*;
  30. import java.util.function.Function;
  31. import java.util.stream.Collectors;
  32. /**
  33. * @author: Leonezhurui
  34. * @Date: 2024/3/15 - 00:40
  35. * @Package: EAI-Backend
  36. */
  37. @Slf4j
  38. @Service
  39. public class AssignmentServiceImpl implements AssignmentService {
  40. private final AssignmentMapper assignmentMapper;
  41. private final CourseMapper courseMapper;
  42. private final StudentAssignmentMapper studentAssignmentMapper;
  43. private final UserMapper userMapper;
  44. private final ClassService classService;
  45. private final OssUtil ossUtil;
  46. private final FileUtil fileUtil = new FileUtil();
  47. private final TextAnalysisService textAnalysisService;
  48. public AssignmentServiceImpl(AssignmentMapper assignmentMapper,
  49. CourseMapper courseMapper,
  50. StudentAssignmentMapper studentAssignmentMapper,
  51. UserMapper userMapper,
  52. OssUtil ossUtil,
  53. CourseServiceImpl courseServiceImpl,
  54. CourseStudentMapper courseStudentMapper,
  55. ClassService classService,
  56. TextAnalysisService textAnalysisService) {
  57. this.assignmentMapper = assignmentMapper;
  58. this.courseMapper = courseMapper;
  59. this.studentAssignmentMapper = studentAssignmentMapper;
  60. this.userMapper = userMapper;
  61. this.ossUtil = ossUtil;
  62. this.textAnalysisService = textAnalysisService;
  63. this.classService = classService;
  64. }
  65. @Override
  66. public AssignmentVO createAssignment(MyUserDetails user, Long courseId, AssignmentDTO assignmentDTO) {
  67. Course course = courseMapper.selectById(courseId);
  68. if (course == null)
  69. throw MyException.create(HttpStatus.BAD_REQUEST, "课程不存在");
  70. if (user.getRole() != Role.ADMIN) {
  71. List<String> teacherIds = Collections.singletonList(Optional.ofNullable(course.getTeacherIds())
  72. .orElse(Collections.emptyList().toString()));
  73. String userIdStr = String.valueOf(user.getId());
  74. boolean hasTeacherId = teacherIds.contains(userIdStr);
  75. boolean pidMatches = Objects.equals(course.getTeacherPid(), user.getPid());
  76. if (!hasTeacherId && !pidMatches) {
  77. throw MyException.create(HttpStatus.BAD_REQUEST, "无权限创建");
  78. }
  79. }
  80. Assignment target = convertToPO(assignmentDTO);
  81. target.setCourseId(courseId);
  82. target.setTeacherId(user.getId());
  83. target.setEngageNumber(0);
  84. target.setCorrectNumber(0);
  85. // TODO:权宜之计
  86. // target.setTeacherId(Long.valueOf(user.getPid()));
  87. target.setCreateTime(new Date());
  88. try {
  89. int code = assignmentMapper.insert(target);
  90. if (code == 0)
  91. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "创建作业失败");
  92. } catch (Exception e) {
  93. log.error(e.getMessage());
  94. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "创建作业失败");
  95. }
  96. return convertToVO(target);
  97. }
  98. @Override
  99. // @Cacheable(value = "assignmentInfo", key = "'assignment_' + #assignmentId")
  100. public AssignmentVO findAssignmentById(Long assignmentId) {
  101. QueryWrapper<Assignment> wrapper = new QueryWrapper<>();
  102. wrapper.eq("assignment_id", assignmentId);
  103. Assignment res = assignmentMapper.selectOne(wrapper);
  104. log.info("数据库查询作业:{}", assignmentId);
  105. if (res == null)
  106. throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
  107. return convertToVO(res);
  108. }
  109. @Override
  110. public IPage<AssignmentVO> findAssignmentPage(Page<Assignment> page, AssignmentQueryDTO assignmentQueryDTO) {
  111. log.info("作业查询服务:{}", assignmentQueryDTO);
  112. QueryWrapper<Assignment> wrapper = new QueryWrapper<>();
  113. if (assignmentQueryDTO.getAssignmentId() != null) { // assignmentId直接判断是否相等
  114. // TODO 检测assignmentId是否正确
  115. wrapper.eq("assignmentId", assignmentQueryDTO.getAssignmentId());
  116. }
  117. if (assignmentQueryDTO.getTeacherId() != null) { // teacherId直接匹配
  118. wrapper.eq("teacher_id", assignmentQueryDTO.getTeacherId());
  119. }
  120. if (assignmentQueryDTO.getCourseId() != null) { // teacherId直接匹配
  121. wrapper.eq("course_id", assignmentQueryDTO.getCourseId());
  122. }
  123. if (assignmentQueryDTO.getAssignmentName() != null) { // 模糊匹配作业名字
  124. wrapper.like("assignment_name", assignmentQueryDTO.getAssignmentName());
  125. }
  126. if(assignmentQueryDTO.getType() != null){
  127. wrapper.eq("type",assignmentQueryDTO.getType());
  128. }
  129. if (assignmentQueryDTO.getStatus() != null) {
  130. AssignmentStatus status = assignmentQueryDTO.getStatus();
  131. if (status == AssignmentStatus.NOT_STARTED) {
  132. wrapper.gt("start_time", LocalDateTime.now()); // 意思是start_time > now()
  133. } else if (status == AssignmentStatus.PROCEEDING) {
  134. wrapper.le("start_time", LocalDateTime.now())
  135. .ge("end_time", LocalDateTime.now());
  136. } else {
  137. wrapper.lt("end_time", LocalDateTime.now());
  138. }
  139. }
  140. IPage<Assignment> assignments = assignmentMapper.selectPage(page, wrapper);
  141. return PageMapperUtil.convert(assignments, this::convertToVO);
  142. }
  143. @Override
  144. @CacheEvict(value = "assignmentInfo", key = "'assignment_' + #assignmentId")
  145. public AssignmentVO updateAssignment(MyUserDetails user, Long assignmentId, AssignmentUpdateDTO assignmentUpdateDTO) {
  146. Assignment target = assignmentMapper.selectById(assignmentId);
  147. if (!Objects.equals(target.getTeacherId(), user.getId()) && !Objects.equals(target.getTeacherPid(), user.getPid()))
  148. throw MyException.create(HttpStatus.BAD_REQUEST, "无权限更新");
  149. Assignment ope = convertToPO(assignmentUpdateDTO);
  150. ope.setAssignmentId(assignmentId);
  151. try {
  152. int code = assignmentMapper.updateById(ope);
  153. if (code == 0)
  154. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "服务器更新失败");
  155. } catch (Exception e) {
  156. log.error(e.getMessage());
  157. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "服务器更新失败");
  158. }
  159. return convertToVO(assignmentMapper.selectById(assignmentId));
  160. }
  161. /**
  162. * 教师删除作业
  163. */
  164. @Override
  165. @Transactional
  166. @CacheEvict(value = "assignmentInfo", key = "'assignment_' + #assignmentId")
  167. public void deleteById(Long teacherId, Long assignmentId) {
  168. Assignment target = assignmentMapper.selectById(assignmentId);
  169. if (!Objects.equals(target.getTeacherId(), teacherId))
  170. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "无权限删除");
  171. try {
  172. List<Engagement> engagements = studentAssignmentMapper.findEngagementByAssignmentId(assignmentId);
  173. for(Engagement engagement : engagements) {
  174. studentAssignmentMapper.delete(engagement.getStudentId(), assignmentId);
  175. }
  176. int code = assignmentMapper.deleteById(assignmentId);
  177. if (code == 0) {
  178. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "删除作业错误");
  179. }
  180. } catch (Exception e) {
  181. log.error(e.getMessage());
  182. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "删除作业错误");
  183. }
  184. }
  185. @Override
  186. public void engageAssignment(Long studentId, Long assignmentId) {
  187. if(studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId) != null){
  188. return;
  189. }
  190. // 1创建Engagement实体类,初始化基本信息
  191. Engagement engagement = new Engagement();
  192. engagement.setStudentId(studentId);
  193. engagement.setAssignmentId(assignmentId);
  194. engagement.setVersion(1); // 设置这是version
  195. engagement.setStatus(AssignmentCompletionStatus.NOT_SUBMITTED); // 已经进入到页面编辑,但是还没有提交
  196. Assignment assignment = assignmentMapper.selectById(assignmentId);
  197. assignment.setEngageNumber(assignment.getEngageNumber() + 1);
  198. // // 2通过FileUtil创建一个空的docx文件
  199. // InputStream inputStream = fileUtil.createEmptyDocx();
  200. //
  201. // String filePath = assignmentId + "_" + studentId + ".docx";
  202. // // 3通过OssUtil工具类上传空文件,注意给其命名为`assignmentId/studentId.docx`,并得到文件链接
  203. // String fileName = ossUtil.uploadEnduringFile(inputStream, filePath);
  204. // engagement.setFileUrl(fileName);
  205. try {
  206. int code = studentAssignmentMapper.insert(engagement);
  207. int code1 = assignmentMapper.updateById(assignment);
  208. if (code == 0 || code1 == 0)
  209. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "参加作业失败");
  210. } catch (Exception e) {
  211. log.error(e.getMessage());
  212. // ossUtil.deleteFile(filePath);
  213. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "参加作业失败");
  214. }
  215. }
  216. /**
  217. * 根据两个外键,搜索学生参与作业的情况(需要在mysql中设置索引)
  218. *
  219. * @param studentId
  220. * @param assignmentId
  221. * @return
  222. */
  223. @Override
  224. public EngagementVO getEngagement(Long studentId, Long assignmentId) {
  225. Engagement engagement = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId);
  226. if (engagement == null)
  227. throw MyException.create(HttpStatus.BAD_REQUEST, "参与作业情况不存在");
  228. return convertToVO(engagement);
  229. }
  230. // 返回顺序: 先是未批改的,然后是批改的按照成绩从高到低返回
  231. @Override
  232. public IPage<EngagementVO> findEngagementPage(Page<Engagement> page, Long assignmentId) {
  233. IPage<Engagement> engagements = studentAssignmentMapper.findEngagementByAssignmentId(page, assignmentId);
  234. return PageMapperUtil.convert(engagements, this::convertToVO);
  235. }
  236. @Override
  237. public EngagementDetailVO getDetailEngagement(Long studentId, Long assignmentId) {
  238. // 1 获取用户详细信息
  239. User student = userMapper.selectById(studentId);
  240. if (student == null)
  241. throw MyException.create(HttpStatus.BAD_REQUEST, "学生不存在");
  242. // 2 获取作业详细信息
  243. Assignment assignment = assignmentMapper.selectById(assignmentId);
  244. if (assignment == null)
  245. throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
  246. // 3 获取作业参与详细信息
  247. Engagement engagement = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId);
  248. if (engagement == null)
  249. throw MyException.create(HttpStatus.BAD_REQUEST, "参与作业情况不存在");
  250. EngagementDetailVO detailVO = ModelMapperUtil.map(engagement, EngagementDetailVO.class);
  251. detailVO.setUserVO(ModelMapperUtil.map(student, UserVO.class));
  252. detailVO.setAssignmentVO(convertToVO(assignment));
  253. // detailVO.setFileKey(assignmentId + "_" + studentId + "_" + engagement.getVersion());
  254. log.info("请求到详细信息:" + detailVO);
  255. return detailVO;
  256. }
  257. /**
  258. * 作业提交,更新文件版本和作业状态
  259. *
  260. * @param studentId
  261. * @param assignmentId
  262. */
  263. @Override
  264. public void engagementSubmit(Long studentId, Long assignmentId) {
  265. Engagement engagement = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId);
  266. if (engagement == null)
  267. throw MyException.create(HttpStatus.BAD_REQUEST, "参与作业情况不存在");
  268. int originalVersion = engagement.getVersion();
  269. engagement.setVersion(originalVersion + 1);
  270. engagement.setStatus(AssignmentCompletionStatus.SUBMITTED);
  271. try {
  272. int code = studentAssignmentMapper.updateById(engagement);
  273. if (code == 0)
  274. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "更新文件版本失败");
  275. } catch (Exception e) {
  276. log.error(e.getMessage());
  277. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "更新文件版本失败");
  278. }
  279. }
  280. /**
  281. * 补交作业,更新文件版本和作业状态为已补交
  282. *
  283. * @param studentId
  284. * @param assignmentId
  285. */
  286. @Override
  287. public void engagementLateSubmit(Long studentId, Long assignmentId) {
  288. Engagement engagement = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId);
  289. if (engagement == null)
  290. throw MyException.create(HttpStatus.BAD_REQUEST, "参与作业情况不存在");
  291. int originalVersion = engagement.getVersion();
  292. engagement.setVersion(originalVersion + 1);
  293. engagement.setStatus(AssignmentCompletionStatus.LATE_SUBMITTED);
  294. try {
  295. int code = studentAssignmentMapper.updateById(engagement);
  296. if (code == 0)
  297. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "更新文件版本失败");
  298. } catch (Exception e) {
  299. log.error(e.getMessage());
  300. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "更新文件版本失败");
  301. }
  302. }
  303. /**
  304. * 作业暂存,更新文件版本,不修改作业状态
  305. *
  306. * @param studentId
  307. * @param assignmentId
  308. */
  309. @Override
  310. public void engagementStage(Long studentId, Long assignmentId, JSONObject jsonObject) {
  311. Engagement engagement = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId);
  312. if (engagement == null)
  313. throw MyException.create(HttpStatus.BAD_REQUEST, "参与作业情况不存在");
  314. int originalVersion = engagement.getVersion();
  315. String quillContent = jsonObject.getString("quillContent");
  316. String textContent = jsonObject.getString("textContent");
  317. String htmlContent = jsonObject.getString("htmlContent");
  318. engagement.setVersion(originalVersion + 1);
  319. engagement.setQuillContent(quillContent);
  320. engagement.setTextContent(textContent);
  321. engagement.setHtmlContent(htmlContent);
  322. try {
  323. int code = studentAssignmentMapper.updateById(engagement);
  324. if (code == 0)
  325. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "更新文件版本失败");
  326. // 异步启动文本分析,不影响主流程返回速度
  327. try {
  328. textAnalysisService.analyzeAndSaveTextContentAsync(studentId, assignmentId);
  329. log.info("已启动异步文本分析 - studentId: {}, assignmentId: {}", studentId, assignmentId);
  330. } catch (Exception e) {
  331. log.error("启动异步文本分析失败 - studentId: {}, assignmentId: {}, error: {}",
  332. studentId, assignmentId, e.getMessage());
  333. // 不抛出异常,避免影响主流程
  334. }
  335. } catch (Exception e) {
  336. log.error(e.getMessage());
  337. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "更新文件版本失败");
  338. }
  339. }
  340. @Override
  341. public void engagementCorrect(Long teacherId, Long studentId, Long assignmentId, CorrectDTO correctDTO) {
  342. Engagement engagement = studentAssignmentMapper.findEngagementByStudentIdAndAssignmentId(studentId, assignmentId);
  343. if (engagement == null)
  344. throw MyException.create(HttpStatus.BAD_REQUEST, "参与作业情况不存在");
  345. Assignment assignment = assignmentMapper.selectById(assignmentId);
  346. if (assignment == null)
  347. throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
  348. if (!Objects.equals(assignment.getTeacherId(), teacherId))
  349. throw MyException.create(HttpStatus.BAD_REQUEST, "无权限批改");
  350. if(engagement.getStatus() != AssignmentCompletionStatus.CORRECTED && engagement.getStatus() != AssignmentCompletionStatus.LATE_SUBMITTED_CORRECTED){
  351. assignment.setCorrectNumber(assignment.getCorrectNumber() + 1);
  352. if(engagement.getStatus() == AssignmentCompletionStatus.SUBMITTED){
  353. engagement.setStatus(AssignmentCompletionStatus.CORRECTED);
  354. } else if(engagement.getStatus() == AssignmentCompletionStatus.LATE_SUBMITTED){
  355. engagement.setStatus(AssignmentCompletionStatus.LATE_SUBMITTED_CORRECTED);
  356. }
  357. }
  358. engagement.setScore(correctDTO.getScore());
  359. engagement.setRemark(correctDTO.getRemark());
  360. try {
  361. int code = studentAssignmentMapper.updateById(engagement);
  362. int code1 = assignmentMapper.updateById(assignment);
  363. if (code == 0 || code1 == 0)
  364. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "批改作业失败");
  365. } catch (Exception e) {
  366. log.error(e.getMessage());
  367. throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "批改作业失败");
  368. }
  369. }
  370. @Override
  371. public long getNextStudentId(Long assignmentId, Long studentId) {
  372. List<Engagement> allRecords = studentAssignmentMapper.selectList(
  373. new QueryWrapper<Engagement>()
  374. .eq("assignment_id", assignmentId)
  375. // 可以在此添加其他查询条件
  376. );
  377. // 对记录进行排序:status为4或6的记录排到最后,其他记录保持原始顺序
  378. List<Engagement> sortedList = allRecords.stream()
  379. .sorted(Comparator.comparing(
  380. e -> e.getStatus() == AssignmentCompletionStatus.PUBLISHED ||
  381. e.getStatus() == AssignmentCompletionStatus.CORRECTED
  382. )).toList();
  383. int currentIndex = -1;
  384. for (int i = 0; i < sortedList.size(); i++) {
  385. if (sortedList.get(i).getStudentId().equals(studentId)) {
  386. currentIndex = i;
  387. break;
  388. }
  389. }
  390. if (currentIndex == allRecords.size() - 1 || currentIndex == -1) {
  391. return sortedList.get(0).getStudentId();
  392. }
  393. return sortedList.get(currentIndex + 1).getStudentId();
  394. }
  395. @Override
  396. public EngageNumberVo getEngageNumber(Long assignmentId) {
  397. Assignment assignment = assignmentMapper.selectById(assignmentId);
  398. if(assignment == null){
  399. throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在");
  400. }
  401. if(assignment.getEngageNumber() != null && assignment.getCorrectNumber() != null){
  402. return new EngageNumberVo(assignment.getEngageNumber(), assignment.getCorrectNumber());
  403. } else {
  404. throw MyException.create(HttpStatus.BAD_REQUEST, "未建立作业统计");
  405. }
  406. }
  407. private Assignment convertToPO(AssignmentDTO assignmentDTO) {
  408. Assignment assignment = new Assignment();
  409. BeanUtils.copyProperties(assignmentDTO, assignment);
  410. if (assignmentDTO.getAttachments() != null)
  411. assignment.setAttachments(ConvertUtil.listToString(assignmentDTO.getAttachments()));
  412. return assignment;
  413. }
  414. private Assignment convertToPO(AssignmentUpdateDTO assignmentDTO) {
  415. Assignment assignment = new Assignment();
  416. BeanUtils.copyProperties(assignmentDTO, assignment);
  417. if (assignmentDTO.getAttachments() != null)
  418. assignment.setAttachments(ConvertUtil.listToString(assignmentDTO.getAttachments()));
  419. return assignment;
  420. }
  421. private AssignmentVO convertToVO(Assignment assignment) {
  422. AssignmentVO res = new AssignmentVO();
  423. BeanUtils.copyProperties(assignment, res);
  424. if (assignment.getAttachments() != null)
  425. res.setAttachments(ConvertUtil.stringToList(assignment.getAttachments(), String::valueOf));
  426. res.setStatus(calculateStatus(res.getStartTime(), res.getEndTime()));
  427. // 组装老师姓名
  428. res.setTeacherName(userMapper.selectNameById(assignment.getTeacherId()));
  429. return res;
  430. }
  431. private EngagementVO convertToVO(Engagement engagement) {
  432. EngagementVO res = ModelMapperUtil.map(engagement, EngagementVO.class);
  433. // 组装文件key
  434. // res.setFileKey(res.getAssignmentId() + "_" + res.getStudentId() + "_" + res.getVersion());
  435. // 组装学生姓名
  436. String studentName = userMapper.selectNameById(engagement.getStudentId());
  437. res.setStudentName(studentName);
  438. return res;
  439. }
  440. private AssignmentStatus calculateStatus(Date startTime, Date endTime) {
  441. Date now = new Date();
  442. if (now.before(startTime)) {
  443. return AssignmentStatus.NOT_STARTED;
  444. } else if (now.after(endTime)) {
  445. return AssignmentStatus.FINISHED;
  446. } else {
  447. return AssignmentStatus.PROCEEDING;
  448. }
  449. }
  450. @Override
  451. public List<StudentAssignmentStatusVO> getStudentsAssignmentStatus(Long classId, Long assignmentId) {
  452. // 1. 验证班级和作业存在性
  453. Assignment assignment = assignmentMapper.selectById(assignmentId);
  454. if (assignment == null) {
  455. throw new RuntimeException("作业不存在"); // 建议替换为项目自定义异常
  456. }
  457. // 2. 获取班级所有学生(从class_student表)
  458. List<StudentInfoVO> classStudents = classService.getStudentsByClassId(classId);
  459. if (classStudents.isEmpty()) {
  460. return Collections.emptyList();
  461. }
  462. // 3. 提取学号列表,查询对应的用户ID(users表)
  463. List<String> officialNumbers = classStudents.stream()
  464. .map(StudentInfoVO::getOfficialNumber)
  465. .collect(Collectors.toList());
  466. List<User> users = userMapper.selectUserIdByOfficialNumbers(officialNumbers);
  467. Map<String, Long> officialNumberToUserIdMap = users.stream()
  468. .collect(Collectors.toMap(
  469. User::getOfficialNumber,
  470. User::getId
  471. ));
  472. // 4. 查询这些学生的作业提交情况(student_assignment表)
  473. List<Long> studentIds = new ArrayList<>(officialNumberToUserIdMap.values());
  474. List<StudentAssignment> studentAssignments = studentAssignmentMapper.findByAssignmentIdAndStudentIds(assignmentId, studentIds);
  475. // 5. 构建学生ID到作业情况的映射
  476. Map<Long, StudentAssignment> studentIdToAssignmentMap = studentAssignments.stream()
  477. .collect(Collectors.toMap(
  478. StudentAssignment::getStudentId,
  479. Function.identity()
  480. ));
  481. // 6. 组装返回结果
  482. return classStudents.stream()
  483. .map(student -> {
  484. StudentAssignmentStatusVO vo = new StudentAssignmentStatusVO();
  485. vo.setOfficialNumber(student.getOfficialNumber());
  486. vo.setStuName(student.getStuName());
  487. // 设置学生ID
  488. Long studentId = officialNumberToUserIdMap.get(student.getOfficialNumber());
  489. vo.setStudentId(studentId);
  490. // 设置状态和成绩
  491. StudentAssignment studentAssignment = studentIdToAssignmentMap.get(studentId);
  492. if (studentAssignment == null) {
  493. // 未参与作业,按未提交处理
  494. vo.setStatus(AssignmentCompletionStatus.NOT_SUBMITTED);
  495. vo.setScore(0);
  496. } else {
  497. // 转换状态为枚举
  498. vo.setStatus(AssignmentCompletionStatus.fromValue(studentAssignment.getStatus()));
  499. // 处理成绩(BigDecimal转Integer,未批改为0)
  500. vo.setScore(studentAssignment.getScore() != null ?
  501. studentAssignment.getScore().intValue() : 0);
  502. }
  503. return vo;
  504. })
  505. .collect(Collectors.toList());
  506. }
  507. }