Fix: Исправления для вопросов

 Ответы с картинками без текста теперь сохраняются
 TinyMCE инициализируется после DOMContentLoaded
 Валидация: хотя бы текст ИЛИ картинка в ответе
 Обновлены store и update методы

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
mirivlad 2026-03-27 10:41:14 +08:00
parent 1c94812f7d
commit ffcdd86712
2 changed files with 59 additions and 29 deletions

View File

@ -53,6 +53,20 @@ class QuestionController extends Controller
'ordering_items' => 'nullable|array', 'ordering_items' => 'nullable|array',
]); ]);
// Проверка что есть хотя бы текст или картинка в ответах
if ($validated['type'] === 'multiple_choice' && !empty($validated['answers'])) {
$hasValidAnswer = false;
foreach ($validated['answers'] as $answer) {
if (!empty($answer['text']) || !empty($answer['image'])) {
$hasValidAnswer = true;
break;
}
}
if (!$hasValidAnswer) {
return back()->withErrors(['answers' => 'Добавьте хотя бы один ответ (текст или картинку)'])->withInput();
}
}
DB::transaction(function () use ($test, $validated) { DB::transaction(function () use ($test, $validated) {
$question = $test->questions()->create([ $question = $test->questions()->create([
'type' => $validated['type'], 'type' => $validated['type'],
@ -66,7 +80,7 @@ class QuestionController extends Controller
// Ответы для multiple_choice // Ответы для multiple_choice
if ($validated['type'] === 'multiple_choice' && !empty($validated['answers'])) { if ($validated['type'] === 'multiple_choice' && !empty($validated['answers'])) {
foreach ($validated['answers'] as $answer) { foreach ($validated['answers'] as $answer) {
if (!empty($answer['text'])) { if (!empty($answer['text']) || !empty($answer['image'])) {
$imagePath = null; $imagePath = null;
if (!empty($answer['image'])) { if (!empty($answer['image'])) {
$imagePath = $answer['image']->store('questions/answers', 'public'); $imagePath = $answer['image']->store('questions/answers', 'public');
@ -145,6 +159,20 @@ class QuestionController extends Controller
'ordering_items' => 'nullable|array', 'ordering_items' => 'nullable|array',
]); ]);
// Проверка что есть хотя бы текст или картинка в ответах
if ($validated['type'] === 'multiple_choice' && !empty($validated['answers'])) {
$hasValidAnswer = false;
foreach ($validated['answers'] as $answer) {
if (!empty($answer['text']) || !empty($answer['image'])) {
$hasValidAnswer = true;
break;
}
}
if (!$hasValidAnswer) {
return back()->withErrors(['answers' => 'Добавьте хотя бы один ответ (текст или картинку)'])->withInput();
}
}
DB::transaction(function () use ($question, $validated) { DB::transaction(function () use ($question, $validated) {
$question->update([ $question->update([
'type' => $validated['type'], 'type' => $validated['type'],
@ -159,7 +187,7 @@ class QuestionController extends Controller
if ($validated['type'] === 'multiple_choice' && !empty($validated['answers'])) { if ($validated['type'] === 'multiple_choice' && !empty($validated['answers'])) {
$question->answers()->delete(); $question->answers()->delete();
foreach ($validated['answers'] as $answer) { foreach ($validated['answers'] as $answer) {
if (!empty($answer['text'])) { if (!empty($answer['text']) || !empty($answer['image'])) {
$imagePath = null; $imagePath = null;
if (!empty($answer['image'])) { if (!empty($answer['image'])) {
$imagePath = $answer['image']->store('questions/answers', 'public'); $imagePath = $answer['image']->store('questions/answers', 'public');

View File

@ -94,34 +94,36 @@
<!-- TinyMCE --> <!-- TinyMCE -->
<script src="https://cdn.tiny.mce.com/1/tinymce/7/tinymce.min.js" referrerpolicy="origin"></script> <script src="https://cdn.tiny.mce.com/1/tinymce/7/tinymce.min.js" referrerpolicy="origin"></script>
<script> <script>
// Инициализация TinyMCE // Инициализация TinyMCE после загрузки DOM
tinymce.init({ document.addEventListener('DOMContentLoaded', function() {
selector: '#questionText, #questionExplanation', tinymce.init({
height: 300, selector: '#questionText, #questionExplanation',
plugins: 'image link table lists code', height: 300,
toolbar: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright | bullist numlist | image link | code', plugins: 'image link table lists code',
image_title: true, toolbar: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright | bullist numlist | image link | code',
automatic_uploads: true, image_title: true,
file_picker_types: 'image', automatic_uploads: true,
file_picker_callback: function(cb, value, meta) { file_picker_types: 'image',
const input = document.createElement('input'); file_picker_callback: function(cb, value, meta) {
input.setAttribute('type', 'file'); const input = document.createElement('input');
input.setAttribute('accept', 'image/*'); input.setAttribute('type', 'file');
input.addEventListener('change', function(e) { input.setAttribute('accept', 'image/*');
const file = e.target.files[0]; input.addEventListener('change', function(e) {
const reader = new FileReader(); const file = e.target.files[0];
reader.addEventListener('load', function() { const reader = new FileReader();
const id = 'blobid' + (new Date()).getTime(); reader.addEventListener('load', function() {
const blobCache = tinymce.activeEditor.editorUpload.blobCache; const id = 'blobid' + (new Date()).getTime();
const base64 = reader.result.split(',')[1]; const blobCache = tinymce.activeEditor.editorUpload.blobCache;
const blobInfo = blobCache.create(id, file, base64); const base64 = reader.result.split(',')[1];
blobCache.add(blobInfo); const blobInfo = blobCache.create(id, file, base64);
cb(blobInfo.blobUri(), { title: file.name }); blobCache.add(blobInfo);
cb(blobInfo.blobUri(), { title: file.name });
});
reader.readAsDataURL(file);
}); });
reader.readAsDataURL(file); input.click();
}); }
input.click(); });
}
}); });
function updateQuestionType() { function updateQuestionType() {