|
|
|
|
@ -805,6 +805,42 @@
|
|
|
|
|
let _extractedText = ''; |
|
|
|
|
let _extractedFileName = ''; |
|
|
|
|
|
|
|
|
|
/** HTML карточки вопроса в модалке предпросмотра импорта (как в разборе: текст, подсказка, все варианты). */ |
|
|
|
|
function buildImportPreviewQuestionHtml(q, index) { |
|
|
|
|
const hint = (q.aiHint || '').trim(); |
|
|
|
|
const opts = Array.isArray(q.options) ? q.options : []; |
|
|
|
|
const optionsHtml = opts.length |
|
|
|
|
? `<ul class="attempt-review-options" role="list">${opts.map((o) => { |
|
|
|
|
const correct = !!o.isCorrect; |
|
|
|
|
const liCls = correct |
|
|
|
|
? 'attempt-review-option attempt-review-option--correct' |
|
|
|
|
: 'attempt-review-option'; |
|
|
|
|
const tag = correct ? '<span class="attempt-review-option__tag">верный ответ</span>' : ''; |
|
|
|
|
return `<li class="${liCls}">
|
|
|
|
|
<span class="attempt-review-option__text"> |
|
|
|
|
<span class="attempt-review-option__mark" aria-hidden="true">☐</span> |
|
|
|
|
<span class="attempt-review-option__body">${escHtml(o.text || '')}${tag}</span> |
|
|
|
|
</span> |
|
|
|
|
</li>`; |
|
|
|
|
}).join('')}</ul>` |
|
|
|
|
: ''; |
|
|
|
|
const hintHtml = hint |
|
|
|
|
? `<div class="attempt-review-hint">
|
|
|
|
|
<span class="attempt-review-hint__label">Подсказка</span> |
|
|
|
|
<p class="attempt-review-hint__text">${escHtml(hint)}</p> |
|
|
|
|
</div>` |
|
|
|
|
: ''; |
|
|
|
|
return `<article class="attempt-card attempt-review-card import-modal-review__card">
|
|
|
|
|
<div class="attempt-review-card__head"> |
|
|
|
|
<span class="attempt-review-card__num">${index + 1}</span> |
|
|
|
|
<span class="attempt-review-card__badge attempt-review-card__badge--preview">черновик</span> |
|
|
|
|
</div> |
|
|
|
|
<p class="attempt-review-card__question">${escHtml(q.text || '')}</p> |
|
|
|
|
${hintHtml} |
|
|
|
|
${optionsHtml} |
|
|
|
|
</article>`; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function openImportModal(title, bodyHtml, actions) { |
|
|
|
|
importModalTitle.textContent = title; |
|
|
|
|
importModalBody.innerHTML = bodyHtml; |
|
|
|
|
@ -842,7 +878,7 @@
|
|
|
|
|
aiStatusEl.textContent = ''; |
|
|
|
|
openImportModal( |
|
|
|
|
'Ошибка загрузки', |
|
|
|
|
`<p class="text-red-700">${escHtml(e.message || 'Не удалось загрузить файл.')}</p>`, |
|
|
|
|
`<div class="import-modal-review"><p class="import-modal-review__alert import-modal-review__alert--error">${escHtml(e.message || 'Не удалось загрузить файл.')}</p></div>`, |
|
|
|
|
[{ label: 'Закрыть', onClick: () => importModal.close() }], |
|
|
|
|
); |
|
|
|
|
} finally { |
|
|
|
|
@ -884,9 +920,7 @@
|
|
|
|
|
if (!g.available) { |
|
|
|
|
openImportModal( |
|
|
|
|
'AI недоступен', |
|
|
|
|
`<p class="mb-2 text-amber-700 bg-amber-50 border border-amber-200 rounded px-3 py-2 text-xs">
|
|
|
|
|
${escHtml(g.message || 'AI недоступен — ключ не настроен.')} |
|
|
|
|
</p>`, |
|
|
|
|
`<div class="import-modal-review"><p class="import-modal-review__alert import-modal-review__alert--warn">${escHtml(g.message || 'AI недоступен — ключ не настроен.')}</p></div>`, |
|
|
|
|
[{ label: 'Закрыть', onClick: () => importModal.close() }], |
|
|
|
|
); |
|
|
|
|
return; |
|
|
|
|
@ -894,19 +928,15 @@
|
|
|
|
|
|
|
|
|
|
const draft = g.draft || {}; |
|
|
|
|
const qs = draft.questions || []; |
|
|
|
|
const qPreview = qs.slice(0, 4).map((q, i) => |
|
|
|
|
`<li class="text-xs text-ink-600">${i + 1}. ${escHtml((q.text || '').slice(0, 80))}${(q.text || '').length > 80 ? '…' : ''}</li>` |
|
|
|
|
).join(''); |
|
|
|
|
const moreCount = qs.length > 4 ? qs.length - 4 : 0; |
|
|
|
|
const qCards = qs.map((q, i) => buildImportPreviewQuestionHtml(q, i)).join(''); |
|
|
|
|
const bodyHtml = ` |
|
|
|
|
${draft.title ? `<p class="font-medium text-ink-800 mb-1">${escHtml(draft.title)}</p>` : ''} |
|
|
|
|
${draft.description ? `<p class="text-xs text-ink-500 mb-2">${escHtml(draft.description)}</p>` : ''} |
|
|
|
|
<p class="text-xs text-ink-500 mb-1">Вопросов: <b>${qs.length}</b></p> |
|
|
|
|
${qs.length ? `<ul class="space-y-0.5 mb-1">${qPreview}</ul>
|
|
|
|
|
${moreCount ? `<p class="text-xs text-ink-400">…и ещё ${moreCount}</p>` : ''}` : ''}
|
|
|
|
|
<p class="mt-3 text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded px-3 py-2"> |
|
|
|
|
Текущие вопросы теста будут <b>заменены</b>. |
|
|
|
|
</p>`; |
|
|
|
|
<div class="import-modal-review"> |
|
|
|
|
${draft.title ? `<p class="import-modal-review__draft-title">${escHtml(draft.title)}</p>` : ''} |
|
|
|
|
${draft.description ? `<p class="import-modal-review__desc attempt-review-page__params">${escHtml(draft.description)}</p>` : ''} |
|
|
|
|
<p class="import-modal-review__stats attempt-review-page__params">Вопросов в черновике: <strong>${qs.length}</strong></p> |
|
|
|
|
${qs.length ? `<div class="import-modal-review__list">${qCards}</div>` : ''} |
|
|
|
|
<div class="import-modal-review__warn" role="status">Текущие вопросы теста будут <strong>заменены</strong> после «Применить».</div> |
|
|
|
|
</div>`; |
|
|
|
|
|
|
|
|
|
openImportModal( |
|
|
|
|
`Черновик из «${escHtml(_extractedFileName)}»`, |
|
|
|
|
@ -941,7 +971,7 @@
|
|
|
|
|
aiStatusEl.textContent = ''; |
|
|
|
|
openImportModal( |
|
|
|
|
'Ошибка генерации', |
|
|
|
|
`<p class="text-red-700">${escHtml(e.message || 'Не удалось сгенерировать тест.')}</p>`, |
|
|
|
|
`<div class="import-modal-review"><p class="import-modal-review__alert import-modal-review__alert--error">${escHtml(e.message || 'Не удалось сгенерировать тест.')}</p></div>`, |
|
|
|
|
[{ label: 'Закрыть', onClick: () => importModal.close() }], |
|
|
|
|
); |
|
|
|
|
} finally { |
|
|
|
|
|