| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570 |
- <div>
- <div class="space-y-6">
- @php
- $record = $this->record();
- @endphp
-
- {{-- 面包屑导航 --}}
- <div class="breadcrumbs text-sm">
- <ul>
- <li>
- <a href="{{ route('filament.admin.pages.ocr-records') }}" class="text-primary hover:underline">
- OCR识别记录
- </a>
- </li>
- <li>记录详情</li>
- </ul>
- </div>
- @if($record)
- {{-- 基本信息卡片 --}}
- <div class="card bg-base-100 shadow-lg border">
- <div class="card-body">
- <div class="flex justify-between items-start mb-4">
- <h2 class="card-title text-xl">
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
- </svg>
- 基本信息
- </h2>
- <div class="flex gap-2">
- @php
- $statusConfig = $this->getStatusBadgeConfig($record->status);
- @endphp
- <span class="badge {{ $statusConfig['class'] }} badge-lg">
- {{ $statusConfig['text'] }}
- </span>
- @if($record->status === 'pending' || $record->status === 'failed')
- <button
- wire:click="startRecognition"
- class="btn btn-primary btn-sm"
- >
- <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
- </svg>
- 开始识别
- </button>
- @endif
- <a href="{{ route('filament.admin.pages.ocr-records') }}" class="btn btn-ghost btn-sm">
- <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
- </svg>
- 返回列表
- </a>
- </div>
- </div>
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
- <div class="stat bg-base-200 rounded-lg">
- <div class="stat-title">学生姓名</div>
- <div class="stat-value text-lg">{{ $record->student->name ?? '未知' }}</div>
- <div class="stat-desc">
- {{ $record->student->grade ?? '-' }} - {{ $record->student->class_name ?? '-' }}
- </div>
- </div>
- <div class="stat bg-base-200 rounded-lg">
- <div class="stat-title">图片名称</div>
- <div class="stat-value text-lg">{{ $record->image_filename }}</div>
- <div class="stat-desc">
- @if($record->image_size)
- {{ number_format($record->image_size / 1024, 2) }} KB
- @else
- -
- @endif
- </div>
- </div>
- <div class="stat bg-base-200 rounded-lg">
- <div class="stat-title">识别进度</div>
- <div class="stat-value text-lg">
- {{ $record->processed_questions ?? 0 }}/{{ $record->total_questions ?? 0 }}
- </div>
- <div class="stat-desc">
- @if($record->total_questions > 0)
- @php
- $percent = round(($record->processed_questions / $record->total_questions) * 100, 1);
- @endphp
- {{ $percent }}%
- @else
- 未开始
- @endif
- </div>
- </div>
- <div class="stat bg-base-200 rounded-lg">
- <div class="stat-title">平均置信度</div>
- <div class="stat-value text-lg">
- @if($record->confidence_avg)
- {{ number_format($record->confidence_avg * 100, 1) }}%
- @else
- -
- @endif
- </div>
- <div class="stat-desc">
- @if($record->confidence_avg)
- @if($record->confidence_avg >= 0.7)
- <span class="text-success">优秀</span>
- @elseif($record->confidence_avg >= 0.5)
- <span class="text-warning">良好</span>
- @else
- <span class="text-error">需改进</span>
- @endif
- @else
- 暂无数据
- @endif
- </div>
- </div>
- </div>
- @if($record->error_message)
- <div class="alert alert-error mt-4">
- <svg class="w-6 h-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
- </svg>
- <div>
- <h3 class="font-bold">错误信息</h3>
- <div class="text-xs">{{ $record->error_message }}</div>
- </div>
- </div>
- @endif
- </div>
- </div>
- {{-- 图片预览卡片 --}}
- @if($record->image_path)
- <div class="card bg-base-100 shadow-lg border">
- <div class="card-body">
- <h2 class="card-title text-xl mb-4">
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
- </svg>
- 原图预览
- </h2>
- <div class="flex justify-center">
- <div class="max-w-4xl">
- <img
- src="{{ asset('storage/' . $record->image_path) }}"
- alt="卷子图片"
- class="w-full h-auto rounded-lg border"
- >
- </div>
- </div>
- <div class="mt-4 grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
- <div>
- <span class="text-gray-500">文件大小:</span>
- @if($record->image_size)
- {{ number_format($record->image_size / 1024, 2) }} KB
- @else
- -
- @endif
- </div>
- @if($record->image_width)
- <div>
- <span class="text-gray-500">宽度:</span>{{ $record->image_width }} px
- </div>
- @endif
- @if($record->image_height)
- <div>
- <span class="text-gray-500">高度:</span>{{ $record->image_height }} px
- </div>
- @endif
- <div>
- <span class="text-gray-500">创建时间:</span>
- {{ $record->created_at->format('Y-m-d H:i:s') }}
- </div>
- </div>
- </div>
- </div>
- @endif
- {{-- 识别结果卡片 --}}
- <div class="card bg-base-100 shadow-lg border">
- <div class="card-body">
- <h2 class="card-title text-xl mb-4">
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
- </svg>
- 题目识别结果
- </h2>
- @if($record->questions && count($record->questions) > 0)
- <div class="space-y-4">
- @foreach($record->questions as $question)
- <div class="card bg-base-200 border">
- <div class="card-body">
- <div class="flex justify-between items-start">
- <div class="flex items-center gap-2">
- <span class="badge badge-primary badge-lg">
- 题目 {{ $question->question_number }}
- </span>
- @if($question->score_confidence)
- @php
- $confidence = $question->score_confidence * 100;
- $badgeClass = $confidence >= 70 ? 'badge-success' : ($confidence >= 50 ? 'badge-warning' : 'badge-error');
- @endphp
- <span class="badge {{ $badgeClass }}">
- 置信度: {{ number_format($confidence, 1) }}%
- </span>
- @endif
- @if($question->answer_verified)
- <span class="badge badge-success">
- <svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
- </svg>
- 已校验
- </span>
- @endif
- </div>
-
- @if($question->score_value !== null)
- <span class="badge badge-info badge-lg">
- 得分: {{ $question->score_value }}
- </span>
- @endif
- </div>
- <div class="divider my-2"></div>
- {{-- Question Text --}}
- <div class="mb-4">
- <h4 class="font-semibold text-sm text-gray-600 mb-2">题目内容:</h4>
- <div class="bg-base-100 p-4 rounded-lg border">
- @if($question->question_text)
- <p class="text-base leading-relaxed whitespace-pre-wrap">{{ $question->question_text }}</p>
- @else
- <p class="text-gray-400 italic">未识别到题目内容</p>
- @endif
- </div>
- </div>
- {{-- Student Answer Section --}}
- <div class="mb-4">
- <h4 class="font-semibold text-sm text-gray-600 mb-2">学生答案:</h4>
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
- {{-- OCR Result --}}
- <div>
- <label class="label">
- <span class="label-text text-xs">OCR 识别结果</span>
- </label>
- <div class="bg-base-100 p-3 rounded-lg border">
- @if($question->student_answer)
- <span class="text-lg font-bold text-primary">{{ $question->student_answer }}</span>
- @else
- <span class="text-gray-400 italic">未识别</span>
- @endif
- </div>
- </div>
-
- {{-- Manual Input --}}
- <div>
- <label class="label">
- <span class="label-text text-xs">手动校准 (可选)</span>
- </label>
- <input
- type="text"
- wire:model.defer="manualAnswers.{{ $question->id }}"
- placeholder="如 A, B, C, D 或留空使用 OCR 结果"
- class="input input-bordered input-primary w-full"
- maxlength="10"
- value="{{ $question->manual_answer }}"
- >
- </div>
- </div>
- </div>
- {{-- AI Analysis Results --}}
- @if($question->ai_score !== null || $question->ai_feedback !== null)
- <div class="bg-success/10 border border-success/30 rounded-lg p-4">
- <div class="flex items-center gap-2 text-success">
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
- </svg>
- <span class="font-medium">AI 智能分析结果</span>
- </div>
- @if($question->ai_score !== null)
- <div class="flex gap-4 mt-3">
- <div class="stat bg-base-100 rounded-lg border border-success/20">
- <div class="stat-title text-xs">AI 评分</div>
- <div class="stat-value text-2xl text-success">
- {{ $question->ai_score }}
- </div>
- <div class="stat-desc text-xs">满分100分</div>
- </div>
- @if($question->ai_confidence !== null)
- <div class="stat bg-base-100 rounded-lg border border-success/20">
- <div class="stat-title text-xs">置信度</div>
- <div class="stat-value text-lg text-success">
- {{ number_format($question->ai_confidence * 100, 1) }}%
- </div>
- <div class="stat-desc text-xs">AI 置信度</div>
- </div>
- @endif
- </div>
- @endif
- @if($question->ai_feedback)
- <div class="mt-3">
- <div class="text-sm font-medium text-gray-700 mb-1">AI 分析反馈:</div>
- <div class="bg-base-100 p-3 rounded-lg border border-success/20">
- <p class="text-sm">{{ $question->ai_feedback }}</p>
- </div>
- </div>
- @endif
- @if($question->ai_analysis_method)
- <div class="flex gap-2 mt-3 text-xs text-gray-500">
- <span class="badge badge-ghost">分析方法: {{ $question->ai_analysis_method }}</span>
- @if($question->ai_analyzed_at)
- <span class="badge badge-ghost">分析时间: {{ $question->ai_analyzed_at }}</span>
- @endif
- </div>
- @endif
- </div>
- @else
- <div class="bg-warning/10 border border-warning/30 rounded-lg p-4">
- <div class="flex items-center gap-2 text-warning">
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
- </svg>
- <span class="font-medium">AI 智能评分</span>
- </div>
- <p class="text-sm mt-2 text-gray-600">
- 提交答案后进行 AI 分析,将提供:正确性判断、详细反馈、知识点分析
- </p>
- </div>
- @endif
- {{-- Metadata --}}
- <div class="flex gap-4 mt-4 text-xs text-gray-500">
- @if($question->kp_code)
- <div>
- <span class="font-medium">知识点:</span>
- <span class="badge badge-info badge-xs">{{ $question->kp_code }}</span>
- </div>
- @endif
- @if($question->mark_detected)
- <div>
- <span class="font-medium">批改标记:</span>
- {!! $question->mark_badge ?? $question->mark_detected !!}
- </div>
- @endif
- </div>
- </div>
- </div>
- @endforeach
-
- {{-- Batch Submit Button --}}
- @if(!$this->hasAnalysisResults)
- <div class="card bg-primary/10 border border-primary">
- <div class="card-body">
- <div class="flex justify-between items-center">
- <div>
- <h3 class="font-bold text-lg">提交 AI 分析</h3>
- <p class="text-sm text-gray-600">
- 将使用手动校准的答案(如有),否则使用 OCR 识别结果
- </p>
- </div>
- <button
- wire:click="submitForAnalysis"
- class="btn btn-primary btn-lg"
- >
- <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path>
- </svg>
- 提交分析
- </button>
- </div>
- </div>
- </div>
- @else
- <div class="card bg-success/10 border border-success">
- <div class="card-body">
- <div class="flex justify-between items-center">
- <div>
- <h3 class="font-bold text-lg text-success">AI 分析已完成</h3>
- <p class="text-sm text-gray-600">
- 所有题目已完成 AI 智能分析,查看上方各题目的分析结果
- </p>
- @if($record->ai_analyzed_at)
- <p class="text-sm text-gray-500">
- 分析完成时间:{{ $record->ai_analyzed_at }}
- @if($record->ai_analysis_count)
- | 分析题目数:{{ $record->ai_analysis_count }}
- @endif
- </p>
- @endif
- </div>
- <div class="badge badge-success badge-lg">
- <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
- </svg>
- 已分析
- </div>
- </div>
- </div>
- </div>
- @endif
- </div>
- @else
- <div class="text-center py-8 text-gray-500">
- <svg class="w-12 h-12 mx-auto mb-3 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6m-3-3v6m5 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
- </svg>
- <p>暂无识别结果</p>
- @if($record->status === 'pending')
- <p class="text-sm mt-2">点击上方"开始识别"按钮开始处理</p>
- @endif
- </div>
- @endif
- </div>
- </div>
- {{-- 时间线卡片 --}}
- <div class="card bg-base-100 shadow-lg border">
- <div class="card-body">
- <h2 class="card-title text-xl mb-4">
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
- </svg>
- 处理时间线
- </h2>
- <ul class="timeline timeline-snap-icon max-md:timeline-compact timeline-vertical">
- <li>
- <div class="timeline-middle">
- <div class="badge badge-success">
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
- </svg>
- </div>
- </div>
- <div class="timeline-start mb-10">
- <time class="font-mono italic text-sm">{{ $record->created_at->format('Y-m-d H:i:s') }}</time>
- <div class="text-lg font-black">上传成功</div>
- <p class="text-sm">卷子图片已上传,等待OCR识别</p>
- </div>
- <hr class="bg-success" />
- </li>
- @if($record->status === 'processing')
- <li>
- <div class="timeline-middle">
- <div class="badge badge-info animate-pulse">
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
- </svg>
- </div>
- </div>
- <div class="timeline-start mb-10">
- <time class="font-mono italic text-sm">{{ now()->format('Y-m-d H:i:s') }}</time>
- <div class="text-lg font-black text-info">处理中</div>
- <p class="text-sm">OCR识别正在进行中...</p>
- </div>
- <hr class="bg-info" />
- </li>
- @elseif($record->status === 'completed')
- <li>
- <div class="timeline-middle">
- <div class="badge badge-success">
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
- </svg>
- </div>
- </div>
- <div class="timeline-start mb-10">
- <time class="font-mono italic text-sm">{{ $record->processed_at?->format('Y-m-d H:i:s') }}</time>
- <div class="text-lg font-black text-success">处理完成</div>
- <p class="text-sm">OCR识别已完成,识别出 {{ $record->total_questions ?? 0 }} 道题目</p>
- </div>
- <hr class="bg-success" />
- </li>
- @elseif($record->status === 'failed')
- <li>
- <div class="timeline-middle">
- <div class="badge badge-error">
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
- </svg>
- </div>
- </div>
- <div class="timeline-start mb-10">
- <time class="font-mono italic text-sm">{{ now()->format('Y-m-d H:i:s') }}</time>
- <div class="text-lg font-black text-error">处理失败</div>
- @if($record->error_message)
- <p class="text-sm text-error">{{ $record->error_message }}</p>
- @endif
- </div>
- <hr class="bg-error" />
- </li>
- @endif
- {{-- AI Analysis Timeline --}}
- @if($record->status === 'completed' && $record->ai_analyzed_at)
- <li>
- <div class="timeline-middle">
- <div class="badge badge-info">
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
- </svg>
- </div>
- </div>
- <div class="timeline-start mb-10">
- <time class="font-mono italic text-sm">{{ $record->ai_analyzed_at }}</time>
- <div class="text-lg font-black text-info">AI 分析完成</div>
- <p class="text-sm">
- 已完成 {{ $record->ai_analysis_count ?? count($record->questions) }} 道题目的智能分析
- </p>
- <div class="flex gap-2 mt-2">
- <span class="badge badge-success badge-xs">
- <svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
- </svg>
- 智能分析
- </span>
- <span class="badge badge-info badge-xs">学习分析</span>
- <span class="badge badge-warning badge-xs">掌握度评估</span>
- </div>
- </div>
- <hr class="bg-info" />
- </li>
- @endif
- </ul>
- </div>
- </div>
- @else
- <div class="card bg-base-100 shadow-lg border">
- <div class="card-body">
- <div class="alert alert-error">
- <svg class="w-6 h-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
- </svg>
- <div>
- <h3 class="font-bold">记录不存在</h3>
- <div class="text-xs">找不到ID为 {{ $recordId }} 的OCR记录</div>
- </div>
- </div>
- <div class="mt-4">
- <a href="{{ route('filament.admin.pages.ocr-records') }}" class="btn btn-primary">
- <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
- </svg>
- 返回列表
- </a>
- </div>
- </div>
- </div>
- @endif
- </div>
- </div>
|