|
|
@@ -18,6 +18,7 @@ import org.springframework.stereotype.Service;
|
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
import java.io.IOException;
|
|
|
+import com.njuzr.eaibackend.vo.PauseStatisticsVO;
|
|
|
|
|
|
/**
|
|
|
* 将 behaviorOverviews 的数据导出为 Excel
|
|
|
@@ -117,6 +118,67 @@ public class ExportBehaviorOverviewService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 导出指定 assignmentId 下所有学生的停顿行为统计数据为 Excel
|
|
|
+ * Sheet1: PauseStatistics(每行一个学生的停顿统计)
|
|
|
+ */
|
|
|
+ public byte[] exportAssignmentPauseStatisticsExcel(Long assignmentId, Integer threshold) {
|
|
|
+ try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
|
|
+ // PauseStatistics 汇总
|
|
|
+ Sheet summary = workbook.createSheet("PauseStatistics");
|
|
|
+ int rowIdx = 0;
|
|
|
+ Row header = summary.createRow(rowIdx++);
|
|
|
+ String[] headers = new String[]{
|
|
|
+ "name", "studentId", "assignmentId", "totalPauseTime(ms)", "pauseCount",
|
|
|
+ "averagePauseTime(ms)", "medianPauseTime(ms)", "standardDeviation(ms)", "threshold(ms)"
|
|
|
+ };
|
|
|
+ for (int i = 0; i < headers.length; i++) {
|
|
|
+ header.createCell(i).setCellValue(headers[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询该作业下所有概览
|
|
|
+ java.util.List<BehaviorOverview> overviews = behaviorOverviewMapper.findByAssignmentId(assignmentId);
|
|
|
+ if (overviews != null) {
|
|
|
+ // 先批量拉取 studentId -> name 映射,避免 N 次查询
|
|
|
+ Set<Long> studentIds = overviews.stream()
|
|
|
+ .map(BehaviorOverview::getStudentId)
|
|
|
+ .filter(java.util.Objects::nonNull)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+ Map<Long, String> idToName = userService.getNamesByIds(studentIds);
|
|
|
+
|
|
|
+ for (BehaviorOverview ov : overviews) {
|
|
|
+ Long studentId = ov.getStudentId();
|
|
|
+ if (studentId == null) continue;
|
|
|
+
|
|
|
+ // 获取停顿统计数据(使用传入的阈值参数)
|
|
|
+ PauseStatisticsVO pauseStats = behaviorOverviewService.getPauseStatistics(studentId, assignmentId, threshold);
|
|
|
+ String name = idToName != null ? idToName.get(studentId) : null;
|
|
|
+
|
|
|
+ Row row = summary.createRow(rowIdx++);
|
|
|
+ int col = 0;
|
|
|
+ row.createCell(col++).setCellValue(name == null ? "" : name);
|
|
|
+ row.createCell(col++).setCellValue(pauseStats.getStudentId() == null ? 0 : pauseStats.getStudentId());
|
|
|
+ row.createCell(col++).setCellValue(pauseStats.getAssignmentId() == null ? 0 : pauseStats.getAssignmentId());
|
|
|
+ row.createCell(col++).setCellValue(pauseStats.getTotalPauseTime() == null ? 0 : pauseStats.getTotalPauseTime());
|
|
|
+ row.createCell(col++).setCellValue(pauseStats.getPauseCount() == null ? 0 : pauseStats.getPauseCount());
|
|
|
+ row.createCell(col++).setCellValue(pauseStats.getAveragePauseTime() == null ? 0.0 : pauseStats.getAveragePauseTime());
|
|
|
+ row.createCell(col++).setCellValue(pauseStats.getMedianPauseTime() == null ? 0.0 : pauseStats.getMedianPauseTime());
|
|
|
+ row.createCell(col++).setCellValue(pauseStats.getStandardDeviation() == null ? 0.0 : pauseStats.getStandardDeviation());
|
|
|
+ row.createCell(col).setCellValue(pauseStats.getThreshold() == null ? 0 : pauseStats.getThreshold());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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\\[\\]]", "-");
|