|
@@ -0,0 +1,634 @@
|
|
|
|
|
+<x-filament-panels::page>
|
|
|
|
|
+
|
|
|
|
|
+<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="link link-primary link-hover no-underline">
|
|
|
|
|
+ <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="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ OCR识别记录
|
|
|
|
|
+ </a>
|
|
|
|
|
+ </li>
|
|
|
|
|
+ <li>
|
|
|
|
|
+ <span class="text-base-content/60">/</span>
|
|
|
|
|
+ </li>
|
|
|
|
|
+ <li>记录详情 #{{ $record->id }}</li>
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ @if($record)
|
|
|
|
|
+ {{-- 头部信息卡片 --}}
|
|
|
|
|
+ <div class="card bg-base-100 border border-base-300 shadow-xl">
|
|
|
|
|
+ <div class="card-body">
|
|
|
|
|
+ <div class="flex flex-col lg:flex-row justify-between gap-4">
|
|
|
|
|
+ <div class="flex items-center gap-3">
|
|
|
|
|
+ <div class="avatar placeholder">
|
|
|
|
|
+ <div class="bg-primary text-primary-content rounded-full w-12 h-12 flex items-center justify-center">
|
|
|
|
|
+ <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>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h1 class="text-2xl font-bold">OCR记录详情</h1>
|
|
|
|
|
+ <p class="text-sm text-base-content/60">记录ID: {{ $record->id }}</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
|
|
+ @php
|
|
|
|
|
+ $statusConfig = $this->getStatusBadgeConfig($record->status);
|
|
|
|
|
+ @endphp
|
|
|
|
|
+ <div class="badge {{ $statusConfig['class'] }} gap-2">
|
|
|
|
|
+ <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="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ {{ $statusConfig['text'] }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ @if($record->status === 'pending' || $record->status === 'failed')
|
|
|
|
|
+ <button
|
|
|
|
|
+ wire:click="startRecognition"
|
|
|
|
|
+ class="btn btn-primary btn-sm"
|
|
|
|
|
+ >
|
|
|
|
|
+ <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="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" 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="stats stats-vertical lg:stats-horizontal shadow bg-base-200 border border-base-300">
|
|
|
|
|
+ <div class="stat">
|
|
|
|
|
+ <div class="stat-figure text-primary">
|
|
|
|
|
+ <svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <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">
|
|
|
|
|
+ <div class="stat-figure text-secondary">
|
|
|
|
|
+ <svg class="w-8 h-8" 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>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="stat-title">图片</div>
|
|
|
|
|
+ <div class="stat-value text-lg">{{ $record->image_filename }}</div>
|
|
|
|
|
+ <div class="stat-desc">{{ number_format($record->image_size / 1024, 2) }} KB</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="stat">
|
|
|
|
|
+ <div class="stat-figure text-info">
|
|
|
|
|
+ <svg class="w-8 h-8" 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>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <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
|
|
|
|
|
+ <progress class="progress progress-primary w-16" value="{{ $percent }}" max="100"></progress>
|
|
|
|
|
+ {{ $percent }}%
|
|
|
|
|
+ @else
|
|
|
|
|
+ 未开始
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="stat">
|
|
|
|
|
+ <div class="stat-figure text-success">
|
|
|
|
|
+ <svg class="w-8 h-8" 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 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 border border-base-300 shadow-xl">
|
|
|
|
|
+ <div class="card-body">
|
|
|
|
|
+ <h2 class="card-title flex items-center gap-2">
|
|
|
|
|
+ <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="mockup-window border border-base-300">
|
|
|
|
|
+ <div class="mockup-browser-toolbar">
|
|
|
|
|
+ <div class="mockup-browser-dot"></div>
|
|
|
|
|
+ <div class="mockup-browser-dot"></div>
|
|
|
|
|
+ <div class="mockup-browser-dot"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="mockup-browser-content bg-base-200">
|
|
|
|
|
+ <img
|
|
|
|
|
+ src="{{ asset('storage/' . $record->image_path) }}"
|
|
|
|
|
+ alt="卷子图片"
|
|
|
|
|
+ class="w-full h-auto rounded-b-lg"
|
|
|
|
|
+ >
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="mt-4 grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
|
|
|
|
|
+ <div class="stat bg-base-200 rounded-lg border border-base-300">
|
|
|
|
|
+ <div class="stat-title text-xs">文件大小</div>
|
|
|
|
|
+ <div class="stat-value text-sm">{{ number_format($record->image_size / 1024, 2) }} KB</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @if($record->image_width)
|
|
|
|
|
+ <div class="stat bg-base-200 rounded-lg border border-base-300">
|
|
|
|
|
+ <div class="stat-title text-xs">宽度</div>
|
|
|
|
|
+ <div class="stat-value text-sm">{{ $record->image_width }} px</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @if($record->image_height)
|
|
|
|
|
+ <div class="stat bg-base-200 rounded-lg border border-base-300">
|
|
|
|
|
+ <div class="stat-title text-xs">高度</div>
|
|
|
|
|
+ <div class="stat-value text-sm">{{ $record->image_height }} px</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ <div class="stat bg-base-200 rounded-lg border border-base-300">
|
|
|
|
|
+ <div class="stat-title text-xs">创建时间</div>
|
|
|
|
|
+ <div class="stat-value text-sm">{{ $record->created_at->format('m-d H:i') }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+
|
|
|
|
|
+ {{-- 题目识别结果列表 --}}
|
|
|
|
|
+ <div class="card bg-base-100 border border-base-300 shadow-xl">
|
|
|
|
|
+ <div class="card-body">
|
|
|
|
|
+ <div class="flex justify-between items-center mb-6">
|
|
|
|
|
+ <h2 class="card-title text-xl flex items-center gap-2">
|
|
|
|
|
+ <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 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>
|
|
|
|
|
+ 题目识别结果 ({{ count($record->questions ?? []) }} 道题)
|
|
|
|
|
+ </h2>
|
|
|
|
|
+
|
|
|
|
|
+ @if(!$this->hasAnalysisResults)
|
|
|
|
|
+ <div class="badge badge-primary badge-lg gap-2">
|
|
|
|
|
+ <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="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ 待分析
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <div class="badge badge-success badge-lg gap-2">
|
|
|
|
|
+ <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 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ 已分析
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ @if($record->questions && count($record->questions) > 0)
|
|
|
|
|
+ <div class="overflow-x-auto">
|
|
|
|
|
+ <table class="table table-zebra table-compact">
|
|
|
|
|
+ <thead>
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <th class="w-12">#</th>
|
|
|
|
|
+ <th>题目内容</th>
|
|
|
|
|
+ <th>学生答案</th>
|
|
|
|
|
+ <th class="w-32">手动校准</th>
|
|
|
|
|
+ <th class="w-24">AI分析</th>
|
|
|
|
|
+ <th class="w-32">状态</th>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ </thead>
|
|
|
|
|
+ <tbody>
|
|
|
|
|
+ @foreach($record->questions as $index => $question)
|
|
|
|
|
+ <tr class="hover">
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <div class="badge badge-primary badge-sm">
|
|
|
|
|
+ {{ $question->question_number }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <div class="max-w-xs">
|
|
|
|
|
+ @if($question->question_text)
|
|
|
|
|
+ <p class="text-sm leading-tight">{{ Str::limit($question->question_text, 80) }}</p>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <span class="text-gray-400 italic text-sm">未识别到题目内容</span>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
|
|
+ <div class="text-sm font-medium">
|
|
|
|
|
+ @if($question->student_answer)
|
|
|
|
|
+ <span class="text-primary">{{ $question->student_answer }}</span>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <span class="text-gray-400 italic">未识别</span>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @if($question->answer_confidence)
|
|
|
|
|
+ <div class="w-2 h-2 rounded-full" style="background-color: {{ $question->answer_confidence >= 0.7 ? '#10b981' : ($question->answer_confidence >= 0.5 ? '#f59e0b' : '#ef4444') }}"></div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <input
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ wire:model.defer="manualAnswers.{{ $question->id }}"
|
|
|
|
|
+ placeholder="手动输入答案"
|
|
|
|
|
+ class="input input-bordered input-xs w-full"
|
|
|
|
|
+ maxlength="10"
|
|
|
|
|
+ value="{{ $question->manual_answer }}"
|
|
|
|
|
+ >
|
|
|
|
|
+ @if($question->manual_answer)
|
|
|
|
|
+ <div class="mt-1">
|
|
|
|
|
+ <div class="badge badge-success badge-xs">
|
|
|
|
|
+ <svg class="w-3 h-3" 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>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td>
|
|
|
|
|
+ @if($question->ai_score !== null || $question->ai_feedback !== null)
|
|
|
|
|
+ <div class="space-y-1">
|
|
|
|
|
+ @if($question->ai_score !== null)
|
|
|
|
|
+ <div class="text-center">
|
|
|
|
|
+ <div class="stat-value text-lg text-success">{{ $question->ai_score }}</div>
|
|
|
|
|
+ <div class="stat-title text-xs">AI评分</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @if($question->ai_confidence)
|
|
|
|
|
+ <div class="w-full">
|
|
|
|
|
+ <progress class="progress progress-success w-full h-1" value="{{ $question->ai_confidence * 100 }}" max="100"></progress>
|
|
|
|
|
+ <div class="text-xs text-center mt-1">{{ number_format($question->ai_confidence * 100, 1) }}%</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <div class="text-center">
|
|
|
|
|
+ <div class="badge badge-ghost badge-sm">
|
|
|
|
|
+ <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="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ 待分析
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <div class="flex flex-wrap gap-1">
|
|
|
|
|
+ @if($question->answer_verified)
|
|
|
|
|
+ <div class="badge badge-success badge-xs">
|
|
|
|
|
+ <svg class="w-3 h-3" 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>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @if($question->score_value !== null)
|
|
|
|
|
+ <div class="badge badge-info badge-xs">
|
|
|
|
|
+ <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 2.902 0l1.519 1.519a.922.922 0 011.603.921l1.518-1.519a.922.922 0 012.902 0l2.12 2.12a.922.922 0 010-1.303l-2.12-2.12z"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ {{ $question->score_value }}分
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @if($question->kp_code)
|
|
|
|
|
+ <div class="badge badge-warning badge-xs">
|
|
|
|
|
+ <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 00-3.86.517L6.05 15.21a2 2 0 00-1.022.547c-.505 0-.903.197-1.255.537L3.82 16.673a6 6 0 003.86 2.518l.318.158a6 6 0 003.86-.517l2.387-.477a2 2 0 001.022-.547zM10 15.272a8 8 0 00-5.457-2.91l3.569-3.569a8 8 0 015.458 2.91l-3.57 3.568a8 8 0 00-5.457 2.91z"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ {{ $question->kp_code }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @if($question->mark_detected)
|
|
|
|
|
+ <div class="text-lg">
|
|
|
|
|
+ {!! $question->mark_badge ?? $question->mark_detected !!}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ </tbody>
|
|
|
|
|
+ </table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {{-- 提交分析按钮 --}}
|
|
|
|
|
+ @if(!$this->hasAnalysisResults)
|
|
|
|
|
+ <div class="card bg-primary/10 border border-primary mt-6">
|
|
|
|
|
+ <div class="card-body">
|
|
|
|
|
+ <div class="flex justify-between items-center">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h3 class="font-bold text-lg flex items-center gap-2">
|
|
|
|
|
+ <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 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>
|
|
|
|
|
+ 提交 AI 分析
|
|
|
|
|
+ </h3>
|
|
|
|
|
+ <p class="text-sm text-base-content/70 mt-1">
|
|
|
|
|
+ 将使用手动校准的答案(如有),否则使用 OCR 识别结果进行智能分析
|
|
|
|
|
+ </p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <button
|
|
|
|
|
+ wire:click="submitForAnalysis"
|
|
|
|
|
+ class="btn btn-primary btn-lg"
|
|
|
|
|
+ >
|
|
|
|
|
+ <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 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 mt-6">
|
|
|
|
|
+ <div class="card-body">
|
|
|
|
|
+ <div class="flex justify-between items-center">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h3 class="font-bold text-lg text-success flex items-center gap-2">
|
|
|
|
|
+ <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>
|
|
|
|
|
+ AI 分析已完成
|
|
|
|
|
+ </h3>
|
|
|
|
|
+ <p class="text-sm text-base-content/70 mt-1">
|
|
|
|
|
+ 所有题目已完成 AI 智能分析,查看上方表格中的详细分析结果
|
|
|
|
|
+ </p>
|
|
|
|
|
+ @if($record->ai_analyzed_at)
|
|
|
|
|
+ <div class="flex gap-4 mt-2 text-sm text-base-content/60">
|
|
|
|
|
+ <span>分析完成时间:{{ $record->ai_analyzed_at }}</span>
|
|
|
|
|
+ @if($record->ai_analysis_count)
|
|
|
|
|
+ <span>分析题目数:{{ $record->ai_analysis_count }}</span>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="badge badge-success badge-lg gap-2">
|
|
|
|
|
+ <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 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ 已分析
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @else
|
|
|
|
|
+ <div class="text-center py-12 text-base-content/60">
|
|
|
|
|
+ <svg class="w-12 h-12 mx-auto mb-4 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 class="text-lg font-medium">暂无识别结果</p>
|
|
|
|
|
+ @if($record->status === 'pending')
|
|
|
|
|
+ <p class="text-sm mt-2">点击上方"开始识别"按钮开始处理</p>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {{-- DaisyUI 时间轴 --}}
|
|
|
|
|
+ <div class="card bg-base-100 border border-base-300 shadow-xl">
|
|
|
|
|
+ <div class="card-body">
|
|
|
|
|
+ <h2 class="card-title text-xl flex items-center gap-2 mb-6">
|
|
|
|
|
+ <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 timeline-vertical">
|
|
|
|
|
+ <li>
|
|
|
|
|
+ <div class="timeline-middle">
|
|
|
|
|
+ <div class="timeline-box timeline-box-success">
|
|
|
|
|
+ <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="M5 13l4 4L19 7"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="timeline-end">
|
|
|
|
|
+ <time class="text-xs opacity-70">{{ $record->created_at->format('m-d H:i:s') }}</time>
|
|
|
|
|
+ <div class="timeline-title font-bold text-base">上传成功</div>
|
|
|
|
|
+ <div class="timeline-body text-sm opacity-80">卷子图片已上传,等待OCR识别</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <hr class="border-success" />
|
|
|
|
|
+ </li>
|
|
|
|
|
+
|
|
|
|
|
+ @if($record->status === 'processing')
|
|
|
|
|
+ <li>
|
|
|
|
|
+ <div class="timeline-middle">
|
|
|
|
|
+ <div class="timeline-box timeline-box-info animate-pulse">
|
|
|
|
|
+ <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 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-end">
|
|
|
|
|
+ <time class="text-xs opacity-70">{{ now()->format('m-d H:i:s') }}</time>
|
|
|
|
|
+ <div class="timeline-title font-bold text-base text-info">处理中</div>
|
|
|
|
|
+ <div class="timeline-body text-sm opacity-80">OCR识别正在进行中...</div>
|
|
|
|
|
+ <div class="loading loading-spinner loading-sm mt-2"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <hr class="border-info" />
|
|
|
|
|
+ </li>
|
|
|
|
|
+ @elseif($record->status === 'completed')
|
|
|
|
|
+ <li>
|
|
|
|
|
+ <div class="timeline-middle">
|
|
|
|
|
+ <div class="timeline-box timeline-box-success">
|
|
|
|
|
+ <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="M5 13l4 4L19 7"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="timeline-end">
|
|
|
|
|
+ <time class="text-xs opacity-70">{{ $record->processed_at?->format('m-d H:i:s') }}</time>
|
|
|
|
|
+ <div class="timeline-title font-bold text-base text-success">OCR识别完成</div>
|
|
|
|
|
+ <div class="timeline-body text-sm opacity-80">
|
|
|
|
|
+ OCR识别已完成,识别出 {{ $record->total_questions ?? 0 }} 道题目
|
|
|
|
|
+ <div class="badge badge-success badge-sm mt-2">
|
|
|
|
|
+ 准确率: {{ number_format(($record->confidence_avg ?? 0) * 100, 1) }}%
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <hr class="border-success" />
|
|
|
|
|
+ </li>
|
|
|
|
|
+ @elseif($record->status === 'failed')
|
|
|
|
|
+ <li>
|
|
|
|
|
+ <div class="timeline-middle">
|
|
|
|
|
+ <div class="timeline-box timeline-box-error">
|
|
|
|
|
+ <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="M6 18L18 6M6 6l12 12"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="timeline-end">
|
|
|
|
|
+ <time class="text-xs opacity-70">{{ now()->format('m-d H:i:s') }}</time>
|
|
|
|
|
+ <div class="timeline-title font-bold text-base text-error">OCR识别失败</div>
|
|
|
|
|
+ @if($record->error_message)
|
|
|
|
|
+ <div class="timeline-body text-sm text-error bg-error/10 p-2 rounded mt-2">
|
|
|
|
|
+ {{ $record->error_message }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <hr class="border-error" />
|
|
|
|
|
+ </li>
|
|
|
|
|
+ @endif
|
|
|
|
|
+
|
|
|
|
|
+ {{-- AI Analysis Timeline --}}
|
|
|
|
|
+ @if($record->status === 'completed' && $record->ai_analyzed_at)
|
|
|
|
|
+ <li>
|
|
|
|
|
+ <div class="timeline-middle">
|
|
|
|
|
+ <div class="timeline-box timeline-box-info">
|
|
|
|
|
+ <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 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-end">
|
|
|
|
|
+ <time class="text-xs opacity-70">{{ $record->ai_analyzed_at }}</time>
|
|
|
|
|
+ <div class="timeline-title font-bold text-base text-info">AI 分析完成</div>
|
|
|
|
|
+ <div class="timeline-body text-sm opacity-80">
|
|
|
|
|
+ 已完成 {{ $record->ai_analysis_count ?? count($record->questions) }} 道题目的智能分析
|
|
|
|
|
+ <div class="flex gap-2 mt-2">
|
|
|
|
|
+ <div class="badge badge-success badge-sm">
|
|
|
|
|
+ <svg class="w-3 h-3" 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 class="badge badge-info badge-sm">学习分析</div>
|
|
|
|
|
+ <div class="badge badge-warning badge-sm">掌握度评估</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <hr class="border-info" />
|
|
|
|
|
+ </li>
|
|
|
|
|
+ @endif
|
|
|
|
|
+
|
|
|
|
|
+ {{-- 学生仪表板跳转 --}}
|
|
|
|
|
+ @if($record->status === 'completed' && $record->ai_analyzed_at)
|
|
|
|
|
+ <li>
|
|
|
|
|
+ <div class="timeline-middle">
|
|
|
|
|
+ <div class="timeline-box timeline-box-warning">
|
|
|
|
|
+ <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 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-end">
|
|
|
|
|
+ <div class="timeline-title font-bold text-base text-warning">查看详细分析</div>
|
|
|
|
|
+ <div class="timeline-body text-sm opacity-80">
|
|
|
|
|
+ 在学生仪表板中查看更详细的学习分析报告
|
|
|
|
|
+ <div class="mt-3">
|
|
|
|
|
+ @if($record->student)
|
|
|
|
|
+ <a href="{{ route('filament.admin.pages.student-dashboard') }}?student_id={{ $record->student->student_id }}"
|
|
|
|
|
+ class="btn btn-primary btn-sm gap-2 hover:btn-primary-focus transition-all">
|
|
|
|
|
+ <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="M13 7l5 5m0 0l-5 5m5-5H6"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ 学生仪表板
|
|
|
|
|
+ </a>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <div class="btn btn-disabled btn-sm gap-2">
|
|
|
|
|
+ <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="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ 学生信息缺失
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </li>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <div class="card bg-base-100 border border-base-300 shadow-xl">
|
|
|
|
|
+ <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>
|
|
|
|
|
+
|
|
|
|
|
+</x-filament-panels::page>
|