@php
$choiceQuestions = $questions['choice'] ?? [];
$fillQuestions = $questions['fill'] ?? [];
$answerQuestions = $questions['answer'] ?? [];
$gradingMode = $grading ?? false;
// 计算填空空格数量
$countBlanks = function($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) {
$matches = [];
$cnt = preg_match_all('/第\s*\d+\s*步/u', $text ?? '', $matches);
return max(1, $cnt);
};
$renderBoxes = function($num) {
// 判卷方框放大 1.2 倍,保持单行布局
return str_repeat('', $num);
};
@endphp
一、选择题
@if(count($choiceQuestions) > 0)
@php
$choiceTotal = array_sum(array_map(fn($q) => $q->score ?? 5, $choiceQuestions));
@endphp
(本大题共 {{ count($choiceQuestions) }} 小题,共 {{ $choiceTotal }} 分)
@else
(本大题共 0 小题,共 0 分)
@endif
@if(count($choiceQuestions) > 0)
@foreach($choiceQuestions as $index => $q)
@php
$questionNumber = $index + 1;
$cleanContent = preg_replace('/^\d+[\.、]\s*/', '', $q->content);
$cleanContent = trim($cleanContent);
$options = $q->options ?? [];
if (empty($options)) {
$pattern = '/([A-D])[\.、:.:]\s*(.+?)(?=\s*[A-D][\.、:.:]|$)/su';
if (preg_match_all($pattern, $cleanContent, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$optionText = trim($match[2]);
if (!empty($optionText)) {
$options[] = $optionText;
}
}
}
}
$stemLine = $cleanContent;
if (!empty($options)) {
if (preg_match('/^(.+?)(?=[A-D][\.、:.:])/su', $cleanContent, $stemMatch)) {
$stemLine = trim($stemMatch[1]);
}
}
// 将题干中的空括号/下划线替换为短波浪线;如无占位符,则在末尾追加短波浪线
$blankSpan = ' ';
$renderedStem = preg_replace(['/((\s*))/u', '/\(\s*\)/', '/_{2,}/'], $blankSpan, $stemLine);
if ($renderedStem === $stemLine) {
$renderedStem .= ' ' . $blankSpan;
}
$renderedStem = \App\Services\MathFormulaProcessor::processFormulas($renderedStem);
@endphp
@if($gradingMode)
{!! $renderBoxes(1) !!}
@endif
{{ $gradingMode ? '题目 ' : '' }}{{ $questionNumber }}.
{!! $renderedStem !!}
@if(!empty($options))
@php
$optCount = count($options);
$optionsClass = $optCount <= 4 ? 'options-grid-2' : 'options';
@endphp
@foreach($options as $optIndex => $opt)
@php $label = chr(65 + $optIndex); @endphp
{{ $label }}. {!! \App\Services\MathFormulaProcessor::processFormulas($opt) !!}
@endforeach
@endif
@if($gradingMode)
@php
$solutionText = trim($q->solution ?? '');
// 去掉前置的“解题思路”标签,避免出现“解题思路:【解题思路】”重复
$solutionText = preg_replace('/^【?\s*解题思路\s*】?\s*[::]?\s*/u', '', $solutionText);
$solutionHtml = $solutionText === ''
? '
(暂无解题思路)'
: \App\Services\MathFormulaProcessor::processFormulas($solutionText);
@endphp
@endif
@endforeach
@else
@endif
二、填空题
@if(count($fillQuestions) > 0)
@php
$fillTotal = array_sum(array_map(fn($q) => $q->score ?? 5, $fillQuestions));
@endphp
(本大题共 {{ count($fillQuestions) }} 小题,共 {{ $fillTotal }} 分)
@else
(本大题共 0 小题,共 0 分)
@endif
@if(count($fillQuestions) > 0)
@foreach($fillQuestions as $index => $q)
@php
$questionNumber = count($choiceQuestions) + $index + 1;
$blankSpan = ' ';
$renderedContent = preg_replace(['/((\s*))/u', '/\(\s*\)/', '/_{2,}/'], $blankSpan, $q->content);
if ($renderedContent === $q->content) {
$renderedContent .= ' ' . $blankSpan;
}
$renderedContent = \App\Services\MathFormulaProcessor::processFormulas($renderedContent);
@endphp
@if($gradingMode)
{!! $renderBoxes($countBlanks($q->content ?? '')) !!}
@endif
{{ $gradingMode ? '题目 ' : '' }}{{ $questionNumber }}.
{!! $renderedContent !!}
@if($gradingMode)
@php
$solutionText = trim($q->solution ?? '');
// 去掉前置的“解题思路”标签,避免出现“解题思路:【解题思路】”重复
$solutionText = preg_replace('/^【?\s*解题思路\s*】?\s*[::]?\s*/u', '', $solutionText);
$solutionHtml = $solutionText === ''
? '
(暂无解题思路)'
: \App\Services\MathFormulaProcessor::processFormulas($solutionText);
@endphp
@endif
@endforeach
@else
@endif
三、解答题
@if(count($answerQuestions) > 0)
(本大题共 {{ count($answerQuestions) }} 小题,共 {{ array_sum(array_column($answerQuestions, 'score')) }} 分。解答应写出文字说明、证明过程或演算步骤)
@else
(本大题共 0 小题,共 0 分)
@endif
@if(count($answerQuestions) > 0)
@foreach($answerQuestions as $index => $q)
@php
$questionNumber = count($choiceQuestions) + count($fillQuestions) + $index + 1;
@endphp
{{ $gradingMode ? '题目 ' : '' }}{{ $questionNumber }}.
@unless($gradingMode)
(本小题满分 {{ $q->score ?? 10 }} 分)
@endunless
{!! \App\Services\MathFormulaProcessor::processFormulas($q->content) !!}
@unless($gradingMode)
作答
@endunless
@if($gradingMode)
@php
$solutionRaw = $q->solution ?? '';
$solutionProcessed = \App\Services\MathFormulaProcessor::processFormulas($solutionRaw);
// 去掉分步得分等分值标记
$solutionProcessed = preg_replace('/(\s*\d+\s*分\s*)/u', '', $solutionProcessed);
// 优化解析分段格式
$solutionProcessed = preg_replace('/【(解题思路|详细解答|最终答案)】/u', "\n\n【$1】\n\n", $solutionProcessed);
$solutionProcessed = preg_replace('/^【(解题思路|详细解答|最终答案)】\n\n/u', '
【$1】
', $solutionProcessed);
$solutionProcessed = preg_replace('/\n\n【(解题思路|详细解答|最终答案)】\n\n/u', '
【$1】', $solutionProcessed);
$solutionProcessed = preg_replace('/\n\n/u', '
', $solutionProcessed);
// 为每个"第 N 步"前添加方框;若没有,则在【详细解答】段落开头添加一个方框
if (preg_match('/第\s*\d+\s*步/u', $solutionProcessed)) {
$solutionProcessed = preg_replace_callback('/第\s*\d+\s*步/u', function($m) use ($renderBoxes) {
return '
' . $renderBoxes(1) . '' . $m[0] . '';
}, $solutionProcessed);
} else {
// 在【详细解答】标题后追加方框;若无标题则在正文最前补一个
$injected = false;
$count = 0;
$solutionProcessed = preg_replace(
'/(
【详细解答】<\/strong>
)/u',
'$1' . '' . $renderBoxes(1) . ' ',
$solutionProcessed,
1,
$count
);
if (!empty($count)) {
$injected = true;
}
if (!$injected) {
$solutionProcessed = '' . $renderBoxes(1) . ' ' . ltrim($solutionProcessed);
}
}
@endphp
@endif
@endforeach
@else
@endif