|
|
@@ -3,7 +3,9 @@ package com.njuzr.eaibackend.service;
|
|
|
import com.njuzr.eaibackend.exception.MyException;
|
|
|
import com.njuzr.eaibackend.mapper.BehaviorOverviewMapper;
|
|
|
import com.njuzr.eaibackend.po.BehaviorOverview;
|
|
|
+import com.njuzr.eaibackend.service.ClassService;
|
|
|
import com.njuzr.eaibackend.vo.BehaviorOverviewVO;
|
|
|
+import com.njuzr.eaibackend.vo.StudentInfoVO;
|
|
|
import java.util.stream.Collectors;
|
|
|
import java.util.Set;
|
|
|
import java.util.Map;
|
|
|
@@ -18,6 +20,7 @@ import org.springframework.stereotype.Service;
|
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
import java.io.IOException;
|
|
|
+import java.util.List;
|
|
|
import com.njuzr.eaibackend.vo.PauseStatisticsVO;
|
|
|
|
|
|
/**
|
|
|
@@ -29,12 +32,14 @@ public class ExportBehaviorOverviewService {
|
|
|
private final BehaviorOverviewService behaviorOverviewService;
|
|
|
private final BehaviorOverviewMapper behaviorOverviewMapper;
|
|
|
private final UserService userService;
|
|
|
+ private final ClassService classService;
|
|
|
|
|
|
@Autowired
|
|
|
- public ExportBehaviorOverviewService(BehaviorOverviewService behaviorOverviewService, BehaviorOverviewMapper behaviorOverviewMapper, UserService userService) {
|
|
|
+ public ExportBehaviorOverviewService(BehaviorOverviewService behaviorOverviewService, BehaviorOverviewMapper behaviorOverviewMapper, UserService userService, ClassService classService) {
|
|
|
this.behaviorOverviewService = behaviorOverviewService;
|
|
|
this.behaviorOverviewMapper = behaviorOverviewMapper;
|
|
|
this.userService = userService;
|
|
|
+ this.classService = classService;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -179,6 +184,86 @@ public class ExportBehaviorOverviewService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 导出指定 classId 下所有学生的行为概览数据为 Excel
|
|
|
+ * Sheet1: Summary(每行一个学生概览)
|
|
|
+ * Sheet2..N: 每个学生一个 Events 明细表(按 studentId 命名,避免超长或重复名冲突)
|
|
|
+ */
|
|
|
+ public byte[] exportClassBehaviorOverviewExcel(Long classId) {
|
|
|
+ try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
|
|
+ // Summary 汇总
|
|
|
+ Sheet summary = workbook.createSheet("Summary");
|
|
|
+ int rowIdx = 0;
|
|
|
+ Row header = summary.createRow(rowIdx++);
|
|
|
+ String[] headers = new String[]{
|
|
|
+ "name", "studentId", "insertCount", "deleteCount", "copyCount", "copyCharacterCount", "longPauseCount"
|
|
|
+ };
|
|
|
+ for (int i = 0; i < headers.length; i++) {
|
|
|
+ header.createCell(i).setCellValue(headers[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取班级下的所有学生
|
|
|
+ List<StudentInfoVO> students = classService.getStudentsByClassId(classId);
|
|
|
+ if (students != null && !students.isEmpty()) {
|
|
|
+ // 先批量拉取 studentId -> name 映射,避免 N 次查询
|
|
|
+ Set<Long> studentIds = students.stream()
|
|
|
+ .map(StudentInfoVO::getStudentId)
|
|
|
+ .filter(java.util.Objects::nonNull)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+ Map<Long, String> idToName = userService.getNamesByIds(studentIds);
|
|
|
+
|
|
|
+ for (StudentInfoVO student : students) {
|
|
|
+ Long studentId = student.getStudentId();
|
|
|
+ if (studentId == null) continue;
|
|
|
+
|
|
|
+ // 查询该学生的所有行为概览
|
|
|
+ java.util.List<BehaviorOverview> overviews = behaviorOverviewMapper.findByStudentId(studentId);
|
|
|
+ if (overviews != null && !overviews.isEmpty()) {
|
|
|
+ for (BehaviorOverview ov : overviews) {
|
|
|
+ BehaviorOverviewVO vo = behaviorOverviewService.getBehaviorOverview(studentId, ov.getAssignmentId());
|
|
|
+ Row row = summary.createRow(rowIdx++);
|
|
|
+ int col = 0;
|
|
|
+ String name = idToName != null ? idToName.get(studentId) : student.getStuName();
|
|
|
+ row.createCell(col++).setCellValue(name == null ? "" : name);
|
|
|
+ row.createCell(col++).setCellValue(vo.getStudentId() == null ? 0 : vo.getStudentId());
|
|
|
+ row.createCell(col++).setCellValue(vo.getInsertCount() == null ? 0 : vo.getInsertCount());
|
|
|
+ row.createCell(col++).setCellValue(vo.getDeleteCount() == null ? 0 : vo.getDeleteCount());
|
|
|
+ row.createCell(col++).setCellValue(vo.getCopyCount() == null ? 0 : vo.getCopyCount());
|
|
|
+ row.createCell(col++).setCellValue(vo.getCopyCharacterCount() == null ? 0 : vo.getCopyCharacterCount());
|
|
|
+ row.createCell(col).setCellValue(vo.getLongPauseCount() == null ? 0 : vo.getLongPauseCount());
|
|
|
+
|
|
|
+ // 为每个学生的每个作业创建一个事件明细sheet,添加作业ID确保名称唯一
|
|
|
+ String sheetName = safeSheetName("S-" + vo.getStudentId() + "-" + (name != null ? name : "Unknown") + "-A" + vo.getAssignmentId());
|
|
|
+ Sheet eventsSheet = workbook.createSheet(sheetName);
|
|
|
+ createEventsSheet(eventsSheet, vo.getStudentId(), vo.getAssignmentId());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 没有行为概览数据的学生
|
|
|
+ Row row = summary.createRow(rowIdx++);
|
|
|
+ int col = 0;
|
|
|
+ String name = idToName != null ? idToName.get(studentId) : student.getStuName();
|
|
|
+ row.createCell(col++).setCellValue(name == null ? "" : name);
|
|
|
+ row.createCell(col++).setCellValue(studentId);
|
|
|
+ row.createCell(col++).setCellValue(0);
|
|
|
+ row.createCell(col++).setCellValue(0);
|
|
|
+ row.createCell(col++).setCellValue(0);
|
|
|
+ row.createCell(col++).setCellValue(0);
|
|
|
+ row.createCell(col).setCellValue(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < headers.length; i++) {
|
|
|
+ summary.autoSizeColumn(i);
|
|
|
+ }
|
|
|
+
|
|
|
+ workbook.write(baos);
|
|
|
+ return baos.toByteArray();
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw MyException.create(HttpStatus.INTERNAL_SERVER_ERROR, "导出班级行为概览Excel失败" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private String safeSheetName(String name) {
|
|
|
// Excel sheet 名称长度限制31,且不允许某些字符
|
|
|
String n = name.replaceAll("[\\\\/:*?\\n\\r\\[\\]]", "-");
|