|
@@ -7,6 +7,8 @@
|
|
|
|
|
|
|
|
// 【修复】从insights中获取AI分析结果(而不是从analysis_data)
|
|
// 【修复】从insights中获取AI分析结果(而不是从analysis_data)
|
|
|
$questionAnalysis = $insights ?? [];
|
|
$questionAnalysis = $insights ?? [];
|
|
|
|
|
+ // 生成时间(格式:2026年01月30日 15:04:05)
|
|
|
|
|
+ $generateDateTime = now()->format('Y年m月d日 H:i:s');
|
|
|
@endphp
|
|
@endphp
|
|
|
<!DOCTYPE html>
|
|
<!DOCTYPE html>
|
|
|
<html lang="zh-CN">
|
|
<html lang="zh-CN">
|
|
@@ -17,25 +19,35 @@
|
|
|
<style>
|
|
<style>
|
|
|
@page {
|
|
@page {
|
|
|
size: A4;
|
|
size: A4;
|
|
|
- margin: 1.5cm 1.5cm 2cm 1.5cm;
|
|
|
|
|
|
|
+ margin: 2.2cm 2cm 2.3cm 2cm;
|
|
|
@top-left {
|
|
@top-left {
|
|
|
- content: "知了数学";
|
|
|
|
|
- font-size: 10px;
|
|
|
|
|
|
|
+ content: "知了数学·{{ $generateDateTime }}";
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ }
|
|
|
|
|
+ @top-center {
|
|
|
|
|
+ content: "{{ $student['name'] ?? '-' }}";
|
|
|
|
|
+ font-size: 13px;
|
|
|
color: #666;
|
|
color: #666;
|
|
|
}
|
|
}
|
|
|
@top-right {
|
|
@top-right {
|
|
|
content: "{{ $reportCode }}";
|
|
content: "{{ $reportCode }}";
|
|
|
- font-size: 10px;
|
|
|
|
|
- color: #666;
|
|
|
|
|
|
|
+ font-size: 19px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ font-family: "Noto Sans", "Liberation Sans", "Nimbus Sans", sans-serif;
|
|
|
|
|
+ letter-spacing: 0;
|
|
|
|
|
+ padding-right: 3mm;
|
|
|
|
|
+ padding-top: 1.8mm;
|
|
|
|
|
+ color: #222;
|
|
|
}
|
|
}
|
|
|
@bottom-left {
|
|
@bottom-left {
|
|
|
content: "{{ $reportCode }}";
|
|
content: "{{ $reportCode }}";
|
|
|
- font-size: 10px;
|
|
|
|
|
|
|
+ font-size: 11px;
|
|
|
color: #666;
|
|
color: #666;
|
|
|
}
|
|
}
|
|
|
@bottom-right {
|
|
@bottom-right {
|
|
|
content: counter(page) "/" counter(pages);
|
|
content: counter(page) "/" counter(pages);
|
|
|
- font-size: 10px;
|
|
|
|
|
|
|
+ font-size: 13px;
|
|
|
color: #666;
|
|
color: #666;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -51,9 +63,8 @@
|
|
|
}
|
|
}
|
|
|
h1, h2, h3 { margin: 0; color: #000; }
|
|
h1, h2, h3 { margin: 0; color: #000; }
|
|
|
.card { background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px 16px; margin-bottom: 12px; box-shadow: 0 2px 8px rgba(15, 23, 42, 0.04); }
|
|
.card { background: #fff; border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px 16px; margin-bottom: 12px; box-shadow: 0 2px 8px rgba(15, 23, 42, 0.04); }
|
|
|
- .header { text-align: center; margin-bottom: 1rem; border-bottom: 2px solid #000; padding-bottom: 0.5rem; }
|
|
|
|
|
- .school-name { font-size: 24px; font-weight: bold; margin-bottom: 10px; }
|
|
|
|
|
- .paper-title { font-size: 20px; font-weight: bold; margin-bottom: 15px; }
|
|
|
|
|
|
|
+ .header { text-align: center; margin-bottom: 1.5rem; border-bottom: 2px solid #000; padding-bottom: 1rem; }
|
|
|
|
|
+ .paper-title { font-size: 22px; font-weight: bold; margin-bottom: 14px; }
|
|
|
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
|
|
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
|
|
|
.tag { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px; color: #374151; background: #e5e7eb; }
|
|
.tag { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px; color: #374151; background: #e5e7eb; }
|
|
|
.section-title { font-size: 16px; margin-bottom: 10px; display: flex; align-items: center; gap: 8px; }
|
|
.section-title { font-size: 16px; margin-bottom: 10px; display: flex; align-items: center; gap: 8px; }
|
|
@@ -68,22 +79,143 @@
|
|
|
.progress-wrap { background: #f3f4f6; border-radius: 999px; overflow: hidden; height: 10px; }
|
|
.progress-wrap { background: #f3f4f6; border-radius: 999px; overflow: hidden; height: 10px; }
|
|
|
.progress-bar { height: 100%; background: linear-gradient(90deg, #4f46e5, #10b981); }
|
|
.progress-bar { height: 100%; background: linear-gradient(90deg, #4f46e5, #10b981); }
|
|
|
.recommend-card { border: 1px dashed #cbd5e1; border-radius: 10px; padding: 10px 12px; margin-bottom: 8px; background: #f8fafc; }
|
|
.recommend-card { border: 1px dashed #cbd5e1; border-radius: 10px; padding: 10px 12px; margin-bottom: 8px; background: #f8fafc; }
|
|
|
|
|
+ .relation-board { margin: 6px 0 10px; padding: 10px 12px; border: 1px solid #e2e8f0; border-radius: 8px; background: #f8fafc; }
|
|
|
|
|
+ .relation-block { margin-bottom: 10px; padding: 8px; border: 1px solid #dbeafe; border-radius: 8px; background: #fff; }
|
|
|
|
|
+ .tree-cards { width: 100%; border-collapse: collapse; table-layout: fixed; }
|
|
|
|
|
+ .tree-cards td { border: none; padding: 0; vertical-align: top; }
|
|
|
|
|
+ .tree-left { width: 45%; padding-right: 10px; }
|
|
|
|
|
+ .tree-right { width: 55%; padding-left: 10px; }
|
|
|
|
|
+ .tree-parent {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ margin-bottom: 6px;
|
|
|
|
|
+ padding: 4px 8px;
|
|
|
|
|
+ border-radius: 999px;
|
|
|
|
|
+ border: 1px solid #93c5fd;
|
|
|
|
|
+ background: #dbeafe;
|
|
|
|
|
+ color: #1e3a8a;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .tree-lines { margin: 0; padding-left: 14px; border-left: 2px solid #cbd5e1; }
|
|
|
|
|
+ .tree-line {
|
|
|
|
|
+ font-size: 11px;
|
|
|
|
|
+ color: #334155;
|
|
|
|
|
+ margin-bottom: 3px;
|
|
|
|
|
+ white-space: normal;
|
|
|
|
|
+ overflow: visible;
|
|
|
|
|
+ text-overflow: clip;
|
|
|
|
|
+ word-break: break-all;
|
|
|
|
|
+ line-height: 1.45;
|
|
|
|
|
+ }
|
|
|
|
|
+ .tree-line.hit { font-weight: 700; color: #1d4ed8; }
|
|
|
|
|
+ .tree-line-badge { display: inline-block; margin-left: 6px; padding: 1px 5px; border-radius: 999px; font-size: 10px; border: 1px solid transparent; }
|
|
|
|
|
+ .tree-line-badge.high { background: #ecfdf3; color: #15803d; border-color: #86efac; }
|
|
|
|
|
+ .tree-line-badge.mid { background: #fffbeb; color: #b45309; border-color: #fcd34d; }
|
|
|
|
|
+ .tree-line-badge.low { background: #fef2f2; color: #b91c1c; border-color: #fca5a5; }
|
|
|
|
|
+ .tree-line-badge.miss { background: #f3f4f6; color: #6b7280; border-color: #d1d5db; }
|
|
|
|
|
+ .detail-card {
|
|
|
|
|
+ border: 1px solid #e2e8f0;
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ background: #f8fafc;
|
|
|
|
|
+ padding: 6px 8px;
|
|
|
|
|
+ margin-bottom: 5px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .detail-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
|
|
|
|
|
+ .detail-title { font-size: 11px; color: #0f172a; font-weight: 700; margin-bottom: 2px; }
|
|
|
|
|
+ .detail-meta { font-size: 11px; color: #475569; margin-top: 3px; }
|
|
|
|
|
+ .detail-mastery { font-size: 38px; color: #0f172a; font-weight: 700; line-height: 1; margin: 0; }
|
|
|
|
|
+ .detail-mastery.high { color: #16a34a; }
|
|
|
|
|
+ .detail-mastery.mid { color: #d97706; }
|
|
|
|
|
+ .detail-mastery.low { color: #dc2626; }
|
|
|
|
|
+ .node-tags { margin-top: 2px; }
|
|
|
|
|
+ .node-tag {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ margin: 0 6px 6px 0;
|
|
|
|
|
+ padding: 1px 7px;
|
|
|
|
|
+ border-radius: 999px;
|
|
|
|
|
+ font-size: 10px;
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+ color: #475569;
|
|
|
|
|
+ background: #f1f5f9;
|
|
|
|
|
+ border: 1px solid #cbd5e1;
|
|
|
|
|
+ }
|
|
|
|
|
+ .suggest-tags { display: inline; }
|
|
|
|
|
+ .suggest-tag {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ margin: 0 6px 6px 0;
|
|
|
|
|
+ padding: 1px 7px;
|
|
|
|
|
+ border-radius: 999px;
|
|
|
|
|
+ font-size: 10px;
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+ color: #334155;
|
|
|
|
|
+ background: #f8fafc;
|
|
|
|
|
+ border: 1px solid #d1d5db;
|
|
|
|
|
+ }
|
|
|
|
|
+ .weak-kp-tags { margin-top: 6px; }
|
|
|
|
|
+ .weak-kp-tag {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ margin: 0 6px 6px 0;
|
|
|
|
|
+ padding: 1px 7px;
|
|
|
|
|
+ border-radius: 999px;
|
|
|
|
|
+ font-size: 10px;
|
|
|
|
|
+ line-height: 1.45;
|
|
|
|
|
+ color: #854d0e;
|
|
|
|
|
+ background: #fef3c7;
|
|
|
|
|
+ border: 1px solid #fcd34d;
|
|
|
|
|
+ }
|
|
|
|
|
+ .error-kp-tag {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ margin: 0 6px 6px 0;
|
|
|
|
|
+ padding: 1px 7px;
|
|
|
|
|
+ border-radius: 999px;
|
|
|
|
|
+ font-size: 10px;
|
|
|
|
|
+ line-height: 1.45;
|
|
|
|
|
+ color: #334155;
|
|
|
|
|
+ background: #f8fafc;
|
|
|
|
|
+ border: 1px solid #d1d5db;
|
|
|
|
|
+ }
|
|
|
|
|
+ .error-kp-tag.high-risk {
|
|
|
|
|
+ color: #b91c1c;
|
|
|
|
|
+ border-color: #fca5a5;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ }
|
|
|
|
|
+ .detail-change-up { color: #16a34a; font-weight: 700; }
|
|
|
|
|
+ .detail-change-down { color: #dc2626; font-weight: 700; }
|
|
|
|
|
+ .aggregate-tip { font-size: 11px; color: #475569; margin-top: 6px; }
|
|
|
|
|
+ .question-card { border:1px solid #e5e7eb; border-radius:8px; padding:6px 9px; margin-bottom:5px; background:#fff; page-break-inside: auto; break-inside: auto; }
|
|
|
|
|
+ .question-block { margin-bottom: 5px; padding: 5px; border-radius: 4px; }
|
|
|
|
|
+ .solution-content {
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ line-height: 1.75;
|
|
|
|
|
+ white-space: normal;
|
|
|
|
|
+ word-break: break-word;
|
|
|
|
|
+ }
|
|
|
</style>
|
|
</style>
|
|
|
</head>
|
|
</head>
|
|
|
<body>
|
|
<body>
|
|
|
<div class="page">
|
|
<div class="page">
|
|
|
<div class="header">
|
|
<div class="header">
|
|
|
<h1 class="paper-title">学情分析报告</h1>
|
|
<h1 class="paper-title">学情分析报告</h1>
|
|
|
- <div style="margin-top: 10px; font-size: 14px;">
|
|
|
|
|
- 试卷:{{ $paper['name'] ?? '-' }} | 学生:{{ $student['name'] ?? '-' }} | 年级:{{ $student['grade'] ?? '-' }}
|
|
|
|
|
- </div>
|
|
|
|
|
- <div style="margin-top: 6px; font-size: 14px;">
|
|
|
|
|
- 题目数:{{ is_array($questions ?? null) ? count($questions) : ($paper['total_questions'] ?? '-') }}
|
|
|
|
|
|
|
+ @php
|
|
|
|
|
+ $teacherName = trim((string) ($teacher['name'] ?? ''));
|
|
|
|
|
+ $showTeacher = $teacherName !== '' && $teacherName !== '________' && $teacherName !== '未知老师';
|
|
|
|
|
+ @endphp
|
|
|
|
|
+ <div style="display:flex;justify-content:space-between;font-size:14px;margin-top:8px;">
|
|
|
|
|
+ @if($showTeacher)
|
|
|
|
|
+ <span>老师:{{ $teacherName }}</span>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ <span>年级:@formatGrade($student['grade'] ?? '________')</span>
|
|
|
|
|
+ @if(!empty($paper['assemble_type_label']) && $paper['assemble_type_label'] !== '未知类型')
|
|
|
|
|
+ <span>类型:{{ $paper['assemble_type_label'] }}</span>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ <span>姓名:{{ $student['name'] ?? '________' }}</span>
|
|
|
|
|
+ <span>题目数:{{ $paper['total_questions'] ?? (is_array($questions ?? null) ? count($questions) : '-') }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="card">
|
|
<div class="card">
|
|
|
- <div class="section-title">知识点掌握度</div>
|
|
|
|
|
|
|
+ <div class="section-title">本次命中子知识点掌握度</div>
|
|
|
@php
|
|
@php
|
|
|
// 【修复】过滤掉K-GENERAL等通用知识点,只显示有值的知识点
|
|
// 【修复】过滤掉K-GENERAL等通用知识点,只显示有值的知识点
|
|
|
$filteredMasteryItems = [];
|
|
$filteredMasteryItems = [];
|
|
@@ -117,7 +249,7 @@
|
|
|
<div style="font-weight: 600; font-size: 14px;">{{ $item['kp_name'] ?? $item['kp_code'] ?? '未知知识点' }}</div>
|
|
<div style="font-weight: 600; font-size: 14px;">{{ $item['kp_name'] ?? $item['kp_code'] ?? '未知知识点' }}</div>
|
|
|
<div style="font-weight: 600; color: {{ $barColor }}; font-size: 14px;">
|
|
<div style="font-weight: 600; color: {{ $barColor }}; font-size: 14px;">
|
|
|
{{ number_format($pct, 1) }}%
|
|
{{ number_format($pct, 1) }}%
|
|
|
- <span style="margin-left: 8px; color: #666; font-size: 12px;">{{ $changeText }}</span>
|
|
|
|
|
|
|
+ <span style="margin-left: 8px; color: #666; font-size: 12px;">{{ $changeText ? '子节点变化 ' . $changeText : '' }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="progress-wrap" style="height: 12px;">
|
|
<div class="progress-wrap" style="height: 12px;">
|
|
@@ -135,67 +267,177 @@
|
|
|
@php
|
|
@php
|
|
|
$parentMasteryLevels = $parent_mastery_levels ?? [];
|
|
$parentMasteryLevels = $parent_mastery_levels ?? [];
|
|
|
$hasParentMastery = !empty($parentMasteryLevels);
|
|
$hasParentMastery = !empty($parentMasteryLevels);
|
|
|
|
|
+ $childMasteryMap = [];
|
|
|
|
|
+ foreach (($filteredMasteryItems ?? []) as $it) {
|
|
|
|
|
+ $childMasteryMap[$it['kp_code']] = [
|
|
|
|
|
+ 'level' => floatval($it['mastery_level'] ?? 0),
|
|
|
|
|
+ 'delta' => isset($it['mastery_change']) ? floatval($it['mastery_change']) : null,
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
@endphp
|
|
@endphp
|
|
|
|
|
|
|
|
@if($hasParentMastery)
|
|
@if($hasParentMastery)
|
|
|
- @foreach($parentMasteryLevels as $parentData)
|
|
|
|
|
- @php
|
|
|
|
|
- $pct = $parentData['mastery_percentage'] ?? 0;
|
|
|
|
|
- $barColor = $pct >= 80 ? '#10b981' : ($pct >= 60 ? '#f59e0b' : '#ef4444');
|
|
|
|
|
- $parentName = $parentData['kp_name'] ?? $parentData['kp_code'];
|
|
|
|
|
- $children = $parentData['children'] ?? [];
|
|
|
|
|
- $level = $parentData['level'] ?? 1;
|
|
|
|
|
- $delta = $parentData['mastery_change'] ?? null;
|
|
|
|
|
- // 只有当有变化值时才显示变化信息
|
|
|
|
|
- $changeText = '';
|
|
|
|
|
- if ($delta !== null && $delta !== '' && abs($delta) > 0.001) {
|
|
|
|
|
- $changeText = ($delta > 0 ? '↑ ' : '↓ ') . number_format(abs($delta) * 100, 1) . '%';
|
|
|
|
|
- }
|
|
|
|
|
- @endphp
|
|
|
|
|
- <div style="margin-bottom: 14px; padding: 10px; border: 1px solid #e0f2fe; border-radius: 6px; background: #f8fafc;">
|
|
|
|
|
- <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom: 8px;">
|
|
|
|
|
- <div style="font-weight: 700; font-size: 15px; color: #0f172a;">
|
|
|
|
|
- 【第{{ $level }}级】{{ $parentName }}
|
|
|
|
|
- <span style="margin-left: 8px; font-size: 11px; color: #64748b; font-weight: 400;">
|
|
|
|
|
- ({{ $parentData['kp_code'] }})
|
|
|
|
|
- </span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div style="font-weight: 700; color: {{ $barColor }}; font-size: 15px;">
|
|
|
|
|
- {{ number_format($pct, 1) }}%
|
|
|
|
|
- @if(!empty($changeText))
|
|
|
|
|
- <span style="margin-left: 8px; color: #666; font-size: 12px;">{{ $changeText }}</span>
|
|
|
|
|
- @endif
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="progress-wrap" style="height: 12px; margin-bottom: 8px;">
|
|
|
|
|
- <div class="progress-bar" style="width: {{ $pct }}%; background: {{ $barColor }};"></div>
|
|
|
|
|
|
|
+ <div class="relation-board">
|
|
|
|
|
+ <div style="font-size:12px; color:#334155; margin-bottom:6px; font-weight:600;">父子知识点关系</div>
|
|
|
|
|
+ @foreach($parentMasteryLevels as $parentData)
|
|
|
|
|
+ @php
|
|
|
|
|
+ $childrenAll = $parentData['children_all'] ?? [];
|
|
|
|
|
+ $children = $parentData['children'] ?? []; // 命中子节点
|
|
|
|
|
+ $childCount = count($childrenAll);
|
|
|
|
|
+ $hitCount = count($children);
|
|
|
|
|
+ $hitAvg = $parentData['children_hit_avg_mastery'] ?? null;
|
|
|
|
|
+ $parentPct = number_format(floatval($parentData['mastery_percentage'] ?? 0), 1);
|
|
|
|
|
+ $parentLevel = floatval($parentData['mastery_level'] ?? 0);
|
|
|
|
|
+ $parentClass = $parentLevel >= 0.8 ? 'high' : ($parentLevel >= 0.6 ? 'mid' : 'low');
|
|
|
|
|
+ $delta = $parentData['mastery_change'] ?? null;
|
|
|
|
|
+ $hitNames = array_values(array_map(fn($c) => $c['kp_name'] ?? ($c['kp_code'] ?? ''), $children));
|
|
|
|
|
+ $allChildrenPerfect = !empty($childrenAll) && count(array_filter($childrenAll, function ($c) {
|
|
|
|
|
+ return floatval($c['mastery_level'] ?? 0) >= 0.999;
|
|
|
|
|
+ })) === count($childrenAll);
|
|
|
|
|
+ @endphp
|
|
|
|
|
+ <div class="relation-block">
|
|
|
|
|
+ <table class="tree-cards">
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <td class="tree-left">
|
|
|
|
|
+ <div class="tree-parent">{{ $parentData['kp_name'] ?? $parentData['kp_code'] }}</div>
|
|
|
|
|
+ @if(!empty($childrenAll))
|
|
|
|
|
+ <div class="tree-lines">
|
|
|
|
|
+ @foreach($childrenAll as $child)
|
|
|
|
|
+ @php
|
|
|
|
|
+ $isHit = !empty($child['is_hit']);
|
|
|
|
|
+ $m = floatval($child['mastery_level'] ?? 0);
|
|
|
|
|
+ $badgeClass = $m >= 0.8 ? 'high' : ($m >= 0.6 ? 'mid' : ($m > 0 ? 'low' : 'miss'));
|
|
|
|
|
+ $badgeText = number_format($m * 100, 1) . '%';
|
|
|
|
|
+ @endphp
|
|
|
|
|
+ <div class="tree-line {{ $isHit ? 'hit' : '' }}">
|
|
|
|
|
+ └─ {{ $child['kp_name'] }}
|
|
|
|
|
+ <span class="tree-line-badge {{ $badgeClass }}">{{ $badgeText }}</span>
|
|
|
|
|
+ @if($isHit)
|
|
|
|
|
+ <span class="tree-line-badge high">本次命中</span>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <div class="muted">无命中子知识点</div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td class="tree-right">
|
|
|
|
|
+ <div class="detail-card">
|
|
|
|
|
+ <div class="detail-head">
|
|
|
|
|
+ <div class="detail-title">{{ $parentData['kp_name'] ?? $parentData['kp_code'] }}</div>
|
|
|
|
|
+ <div class="detail-mastery {{ $parentClass }}">{{ $parentPct }}%</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="detail-meta">
|
|
|
|
|
+ 父节点变化:
|
|
|
|
|
+ @if($delta !== null)
|
|
|
|
|
+ <span class="{{ $delta >= 0 ? 'detail-change-up' : 'detail-change-down' }}">
|
|
|
|
|
+ {{ $delta >= 0 ? '↑ ' : '↓ ' }}{{ number_format(abs($delta) * 100, 1) }}%
|
|
|
|
|
+ </span>
|
|
|
|
|
+ @else
|
|
|
|
|
+ -
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="detail-meta" style="margin-top: 3px;">
|
|
|
|
|
+ 本次重点子节点:
|
|
|
|
|
+ @if($hitCount > 0)
|
|
|
|
|
+ <span class="node-tags">
|
|
|
|
|
+ @foreach($hitNames as $hitName)
|
|
|
|
|
+ @if(!empty(trim($hitName)))
|
|
|
|
|
+ <span class="node-tag">{{ $hitName }}</span>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ </span>
|
|
|
|
|
+ @else
|
|
|
|
|
+ 无
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="detail-meta">
|
|
|
|
|
+ 子节点总数 {{ $childCount }} 个,本次命中 {{ $hitCount }} 个,命中均值 {{ $hitAvg !== null ? number_format(floatval($hitAvg) * 100, 1) . '%' : '-' }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ </table>
|
|
|
</div>
|
|
</div>
|
|
|
- @if(!empty($children))
|
|
|
|
|
- <div style="font-size: 12px; color: #475569;">
|
|
|
|
|
- <strong>包含子知识点({{ count($children) }}个):</strong>
|
|
|
|
|
- @foreach($children as $index => $child)
|
|
|
|
|
- @if($index < 8)
|
|
|
|
|
- <span style="display:inline-block; margin: 2px 4px; padding: 2px 6px; background: #e0f2fe; border-radius: 3px; font-size: 11px;">
|
|
|
|
|
- {{ $child['kp_name'] }}
|
|
|
|
|
- </span>
|
|
|
|
|
- @endif
|
|
|
|
|
- @endforeach
|
|
|
|
|
- @if(count($children) > 8)
|
|
|
|
|
- <span style="color: #64748b; font-style: italic;">...等{{ count($children) }}个知识点</span>
|
|
|
|
|
- @endif
|
|
|
|
|
- </div>
|
|
|
|
|
- @else
|
|
|
|
|
- <div style="font-size: 12px; color: #64748b;">
|
|
|
|
|
- <em>无直接子知识点或子知识点掌握度为0</em>
|
|
|
|
|
- </div>
|
|
|
|
|
- @endif
|
|
|
|
|
- </div>
|
|
|
|
|
- @endforeach
|
|
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @php
|
|
|
|
|
+ $allParentPerfect = !empty($parentMasteryLevels) && count(array_filter($parentMasteryLevels, function ($p) {
|
|
|
|
|
+ return floatval($p['mastery_level'] ?? 0) >= 0.999;
|
|
|
|
|
+ })) === count($parentMasteryLevels);
|
|
|
|
|
+ $allHitChildrenPerfect = !empty($filteredMasteryItems) && count(array_filter($filteredMasteryItems, function ($it) {
|
|
|
|
|
+ return floatval($it['mastery_level'] ?? 0) >= 0.999;
|
|
|
|
|
+ })) === count($filteredMasteryItems);
|
|
|
|
|
+ $isAllPerfect = $allParentPerfect && $allHitChildrenPerfect;
|
|
|
|
|
+ // 1) 优先:本次命中子知识点中的低掌握度(<60%)
|
|
|
|
|
+ $hitWeakChildren = [];
|
|
|
|
|
+ $hitWeakKeys = [];
|
|
|
|
|
+ foreach (($filteredMasteryItems ?? []) as $hitItem) {
|
|
|
|
|
+ $level = floatval($hitItem['mastery_level'] ?? 0);
|
|
|
|
|
+ $name = trim((string) ($hitItem['kp_name'] ?? $hitItem['kp_code'] ?? ''));
|
|
|
|
|
+ if ($name === '' || $level >= 0.6) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $key = (string) ($hitItem['kp_code'] ?? $name);
|
|
|
|
|
+ $hitWeakChildren[$key] = [
|
|
|
|
|
+ 'name' => $name,
|
|
|
|
|
+ 'level' => $level,
|
|
|
|
|
+ ];
|
|
|
|
|
+ $hitWeakKeys[$key] = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ $hitWeakChildren = array_values($hitWeakChildren);
|
|
|
|
|
+ usort($hitWeakChildren, function ($a, $b) {
|
|
|
|
|
+ return $a['level'] <=> $b['level'];
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
|
|
+ // 2) 兜底:若命中子知识点都 >=60%,再从其他低掌握度子知识点补
|
|
|
|
|
+ $otherWeakChildren = [];
|
|
|
|
|
+ foreach (($parentMasteryLevels ?? []) as $pData) {
|
|
|
|
|
+ foreach (($pData['children_all'] ?? []) as $child) {
|
|
|
|
|
+ $level = floatval($child['mastery_level'] ?? 0);
|
|
|
|
|
+ $name = trim((string) ($child['kp_name'] ?? $child['kp_code'] ?? ''));
|
|
|
|
|
+ if ($name === '' || $level >= 0.6) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $key = ($child['kp_code'] ?? $name);
|
|
|
|
|
+ if (isset($hitWeakKeys[$key])) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $otherWeakChildren[$key] = [
|
|
|
|
|
+ 'name' => $name,
|
|
|
|
|
+ 'level' => $level,
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ $otherWeakChildren = array_values($otherWeakChildren);
|
|
|
|
|
+ usort($otherWeakChildren, function ($a, $b) {
|
|
|
|
|
+ return $a['level'] <=> $b['level'];
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 3) 最终展示:总数不超过5
|
|
|
|
|
+ $globalWeakChildren = [];
|
|
|
|
|
+ if (!empty($hitWeakChildren)) {
|
|
|
|
|
+ $globalWeakChildren = array_slice($hitWeakChildren, 0, 5);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $globalWeakChildren = array_slice($otherWeakChildren, 0, 5);
|
|
|
|
|
+ }
|
|
|
|
|
+ @endphp
|
|
|
<div style="margin-top: 12px; padding: 8px; background: #fefce8; border-left: 4px solid #eab308; border-radius: 4px;">
|
|
<div style="margin-top: 12px; padding: 8px; background: #fefce8; border-left: 4px solid #eab308; border-radius: 4px;">
|
|
|
<div style="font-size: 12px; color: #854d0e; line-height: 1.6;">
|
|
<div style="font-size: 12px; color: #854d0e; line-height: 1.6;">
|
|
|
<strong>学习建议:</strong>
|
|
<strong>学习建议:</strong>
|
|
|
- 建议重点关注掌握度较低的知识点,通过专项练习提升整体学习水平。优先练习掌握度低于60%的知识点。
|
|
|
|
|
|
|
+ @if($isAllPerfect)
|
|
|
|
|
+ 本次学案表现非常出色,相关知识点掌握稳定且完整。建议继续进入新的知识点专题学习,优先选择同层级未覆盖内容或更高难度综合题,保持进阶节奏。
|
|
|
|
|
+ @else
|
|
|
|
|
+ 建议重点关注掌握度较低的知识点,通过专项练习提升整体学习水平。优先练习掌握度低于60%的知识点。
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @if(!empty($globalWeakChildren))
|
|
|
|
|
+ <div class="weak-kp-tags">
|
|
|
|
|
+ @foreach($globalWeakChildren as $weakChild)
|
|
|
|
|
+ <span class="weak-kp-tag">{{ $weakChild['name'] }}({{ number_format($weakChild['level'] * 100, 1) }}%)</span>
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
@else
|
|
@else
|
|
@@ -206,18 +448,111 @@
|
|
|
@endif
|
|
@endif
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div class="card">
|
|
|
|
|
- <div class="section-title">题目列表</div>
|
|
|
|
|
- @php
|
|
|
|
|
- $insightMap = [];
|
|
|
|
|
- foreach (($question_insights ?? []) as $insight) {
|
|
|
|
|
- $no = $insight['question_number'] ?? $insight['question_id'] ?? null;
|
|
|
|
|
- if ($no !== null) {
|
|
|
|
|
- $insightMap[$no] = $insight;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ @php
|
|
|
|
|
+ $insightMap = [];
|
|
|
|
|
+ foreach (($question_insights ?? []) as $insight) {
|
|
|
|
|
+ $no = $insight['question_number'] ?? $insight['question_id'] ?? null;
|
|
|
|
|
+ if ($no !== null) {
|
|
|
|
|
+ $insightMap[$no] = $insight;
|
|
|
}
|
|
}
|
|
|
- @endphp
|
|
|
|
|
- @foreach($questions as $q)
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $analysisWrongMap = [];
|
|
|
|
|
+ foreach (($analysis_data['question_analysis'] ?? []) as $qa) {
|
|
|
|
|
+ $qid = $qa['question_bank_id'] ?? $qa['question_id'] ?? null;
|
|
|
|
|
+ if ($qid === null || $qid === '') {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $rawCorrect = $qa['is_correct'] ?? null;
|
|
|
|
|
+ $isWrongFromAnalysis = false;
|
|
|
|
|
+ if (is_array($rawCorrect)) {
|
|
|
|
|
+ $isWrongFromAnalysis = in_array(0, $rawCorrect, true);
|
|
|
|
|
+ } elseif ($rawCorrect !== null) {
|
|
|
|
|
+ $isWrongFromAnalysis = !boolval($rawCorrect);
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($isWrongFromAnalysis) {
|
|
|
|
|
+ $analysisWrongMap[(string)$qid] = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $wrongQuestions = [];
|
|
|
|
|
+ foreach (($questions ?? []) as $qItem) {
|
|
|
|
|
+ $studentAnswerProbe = $qItem['student_answer'] ?? null;
|
|
|
|
|
+ $correctAnswerProbe = $qItem['answer'] ?? ($qItem['correct_answer'] ?? null);
|
|
|
|
|
+ $isCorrectProbe = $qItem['is_correct'] ?? null;
|
|
|
|
|
+ if ($isCorrectProbe === null && !empty($studentAnswerProbe) && !empty($correctAnswerProbe)) {
|
|
|
|
|
+ $isCorrectProbe = (trim((string)$studentAnswerProbe) === trim((string)$correctAnswerProbe)) ? 1 : 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ $normalizedCorrect = $isCorrectProbe;
|
|
|
|
|
+ if ($isCorrectProbe !== null) {
|
|
|
|
|
+ $normalizedCorrect = is_bool($isCorrectProbe) ? ($isCorrectProbe ? 1 : 0) : intval($isCorrectProbe);
|
|
|
|
|
+ }
|
|
|
|
|
+ $qidProbe = (string)($qItem['question_bank_id'] ?? $qItem['question_id'] ?? '');
|
|
|
|
|
+ $isWrongByAnalysis = ($qidProbe !== '' && isset($analysisWrongMap[$qidProbe]));
|
|
|
|
|
+ if ($normalizedCorrect === 0 || $isWrongByAnalysis) {
|
|
|
|
|
+ $wrongQuestions[] = $qItem;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 错题知识点聚合统计(同知识点错几题/共几题)
|
|
|
|
|
+ $kpStats = [];
|
|
|
|
|
+ foreach (($questions ?? []) as $qItem) {
|
|
|
|
|
+ $kpName = trim((string)($qItem['knowledge_point_name'] ?? $qItem['knowledge_point'] ?? '未标注知识点'));
|
|
|
|
|
+ if ($kpName === '') {
|
|
|
|
|
+ $kpName = '未标注知识点';
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!isset($kpStats[$kpName])) {
|
|
|
|
|
+ $kpStats[$kpName] = ['total' => 0, 'wrong' => 0];
|
|
|
|
|
+ }
|
|
|
|
|
+ $kpStats[$kpName]['total']++;
|
|
|
|
|
+ }
|
|
|
|
|
+ foreach ($wrongQuestions as $qItem) {
|
|
|
|
|
+ $kpName = trim((string)($qItem['knowledge_point_name'] ?? $qItem['knowledge_point'] ?? '未标注知识点'));
|
|
|
|
|
+ if ($kpName === '') {
|
|
|
|
|
+ $kpName = '未标注知识点';
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!isset($kpStats[$kpName])) {
|
|
|
|
|
+ $kpStats[$kpName] = ['total' => 0, 'wrong' => 0];
|
|
|
|
|
+ }
|
|
|
|
|
+ $kpStats[$kpName]['wrong']++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $kpWrongStats = [];
|
|
|
|
|
+ foreach ($kpStats as $kpName => $stat) {
|
|
|
|
|
+ if (($stat['wrong'] ?? 0) <= 0) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $total = max(1, intval($stat['total'] ?? 0));
|
|
|
|
|
+ $wrong = intval($stat['wrong'] ?? 0);
|
|
|
|
|
+ $kpWrongStats[] = [
|
|
|
|
|
+ 'kp_name' => $kpName,
|
|
|
|
|
+ 'wrong' => $wrong,
|
|
|
|
|
+ 'total' => $total,
|
|
|
|
|
+ 'rate' => $wrong / $total,
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+ usort($kpWrongStats, function ($a, $b) {
|
|
|
|
|
+ if ($a['rate'] === $b['rate']) {
|
|
|
|
|
+ return $b['wrong'] <=> $a['wrong'];
|
|
|
|
|
+ }
|
|
|
|
|
+ return $b['rate'] <=> $a['rate'];
|
|
|
|
|
+ });
|
|
|
|
|
+ @endphp
|
|
|
|
|
+
|
|
|
|
|
+ @if(!empty($wrongQuestions))
|
|
|
|
|
+ <div class="card">
|
|
|
|
|
+ <div class="section-title">错题列表</div>
|
|
|
|
|
+ @if(!empty($kpWrongStats))
|
|
|
|
|
+ <div style="margin-bottom:8px; padding:8px; border:1px solid #e5e7eb; border-radius:6px; background:#f8fafc;">
|
|
|
|
|
+ <div style="font-size:12px; font-weight:600; color:#111827; margin-bottom:6px;">知识点错误率</div>
|
|
|
|
|
+ <div style="font-size:11px; color:#475569; line-height:1.7;">
|
|
|
|
|
+ @foreach($kpWrongStats as $item)
|
|
|
|
|
+ <span class="error-kp-tag {{ $item['rate'] > 0.5 ? 'high-risk' : '' }}">{{ $item['kp_name'] }}:{{ $item['wrong'] }}/{{ $item['total'] }}({{ number_format($item['rate'] * 100, 1) }}%)</span>
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @foreach($wrongQuestions as $q)
|
|
|
@php
|
|
@php
|
|
|
// 【修复】从题目数据中获取学生答案、正确答案和判分结果
|
|
// 【修复】从题目数据中获取学生答案、正确答案和判分结果
|
|
|
$studentAnswer = $q['student_answer'] ?? $q['student_answer'] ?? null;
|
|
$studentAnswer = $q['student_answer'] ?? $q['student_answer'] ?? null;
|
|
@@ -273,6 +608,19 @@
|
|
|
if ($analysis === null || $analysis === '') {
|
|
if ($analysis === null || $analysis === '') {
|
|
|
$analysis = '暂无解题思路,待补充';
|
|
$analysis = '暂无解题思路,待补充';
|
|
|
}
|
|
}
|
|
|
|
|
+ $formatSolutionLikeGrading = function ($text) {
|
|
|
|
|
+ if (!is_string($text) || trim($text) === '') {
|
|
|
|
|
+ return $text;
|
|
|
|
|
+ }
|
|
|
|
|
+ $normalized = preg_replace('/\s*;\s*步骤\s*(\d+)/u', ";\n步骤$1", $text);
|
|
|
|
|
+ $normalized = preg_replace('/\s*。\s*步骤\s*(\d+)/u', "。\n步骤$1", $normalized);
|
|
|
|
|
+ $normalized = preg_replace('/(?<!^)(步骤\s*\d+\s*[::])/u', "\n$1", $normalized);
|
|
|
|
|
+ $normalized = preg_replace('/(?<!^)(第\s*\d+\s*步\s*[::]?)/u', "\n$1", $normalized);
|
|
|
|
|
+ $normalized = preg_replace('/\n{3,}/u', "\n\n", $normalized);
|
|
|
|
|
+ // 去掉每行左侧缩进空白,避免出现“左边空好几个字符”
|
|
|
|
|
+ $normalized = preg_replace('/^[\h\x{3000}]+/mu', '', $normalized);
|
|
|
|
|
+ return trim($normalized);
|
|
|
|
|
+ };
|
|
|
$stepsRaw = $insight['steps'] ?? $insight['solution_steps'] ?? $insight['analysis_steps'] ?? null;
|
|
$stepsRaw = $insight['steps'] ?? $insight['solution_steps'] ?? $insight['analysis_steps'] ?? null;
|
|
|
$steps = [];
|
|
$steps = [];
|
|
|
if (is_array($stepsRaw)) {
|
|
if (is_array($stepsRaw)) {
|
|
@@ -284,11 +632,13 @@
|
|
|
$typeLabel = $typeMap[$q['question_type'] ?? ''] ?? ($q['question_type'] ?? '题型未标注');
|
|
$typeLabel = $typeMap[$q['question_type'] ?? ''] ?? ($q['question_type'] ?? '题型未标注');
|
|
|
$questionText = is_string($q['question_text']) ? $q['question_text'] : json_encode($q['question_text'], JSON_UNESCAPED_UNICODE);
|
|
$questionText = is_string($q['question_text']) ? $q['question_text'] : json_encode($q['question_text'], JSON_UNESCAPED_UNICODE);
|
|
|
$solution = $q['solution'] ?? null;
|
|
$solution = $q['solution'] ?? null;
|
|
|
|
|
+ $solution = $formatSolutionLikeGrading($solution);
|
|
|
|
|
+ $analysis = $formatSolutionLikeGrading($analysis);
|
|
|
@endphp
|
|
@endphp
|
|
|
- <div style="border:1px solid #e5e7eb; border-radius:8px; padding:8px 12px; margin-bottom:8px; background:#fff; page-break-inside: avoid;">
|
|
|
|
|
|
|
+ <div class="question-card">
|
|
|
<div style="display:flex; justify-content:space-between; align-items:center; gap:8px; margin-bottom:4px;">
|
|
<div style="display:flex; justify-content:space-between; align-items:center; gap:8px; margin-bottom:4px;">
|
|
|
<div style="display:flex; align-items:center; gap:8px; font-weight:600;">
|
|
<div style="display:flex; align-items:center; gap:8px; font-weight:600;">
|
|
|
- <span class="tag">题号 {{ $q['display_number'] ?? $q['question_number'] }}</span>
|
|
|
|
|
|
|
+ <span class="tag">题号 {{ $q['display_number'] ?? $q['question_number'] }} · {{ $typeLabel }}</span>
|
|
|
@php
|
|
@php
|
|
|
$kpName = $q['knowledge_point_name'] ?? $q['knowledge_point'] ?? null;
|
|
$kpName = $q['knowledge_point_name'] ?? $q['knowledge_point'] ?? null;
|
|
|
if (!empty($kpName) && $kpName !== '-' && $kpName !== '未标注') {
|
|
if (!empty($kpName) && $kpName !== '-' && $kpName !== '未标注') {
|
|
@@ -306,7 +656,7 @@
|
|
|
|
|
|
|
|
{{-- 【新增】学生答案显示(如果有) --}}
|
|
{{-- 【新增】学生答案显示(如果有) --}}
|
|
|
@if(!empty($studentAnswer))
|
|
@if(!empty($studentAnswer))
|
|
|
- <div style="margin-bottom:6px; padding:6px; background:#fef2f2; border-left:3px solid #ef4444; border-radius:4px;">
|
|
|
|
|
|
|
+ <div class="question-block" style="background:#fef2f2; border-left:3px solid #ef4444;">
|
|
|
<div style="font-weight:600; font-size:12px; color:#111827; margin-bottom:3px;">学生答案</div>
|
|
<div style="font-weight:600; font-size:12px; color:#111827; margin-bottom:3px;">学生答案</div>
|
|
|
<div class="math-content" style="font-size:12px; line-height:1.5; color:#374151;">
|
|
<div class="math-content" style="font-size:12px; line-height:1.5; color:#374151;">
|
|
|
{!! nl2br(e($studentAnswer)) !!}
|
|
{!! nl2br(e($studentAnswer)) !!}
|
|
@@ -315,11 +665,10 @@
|
|
|
@endif
|
|
@endif
|
|
|
|
|
|
|
|
<div class="math-content" style="margin-bottom:6px; font-size:12px;">{!! $questionText !!}</div>
|
|
<div class="math-content" style="margin-bottom:6px; font-size:12px;">{!! $questionText !!}</div>
|
|
|
- <div class="muted" style="margin-bottom:6px; font-size:12px;">题型:{{ $typeLabel }}</div>
|
|
|
|
|
|
|
|
|
|
{{-- 【修复】正确答案显示 --}}
|
|
{{-- 【修复】正确答案显示 --}}
|
|
|
@if(!empty($correctAnswer))
|
|
@if(!empty($correctAnswer))
|
|
|
- <div style="margin-bottom:6px; padding:6px; background:#f0fdf4; border-left:3px solid #10b981; border-radius:4px;">
|
|
|
|
|
|
|
+ <div class="question-block" style="background:#f0fdf4; border-left:3px solid #10b981;">
|
|
|
<div style="font-weight:600; font-size:12px; color:#111827; margin-bottom:3px;">正确答案</div>
|
|
<div style="font-weight:600; font-size:12px; color:#111827; margin-bottom:3px;">正确答案</div>
|
|
|
<div class="math-content" style="font-size:12px; line-height:1.5; color:#374151;">
|
|
<div class="math-content" style="font-size:12px; line-height:1.5; color:#374151;">
|
|
|
{!! is_string($correctAnswer) ? $correctAnswer : json_encode($correctAnswer, JSON_UNESCAPED_UNICODE) !!}
|
|
{!! is_string($correctAnswer) ? $correctAnswer : json_encode($correctAnswer, JSON_UNESCAPED_UNICODE) !!}
|
|
@@ -329,16 +678,16 @@
|
|
|
|
|
|
|
|
{{-- 【修改】解题思路显示(优先显示solution,其次显示analysis) --}}
|
|
{{-- 【修改】解题思路显示(优先显示solution,其次显示analysis) --}}
|
|
|
@if(!empty($solution))
|
|
@if(!empty($solution))
|
|
|
- <div style="margin-top:6px; padding:6px; background:#eff6ff; border-left:3px solid #3b82f6; border-radius:4px;">
|
|
|
|
|
|
|
+ <div class="question-block" style="margin-top:6px; background:#eff6ff; border-left:3px solid #3b82f6;">
|
|
|
<div style="font-weight:600; font-size:12px; color:#111827; margin-bottom:4px;">解题思路</div>
|
|
<div style="font-weight:600; font-size:12px; color:#111827; margin-bottom:4px;">解题思路</div>
|
|
|
- <div class="math-content" style="font-size:12px; line-height:1.5; color:#374151;">
|
|
|
|
|
- {!! is_array($solution) ? json_encode($solution, JSON_UNESCAPED_UNICODE) : $solution !!}
|
|
|
|
|
|
|
+ <div class="math-content solution-content" style="font-size:12px; color:#374151;">
|
|
|
|
|
+ {!! nl2br(e(is_array($solution) ? json_encode($solution, JSON_UNESCAPED_UNICODE) : (string) $solution)) !!}
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
@elseif(!empty($analysis) && $analysis !== '暂无解题思路记录')
|
|
@elseif(!empty($analysis) && $analysis !== '暂无解题思路记录')
|
|
|
- <div style="margin-top:6px; padding:6px; background:#eff6ff; border-left:3px solid #3b82f6; border-radius:4px;">
|
|
|
|
|
|
|
+ <div class="question-block" style="margin-top:6px; background:#eff6ff; border-left:3px solid #3b82f6;">
|
|
|
<div style="font-weight:600; font-size:12px; color:#111827; margin-bottom:4px;">解题思路</div>
|
|
<div style="font-weight:600; font-size:12px; color:#111827; margin-bottom:4px;">解题思路</div>
|
|
|
- <div class="math-content" style="font-size:12px; line-height:1.5; color:#374151;">{!! $analysis !!}</div>
|
|
|
|
|
|
|
+ <div class="math-content solution-content" style="font-size:12px; color:#374151;">{!! nl2br(e((string) $analysis)) !!}</div>
|
|
|
</div>
|
|
</div>
|
|
|
@endif
|
|
@endif
|
|
|
|
|
|
|
@@ -356,6 +705,7 @@
|
|
|
</div>
|
|
</div>
|
|
|
@endforeach
|
|
@endforeach
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ @endif
|
|
|
</div> {{-- 闭合page div --}}
|
|
</div> {{-- 闭合page div --}}
|
|
|
|
|
|
|
|
<script src="/js/katex.min.js"></script>
|
|
<script src="/js/katex.min.js"></script>
|