|
@@ -3,10 +3,99 @@
|
|
|
<style>
|
|
<style>
|
|
|
.exam-card {
|
|
.exam-card {
|
|
|
transition: all 0.3s ease;
|
|
transition: all 0.3s ease;
|
|
|
|
|
+ border: 1px solid rgba(0, 0, 0, 0.05);
|
|
|
}
|
|
}
|
|
|
.exam-card:hover {
|
|
.exam-card:hover {
|
|
|
transform: translateY(-2px);
|
|
transform: translateY(-2px);
|
|
|
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
|
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
|
|
|
|
+ border-color: rgba(59, 130, 246, 0.2);
|
|
|
|
|
+ }
|
|
|
|
|
+ .generate-button {
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
|
|
+ box-shadow: 0 4px 15px 0 rgba(102, 126, 234, 0.4);
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ padding: 14px 28px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .generate-button:hover:not(:disabled) {
|
|
|
|
|
+ transform: translateY(-2px);
|
|
|
|
|
+ box-shadow: 0 6px 20px 0 rgba(102, 126, 234, 0.6);
|
|
|
|
|
+ background: linear-gradient(135deg, #5568d3 0%, #653a8b 100%);
|
|
|
|
|
+ }
|
|
|
|
|
+ .generate-button:active:not(:disabled) {
|
|
|
|
|
+ transform: translateY(0);
|
|
|
|
|
+ }
|
|
|
|
|
+ .generate-button:disabled {
|
|
|
|
|
+ background: #cbd5e1;
|
|
|
|
|
+ box-shadow: none;
|
|
|
|
|
+ cursor: not-allowed;
|
|
|
|
|
+ }
|
|
|
|
|
+ .step-indicator {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ padding-left: 30px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .step-indicator::before {
|
|
|
|
|
+ content: '';
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 10px;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ width: 2px;
|
|
|
|
|
+ background: #e5e7eb;
|
|
|
|
|
+ }
|
|
|
|
|
+ .step-item {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .step-item::before {
|
|
|
|
|
+ content: attr(data-step);
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: -30px;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ width: 20px;
|
|
|
|
|
+ height: 20px;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border: 2px solid #d1d5db;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ font-size: 11px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #9ca3af;
|
|
|
|
|
+ }
|
|
|
|
|
+ .step-item.completed::before {
|
|
|
|
|
+ background: #10b981;
|
|
|
|
|
+ border-color: #10b981;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+ .step-item.active::before {
|
|
|
|
|
+ background: #3b82f6;
|
|
|
|
|
+ border-color: #3b82f6;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+ .selection-card {
|
|
|
|
|
+ transition: all 0.2s ease;
|
|
|
|
|
+ }
|
|
|
|
|
+ .selection-card:hover {
|
|
|
|
|
+ background-color: #f9fafb;
|
|
|
|
|
+ border-color: #3b82f6;
|
|
|
|
|
+ }
|
|
|
|
|
+ .selection-card.selected {
|
|
|
|
|
+ background-color: #eff6ff;
|
|
|
|
|
+ border-color: #3b82f6;
|
|
|
|
|
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
|
|
|
+ }
|
|
|
|
|
+ .form-select, .form-input {
|
|
|
|
|
+ background-color: white;
|
|
|
|
|
+ border: 2px solid #e5e7eb;
|
|
|
|
|
+ transition: all 0.2s ease;
|
|
|
|
|
+ }
|
|
|
|
|
+ .form-select:focus, .form-input:focus {
|
|
|
|
|
+ border-color: #3b82f6;
|
|
|
|
|
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
|
|
|
+ outline: none;
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|
|
|
@endpush
|
|
@endpush
|
|
@@ -49,51 +138,59 @@
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<!-- 基本信息卡片 -->
|
|
<!-- 基本信息卡片 -->
|
|
|
- <div class="bg-white p-6 rounded-lg border shadow-sm">
|
|
|
|
|
- <h3 class="text-lg font-semibold text-gray-900 mb-4">基本信息</h3>
|
|
|
|
|
|
|
+ <div class="bg-white p-8 rounded-xl border shadow-sm exam-card">
|
|
|
|
|
+ <div class="flex items-center gap-3 mb-6">
|
|
|
|
|
+ <div class="w-12 h-12 bg-blue-100 rounded-xl flex items-center justify-center">
|
|
|
|
|
+ <svg class="w-6 h-6 text-blue-600" 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" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h3 class="text-xl font-semibold text-gray-900">步骤 1:基本信息设置</h3>
|
|
|
|
|
+ <p class="text-sm text-gray-500">设置试卷的基本参数</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
<div class="space-y-4">
|
|
<div class="space-y-4">
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
<div class="grid grid-cols-3 gap-4">
|
|
<div class="grid grid-cols-3 gap-4">
|
|
|
- <div>
|
|
|
|
|
|
|
+ <div class="selection-card border rounded-lg p-4">
|
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">难度分类</label>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">难度分类</label>
|
|
|
- <select wire:model="difficultyCategory" class="form-select w-full px-3 py-2 border rounded-lg">
|
|
|
|
|
|
|
+ <select wire:model="difficultyCategory" class="form-select w-full px-3 py-2 rounded-lg text-sm">
|
|
|
<option value="基础">基础</option>
|
|
<option value="基础">基础</option>
|
|
|
<option value="进阶">进阶</option>
|
|
<option value="进阶">进阶</option>
|
|
|
<option value="竞赛">竞赛</option>
|
|
<option value="竞赛">竞赛</option>
|
|
|
</select>
|
|
</select>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div>
|
|
|
|
|
|
|
+ <div class="selection-card border rounded-lg p-4">
|
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">题目数量 <span class="text-red-500">*</span></label>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">题目数量 <span class="text-red-500">*</span></label>
|
|
|
<input
|
|
<input
|
|
|
type="number"
|
|
type="number"
|
|
|
wire:model="totalQuestions"
|
|
wire:model="totalQuestions"
|
|
|
- class="form-input w-full px-3 py-2 border rounded-lg"
|
|
|
|
|
|
|
+ class="form-input w-full px-3 py-2 rounded-lg text-sm"
|
|
|
min="6"
|
|
min="6"
|
|
|
max="100"
|
|
max="100"
|
|
|
required
|
|
required
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div>
|
|
|
|
|
|
|
+ <div class="selection-card border rounded-lg p-4">
|
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">总分</label>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">总分</label>
|
|
|
<input
|
|
<input
|
|
|
type="number"
|
|
type="number"
|
|
|
wire:model="totalScore"
|
|
wire:model="totalScore"
|
|
|
- class="form-input w-full px-3 py-2 border rounded-lg"
|
|
|
|
|
|
|
+ class="form-input w-full px-3 py-2 rounded-lg text-sm"
|
|
|
min="0"
|
|
min="0"
|
|
|
max="200"
|
|
max="200"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div>
|
|
|
|
|
|
|
+ <div class="selection-card border rounded-lg p-4">
|
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">试卷名称 <span class="text-gray-400 font-normal">(选填,未填则自动生成)</span></label>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">试卷名称 <span class="text-gray-400 font-normal">(选填,未填则自动生成)</span></label>
|
|
|
<input
|
|
<input
|
|
|
type="text"
|
|
type="text"
|
|
|
wire:model="paperName"
|
|
wire:model="paperName"
|
|
|
- class="form-input w-full px-3 py-2 border rounded-lg"
|
|
|
|
|
|
|
+ class="form-input w-full px-3 py-2 rounded-lg text-sm"
|
|
|
placeholder="例如:因式分解专项练习(基础版)"
|
|
placeholder="例如:因式分解专项练习(基础版)"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
@@ -101,16 +198,26 @@
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<!-- 教师和学生选择 -->
|
|
<!-- 教师和学生选择 -->
|
|
|
- <div class="bg-white p-6 rounded-lg border shadow-sm">
|
|
|
|
|
- <h3 class="text-lg font-semibold text-gray-900 mb-4">针对性出卷</h3>
|
|
|
|
|
|
|
+ <div class="bg-white p-8 rounded-xl border shadow-sm exam-card">
|
|
|
|
|
+ <div class="flex items-center gap-3 mb-6">
|
|
|
|
|
+ <div class="w-12 h-12 bg-purple-100 rounded-xl flex items-center justify-center">
|
|
|
|
|
+ <svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h3 class="text-xl font-semibold text-gray-900">步骤 2:选择教师与学生</h3>
|
|
|
|
|
+ <p class="text-sm text-gray-500">启用个性化出卷功能</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
<div class="space-y-6">
|
|
<div class="space-y-6">
|
|
|
<!-- 直接在父组件中显示教师和学生选择,避免组件间通信问题 -->
|
|
<!-- 直接在父组件中显示教师和学生选择,避免组件间通信问题 -->
|
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
|
- <div>
|
|
|
|
|
|
|
+ <div class="selection-card border rounded-lg p-4">
|
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">选择教师</label>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">选择教师</label>
|
|
|
<select
|
|
<select
|
|
|
wire:model.live="selectedTeacherId"
|
|
wire:model.live="selectedTeacherId"
|
|
|
- class="w-full px-3 py-2 border rounded-lg"
|
|
|
|
|
|
|
+ class="form-select w-full px-3 py-2 rounded-lg text-sm"
|
|
|
>
|
|
>
|
|
|
<option value="">-- 请选择教师 --</option>
|
|
<option value="">-- 请选择教师 --</option>
|
|
|
@foreach($this->teachers as $teacher)
|
|
@foreach($this->teachers as $teacher)
|
|
@@ -121,11 +228,11 @@
|
|
|
</select>
|
|
</select>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div>
|
|
|
|
|
|
|
+ <div class="selection-card border rounded-lg p-4">
|
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">选择学生</label>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">选择学生</label>
|
|
|
<select
|
|
<select
|
|
|
wire:model.live="selectedStudentId"
|
|
wire:model.live="selectedStudentId"
|
|
|
- class="w-full px-3 py-2 border rounded-lg"
|
|
|
|
|
|
|
+ class="form-select w-full px-3 py-2 rounded-lg text-sm"
|
|
|
@if(empty($selectedTeacherId)) disabled @endif
|
|
@if(empty($selectedTeacherId)) disabled @endif
|
|
|
>
|
|
>
|
|
|
<option value="">
|
|
<option value="">
|
|
@@ -144,14 +251,6 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <!-- 原有的组件暂时保留但不显示,用于调试 -->
|
|
|
|
|
- <div style="display:none;">
|
|
|
|
|
- <livewire:teacher-student-selector
|
|
|
|
|
- :initial-teacher-id="$selectedTeacherId"
|
|
|
|
|
- :initial-student-id="$selectedStudentId"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
<!-- 显示当前选择状态 -->
|
|
<!-- 显示当前选择状态 -->
|
|
|
<div class="mt-4 p-4 bg-gray-50 rounded-lg">
|
|
<div class="mt-4 p-4 bg-gray-50 rounded-lg">
|
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
@@ -198,25 +297,31 @@
|
|
|
|
|
|
|
|
<!-- 学生薄弱知识点展示区域 -->
|
|
<!-- 学生薄弱知识点展示区域 -->
|
|
|
@if($selectedStudentId && $filterByStudentWeakness && count($this->studentWeaknesses) > 0)
|
|
@if($selectedStudentId && $filterByStudentWeakness && count($this->studentWeaknesses) > 0)
|
|
|
- <div class="bg-white p-6 rounded-lg border shadow-sm">
|
|
|
|
|
- <h3 class="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
|
|
|
|
|
- <svg class="w-5 h-5 text-orange-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
|
|
|
|
- </svg>
|
|
|
|
|
- 学生薄弱知识点
|
|
|
|
|
- <span class="text-sm font-normal text-gray-500">(共{{ count($this->studentWeaknesses) }}个)</span>
|
|
|
|
|
- </h3>
|
|
|
|
|
- <div class="bg-orange-50 border-l-4 border-orange-400 p-4 mb-4">
|
|
|
|
|
- <div class="flex">
|
|
|
|
|
- <div class="flex-shrink-0">
|
|
|
|
|
- <svg class="h-5 w-5 text-orange-400" viewBox="0 0 20 20" fill="currentColor">
|
|
|
|
|
- <path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"></path>
|
|
|
|
|
- </svg>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="ml-3">
|
|
|
|
|
|
|
+ <div class="bg-white p-8 rounded-xl border shadow-sm exam-card">
|
|
|
|
|
+ <div class="flex items-center gap-3 mb-6">
|
|
|
|
|
+ <div class="w-12 h-12 bg-orange-100 rounded-xl flex items-center justify-center">
|
|
|
|
|
+ <svg class="w-6 h-6 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h3 class="text-xl font-semibold text-gray-900">学生薄弱知识点分析</h3>
|
|
|
|
|
+ <p class="text-sm text-gray-500">基于答题数据的智能分析(共{{ count($this->studentWeaknesses) }}个)</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="bg-gradient-to-r from-orange-50 to-amber-50 border border-orange-200 rounded-xl p-5 mb-6">
|
|
|
|
|
+ <div class="flex items-start gap-3">
|
|
|
|
|
+ <svg class="h-6 w-6 text-orange-500 flex-shrink-0 mt-0.5" viewBox="0 0 20 20" fill="currentColor">
|
|
|
|
|
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <p class="text-sm text-orange-800 font-medium mb-1">
|
|
|
|
|
+ 智能分析结果(可选)
|
|
|
|
|
+ </p>
|
|
|
<p class="text-sm text-orange-700">
|
|
<p class="text-sm text-orange-700">
|
|
|
以下是根据该学生的答题数据自动分析出的薄弱知识点(共{{ count($this->studentWeaknesses) }}个)。
|
|
以下是根据该学生的答题数据自动分析出的薄弱知识点(共{{ count($this->studentWeaknesses) }}个)。
|
|
|
- <strong>请手动勾选</strong>您希望该学生练习的知识点,或点击下方按钮进行批量操作。
|
|
|
|
|
|
|
+ <strong>您可以选择这些薄弱点</strong>,或者在下方<strong>步骤3</strong>中手动选择任何知识点。
|
|
|
|
|
+ 两个区域的知识点会合并生效。
|
|
|
</p>
|
|
</p>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -231,106 +336,128 @@
|
|
|
$priority = $weakness['priority'] ?? '中';
|
|
$priority = $weakness['priority'] ?? '中';
|
|
|
$priorityColor = $priority === '高' ? 'bg-red-100 text-red-800 border-red-200' : ($priority === '中' ? 'bg-yellow-100 text-yellow-800 border-yellow-200' : 'bg-green-100 text-green-800 border-green-200');
|
|
$priorityColor = $priority === '高' ? 'bg-red-100 text-red-800 border-red-200' : ($priority === '中' ? 'bg-yellow-100 text-yellow-800 border-yellow-200' : 'bg-green-100 text-green-800 border-green-200');
|
|
|
@endphp
|
|
@endphp
|
|
|
- <div class="border rounded-lg p-4 {{ $isSelected ? 'bg-blue-50 border-blue-300' : 'bg-white' }}">
|
|
|
|
|
|
|
+ <div class="selection-card border rounded-xl p-5 {{ $isSelected ? 'selected' : '' }}">
|
|
|
<div class="flex items-start justify-between">
|
|
<div class="flex items-start justify-between">
|
|
|
- <div class="flex items-start gap-3 flex-1">
|
|
|
|
|
|
|
+ <div class="flex items-start gap-4 flex-1">
|
|
|
<div class="mt-1">
|
|
<div class="mt-1">
|
|
|
@if($isSelected)
|
|
@if($isSelected)
|
|
|
- <svg class="w-5 h-5 text-blue-600" fill="currentColor" viewBox="0 0 20 20">
|
|
|
|
|
|
|
+ <svg class="w-6 h-6 text-blue-600" fill="currentColor" viewBox="0 0 20 20">
|
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
|
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
|
|
|
</svg>
|
|
</svg>
|
|
|
@else
|
|
@else
|
|
|
<input
|
|
<input
|
|
|
type="checkbox"
|
|
type="checkbox"
|
|
|
- wire:model="selectedKpCodes"
|
|
|
|
|
|
|
+ wire:model.live="selectedKpCodes"
|
|
|
value="{{ $weakness['kp_code'] }}"
|
|
value="{{ $weakness['kp_code'] }}"
|
|
|
- class="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
|
|
|
|
|
+ class="w-5 h-5 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
|
|
|
+ wire:key="weakness-{{ $weakness['kp_code'] }}"
|
|
|
/>
|
|
/>
|
|
|
@endif
|
|
@endif
|
|
|
</div>
|
|
</div>
|
|
|
<div class="flex-1">
|
|
<div class="flex-1">
|
|
|
- <div class="font-medium text-gray-900">
|
|
|
|
|
|
|
+ <div class="font-semibold text-gray-900 text-base">
|
|
|
{{ $weakness['kp_name'] ?? $weakness['kp_code'] }}
|
|
{{ $weakness['kp_name'] ?? $weakness['kp_code'] }}
|
|
|
- <span class="ml-2 text-xs text-gray-500">({{ $weakness['kp_code'] }})</span>
|
|
|
|
|
|
|
+ <span class="ml-2 text-sm text-gray-500">({{ $weakness['kp_code'] }})</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="mt-2 flex items-center gap-4 text-sm">
|
|
|
|
|
- <div class="flex items-center gap-1">
|
|
|
|
|
- <span class="text-gray-600">掌握度:</span>
|
|
|
|
|
- <span class="font-semibold {{ $masteryPercent < 50 ? 'text-red-600' : ($masteryPercent < 70 ? 'text-yellow-600' : 'text-green-600') }}">
|
|
|
|
|
|
|
+ <div class="mt-3 flex items-center gap-6 text-sm">
|
|
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
|
|
+ <span class="text-gray-600">掌握度</span>
|
|
|
|
|
+ <span class="font-bold text-lg {{ $masteryPercent < 50 ? 'text-red-600' : ($masteryPercent < 70 ? 'text-yellow-600' : 'text-green-600') }}">
|
|
|
{{ $masteryPercent }}%
|
|
{{ $masteryPercent }}%
|
|
|
</span>
|
|
</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="flex items-center gap-1">
|
|
|
|
|
- <span class="text-gray-600">练习次数:</span>
|
|
|
|
|
- <span class="text-gray-900">{{ $weakness['practice_count'] ?? 0 }}</span>
|
|
|
|
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
|
|
+ <span class="text-gray-600">练习次数</span>
|
|
|
|
|
+ <span class="font-semibold text-gray-900">{{ $weakness['practice_count'] ?? 0 }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="flex items-center gap-1">
|
|
|
|
|
- <span class="text-gray-600">成功率:</span>
|
|
|
|
|
- <span class="text-gray-900">{{ round(($weakness['success_rate'] ?? 0) * 100, 1) }}%</span>
|
|
|
|
|
|
|
+ <div class="flex items-center gap-2">
|
|
|
|
|
+ <span class="text-gray-600">成功率</span>
|
|
|
|
|
+ <span class="font-semibold text-gray-900">{{ round(($weakness['success_rate'] ?? 0) * 100, 1) }}%</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <span class="px-2 py-1 text-xs font-medium rounded border {{ $priorityColor }}">
|
|
|
|
|
- 优先级: {{ $priority }}
|
|
|
|
|
|
|
+ <span class="px-3 py-1.5 text-sm font-semibold rounded-full {{ $priorityColor }}">
|
|
|
|
|
+ {{ $priority }}优先级
|
|
|
</span>
|
|
</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
@endforeach
|
|
@endforeach
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div class="mt-4 flex items-center justify-between">
|
|
|
|
|
|
|
+ <div class="mt-6 flex items-center justify-between bg-gray-50 rounded-xl p-4">
|
|
|
<div class="flex items-center gap-3">
|
|
<div class="flex items-center gap-3">
|
|
|
<button
|
|
<button
|
|
|
wire:click="selectAllWeaknesses"
|
|
wire:click="selectAllWeaknesses"
|
|
|
type="button"
|
|
type="button"
|
|
|
- class="px-4 py-2 bg-orange-600 text-white text-sm font-medium rounded hover:bg-orange-700 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-2"
|
|
|
|
|
|
|
+ class="px-5 py-2.5 bg-gradient-to-r from-orange-500 to-amber-500 text-white text-sm font-semibold rounded-lg hover:from-orange-600 hover:to-amber-600 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-2 transition-all shadow-md"
|
|
|
>
|
|
>
|
|
|
全选薄弱知识点 ({{ count($this->studentWeaknesses) }})
|
|
全选薄弱知识点 ({{ count($this->studentWeaknesses) }})
|
|
|
</button>
|
|
</button>
|
|
|
<button
|
|
<button
|
|
|
wire:click="clearSelection"
|
|
wire:click="clearSelection"
|
|
|
type="button"
|
|
type="button"
|
|
|
- class="px-4 py-2 bg-gray-500 text-white text-sm font-medium rounded hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2"
|
|
|
|
|
|
|
+ class="px-5 py-2.5 bg-white border-2 border-gray-300 text-gray-700 text-sm font-semibold rounded-lg hover:bg-gray-50 hover:border-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 transition-all"
|
|
|
>
|
|
>
|
|
|
清空选择
|
|
清空选择
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="text-sm text-gray-600">
|
|
|
|
|
- 已选择 <span class="font-semibold">{{ count($selectedKpCodes) }}</span> 个知识点
|
|
|
|
|
|
|
+ <div class="flex items-center gap-2 text-sm text-gray-600" x-data x-effect="$el.querySelector('.count').textContent = $wire.selectedKpCodes.length">
|
|
|
|
|
+ <span>已选择</span>
|
|
|
|
|
+ <span class="font-bold text-lg text-blue-600 count">{{ count($selectedKpCodes) }}</span>
|
|
|
|
|
+ <span>个知识点</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
@endif
|
|
@endif
|
|
|
|
|
|
|
|
<!-- 知识点选择 -->
|
|
<!-- 知识点选择 -->
|
|
|
- <div class="bg-white p-6 rounded-lg border shadow-sm">
|
|
|
|
|
- <div class="flex items-center justify-between mb-4">
|
|
|
|
|
- <h3 class="text-lg font-semibold text-gray-900">知识点选择</h3>
|
|
|
|
|
- <div class="text-sm text-gray-500">
|
|
|
|
|
- 已选择: {{ count($selectedKpCodes) }} 个
|
|
|
|
|
|
|
+ <div class="bg-white p-8 rounded-xl border shadow-sm exam-card">
|
|
|
|
|
+ <div class="flex items-center gap-3 mb-6">
|
|
|
|
|
+ <div class="w-12 h-12 bg-green-100 rounded-xl flex items-center justify-center">
|
|
|
|
|
+ <svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h3 class="text-xl font-semibold text-gray-900">步骤 3:选择知识点</h3>
|
|
|
|
|
+ <p class="text-sm text-gray-500" x-data x-effect="$el.textContent = `勾选要考查的知识点(已选择: ${$wire.selectedKpCodes.length} 个)`">
|
|
|
|
|
+ 勾选要考查的知识点(已选择: {{ count($selectedKpCodes) }} 个)
|
|
|
|
|
+ </p>
|
|
|
|
|
+ @if($selectedStudentId && $filterByStudentWeakness && count($this->studentWeaknesses) > 0)
|
|
|
|
|
+ <p class="text-xs text-blue-600 mt-1">
|
|
|
|
|
+ 💡 提示:您也可以在上方选择学生的薄弱知识点,两个区域的知识点会合并生效
|
|
|
|
|
+ </p>
|
|
|
|
|
+ @endif
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div class="grid grid-cols-1 md:grid-cols-2 gap-3 max-h-64 overflow-y-auto">
|
|
|
|
|
|
|
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-3 max-h-36 overflow-y-auto pr-1 scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-gray-100">
|
|
|
@foreach($this->knowledgePoints as $kp)
|
|
@foreach($this->knowledgePoints as $kp)
|
|
|
- <label class="flex items-start gap-3 p-3 border rounded-lg hover:bg-gray-50 cursor-pointer">
|
|
|
|
|
|
|
+ @php
|
|
|
|
|
+ $isSelected = in_array($kp['kp_code'], $selectedKpCodes);
|
|
|
|
|
+ @endphp
|
|
|
|
|
+ <label class="selection-card flex items-start gap-3 p-3 border rounded-lg cursor-pointer hover:bg-blue-50 hover:border-blue-400 transition-all shadow-sm hover:shadow-md {{ $isSelected ? 'border-blue-500 bg-blue-50' : '' }}">
|
|
|
<input
|
|
<input
|
|
|
type="checkbox"
|
|
type="checkbox"
|
|
|
- wire:model="selectedKpCodes"
|
|
|
|
|
|
|
+ wire:model.live="selectedKpCodes"
|
|
|
value="{{ $kp['kp_code'] }}"
|
|
value="{{ $kp['kp_code'] }}"
|
|
|
- class="mt-1"
|
|
|
|
|
|
|
+ class="mt-0.5 w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
|
|
|
+ wire:key="kp-{{ $kp['kp_code'] }}"
|
|
|
/>
|
|
/>
|
|
|
- <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">
|
|
|
|
|
|
|
+ <div class="flex-1 min-w-0">
|
|
|
|
|
+ <div class="font-semibold text-gray-900 text-sm leading-tight">{{ Str::limit($kp['cn_name'] ?? $kp['kp_code'], 16) }}</div>
|
|
|
|
|
+ <div class="flex items-center gap-1 mt-1.5">
|
|
|
|
|
+ <span class="text-xs px-2 py-0.5 bg-blue-100 text-blue-700 rounded-full font-medium">
|
|
|
{{ $kp['kp_code'] }}
|
|
{{ $kp['kp_code'] }}
|
|
|
</span>
|
|
</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ @if(!empty($kp['description']))
|
|
|
|
|
+ <div class="text-xs text-gray-500 mt-1 line-clamp-2">{{ Str::limit($kp['description'], 30) }}</div>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ @if($isSelected)
|
|
|
|
|
+ <div class="text-xs text-blue-600 mt-1 font-medium">✓ 已选择</div>
|
|
|
|
|
+ @endif
|
|
|
</div>
|
|
</div>
|
|
|
</label>
|
|
</label>
|
|
|
@endforeach
|
|
@endforeach
|
|
@@ -344,131 +471,227 @@
|
|
|
$questionCountValid = $totalQuestions >= 6;
|
|
$questionCountValid = $totalQuestions >= 6;
|
|
|
$readyToGenerate = $this->canGenerate();
|
|
$readyToGenerate = $this->canGenerate();
|
|
|
$missingSteps = [];
|
|
$missingSteps = [];
|
|
|
- if (!$hasTeacherStudent) { $missingSteps[] = '选择教师与学生'; }
|
|
|
|
|
|
|
+ if (empty($selectedTeacherId)) { $missingSteps[] = '选择教师'; }
|
|
|
|
|
+ if (empty($selectedStudentId)) { $missingSteps[] = '选择学生'; }
|
|
|
if (!$hasKnowledgePoints) { $missingSteps[] = '勾选至少 1 个知识点'; }
|
|
if (!$hasKnowledgePoints) { $missingSteps[] = '勾选至少 1 个知识点'; }
|
|
|
if (!$questionCountValid) { $missingSteps[] = '题目数量需 ≥ 6 题'; }
|
|
if (!$questionCountValid) { $missingSteps[] = '题目数量需 ≥ 6 题'; }
|
|
|
|
|
+
|
|
|
|
|
+ // 强制访问 selectedKpCodes 来触发 Livewire 刷新
|
|
|
|
|
+ $selectedKpCodesForDebug = $selectedKpCodes;
|
|
|
|
|
+
|
|
|
|
|
+ // 调试信息
|
|
|
|
|
+ $debugInfo = "教师: " . ($selectedTeacherId ? "✓" : "✗") .
|
|
|
|
|
+ " | 学生: " . ($selectedStudentId ? "✓" : "✗") .
|
|
|
|
|
+ " | 知识点: " . ($hasKnowledgePoints ? "✓ (" . count($selectedKpCodesForDebug) . "个)" : "✗ (实际:" . count($selectedKpCodesForDebug) . "个)") .
|
|
|
|
|
+ " | 题目数: " . ($questionCountValid ? "✓ ({$totalQuestions})" : "✗ ({$totalQuestions})");
|
|
|
|
|
+
|
|
|
|
|
+ // 显示实际的知识点代码
|
|
|
|
|
+ $kpCodesList = implode(', ', array_slice($selectedKpCodesForDebug, 0, 10));
|
|
|
|
|
+ if (count($selectedKpCodesForDebug) > 10) {
|
|
|
|
|
+ $kpCodesList .= '...';
|
|
|
|
|
+ }
|
|
|
@endphp
|
|
@endphp
|
|
|
- <div class="bg-white p-6 rounded-lg border shadow-sm space-y-4">
|
|
|
|
|
|
|
+ <div class="bg-white p-8 rounded-xl border shadow-sm exam-card space-y-6">
|
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center justify-between">
|
|
|
- <h3 class="text-lg font-semibold text-gray-900 flex items-center gap-2">
|
|
|
|
|
- <svg class="w-5 h-5 text-primary-600" 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" />
|
|
|
|
|
- </svg>
|
|
|
|
|
- 出卷前检查
|
|
|
|
|
- </h3>
|
|
|
|
|
- <span class="inline-flex items-center gap-2 px-3 py-1 text-xs font-semibold rounded-full {{ $readyToGenerate ? 'bg-green-100 text-green-800' : 'bg-amber-100 text-amber-800' }}">
|
|
|
|
|
- <span class="h-2 w-2 rounded-full {{ $readyToGenerate ? 'bg-green-500' : 'bg-amber-500' }}"></span>
|
|
|
|
|
- {{ $readyToGenerate ? '可以生成' : '待完善' }}
|
|
|
|
|
|
|
+ <div class="flex items-center gap-3">
|
|
|
|
|
+ <div class="w-12 h-12 bg-gradient-to-br from-blue-500 to-purple-600 rounded-xl flex items-center justify-center">
|
|
|
|
|
+ <svg class="w-6 h-6 text-white" 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" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h3 class="text-xl font-semibold text-gray-900">步骤 4:出卷前检查与生成</h3>
|
|
|
|
|
+ <p class="text-sm text-gray-500">验证配置并生成试卷</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span class="inline-flex items-center gap-2 px-4 py-2 text-sm font-semibold rounded-full {{ $readyToGenerate ? 'bg-green-100 text-green-800 border-2 border-green-300' : 'bg-amber-100 text-amber-800 border-2 border-amber-300' }}">
|
|
|
|
|
+ <span class="h-2.5 w-2.5 rounded-full {{ $readyToGenerate ? 'bg-green-500 animate-pulse' : 'bg-amber-500' }}"></span>
|
|
|
|
|
+ {{ $readyToGenerate ? '✓ 可以生成试卷' : '⚠ 待完善配置' }}
|
|
|
</span>
|
|
</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div class="grid grid-cols-1 md:grid-cols-3 gap-3">
|
|
|
|
|
- <div class="p-3 rounded-lg border {{ $hasTeacherStudent ? 'border-green-200 bg-green-50' : 'border-amber-200 bg-amber-50' }}">
|
|
|
|
|
- <div class="flex items-center gap-2 text-sm font-medium {{ $hasTeacherStudent ? 'text-green-800' : 'text-amber-800' }}">
|
|
|
|
|
- <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="{{ $hasTeacherStudent ? 'M5 13l4 4L19 7' : 'M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z' }}" />
|
|
|
|
|
- </svg>
|
|
|
|
|
- 教师 / 学生
|
|
|
|
|
|
|
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
|
|
|
+ <div class="selection-card border-2 rounded-xl p-5 {{ $hasTeacherStudent ? 'border-green-400 bg-gradient-to-br from-green-50 to-emerald-50' : 'border-amber-300 bg-gradient-to-br from-amber-50 to-orange-50' }}">
|
|
|
|
|
+ <div class="flex items-center gap-3 mb-2">
|
|
|
|
|
+ <div class="w-10 h-10 rounded-lg {{ $hasTeacherStudent ? 'bg-green-100' : 'bg-amber-100' }} flex items-center justify-center">
|
|
|
|
|
+ @if($hasTeacherStudent)
|
|
|
|
|
+ <svg class="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <svg class="w-5 h-5 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span class="text-sm font-bold {{ $hasTeacherStudent ? 'text-green-800' : 'text-amber-800' }}">教师 / 学生</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <p class="mt-1 text-xs text-gray-700">
|
|
|
|
|
- {{ $hasTeacherStudent ? '已选择:' . $this->getSelectedTeacherName() . ' / ' . $this->getSelectedStudentName() : '请选择教师并选择其学生后出卷' }}
|
|
|
|
|
|
|
+ <p class="text-sm {{ $hasTeacherStudent ? 'text-green-700' : 'text-amber-700' }}">
|
|
|
|
|
+ {{ $hasTeacherStudent ? '✓ ' . $this->getSelectedTeacherName() . ' / ' . $this->getSelectedStudentName() : '请选择教师和学生' }}
|
|
|
</p>
|
|
</p>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div class="p-3 rounded-lg border {{ $hasKnowledgePoints ? 'border-green-200 bg-green-50' : 'border-amber-200 bg-amber-50' }}">
|
|
|
|
|
- <div class="flex items-center gap-2 text-sm font-medium {{ $hasKnowledgePoints ? 'text-green-800' : 'text-amber-800' }}">
|
|
|
|
|
- <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="{{ $hasKnowledgePoints ? 'M5 13l4 4L19 7' : 'M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z' }}" />
|
|
|
|
|
- </svg>
|
|
|
|
|
- 知识点选择
|
|
|
|
|
|
|
+ <div class="selection-card border-2 rounded-xl p-5 {{ $hasKnowledgePoints ? 'border-green-400 bg-gradient-to-br from-green-50 to-emerald-50' : 'border-amber-300 bg-gradient-to-br from-amber-50 to-orange-50' }}">
|
|
|
|
|
+ <div class="flex items-center gap-3 mb-2">
|
|
|
|
|
+ <div class="w-10 h-10 rounded-lg {{ $hasKnowledgePoints ? 'bg-green-100' : 'bg-amber-100' }} flex items-center justify-center">
|
|
|
|
|
+ @if($hasKnowledgePoints)
|
|
|
|
|
+ <svg class="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <svg class="w-5 h-5 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span class="text-sm font-bold {{ $hasKnowledgePoints ? 'text-green-800' : 'text-amber-800' }}">知识点选择</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <p class="mt-1 text-xs text-gray-700">
|
|
|
|
|
- {{ $hasKnowledgePoints ? '已选 ' . count($selectedKpCodes) . ' 个知识点' : '请勾选学生薄弱点或手动选择知识点' }}
|
|
|
|
|
|
|
+ <p class="text-sm {{ $hasKnowledgePoints ? 'text-green-700' : 'text-amber-700' }}" x-data x-effect="$el.textContent = $wire.selectedKpCodes.length > 0 ? `✓ 已选 ${$wire.selectedKpCodes.length} 个知识点` : '请选择至少1个知识点'">
|
|
|
|
|
+ {{ $hasKnowledgePoints ? '✓ 已选 ' . count($selectedKpCodes) . ' 个知识点' : '请选择至少1个知识点' }}
|
|
|
</p>
|
|
</p>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div class="p-3 rounded-lg border {{ $questionCountValid ? 'border-green-200 bg-green-50' : 'border-amber-200 bg-amber-50' }}">
|
|
|
|
|
- <div class="flex items-center gap-2 text-sm font-medium {{ $questionCountValid ? 'text-green-800' : 'text-amber-800' }}">
|
|
|
|
|
- <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="{{ $questionCountValid ? 'M5 13l4 4L19 7' : 'M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z' }}" />
|
|
|
|
|
- </svg>
|
|
|
|
|
- 题目数量
|
|
|
|
|
|
|
+ <div class="selection-card border-2 rounded-xl p-5 {{ $questionCountValid ? 'border-green-400 bg-gradient-to-br from-green-50 to-emerald-50' : 'border-amber-300 bg-gradient-to-br from-amber-50 to-orange-50' }}">
|
|
|
|
|
+ <div class="flex items-center gap-3 mb-2">
|
|
|
|
|
+ <div class="w-10 h-10 rounded-lg {{ $questionCountValid ? 'bg-green-100' : 'bg-amber-100' }} flex items-center justify-center">
|
|
|
|
|
+ @if($questionCountValid)
|
|
|
|
|
+ <svg class="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ @else
|
|
|
|
|
+ <svg class="w-5 h-5 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <span class="text-sm font-bold {{ $questionCountValid ? 'text-green-800' : 'text-amber-800' }}">题目数量</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <p class="mt-1 text-xs text-gray-700">
|
|
|
|
|
- {{ $questionCountValid ? '将生成 ' . $totalQuestions . ' 题' : '题目数量需不少于 6 题' }}
|
|
|
|
|
|
|
+ <p class="text-sm {{ $questionCountValid ? 'text-green-700' : 'text-amber-700' }}" x-data x-effect="$el.textContent = $wire.totalQuestions >= 6 ? `✓ 将生成 ${$wire.totalQuestions} 题` : '至少需要6题'">
|
|
|
|
|
+ {{ $questionCountValid ? '✓ 将生成 ' . $totalQuestions . ' 题' : '至少需要6题' }}
|
|
|
</p>
|
|
</p>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
@unless($readyToGenerate)
|
|
@unless($readyToGenerate)
|
|
|
- <div class="rounded-md border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800">
|
|
|
|
|
- 完成以下步骤后再点击生成:{{ implode(' / ', $missingSteps) ?: '所有条件已满足' }}
|
|
|
|
|
|
|
+ <div class="rounded-xl border-2 border-amber-300 bg-gradient-to-r from-amber-50 to-orange-50 px-6 py-4">
|
|
|
|
|
+ <div class="flex items-start gap-3">
|
|
|
|
|
+ <svg class="w-6 h-6 text-amber-600 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <p class="text-sm font-bold text-amber-800 mb-1">请完成以下必填项</p>
|
|
|
|
|
+ <p class="text-sm text-amber-700">{{ implode(' / ', $missingSteps) }}</p>
|
|
|
|
|
+ <p class="text-xs text-amber-600 mt-2">
|
|
|
|
|
+ <strong>实时状态:</strong> {{ $debugInfo }}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <p class="text-xs text-amber-600 mt-1">
|
|
|
|
|
+ <strong>实际代码:</strong> {{ $kpCodesList ?: '(无)' }}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
@endunless
|
|
@endunless
|
|
|
|
|
|
|
|
- <button
|
|
|
|
|
- wire:click="generateExam"
|
|
|
|
|
- type="button"
|
|
|
|
|
- class="filament-button filament-button-size-lg filament-button-color-primary filament-button-icon-start inline-flex items-center justify-center w-full px-6 py-3 text-base font-medium transition-colors border border-transparent rounded-lg focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
|
|
|
|
|
- wire:loading.attr="disabled"
|
|
|
|
|
- @if(!$readyToGenerate) disabled @endif
|
|
|
|
|
- aria-disabled="{{ $readyToGenerate ? 'false' : 'true' }}"
|
|
|
|
|
- title="{{ $readyToGenerate ? '根据当前选择生成试卷' : '请先完成必选项再生成' }}"
|
|
|
|
|
- >
|
|
|
|
|
- @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
|
|
|
|
|
- <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="M12 4v16m8-8H4"></path>
|
|
|
|
|
- </svg>
|
|
|
|
|
- 智能生成试卷
|
|
|
|
|
- @endif
|
|
|
|
|
- </button>
|
|
|
|
|
-
|
|
|
|
|
- @if($generatedPaperId)
|
|
|
|
|
- <div class="mt-4 p-4 bg-green-50 rounded-lg">
|
|
|
|
|
- <div class="flex items-center gap-2 text-green-800">
|
|
|
|
|
|
|
+ <div class="relative">
|
|
|
|
|
+ <button
|
|
|
|
|
+ wire:click="generateExam"
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ class="generate-button w-full text-white rounded-xl py-4 px-8 text-lg font-bold flex items-center justify-center gap-3 {{ !$readyToGenerate ? 'opacity-50 cursor-not-allowed' : 'hover:shadow-2xl' }}"
|
|
|
|
|
+ wire:loading.attr="disabled"
|
|
|
|
|
+ @if(!$readyToGenerate) disabled @endif
|
|
|
|
|
+ aria-disabled="{{ $readyToGenerate ? 'false' : 'true' }}"
|
|
|
|
|
+ title="{{ $readyToGenerate ? '根据当前选择生成试卷' : '请先完成必选项再生成' }}"
|
|
|
|
|
+ >
|
|
|
|
|
+ @if($isGenerating)
|
|
|
|
|
+ <svg class="animate-spin h-6 w-6 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>
|
|
|
|
|
+ <span class="text-lg">正在生成试卷,请稍候...</span>
|
|
|
|
|
+ @else
|
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<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="M5 13l4 4L19 7"/>
|
|
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ <span class="text-lg">🚀 智能生成试卷</span>
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </button>
|
|
|
|
|
+
|
|
|
|
|
+ @if($readyToGenerate && !$isGenerating)
|
|
|
|
|
+ <div class="absolute -top-3 -right-3 w-8 h-8 bg-yellow-400 rounded-full flex items-center justify-center animate-bounce">
|
|
|
|
|
+ <svg class="w-5 h-5 text-yellow-800" fill="currentColor" viewBox="0 0 20 20">
|
|
|
|
|
+ <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
|
|
|
</svg>
|
|
</svg>
|
|
|
- <div class="font-medium">生成成功</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="mt-2 text-sm text-green-700">
|
|
|
|
|
- 已生成试卷ID: <span class="font-mono">{{ $generatedPaperId }}</span>
|
|
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="mt-4 flex gap-2">
|
|
|
|
|
- <button
|
|
|
|
|
- onclick="document.getElementById('pdfPreview').scrollIntoView({behavior: 'smooth'})"
|
|
|
|
|
- type="button"
|
|
|
|
|
- class="filament-button filament-button-size-md filament-button-color-secondary">
|
|
|
|
|
- 查看预览
|
|
|
|
|
- </button>
|
|
|
|
|
- <button wire:click="exportToPdf" type="button" class="filament-button filament-button-size-md filament-button-color-primary">
|
|
|
|
|
- 新窗口打开
|
|
|
|
|
- </button>
|
|
|
|
|
|
|
+ @endif
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ @if($generatedPaperId)
|
|
|
|
|
+ <div class="mt-6 p-6 bg-gradient-to-br from-green-50 to-emerald-50 border-2 border-green-300 rounded-xl">
|
|
|
|
|
+ <div class="flex items-start gap-4">
|
|
|
|
|
+ <div class="w-12 h-12 bg-green-500 rounded-full flex items-center justify-center flex-shrink-0">
|
|
|
|
|
+ <svg class="w-7 h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 13l4 4L19 7"/>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="flex-1">
|
|
|
|
|
+ <h4 class="text-xl font-bold text-green-800 mb-2">🎉 试卷生成成功!</h4>
|
|
|
|
|
+ <div class="space-y-2 text-sm">
|
|
|
|
|
+ <div class="flex items-center gap-2 text-green-700">
|
|
|
|
|
+ <span class="font-semibold">试卷ID:</span>
|
|
|
|
|
+ <span class="font-mono bg-white px-3 py-1 rounded border border-green-300">{{ $generatedPaperId }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="text-green-700">
|
|
|
|
|
+ 试卷已准备就绪,您可以查看预览或导出PDF
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="mt-5 flex gap-3">
|
|
|
|
|
+ <button
|
|
|
|
|
+ onclick="document.getElementById('pdfPreview').scrollIntoView({behavior: 'smooth'})"
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ class="px-5 py-2.5 bg-white border-2 border-green-500 text-green-700 font-semibold rounded-lg hover:bg-green-50 transition-all shadow-sm"
|
|
|
|
|
+ >
|
|
|
|
|
+ 查看预览
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button
|
|
|
|
|
+ wire:click="exportToPdf"
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ class="px-5 py-2.5 bg-gradient-to-r from-green-500 to-emerald-600 text-white font-semibold rounded-lg hover:from-green-600 hover:to-emerald-700 transition-all shadow-md"
|
|
|
|
|
+ >
|
|
|
|
|
+ 导出PDF
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<!-- PDF 预览区域 -->
|
|
<!-- PDF 预览区域 -->
|
|
|
- <div id="pdfPreview" class="mt-6 bg-white rounded-lg border shadow-sm">
|
|
|
|
|
- <div class="p-4 border-b bg-gray-50 flex justify-between items-center">
|
|
|
|
|
- <h3 class="text-lg font-semibold">试卷预览</h3>
|
|
|
|
|
- <button
|
|
|
|
|
- onclick="document.getElementById('pdfFrame').contentWindow.print()"
|
|
|
|
|
- class="filament-button filament-button-size-sm filament-button-color-primary">
|
|
|
|
|
|
|
+ <div id="pdfPreview" class="mt-8 bg-white rounded-xl border-2 border-gray-200 shadow-lg overflow-hidden">
|
|
|
|
|
+ <div class="p-5 border-b bg-gradient-to-r from-gray-50 to-gray-100 flex justify-between items-center">
|
|
|
|
|
+ <div class="flex items-center gap-3">
|
|
|
|
|
+ <div class="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center">
|
|
|
|
|
+ <svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
|
|
|
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <h3 class="text-lg font-bold text-gray-900">试卷预览</h3>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <button
|
|
|
|
|
+ onclick="document.getElementById('pdfFrame').contentWindow.print()"
|
|
|
|
|
+ class="px-4 py-2 bg-blue-600 text-white font-semibold rounded-lg hover:bg-blue-700 transition-all shadow-md flex items-center 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="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z" />
|
|
|
|
|
+ </svg>
|
|
|
打印试卷
|
|
打印试卷
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="p-4">
|
|
|
|
|
- <iframe
|
|
|
|
|
|
|
+ <div class="p-6 bg-gray-100">
|
|
|
|
|
+ <iframe
|
|
|
id="pdfFrame"
|
|
id="pdfFrame"
|
|
|
- src="{{ route('filament.admin.auth.intelligent-exam.pdf', ['paper_id' => $generatedPaperId]) }}"
|
|
|
|
|
- class="w-full border-0"
|
|
|
|
|
- style="height: 1200px;"
|
|
|
|
|
|
|
+ src="{{ route('filament.admin.auth.intelligent-exam.pdf', ['paper_id' => $generatedPaperId]) }}"
|
|
|
|
|
+ class="w-full border-0 rounded-lg shadow-lg"
|
|
|
|
|
+ style="height: 1200px; background: white;"
|
|
|
title="试卷预览">
|
|
title="试卷预览">
|
|
|
</iframe>
|
|
</iframe>
|
|
|
</div>
|
|
</div>
|