|
|
@@ -1,62 +1,95 @@
|
|
|
@php
|
|
|
- // 判题卡项目:保留题号与题目对应方框数(用于OCR锚点+判卷标记)
|
|
|
+ $boxCounter = app(\App\Support\GradingMarkBoxCounter::class);
|
|
|
+ // 按当前试卷真实题目动态生成判题卡条目(题量与方框数)
|
|
|
$scanSheetItems = [];
|
|
|
- $countBlanks = function ($text) {
|
|
|
- $text = (string)$text;
|
|
|
- // 与判卷正文保持一致:下划线、中文空括号、英文空括号
|
|
|
- $count = 0;
|
|
|
- $count += preg_match_all('/_{2,}/u', $text, $m);
|
|
|
- $count += preg_match_all('/(\s*)/u', $text, $m);
|
|
|
- $count += preg_match_all('/\(\s*\)/', $text, $m);
|
|
|
- return max(1, $count);
|
|
|
- };
|
|
|
- $countSteps = function ($text) {
|
|
|
- $text = (string)$text;
|
|
|
- // 与判卷正文保持一致:支持“步骤1”与“第1步”两种写法
|
|
|
- $count = preg_match_all('/(步骤\s*\d+|第\s*\d+\s*步)/u', $text, $m);
|
|
|
- return max(1, $count);
|
|
|
- };
|
|
|
+ $countBlanks = fn($text): int => $boxCounter->countFillBlanks($text);
|
|
|
+ $countSteps = fn($text): int => $boxCounter->countAnswerSteps($text);
|
|
|
|
|
|
foreach (($questions['choice'] ?? []) as $q) {
|
|
|
- $scanSheetItems[] = ['no' => (int)($q->question_number ?? 0), 'box_count' => 1];
|
|
|
+ $scanSheetItems[] = ['no' => (int) ($q->question_number ?? 0), 'box_count' => 1];
|
|
|
}
|
|
|
foreach (($questions['fill'] ?? []) as $q) {
|
|
|
- $scanSheetItems[] = ['no' => (int)($q->question_number ?? 0), 'box_count' => $countBlanks($q->content ?? '')];
|
|
|
+ $scanSheetItems[] = ['no' => (int) ($q->question_number ?? 0), 'box_count' => $countBlanks($q->content ?? '')];
|
|
|
}
|
|
|
foreach (($questions['answer'] ?? []) as $q) {
|
|
|
- $scanSheetItems[] = ['no' => (int)($q->question_number ?? 0), 'box_count' => $countSteps($q->solution ?? '')];
|
|
|
+ $scanSheetItems[] = ['no' => (int) ($q->question_number ?? 0), 'box_count' => $countSteps($q->solution ?? '')];
|
|
|
}
|
|
|
|
|
|
- usort($scanSheetItems, function ($a, $b) {
|
|
|
+ usort($scanSheetItems, static function ($a, $b) {
|
|
|
return ($a['no'] <=> $b['no']);
|
|
|
});
|
|
|
- // 每页容量不是上限20,而是保证至少可容纳20题,并尽量提高单页承载
|
|
|
- $scanSheetPerPage = 24;
|
|
|
- $scanSheetPages = array_chunk($scanSheetItems, $scanSheetPerPage);
|
|
|
+ $scanSheetItems = array_values(array_filter($scanSheetItems, static function ($item) {
|
|
|
+ return (int) ($item['no'] ?? 0) > 0;
|
|
|
+ }));
|
|
|
+
|
|
|
+ $assembleTypeLabel = $pdfMeta['assemble_type_label'] ?? null;
|
|
|
+ $showAssembleType = !empty($assembleTypeLabel) && $assembleTypeLabel !== '未知类型';
|
|
|
+ $scanPaperCode = (string) ($pdfMeta['paper_id_num'] ?? $pdfMeta['exam_code'] ?? '');
|
|
|
+ if ($scanPaperCode === '' && !empty($paper->paper_id)) {
|
|
|
+ $scanPaperCode = preg_replace('/^paper_/', '', (string) $paper->paper_id) ?: (string) $paper->paper_id;
|
|
|
+ }
|
|
|
+
|
|
|
+ $totalItems = count($scanSheetItems);
|
|
|
+ $leftCount = (int) ceil($totalItems / 2);
|
|
|
+ $leftItems = array_slice($scanSheetItems, 0, $leftCount);
|
|
|
+ $rightItems = array_slice($scanSheetItems, $leftCount);
|
|
|
@endphp
|
|
|
-@foreach($scanSheetPages as $pageIndex => $scanSheetPageItems)
|
|
|
- <div class="page scan-sheet-page" style="page-break-before: always; break-before: page; width:100%; max-width:100%; margin:0 auto; padding:0 8px; box-sizing:border-box;">
|
|
|
- <div class="scan-sheet-header" style="text-align:center;margin-bottom:1.5rem;border-bottom:2px solid #000;padding-bottom:1rem;">
|
|
|
- <div style="font-size:22px;font-weight:bold;">判题卡</div>
|
|
|
- <div style="display:flex;justify-content:space-between;font-size:14px;margin-top:8px;">
|
|
|
- <span>老师:{{ $teacher['name'] ?? '________' }}</span>
|
|
|
- <span>年级:@formatGrade($student['grade'] ?? '________')</span>
|
|
|
- <span>姓名:{{ $student['name'] ?? '________' }}</span>
|
|
|
- <span>得分:________</span>
|
|
|
- </div>
|
|
|
+
|
|
|
+<div class="page scan-sheet-page" style="page-break-before: always; break-before: page; width:100%; max-width:100%; margin:0 auto; padding:0 8px; box-sizing:border-box;">
|
|
|
+ <div class="scan-sheet-header" style="text-align:center;margin-bottom:1.5rem;border-bottom:2px solid #000;padding-bottom:1rem;">
|
|
|
+ <div style="font-size:22px;font-weight:bold;">判题卡</div>
|
|
|
+ @if($scanPaperCode !== '')
|
|
|
+ <div class="scan-sheet-paper-code" style="margin-top:6px;font-size:18px;font-weight:700;letter-spacing:0.4px;">{{ $scanPaperCode }}</div>
|
|
|
+ @endif
|
|
|
+ <div style="display:flex;justify-content:space-between;font-size:14px;margin-top:8px;">
|
|
|
+ <span>老师:{{ $teacher['name'] ?? '________' }}</span>
|
|
|
+ <span>年级:@formatGrade($student['grade'] ?? '________')</span>
|
|
|
+ @if($showAssembleType)
|
|
|
+ <span>类型:{{ $assembleTypeLabel }}</span>
|
|
|
+ @endif
|
|
|
+ <span>姓名:{{ $student['name'] ?? '________' }}</span>
|
|
|
+ <span>得分:________</span>
|
|
|
</div>
|
|
|
- <div class="scan-sheet-hint" style="font-size:13px;color:#444;margin-bottom:10px;line-height:1.5;">提示:请根据答案和解析进行批改,在回答正确的 □ 前划 / ,在回答错误的 □ 前打 X 或置空</div>
|
|
|
- <div class="scan-sheet-list" style="display:grid;grid-template-columns:minmax(0,1fr);gap:4px;width:100%;box-sizing:border-box;">
|
|
|
- @foreach($scanSheetPageItems as $scanItem)
|
|
|
- <div class="scan-sheet-item" style="border:1px solid #b5b5b5;border-radius:4px;padding:4px 8px;min-height:28px;display:grid;grid-template-columns:auto 1fr;align-items:center;column-gap:8px;font-size:13px;line-height:1.2;page-break-inside:avoid;break-inside:avoid;width:100%;box-sizing:border-box;">
|
|
|
- <span class="scan-sheet-no" style="font-weight:700;text-align:center;min-width:58px;">题目 {{ $scanItem['no'] > 0 ? $scanItem['no'] : ($pageIndex * $scanSheetPerPage + $loop->iteration) }}.</span>
|
|
|
- <span class="scan-sheet-marks" style="display:flex;align-items:center;gap:4px 6px;justify-content:flex-start;flex-wrap:wrap;max-width:100%;">
|
|
|
- @for($i = 0; $i < max(1, (int)($scanItem['box_count'] ?? 1)); $i++)
|
|
|
- <span class="scan-grade-box" style="width:17px;height:17px;border:1px solid #333;display:inline-block;vertical-align:middle;box-sizing:border-box;"></span>
|
|
|
+ </div>
|
|
|
+ <div class="scan-sheet-hint" style="font-size:14px;color:#444;margin-bottom:14px;line-height:1.5;">提示:请根据答案和解析进行批改,在回答正确的 □ 前划 / ,在回答错误的 □ 前打 X 或置空</div>
|
|
|
+
|
|
|
+ <div class="scan-sheet-two-cols" style="display:flex;align-items:flex-start;gap:18px;">
|
|
|
+ <div class="scan-sheet-col" style="flex:1 1 0;display:grid;row-gap:8px;">
|
|
|
+ @foreach($leftItems as $item)
|
|
|
+ @php
|
|
|
+ $questionNo = (int) ($item['no'] ?? 0);
|
|
|
+ $boxCount = max(1, (int) ($item['box_count'] ?? 1));
|
|
|
+ @endphp
|
|
|
+ <div class="scan-sheet-item" style="display:flex;align-items:center;min-height:24px;">
|
|
|
+ <span class="scan-sheet-no" style="font-weight:700;font-size:14px;line-height:1.2;white-space:nowrap;margin-right:2px;">题目 {{ $questionNo }}.</span>
|
|
|
+ <span class="scan-sheet-marks" style="display:inline-flex;align-items:center;gap:4px;">
|
|
|
+ @for($i = 0; $i < $boxCount; $i++)
|
|
|
+ <span class="scan-grade-box" style="display:inline-block;width:17px;height:17px;border:1px solid #333;box-sizing:border-box;background:#fff;vertical-align:middle;"></span>
|
|
|
+ @endfor
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ @endforeach
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="scan-sheet-col" style="flex:1 1 0;display:grid;row-gap:8px;">
|
|
|
+ @foreach($rightItems as $item)
|
|
|
+ @php
|
|
|
+ $questionNo = (int) ($item['no'] ?? 0);
|
|
|
+ $boxCount = max(1, (int) ($item['box_count'] ?? 1));
|
|
|
+ @endphp
|
|
|
+ <div class="scan-sheet-item" style="display:flex;align-items:center;min-height:24px;">
|
|
|
+ <span class="scan-sheet-no" style="font-weight:700;font-size:14px;line-height:1.2;white-space:nowrap;margin-right:2px;">题目 {{ $questionNo }}.</span>
|
|
|
+ <span class="scan-sheet-marks" style="display:inline-flex;align-items:center;gap:4px;">
|
|
|
+ @for($i = 0; $i < $boxCount; $i++)
|
|
|
+ <span class="scan-grade-box" style="display:inline-block;width:17px;height:17px;border:1px solid #333;box-sizing:border-box;background:#fff;vertical-align:middle;"></span>
|
|
|
@endfor
|
|
|
</span>
|
|
|
</div>
|
|
|
@endforeach
|
|
|
</div>
|
|
|
</div>
|
|
|
-@endforeach
|
|
|
+
|
|
|
+ @if($totalItems === 0)
|
|
|
+ <div class="scan-sheet-empty" style="color:#888;font-size:13px;margin-top:6px;">暂无可渲染题目</div>
|
|
|
+ @endif
|
|
|
+</div>
|