feat(lab-content-engine): phase 5 — кнопка «В лабораторию» на карточке учебника
textbooks.html: батч-запрос /api/lab/links/all?kind=textbook при загрузке -> labLinks byRef; на карточке учебника со связанными симуляциями добавлена кнопка «В лабораторию» (deep-link /lab?sim=<id>, openLabSim со stopPropagation, чтобы клик не открывал учебник). (Прошлый коммит метил не ту разметку карточки — фикс.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+17
-1
@@ -454,16 +454,28 @@
|
|||||||
return String(s || '').replace(/[&<>"']/g, c => ({ '&':'&','<':'<','>':'>','"':'"',"'":''' }[c]));
|
return String(s || '').replace(/[&<>"']/g, c => ({ '&':'&','<':'<','>':'>','"':'"',"'":''' }[c]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let labLinks = {}; // { textbook_slug: [{id,title,cat}] } — связанные симуляции (Фаза 5)
|
||||||
async function loadTextbooks() {
|
async function loadTextbooks() {
|
||||||
try {
|
try {
|
||||||
const r = await LS.api('/api/textbooks');
|
const [r, labRes] = await Promise.all([
|
||||||
|
LS.api('/api/textbooks'),
|
||||||
|
LS.api('/api/lab/links/all?kind=textbook').catch(() => ({ byRef: {} })),
|
||||||
|
]);
|
||||||
textbooks = r.textbooks || [];
|
textbooks = r.textbooks || [];
|
||||||
|
labLinks = (labRes && labRes.byRef) || {};
|
||||||
render();
|
render();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
document.getElementById('tb-grid').innerHTML = `<div class="tb-empty">Не удалось загрузить: ${esc(e.message)}</div>`;
|
document.getElementById('tb-grid').innerHTML = `<div class="tb-empty">Не удалось загрузить: ${esc(e.message)}</div>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Фаза 5: открыть связанную симуляцию из карточки учебника (не уходя в учебник). */
|
||||||
|
function openLabSim(simId, ev) {
|
||||||
|
if (ev) ev.stopPropagation();
|
||||||
|
location.href = '/lab?sim=' + encodeURIComponent(simId);
|
||||||
|
}
|
||||||
|
window.openLabSim = openLabSim;
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
const grid = document.getElementById('tb-grid');
|
const grid = document.getElementById('tb-grid');
|
||||||
if (!textbooks.length) {
|
if (!textbooks.length) {
|
||||||
@@ -509,6 +521,10 @@
|
|||||||
${isTeacher ? `<button class="tb-btn tb-assign-btn" onclick="openAssignModal('${t.slug}', '${esc(t.title)}')" title="Назначить чтение как ДЗ">
|
${isTeacher ? `<button class="tb-btn tb-assign-btn" onclick="openAssignModal('${t.slug}', '${esc(t.title)}')" title="Назначить чтение как ДЗ">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v20M2 12h20"/></svg>
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v20M2 12h20"/></svg>
|
||||||
</button>` : ''}
|
</button>` : ''}
|
||||||
|
${(labLinks[t.slug] && labLinks[t.slug].length) ? `<button class="tb-btn tb-lab-btn" onclick="openLabSim('${esc(labLinks[t.slug][0].id)}', event)" title="Открыть связанную симуляцию в лаборатории">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3h6m-4.5 0v5.5l-4 7.5a1 1 0 0 0 .9 1.5h8.2a1 1 0 0 0 .9-1.5l-4-7.5V3"/></svg>
|
||||||
|
В лабораторию${labLinks[t.slug].length > 1 ? ' (' + labLinks[t.slug].length + ')' : ''}
|
||||||
|
</button>` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>`;
|
</article>`;
|
||||||
|
|||||||
Reference in New Issue
Block a user