package com.njuzr.eaibackend.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.njuzr.eaibackend.exception.MyException; import com.njuzr.eaibackend.mapper.EngagementMapper; import com.njuzr.eaibackend.mapper.serviceIpml.EngagementMapperServiceImpl; import com.njuzr.eaibackend.po.Engagement; import com.njuzr.eaibackend.po.User; import com.njuzr.eaibackend.po.Assignment; import com.njuzr.eaibackend.utils.WordExporter; import com.njuzr.eaibackend.utils.ZipExport; import com.njuzr.eaibackend.vo.AssignmentVO; import com.njuzr.eaibackend.vo.EngagementVO; import com.njuzr.eaibackend.vo.UserVO; import com.njuzr.eaibackend.vo.StudentInfoVO; import com.njuzr.eaibackend.vo.EngagementHistoryVO; import freemarker.template.Configuration; import freemarker.template.TemplateException; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.tuple.Pair; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; @Slf4j @Service public class ExportCompositionService { @Autowired private Configuration freemarkerConfig; @Autowired private EngagementMapper engagementMapper; @Autowired private AssignmentService assignmentService; @Autowired private UserService userService; @Autowired private WordExporter wordExporter; @Autowired private EngagementMapperServiceImpl engagementMapperServiceImpl; @Autowired private com.njuzr.eaibackend.mapper.UserMapper userMapper; @Autowired private com.njuzr.eaibackend.mapper.AssignmentMapper assignmentMapper; public Pair exportWord(Long assignmentId, Long studentId) { AssignmentVO assignment = assignmentService.findAssignmentById(assignmentId); EngagementVO engagement = assignmentService.getEngagement(studentId, assignmentId); UserVO user = userService.searchUsers(new Page<>(1,1), studentId, null, null, null).getRecords().get(0); Map model = buildWordInfoModel(assignment, user, engagement); return Pair.of(user, wordExporter.exportCompositionWord(model)); } private Map buildWordInfoModel(AssignmentVO assignment, UserVO user, EngagementVO engagement) { Map model = new HashMap<>(); model.put("title", assignment.getAssignmentName()); model.put("studentName", user.getName()); model.put("officialNumber", user.getOfficialNumber()); model.put("assignmentName", assignment.getAssignmentName()); model.put("date", new Date()); model.put("content", processContent(engagement.getTextContent())); return model; } public byte[] exportBatchToZip(List studentIds, Long assignmentId) { if(assignmentId == null){ throw MyException.create(HttpStatus.BAD_REQUEST, "assignmentId不能为空"); } if (CollectionUtils.isEmpty(studentIds)) { List engagements = engagementMapperServiceImpl.getEngagementByAssignmentId(assignmentId); if (CollectionUtils.isEmpty(engagements)) { return null; } studentIds = engagements.stream() .map(Engagement::getStudentId) .toList(); } return exportBatchToZipByStudentIds(studentIds, assignmentId); } private byte[] exportBatchToZipByStudentIds(List studentIds, Long assignmentId) { List zipItems = studentIds.stream() .map(studentId -> { try { Pair pair = exportWord(assignmentId, studentId); UserVO student = pair.getLeft(); byte[] wordBytes = pair.getRight(); String fileName = String.format("%s_%s.%s", student.getName(), student.getOfficialNumber(), "docx"); return new ZipExport.ZipItem(fileName, wordBytes); } catch (Exception e) { log.error("exportBatchToZip failed, studentId: {}, reason: {}", studentId, e.getMessage()); return null; } }) .filter(Objects::nonNull) .collect(Collectors.toList()); try { return ZipExport.packToZip(zipItems); } catch (IOException e) { throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "ZIP打包失败"+e.getMessage()); } } public byte[] exportWordTest(Long assignmentId, Long studentId) throws IOException, TemplateException { String assignmentName = "My Favorite Season"; String content = "My favorite season is autumn. The weather is cool and comfortable, and the leaves turn golden, making the scenery beautiful. I enjoy walking in the park and listening to the sound of rustling leaves. Autumn is also a harvest season, with fruits like apples and pears ripe for picking.\n" + "During this season, my family often goes hiking or has picnics. The Mid-Autumn Festival, when we eat mooncakes and admire the full moon, is my favorite holiday. Autumn reminds me of warmth and joy.\n" + "In short, autumn is not only pleasant but also full of happy memories. That’s why I love it most."; Map model = new HashMap<>(); model.put("title", "title_"+assignmentName); model.put("studentName", "柏琪"); model.put("assignmentName", assignmentName); model.put("date", new Date()); model.put("content", content.replaceAll("\n", "
")); return wordExporter.exportCompositionWord(model); } private String processContent(String content) { return content.replaceAll("\n", "
"); } public byte[] downloadClassAssignments(Long classId) { // 获取班级信息 com.njuzr.eaibackend.po.Class cls = classService.getClassById(classId); if (cls == null) { throw MyException.create(HttpStatus.BAD_REQUEST, "班级不存在"); } // 获取班级所有学生 List students = classService.getStudentsByClassId(classId); if (students.isEmpty()) { throw MyException.create(HttpStatus.BAD_REQUEST, "班级无学生"); } // 获取班级对应的课程ID Long courseId = cls.getCourseId(); if (courseId == null) { throw MyException.create(HttpStatus.BAD_REQUEST, "班级未关联课程"); } // 获取课程的所有作业 List courseAssignments = assignmentMapper.selectByCourseId(courseId); if (courseAssignments.isEmpty()) { throw MyException.create(HttpStatus.BAD_REQUEST, "课程无作业"); } // 生成ZIP文件 try { List zipItems = new ArrayList<>(); for (StudentInfoVO student : students) { String officialNumber = student.getOfficialNumber(); User user = userMapper.selectOne(new QueryWrapper().eq("official_number", officialNumber)); if (user == null) { continue; } Long studentId = user.getId(); for (Assignment assignment : courseAssignments) { Long assignmentId = assignment.getAssignmentId(); String assignmentDir = assignment.getAssignmentName() + "/"; String studentDir = assignmentDir + user.getOfficialNumber() + "_" + user.getName() + "/"; try { List historyList = assignmentService.getEngagementHistory(studentId, assignmentId); for (EngagementHistoryVO history : historyList) { Map model = new HashMap<>(); model.put("title", assignment.getAssignmentName()); model.put("studentName", user.getName()); model.put("officialNumber", user.getOfficialNumber()); model.put("assignmentName", assignment.getAssignmentName()); model.put("date", history.getSubmitTime()); model.put("content", processContent(history.getTextContent())); byte[] wordBytes = wordExporter.exportCompositionWord(model); String fileName = studentDir + user.getOfficialNumber() + "_" + user.getName() + "_版本" + history.getVersion() + ".docx"; zipItems.add(new ZipExport.ZipItem(fileName, wordBytes)); } } catch (Exception e) { log.warn("学生 {} 未提交作业 {},跳过", studentId, assignmentId); } } } return ZipExport.packToZip(zipItems); } catch (IOException e) { throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "ZIP打包失败" + e.getMessage()); } } public byte[] downloadAssignmentSubmissions(Long assignmentId) { AssignmentVO assignment = assignmentService.findAssignmentById(assignmentId); if (assignment == null) { throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在"); } Long courseId = assignment.getCourseId(); List courseClasses = classService.select(courseId); if (courseClasses.isEmpty()) { throw MyException.create(HttpStatus.BAD_REQUEST, "课程无班级"); } try { List zipItems = new ArrayList<>(); for (com.njuzr.eaibackend.po.Class cls : courseClasses) { String className = cls.getClassName(); String classDir = className + "/"; List students = classService.getStudentsByClassId(cls.getClassId()); for (StudentInfoVO student : students) { String officialNumber = student.getOfficialNumber(); User user = userMapper.selectOne(new QueryWrapper().eq("official_number", officialNumber)); if (user == null) continue; Long studentId = user.getId(); String studentDir = classDir + user.getOfficialNumber() + "_" + user.getName() + "/"; List historyList = assignmentService.getEngagementHistory(studentId, assignmentId); for (EngagementHistoryVO history : historyList) { Map model = new HashMap<>(); model.put("title", assignment.getAssignmentName()); model.put("studentName", user.getName()); model.put("officialNumber", user.getOfficialNumber()); model.put("assignmentName", assignment.getAssignmentName()); model.put("date", history.getSubmitTime()); model.put("content", processContent(history.getTextContent())); byte[] wordBytes = wordExporter.exportCompositionWord(model); String fileName = studentDir + user.getOfficialNumber() + "_" + user.getName() + "_版本" + history.getVersion() + ".docx"; zipItems.add(new ZipExport.ZipItem(fileName, wordBytes)); } } } return ZipExport.packToZip(zipItems); } catch (IOException e) { throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "ZIP打包失败" + e.getMessage()); } } public byte[] downloadClassAssignment(Long classId, Long assignmentId) { com.njuzr.eaibackend.po.Class cls = classService.getClassById(classId); if (cls == null) { throw MyException.create(HttpStatus.BAD_REQUEST, "班级不存在"); } AssignmentVO assignment = assignmentService.findAssignmentById(assignmentId); if (assignment == null) { throw MyException.create(HttpStatus.BAD_REQUEST, "作业不存在"); } String folderName = cls.getClassName() + "_" + assignment.getAssignmentName(); String folderDir = folderName + "/"; List students = classService.getStudentsByClassId(classId); if (students.isEmpty()) { throw MyException.create(HttpStatus.BAD_REQUEST, "班级无学生"); } try { List zipItems = new ArrayList<>(); for (StudentInfoVO student : students) { String officialNumber = student.getOfficialNumber(); User user = userMapper.selectOne(new QueryWrapper().eq("official_number", officialNumber)); if (user == null) continue; Long studentId = user.getId(); String studentDir = folderDir + user.getOfficialNumber() + "_" + user.getName() + "/"; List historyList = assignmentService.getEngagementHistory(studentId, assignmentId); for (EngagementHistoryVO history : historyList) { Map model = new HashMap<>(); model.put("title", assignment.getAssignmentName()); model.put("studentName", user.getName()); model.put("officialNumber", user.getOfficialNumber()); model.put("assignmentName", assignment.getAssignmentName()); model.put("date", history.getSubmitTime()); model.put("content", processContent(history.getTextContent())); byte[] wordBytes = wordExporter.exportCompositionWord(model); String fileName = studentDir + user.getOfficialNumber() + "_" + user.getName() + "_版本" + history.getVersion() + ".docx"; zipItems.add(new ZipExport.ZipItem(fileName, wordBytes)); } } return ZipExport.packToZip(zipItems); } catch (IOException e) { throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "ZIP打包失败" + e.getMessage()); } } // 需要注入 ClassService @Autowired private ClassService classService; }