Lab page: per-variant create/edit modals, rendered conditions, inline lab edit; student page: compact code field, big score, defense wording, header highlight; toasts tinted; p margin
This commit is contained in:
@@ -96,6 +96,12 @@ a:not(.btn):hover { color: var(--c-text-link-hover); }
|
||||
.user { display: flex; align-items: center; gap: 0.75rem; font-size: 0.84375rem; margin-left: auto; }
|
||||
.nav-user { font-weight: 500; color: var(--c-text); }
|
||||
.nav-user:hover { color: var(--c-accent); }
|
||||
.nav-user.defense-active { color: var(--c-accent); }
|
||||
.nav-user.defense-active::before { content: ""; display: inline-block; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--c-accent); margin-right: 0.4rem; vertical-align: middle; }
|
||||
.score-big { display: inline-block; margin-left: 0.5rem; font-size: 1.75rem; font-weight: 700; line-height: 1; color: var(--c-tone-pos); font-variant-numeric: tabular-nums; vertical-align: middle; }
|
||||
.variant-name { font-weight: 600; }
|
||||
.variant-name b { font-variant-numeric: tabular-nums; }
|
||||
p { margin-top: 0; }
|
||||
.theme-btn { display: inline-flex; align-items: center; justify-content: center; padding: 0.3rem 0.5rem; }
|
||||
.theme-icon { width: 1.05rem; height: 1.05rem; display: block; }
|
||||
.breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; }
|
||||
@@ -274,9 +280,9 @@ tr:last-child td { border-bottom: none; }
|
||||
}
|
||||
.toast-item .toast-text { flex: 1 1 auto; min-width: 0; white-space: pre-line; overflow-wrap: anywhere; }
|
||||
.toast-item .toast-text .code { margin: 0 0.1rem; }
|
||||
.toast-item.toast-success { border-left-color: var(--c-tone-pos); }
|
||||
.toast-item.toast-error { border-left-color: var(--c-tone-neg); }
|
||||
.toast-item.toast-warning { border-left-color: var(--c-badge-warn-text); }
|
||||
.toast-item.toast-success { border-left-color: var(--c-tone-pos); background: var(--c-badge-ok-bg); }
|
||||
.toast-item.toast-error { border-left-color: var(--c-accent); background: var(--c-accent-soft); }
|
||||
.toast-item.toast-warning { border-left-color: var(--c-badge-warn-border); background: var(--c-badge-warn-bg); }
|
||||
.toast-close {
|
||||
flex: 0 0 auto; border: none; background: none; cursor: pointer;
|
||||
color: var(--c-text-muted); font-size: 1rem; line-height: 1; padding: 0 0.1rem;
|
||||
|
||||
@@ -363,7 +363,7 @@ function applyDefenseToCell(s) {
|
||||
: (s.code ? 'код ' + s.code : 'ожидает')));
|
||||
}
|
||||
if (s.status === 'ready') {
|
||||
btn.title = 'Защита завершена: ' + (s.readyReason === 'timeout' ? 'время вышло' : 'студент нажал «Готов»');
|
||||
btn.title = 'Защита: ' + defenseReasonText(s.readyReason);
|
||||
if (label) label.textContent = 'готова';
|
||||
}
|
||||
}
|
||||
@@ -388,7 +388,7 @@ function syncDefenseStatuses(sessions, initial) {
|
||||
var who = (btn && btn.getAttribute('data-student-name')) || 'студент';
|
||||
var lab = (btn && btn.getAttribute('data-lab-name')) || 'лабораторная';
|
||||
var reason = s.readyReason === 'timeout' ? 'время вышло' : 'нажал «Готов»';
|
||||
showToast(who + ' — ' + lab + ': завершил защиту (' + reason + ').');
|
||||
showToast(who + ' — ' + lab + ': ' + reason + '.');
|
||||
}
|
||||
|
||||
// Обновляем открытый диалог, если он про эту сессию.
|
||||
@@ -440,9 +440,8 @@ function startDefenseWatch() {
|
||||
/* ---------- Индивидуальное задание (защита) ---------- */
|
||||
|
||||
function defenseReasonText(reason) {
|
||||
if (reason === 'timeout') return 'время вышло';
|
||||
if (reason === 'button') return 'студент нажал «Готов»';
|
||||
return '';
|
||||
if (reason === 'timeout') return 'Вышло время';
|
||||
return 'Готов к сдаче';
|
||||
}
|
||||
|
||||
function defenseStatusText(status, code, seconds, reason) {
|
||||
@@ -453,8 +452,7 @@ function defenseStatusText(status, code, seconds, reason) {
|
||||
}
|
||||
if (status === 'started') return 'Студент выполняет работу, осталось ' + fmtSeconds(seconds) + '.';
|
||||
if (status === 'ready') {
|
||||
var why = defenseReasonText(reason);
|
||||
return 'Студент готов к сдаче' + (why ? ' (' + why + ')' : '') + '. Можно начать заново для дополнительного задания.';
|
||||
return defenseReasonText(reason) + '. Можно начать заново для дополнительного задания.';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
22
web/src/main/resources/static/js/admin-lab.js
Normal file
22
web/src/main/resources/static/js/admin-lab.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/* Страница лабораторной: переключение просмотра/редактирования параметров. */
|
||||
(function () {
|
||||
function setMode(editing) {
|
||||
var view = document.getElementById('lab-description-view');
|
||||
var form = document.getElementById('lab-edit-form');
|
||||
if (!view || !form) return;
|
||||
view.hidden = editing;
|
||||
form.hidden = !editing;
|
||||
if (editing) {
|
||||
var t = form.querySelector('input[name="title"]');
|
||||
if (t) t.focus();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', function (e) {
|
||||
var a = e.target.closest('[data-action]');
|
||||
if (!a) return;
|
||||
var kind = a.getAttribute('data-action');
|
||||
if (kind === 'lab-edit') setMode(true);
|
||||
if (kind === 'lab-edit-cancel') setMode(false);
|
||||
});
|
||||
})();
|
||||
@@ -84,10 +84,17 @@
|
||||
/* Активный пункт меню */
|
||||
function initNavActive() {
|
||||
var path = window.location.pathname;
|
||||
document.querySelectorAll('#top-nav .nav-link').forEach(function (a) {
|
||||
var links = [].slice.call(document.querySelectorAll('#top-nav .nav-link'));
|
||||
var best = null;
|
||||
var bestLen = -1;
|
||||
links.forEach(function (a) {
|
||||
var href = a.getAttribute('href') || '';
|
||||
if (path === href || (href !== '/' && path.indexOf(href + '/') === 0)) a.classList.add('active');
|
||||
if (href === '/') return;
|
||||
if (path === href || path.indexOf(href + '/') === 0) {
|
||||
if (href.length > bestLen) { best = a; bestLen = href.length; }
|
||||
}
|
||||
});
|
||||
if (best) best.classList.add('active');
|
||||
}
|
||||
|
||||
/* Серверные уведомления: автоскрытие и кнопка закрытия */
|
||||
|
||||
@@ -29,6 +29,12 @@ document.querySelectorAll('.defense-timer').forEach(function (el) {
|
||||
if (left > 0) {
|
||||
render(left);
|
||||
startTick();
|
||||
markDefense(true);
|
||||
}
|
||||
|
||||
function markDefense(active) {
|
||||
var name = document.querySelector('.nav-user');
|
||||
if (name) name.classList.toggle('defense-active', active);
|
||||
}
|
||||
|
||||
if (labId) {
|
||||
@@ -39,9 +45,11 @@ document.querySelectorAll('.defense-timer').forEach(function (el) {
|
||||
if (!res || !res.ok) return;
|
||||
// У сессии закончилось время.
|
||||
if (res.status !== 'started') {
|
||||
markDefense(false);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
markDefense(true);
|
||||
var server = parseInt(res.secondsLeft || '0', 10);
|
||||
if (server <= 0) { finish(); return; }
|
||||
// Подстраиваем локальный отсчёт под серверное время.
|
||||
|
||||
Reference in New Issue
Block a user