@php $choiceQuestions = $questions['choice'] ?? []; $fillQuestions = $questions['fill'] ?? []; $answerQuestions = $questions['answer'] ?? []; $stepPattern = '(步骤\s*[0-9一二三四五六七八九十百零两]+\s*[::]?|第\s*[0-9一二三四五六七八九十百零两]+\s*步\s*[::]?)'; $allQuestions = collect() ->concat(collect($choiceQuestions)->map(fn ($q) => ['q' => $q, 'detail_type' => 'choice'])) ->concat(collect($fillQuestions)->map(fn ($q) => ['q' => $q, 'detail_type' => 'fill'])) ->concat(collect($answerQuestions)->map(fn ($q) => ['q' => $q, 'detail_type' => 'answer'])) ->sortBy(fn ($item) => (int) (($item['q']->question_number ?? 0))) ->values(); $normalizeQuickAnswer = function (?string $answer): string { $answer = trim((string) $answer); if ($answer === '') { return '—'; } $answer = preg_replace('/\s+/u', ' ', $answer) ?? $answer; $answer = str_replace([';', ';'], ' / ', $answer); return trim($answer); }; $quickAnswers = $allQuestions->map(function ($item) use ($normalizeQuickAnswer) { $q = $item['q']; $answerText = $normalizeQuickAnswer($q->answer ?? ''); $isLong = mb_strlen(strip_tags($answerText)) > 20 || str_contains($answerText, "\n") || str_contains($answerText, "\r") || str_contains($answerText, '{') || str_contains($answerText, '\\frac') || str_contains($answerText, '见解析'); $processedAnswer = \App\Services\MathFormulaProcessor::processFormulas($answerText); // 速查统一为流式:移除显式换行 $processedAnswer = preg_replace('//iu', ' ', $processedAnswer) ?? $processedAnswer; return [ 'no' => (int) ($q->question_number ?? 0), 'answer' => $processedAnswer, 'long' => $isLong, ]; })->values(); $normalizeDetailHtml = function (?string $text): string { $text = trim((string) $text); if ($text === '') { return ''; } // 兼容历史/AI返回的非标准图片标签,统一转为标准 $text = preg_replace('/<\s*image\b/iu', '/iu', '', $text) ?? $text; // 兼容被裁掉 "<" 的图片标签文本:img src="..."/> $text = preg_replace('/(^|[\s>])img\s+src\s*=\s*([\'"][^\'"]+[\'"])\s*\/?>/iu', '$1', $text) ?? $text; $text = preg_replace('/font-size\s*:[^;"]+;?/iu', '', $text) ?? $text; $text = preg_replace('/line-height\s*:[^;"]+;?/iu', '', $text) ?? $text; $text = preg_replace('/style\s*=\s*([\'"])\s*\1/iu', '', $text) ?? $text; return $text; }; $formatDetailForReadability = function (?string $text) use ($stepPattern): string { $text = trim((string) $text); if ($text === '') { return ''; } // 仅做轻量分行:遇到“步骤X”时换行,避免整段拥挤 $text = preg_replace('/\s*(' . $stepPattern . ')/u', '
$1', $text) ?? $text; // 软换行点:分号后允许优先换行,缓解长公式串拥挤 $text = str_replace([';', ';'], [';', ';'], $text); // 轻量语义断点:在“则/故/所以”前给换行机会,避免整段公式堆在一行 $text = preg_replace('/,\s*(则|故|所以)/u', ',
$1', $text) ?? $text; // 清理重复换行 $text = preg_replace('/(?:
\s*){2,}/u', '
', $text) ?? $text; // 仅移除前导
标签,避免把 这类标签的起始 "<" 误删 return preg_replace('/^(?:\s*\s*)+/iu', '', $text) ?? $text; }; $renderSolutionLikeGrading = function (string $solutionHtml, bool $withStepBoxes = false) use ($stepPattern): string { $solution = trim($solutionHtml); if ($solution === '' || $solution === '(无详解)') { return $solutionHtml; } // 去掉分步得分等分值标记(与判卷页一致) $solution = preg_replace('/(\s*\d+\s*分\s*)/u', '', $solution) ?? $solution; // 与判卷页一致:先做“解题思路/解题过程”等分段 $solution = preg_replace('/【(解题思路|详细解答|最终答案)】/u', "\n\n===SECTION_START===\n【$1】\n===SECTION_END===\n\n", $solution) ?? $solution; $solution = preg_replace('/(解题过程\s*[^:\n]*:)/u', "\n\n===SECTION_START===\n【解题过程】\n===SECTION_END===\n\n", $solution) ?? $solution; $sections = explode('===SECTION_START===', $solution); $processedSections = []; foreach ($sections as $section) { if (trim((string) $section) === '') { continue; } $section = str_replace('===SECTION_END===', '', $section); if (preg_match('/【(解题思路|详细解答|最终答案|解题过程)】/u', $section, $matches)) { $sectionTitle = $matches[0]; $sectionContent = preg_replace('/【(解题思路|详细解答|最终答案|解题过程)】/u', '', $section) ?? $section; if ($withStepBoxes) { if (preg_match('/' . $stepPattern . '/u', $sectionContent)) { $parts = preg_split('/(?=' . $stepPattern . ')/u', $sectionContent, -1, PREG_SPLIT_NO_EMPTY) ?: []; $processed = ''; foreach ($parts as $index => $part) { $stepText = trim((string) $part); if ($stepText === '') { continue; } $prefix = $index > 0 ? '
' : ''; $isStep = preg_match('/^' . $stepPattern . '/u', $stepText); if ($isStep) { $processed .= $prefix . '' . $stepText . ''; } else { $processed .= $prefix . '' . $stepText . ''; } } $sectionContent = $processed; } else { $sectionContent = '  ' . trim((string) $sectionContent); } } $processedSections[] = '
' . $sectionTitle . '
' . $sectionContent . '
'; } else { $processedSections[] = $section; } } $solution = implode('', $processedSections); if ($withStepBoxes && (empty($processedSections) || (count($processedSections) === 1 && !str_contains($processedSections[0] ?? '', 'step-box')))) { if (preg_match('/' . $stepPattern . '/u', $solution)) { $parts = preg_split('/(?=' . $stepPattern . ')/u', $solution, -1, PREG_SPLIT_NO_EMPTY) ?: []; $processed = ''; foreach ($parts as $index => $part) { $stepText = trim((string) $part); if ($stepText === '') { continue; } $prefix = $index > 0 ? '
' : ''; $isStep = preg_match('/^' . $stepPattern . '/u', $stepText); if ($isStep) { $processed .= $prefix . '' . $stepText . ''; } else { $processed .= $prefix . '' . $stepText . ''; } } $solution = $processed; } else { $solution = '' . trim((string) $solution) . ''; } } $solution = preg_replace('/\n{3,}/u', "\n\n", $solution) ?? $solution; return nl2br($solution); }; @endphp
答案速查
@foreach($quickAnswers as $item) {{ $item['no'] }}. {!! $item['answer'] !!} @endforeach
@foreach($allQuestions as $item) @php $q = $item['q']; $no = (int) ($q->question_number ?? 0); $detailType = strtolower((string) ($item['detail_type'] ?? '')); $isAnswerType = $detailType === 'answer'; $rawAnswer = trim((string) ($q->answer ?? '')); $rawSolution = $normalizeDetailHtml($q->solution ?? ''); $isSeeSolutionAnswer = (bool) preg_match('/^见\s*解析[。\.]?$|^详见解析/u', $rawAnswer); $hasImageLikeSolution = (bool) preg_match('/<\s*img\b|<\s*image\b|(^|[\s>])img\s+src\s*=/iu', $rawSolution); $showAnswer = !$isSeeSolutionAnswer; $renderAnswer = $rawAnswer !== '' ? \App\Services\MathFormulaProcessor::processFormulas($rawAnswer) : '—'; if ($rawSolution === '') { $renderSolution = '(无详解)'; } elseif ($hasImageLikeSolution) { // 与判卷页保持一致:图片型解析优先保留原始HTML结构,避免标签被公式处理链打散为纯文本 $renderSolution = $formatDetailForReadability($rawSolution); } else { $renderSolution = \App\Services\MathFormulaProcessor::processFormulas($formatDetailForReadability($rawSolution)); } if ($isAnswerType) { $renderSolution = $renderSolutionLikeGrading($renderSolution, true); } else { $renderSolution = $renderSolutionLikeGrading($renderSolution, false); } // 版式规则: // 1) 选择/填空同行 // 2) 简答默认解析另起一行 // 3) 若答案为“见解析”被隐藏,则题号与【解析】同行 $useSplitAnalysisLine = $isAnswerType && $showAnswer; @endphp
@if($useSplitAnalysisLine)
{{ $no }}. {!! $renderAnswer !!}
【解析】 {!! $renderSolution !!}
@else
{{ $no }}. @if($showAnswer) {!! $renderAnswer !!} @endif 【解析】 {!! $renderSolution !!}
@endif
@endforeach