feat(export): 多考试对比导出(横向交叉表)
新增 export_multi 接口与多考试选择弹窗: - 第一行显示考试名称,前两列固定为学号/姓名,默认按学号排序 - 每场考试成绩可选「最新成绩」或「最高成绩」(latest 跳过 temp_save 草稿,highest 取跨全部尝试最高分) - 学生取并集(任一考试有提交即纳入),未考的考试单元格留空 - 纯逻辑抽离到 lib/multi_export.php,新增 26 项回归测试(tests/test-multi-export.php)
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__ . '/bootstrap.php';
|
||||
require __DIR__ . '/lib/multi_export.php';
|
||||
|
||||
$action = (string)($_GET['action'] ?? $_POST['action'] ?? '');
|
||||
|
||||
@@ -64,6 +65,11 @@ function ny_absent_sheet_rows(array $absent): array
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多考试对比导出(成绩交叉矩阵)的纯逻辑见 lib/multi_export.php
|
||||
* (ny_exam_cell_score / ny_assemble_multi_exam_matrix),便于在 api.php 与单测中复用。
|
||||
*/
|
||||
|
||||
/**
|
||||
* 带短期缓存的数据构建(含并发锁,避免多人同时刷新时重复打卷王造成惊群)
|
||||
*
|
||||
@@ -854,6 +860,48 @@ try {
|
||||
echo $bin;
|
||||
exit;
|
||||
|
||||
// ---------------- 多考试对比导出(横向交叉表) ----------------
|
||||
case 'export_multi':
|
||||
$idsRaw = (string)($_GET['projectIds'] ?? '');
|
||||
$ids = array_values(array_unique(array_filter(
|
||||
array_map('trim', explode(',', $idsRaw)),
|
||||
static fn($v): bool => $v !== ''
|
||||
)));
|
||||
if ($ids === []) {
|
||||
ny_fail('请至少选择一个问卷 / 考试');
|
||||
}
|
||||
$nameQid = (string)($_GET['nameQid'] ?? '');
|
||||
$scoreMode = ((string)($_GET['scoreMode'] ?? '') === 'highest') ? 'highest' : 'latest';
|
||||
$c = cfg();
|
||||
|
||||
// 逐场考试取数(复用与 data 接口相同的缓存),按选择顺序组装交叉矩阵
|
||||
$exams = [];
|
||||
foreach ($ids as $pid) {
|
||||
$built = ny_build_data($c, $pid, $nameQid, !empty($_GET['force']));
|
||||
$result = $built['result'];
|
||||
$exams[$pid] = [
|
||||
'name' => (string)($result['project']['name'] ?? $pid),
|
||||
'rows' => (array)($result['rows'] ?? []),
|
||||
];
|
||||
}
|
||||
|
||||
$matrix = ny_assemble_multi_exam_matrix($exams, $scoreMode);
|
||||
$sheetRows = array_merge([$matrix['head']], $matrix['rows']);
|
||||
$widths = array_merge([20, 14], array_fill(0, count($matrix['exam_order']), 12));
|
||||
$sheets = [['name' => '多考试对比', 'rows' => $sheetRows, 'widths' => $widths]];
|
||||
|
||||
$safe = static fn(string $s): string => preg_replace('/[\\\\\\/:*?"<>|]/u', '_', $s) ?? '';
|
||||
$filename = '多考试成绩对比_' . count($ids) . '场_'
|
||||
. ($scoreMode === 'highest' ? '最高分' : '最新成绩') . '_' . date('Ymd_His') . '.xlsx';
|
||||
$bin = XlsxWriter::renderMulti($sheets);
|
||||
|
||||
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
header('Content-Disposition: attachment; filename="export.xlsx"; filename*=UTF-8\'\'' . rawurlencode($filename));
|
||||
header('Content-Length: ' . strlen($bin));
|
||||
header('Cache-Control: no-store');
|
||||
echo $bin;
|
||||
exit;
|
||||
|
||||
// ---------------- 随机抽取:导出白名单(xlsx,列:姓名 / 登陆账号) ----------------
|
||||
case 'draw_export':
|
||||
$raw = ny_request_body();
|
||||
|
||||
Reference in New Issue
Block a user