| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- <x-filament-panels::page>
- @push('styles')
- <style>
- .exam-card {
- transition: all 0.3s ease;
- }
- .exam-card:hover {
- transform: translateY(-2px);
- box-shadow: 0 10px 25px rgba(0,0,0,0.1);
- }
- .skill-tag {
- display: inline-block;
- padding: 4px 12px;
- margin: 4px;
- background: #e0f2fe;
- color: #0369a1;
- border-radius: 12px;
- font-size: 12px;
- }
- .difficulty-indicator {
- width: 100%;
- height: 8px;
- border-radius: 4px;
- overflow: hidden;
- }
- .difficulty-easy { background: #86efac; }
- .difficulty-medium { background: #fde047; }
- .difficulty-hard { background: #fca5a5; }
- </style>
- @endpush
- <div class="space-y-6">
- <!-- 页面标题和操作 -->
- <div class="flex justify-between items-center">
- <div>
- <h2 class="text-2xl font-bold text-gray-900">智能出卷系统</h2>
- <p class="mt-1 text-sm text-gray-500">
- 基于知识点掌握度和技能依赖关系,智能生成个性化试卷
- </p>
- </div>
- <div class="flex gap-3">
- button
- color="gray"
- wire:click="resetForm"
- >
- 重置
- /button>
- </div>
- </div>
- <!-- 主要内容区 -->
- <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
- <!-- 左侧:配置表单 -->
- <div class="lg:col-span-2 space-y-6">
- <!-- 基本信息 -->
- <div class="bg-white p-6 rounded-lg border shadow-sm" class="exam-card">
- <x-slot name="header">
- <div class="flex items-center gap-3">
- <div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
- <x-heroicon-o-document-text class="w-6 h-6 text-blue-600" />
- </div>
- <div>
- <h3 class="text-lg font-semibold text-gray-900">基本信息</h3>
- <p class="text-sm text-gray-500">设置试卷名称、难度和题目数量</p>
- </div>
- </div>
- </x-slot>
- <div class="space-y-4">
- <input
- wire:model="paperName"
- label="试卷名称"
- placeholder="例如:因式分解专项练习(基础版)"
- required
- />
- <textarea
- wire:model="paperDescription"
- label="试卷描述"
- placeholder="描述本试卷的特点、适用对象等(可选)"
- rows="3"
- />
- <div class="grid grid-cols-3 gap-4">
- <select
- wire:model="difficultyCategory"
- label="难度分类"
- >
- <option value="基础">基础</option>
- <option value="进阶">进阶</option>
- <option value="竞赛">竞赛</option>
- /select>
- <input
- wire:model="totalQuestions"
- type="number"
- label="题目数量"
- min="5"
- max="100"
- required
- />
- <input
- wire:model="totalScore"
- type="number"
- label="总分"
- min="0"
- max="200"
- />
- </div>
- </div>
- </div>
- <!-- 知识点选择 -->
- <div class="bg-white p-6 rounded-lg border shadow-sm" class="exam-card">
- <x-slot name="header">
- <div class="flex items-center justify-between">
- <div class="flex items-center gap-3">
- <div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center">
- <x-heroicon-o-academic-cap class="w-6 h-6 text-green-600" />
- </div>
- <div>
- <h3 class="text-lg font-semibold text-gray-900">知识点选择</h3>
- <p class="text-sm text-gray-500">选择要考查的知识点(可多选)</p>
- </div>
- </div>
- <div class="text-sm text-gray-500">
- 已选择: {{ count($selectedKpCodes) }} 个
- </div>
- </div>
- </x-slot>
- <div class="space-y-3">
- <div class="grid grid-cols-1 md:grid-cols-2 gap-3 max-h-64 overflow-y-auto">
- @foreach($this->knowledgePoints as $kp)
- <label class="flex items-start gap-3 p-3 border rounded-lg hover:bg-gray-50 cursor-pointer">
- <input type="checkbox"
- wire:model="selectedKpCodes"
- value="{{ $kp['kp_code'] }}"
- class="mt-1"
- />
- <div class="flex-1">
- <div class="font-medium text-gray-900">{{ $kp['cn_name'] ?? $kp['kp_code'] }}</div>
- @if(!empty($kp['description']))
- <div class="text-sm text-gray-500 mt-1">{{ Str::limit($kp['description'], 80) }}</div>
- @endif
- <div class="flex items-center gap-2 mt-2">
- <span class="text-xs px-2 py-0.5 bg-blue-100 text-blue-700 rounded">
- {{ $kp['kp_code'] }}
- </span>
- @if(!empty($kp['level']))
- <span class="text-xs px-2 py-0.5 bg-gray-100 text-gray-700 rounded">
- Level {{ $kp['level'] }}
- </span>
- @endif
- </div>
- </div>
- </label>
- @endforeach
- </div>
- </div>
- </div>
- <!-- 技能点选择 -->
- @if(count($this->skills) > 0)
- <div class="bg-white p-6 rounded-lg border shadow-sm" class="exam-card">
- <x-slot name="header">
- <div class="flex items-center justify-between">
- <div class="flex items-center gap-3">
- <div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
- <x-heroicon-o-adjustments-horizontal class="w-6 h-6 text-purple-600" />
- </div>
- <div>
- <h3 class="text-lg font-semibold text-gray-900">技能点选择</h3>
- <p class="text-sm text-gray-500">根据知识点自动获取相关技能点</p>
- </div>
- </div>
- </div>
- </x-slot>
- <div class="space-y-3">
- <div class="flex flex-wrap gap-2">
- @foreach($this->skills as $skill)
- <label class="skill-tag cursor-pointer">
- <input type="checkbox"
- wire:model="selectedSkills"
- value="{{ $skill['skill_name'] }}"
- class="sr-only"
- />
- {{ $skill['skill_name'] }}
- </label>
- @endforeach
- </div>
- </div>
- </div>
- @endif
- <!-- 题型配比 -->
- <div class="bg-white p-6 rounded-lg border shadow-sm" class="exam-card">
- <x-slot name="header">
- <div class="flex items-center gap-3">
- <div class="w-10 h-10 bg-yellow-100 rounded-lg flex items-center justify-center">
- <x-heroicon-o-chart-pie class="w-6 h-6 text-yellow-600" />
- </div>
- <div>
- <h3 class="text-lg font-semibold text-gray-900">题型配比</h3>
- <p class="text-sm text-gray-500">设置各类题型的比例(总和为100%)</p>
- </div>
- </div>
- </x-slot>
- <div class="space-y-3">
- @foreach($questionTypeRatio as $type => $percentage)
- <div class="flex items-center gap-4">
- <div class="w-24 text-sm font-medium text-gray-700">{{ $type }}</div>
- <div class="flex-1">
- <input
- type="range"
- min="0"
- max="100"
- wire:model="questionTypeRatio.{{ $type }}"
- class="w-full"
- />
- </div>
- <div class="w-16 text-sm text-gray-600">{{ $percentage }}%</div>
- </div>
- @endforeach
- <div class="text-xs text-gray-500">
- 总计: {{ array_sum($questionTypeRatio) }}%
- @if(array_sum($questionTypeRatio) !== 100)
- <span class="text-red-500 ml-2">(应为100%)</span>
- @endif
- </div>
- </div>
- </div>
- <!-- 难度配比 -->
- <div class="bg-white p-6 rounded-lg border shadow-sm" class="exam-card">
- <x-slot name="header">
- <div class="flex items-center gap-3">
- <div class="w-10 h-10 bg-indigo-100 rounded-lg flex items-center justify-center">
- <x-heroicon-o-signal class="w-6 h-6 text-indigo-600" />
- </div>
- <div>
- <h3 class="text-lg font-semibold text-gray-900">难度配比</h3>
- <p class="text-sm text-gray-500">设置各难度题目的比例</p>
- </div>
- </div>
- </x-slot>
- <div class="space-y-3">
- @foreach($difficultyRatio as $level => $percentage)
- <div class="flex items-center gap-4">
- <div class="w-24 text-sm font-medium text-gray-700">{{ $level }}</div>
- <div class="flex-1">
- <input
- type="range"
- min="0"
- max="100"
- wire:model="difficultyRatio.{{ $level }}"
- class="w-full"
- />
- </div>
- <div class="w-16 text-sm text-gray-600">{{ $percentage }}%</div>
- </div>
- @endforeach
- <div class="text-xs text-gray-500">
- 总计: {{ array_sum($difficultyRatio) }}%
- @if(array_sum($difficultyRatio) !== 100)
- <span class="text-red-500 ml-2">(应为100%)</span>
- @endif
- </div>
- </div>
- </div>
- </div>
- <!-- 右侧:操作面板 -->
- <div class="space-y-6">
- <!-- 学生选择(可选) -->
- <div class="bg-white p-6 rounded-lg border shadow-sm" class="exam-card">
- <x-slot name="header">
- <div class="flex items-center gap-3">
- <div class="w-10 h-10 bg-pink-100 rounded-lg flex items-center justify-center">
- <x-heroicon-o-user class="w-6 h-6 text-pink-600" />
- </div>
- <div>
- <h3 class="text-lg font-semibold text-gray-900">个性化设置</h3>
- <p class="text-sm text-gray-500">根据学生情况定制</p>
- </div>
- </div>
- </x-slot>
- <div class="space-y-4">
- <select
- wire:model="selectedStudentId"
- label="选择学生(可选)"
- placeholder="不指定则生成通用试卷"
- >
- <option value="">-- 不指定 --</option>
- @foreach($this->students as $student)
- <option value="{{ $student['student_id'] }}">
- {{ $student['name'] ?? $student['student_id'] }}
- </option>
- @endforeach
- /select>
- <label class="flex items-start gap-3">
- <input type="checkbox"
- wire:model="filterByStudentWeakness"
- wire:click="$refresh"
- />
- <div>
- <div class="text-sm font-medium text-gray-900">基于学生薄弱点</div>
- <div class="text-xs text-gray-500">
- 根据学生历史答题数据,自动筛选其薄弱知识点
- </div>
- </div>
- </label>
- @if(count($this->studentWeaknesses) > 0)
- <div class="mt-4 p-3 bg-amber-50 rounded-lg">
- <div class="text-sm font-medium text-amber-800 mb-2">检测到学生的薄弱点:</div>
- <div class="space-y-1">
- @foreach($this->studentWeaknesses as $weakness)
- <div class="text-xs text-amber-700 flex items-center gap-2">
- <span>{{ $weakness['kp_name'] ?? $weakness['kp_code'] }}</span>
- <span class="text-amber-600">
- (掌握度: {{ number_format($weakness['mastery'] * 100, 1) }}%)
- </span>
- </div>
- @endforeach
- </div>
- </div>
- @endif
- </div>
- </div>
- <!-- 生成按钮 -->
- <div class="bg-white p-6 rounded-lg border shadow-sm">
- <div class="space-y-4">
- button
- wire:click="generateExam"
- color="primary"
- class="w-full"
- size="lg"
- :disabled="$isGenerating"
- >
- @if($isGenerating)
- <svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
- <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
- <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
- </svg>
- 生成中...
- @else
- <x-heroicon-m-sparkles class="w-5 h-5 mr-2" />
- 智能生成试卷
- @endif
- /button>
- @if($generatedPaperId)
- button
- wire:click="exportToPdf"
- color="success"
- class="w-full"
- size="lg"
- >
- <x-heroicon-m-arrow-down-tray class="w-5 h-5 mr-2" />
- 导出PDF
- /button>
- @endif
- @if(!empty($generatedQuestions))
- <div class="mt-4 p-4 bg-green-50 rounded-lg">
- <div class="flex items-center gap-2 text-green-800">
- <x-heroicon-o-check-circle class="w-5 h-5" />
- <div class="font-medium">生成成功</div>
- </div>
- <div class="mt-2 text-sm text-green-700">
- 已生成试卷ID: <span class="font-mono">{{ $generatedPaperId }}</span>
- </div>
- <div class="mt-1 text-sm text-green-700">
- 题目数量: {{ count($generatedQuestions) }} 题
- </div>
- </div>
- @endif
- </div>
- </div>
- </div>
- </div>
- <!-- 生成的试卷预览 -->
- @if(!empty($generatedQuestions))
- <div class="bg-white p-6 rounded-lg border shadow-sm" class="mt-6">
- <x-slot name="header">
- <div class="flex items-center gap-3">
- <div class="w-10 h-10 bg-emerald-100 rounded-lg flex items-center justify-center">
- <x-heroicon-o-document-magnifying-glass class="w-6 h-6 text-emerald-600" />
- </div>
- <div>
- <h3 class="text-lg font-semibold text-gray-900">试卷预览</h3>
- <p class="text-sm text-gray-500">生成的题目列表</p>
- </div>
- </div>
- </x-slot>
- <div class="space-y-4">
- @foreach($generatedQuestions as $index => $question)
- <div class="border rounded-lg p-4">
- <div class="flex items-start gap-4">
- <div class="flex-shrink-0 w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center text-blue-700 font-semibold">
- {{ $index + 1 }}
- </div>
- <div class="flex-1">
- <div class="flex items-center gap-2 mb-2">
- <span class="text-sm px-2 py-0.5 bg-gray-100 text-gray-700 rounded">
- {{ $question['kp_code'] }}
- </span>
- <span class="text-sm px-2 py-0.5 bg-blue-100 text-blue-700 rounded">
- {{ $question['question_type'] ?? '解答题' }}
- </span>
- @if(isset($question['difficulty']))
- <span class="text-sm px-2 py-0.5
- @if($question['difficulty'] <= 0.3) bg-green-100 text-green-700
- @elseif($question['difficulty'] <= 0.7) bg-yellow-100 text-yellow-700
- @else bg-red-100 text-red-700
- @endif
- rounded">
- {{ $question['difficulty'] <= 0.3 ? '基础' : ($question['difficulty'] <= 0.7 ? '中等' : '拔高') }}
- </span>
- @endif
- </div>
- <div class="prose prose-sm max-w-none text-gray-900">
- {!! $question['stem'] !!}
- </div>
- @if(!empty($question['answer']))
- <div class="mt-2 text-sm text-gray-600">
- <strong>参考答案:</strong> {!! $question['answer'] !!}
- </div>
- @endif
- </div>
- </div>
- </div>
- @endforeach
- </div>
- </div>
- @endif
- </div>
- </x-filament-pages::page>
|