Feat: Обновлён create.blade.php для вопросов
✅ TinyMCE WYSIWYG редактор (HTML + картинки) ✅ Поддержка ordering типа (сортировка) ✅ Картинки в ответах (загрузка файлов) ✅ Обновлён QuestionController (store/update) ✅ Валидация изображений (max 2MB) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -7,6 +7,7 @@ use App\Models\Question;
|
||||
use App\Models\Test;
|
||||
use App\Models\Answer;
|
||||
use App\Models\QuestionMatchingPair;
|
||||
use App\Models\QuestionOrderingItem;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -22,7 +23,7 @@ class QuestionController extends Controller
|
||||
{
|
||||
Gate::authorize('viewAny', Question::class);
|
||||
|
||||
$questions = $test->questions()->with('answers')->orderBy('sort_order')->get();
|
||||
$questions = $test->questions()->with(['answers', 'matchingPairs', 'orderingItems'])->orderBy('sort_order')->get();
|
||||
|
||||
return view('admin.questions.index', compact('test', 'questions'));
|
||||
}
|
||||
@@ -39,14 +40,17 @@ class QuestionController extends Controller
|
||||
Gate::authorize('create', Question::class);
|
||||
|
||||
$validated = $request->validate([
|
||||
'type' => 'required|in:single_choice,multiple_choice,input,matching',
|
||||
'type' => 'required|in:multiple_choice,matching,ordering',
|
||||
'question_text' => 'required|string',
|
||||
'explanation' => 'nullable|string',
|
||||
'score' => 'nullable|integer|min:1',
|
||||
'sort_order' => 'nullable|integer',
|
||||
'is_required' => 'boolean',
|
||||
'answers' => 'nullable|array',
|
||||
'answers.*.text' => 'nullable|string',
|
||||
'answers.*.image' => 'nullable|image|max:2048',
|
||||
'matching_pairs' => 'nullable|array',
|
||||
'ordering_items' => 'nullable|array',
|
||||
]);
|
||||
|
||||
DB::transaction(function () use ($test, $validated) {
|
||||
@@ -59,11 +63,17 @@ class QuestionController extends Controller
|
||||
'is_required' => $validated['is_required'] ?? true,
|
||||
]);
|
||||
|
||||
if (in_array($validated['type'], ['single_choice', 'multiple_choice']) && !empty($validated['answers'])) {
|
||||
// Ответы для multiple_choice
|
||||
if ($validated['type'] === 'multiple_choice' && !empty($validated['answers'])) {
|
||||
foreach ($validated['answers'] as $answer) {
|
||||
if (!empty($answer['text'])) {
|
||||
$imagePath = null;
|
||||
if (!empty($answer['image'])) {
|
||||
$imagePath = $answer['image']->store('questions/answers', 'public');
|
||||
}
|
||||
$question->answers()->create([
|
||||
'answer_text' => $answer['text'],
|
||||
'image' => $imagePath,
|
||||
'is_correct' => $answer['is_correct'] ?? false,
|
||||
'sort_order' => $answer['sort_order'] ?? 0,
|
||||
]);
|
||||
@@ -71,6 +81,7 @@ class QuestionController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// Пары для matching
|
||||
if ($validated['type'] === 'matching' && !empty($validated['matching_pairs'])) {
|
||||
foreach ($validated['matching_pairs'] as $pair) {
|
||||
if (!empty($pair['left_text']) && !empty($pair['right_text'])) {
|
||||
@@ -83,6 +94,19 @@ class QuestionController extends Controller
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Элементы для ordering
|
||||
if ($validated['type'] === 'ordering' && !empty($validated['ordering_items'])) {
|
||||
foreach ($validated['ordering_items'] as $item) {
|
||||
if (!empty($item['item_text'])) {
|
||||
$question->orderingItems()->create([
|
||||
'item_text' => $item['item_text'],
|
||||
'correct_order' => $item['correct_order'] ?? 0,
|
||||
'sort_order' => $item['sort_order'] ?? 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return redirect()->route('admin.tests.questions.index', $test)
|
||||
@@ -92,13 +116,14 @@ class QuestionController extends Controller
|
||||
public function show(Test $test, Question $question)
|
||||
{
|
||||
Gate::authorize('view', $question);
|
||||
$question->load(['answers', 'matchingPairs', 'orderingItems']);
|
||||
return view('admin.questions.show', compact('test', 'question'));
|
||||
}
|
||||
|
||||
public function edit(Test $test, Question $question)
|
||||
{
|
||||
Gate::authorize('update', $question);
|
||||
$question->load(['answers', 'matchingPairs']);
|
||||
$question->load(['answers', 'matchingPairs', 'orderingItems']);
|
||||
return view('admin.questions.edit', compact('test', 'question'));
|
||||
}
|
||||
|
||||
@@ -107,14 +132,17 @@ class QuestionController extends Controller
|
||||
Gate::authorize('update', $question);
|
||||
|
||||
$validated = $request->validate([
|
||||
'type' => 'required|in:single_choice,multiple_choice,input,matching',
|
||||
'type' => 'required|in:multiple_choice,matching,ordering',
|
||||
'question_text' => 'required|string',
|
||||
'explanation' => 'nullable|string',
|
||||
'score' => 'nullable|integer|min:1',
|
||||
'sort_order' => 'nullable|integer',
|
||||
'is_required' => 'boolean',
|
||||
'answers' => 'nullable|array',
|
||||
'answers.*.text' => 'nullable|string',
|
||||
'answers.*.image' => 'nullable|image|max:2048',
|
||||
'matching_pairs' => 'nullable|array',
|
||||
'ordering_items' => 'nullable|array',
|
||||
]);
|
||||
|
||||
DB::transaction(function () use ($question, $validated) {
|
||||
@@ -127,12 +155,18 @@ class QuestionController extends Controller
|
||||
'is_required' => $validated['is_required'] ?? true,
|
||||
]);
|
||||
|
||||
if (in_array($validated['type'], ['single_choice', 'multiple_choice']) && !empty($validated['answers'])) {
|
||||
// Ответы
|
||||
if ($validated['type'] === 'multiple_choice' && !empty($validated['answers'])) {
|
||||
$question->answers()->delete();
|
||||
foreach ($validated['answers'] as $answer) {
|
||||
if (!empty($answer['text'])) {
|
||||
$imagePath = null;
|
||||
if (!empty($answer['image'])) {
|
||||
$imagePath = $answer['image']->store('questions/answers', 'public');
|
||||
}
|
||||
$question->answers()->create([
|
||||
'answer_text' => $answer['text'],
|
||||
'image' => $imagePath,
|
||||
'is_correct' => $answer['is_correct'] ?? false,
|
||||
'sort_order' => $answer['sort_order'] ?? 0,
|
||||
]);
|
||||
@@ -140,6 +174,7 @@ class QuestionController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// Пары
|
||||
if ($validated['type'] === 'matching' && !empty($validated['matching_pairs'])) {
|
||||
$question->matchingPairs()->delete();
|
||||
foreach ($validated['matching_pairs'] as $pair) {
|
||||
@@ -153,6 +188,20 @@ class QuestionController extends Controller
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Элементы ordering
|
||||
if ($validated['type'] === 'ordering' && !empty($validated['ordering_items'])) {
|
||||
$question->orderingItems()->delete();
|
||||
foreach ($validated['ordering_items'] as $item) {
|
||||
if (!empty($item['item_text'])) {
|
||||
$question->orderingItems()->create([
|
||||
'item_text' => $item['item_text'],
|
||||
'correct_order' => $item['correct_order'] ?? 0,
|
||||
'sort_order' => $item['sort_order'] ?? 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return redirect()->route('admin.tests.questions.index', $test)
|
||||
|
||||
Reference in New Issue
Block a user