fix(ui): различать готовность защиты и истечение времени

This commit is contained in:
2026-10-26 15:47:34 +03:00
parent 7c45de8d9f
commit 24a92632fd
3 changed files with 12 additions and 9 deletions

View File

@@ -324,7 +324,9 @@ function applyDefenseToCell(s) {
if (s.status === 'started' && s.endsAt) btn.setAttribute('data-seconds', String(Math.max(0, Math.ceil((s.endsAt - Date.now()) / 1000)))); if (s.status === 'started' && s.endsAt) btn.setAttribute('data-seconds', String(Math.max(0, Math.ceil((s.endsAt - Date.now()) / 1000))));
if (s.code) btn.setAttribute('data-code', s.code); else btn.removeAttribute('data-code'); if (s.code) btn.setAttribute('data-code', s.code); else btn.removeAttribute('data-code');
btn.classList.remove('ok', 'warn', 'dim'); btn.classList.remove('ok', 'warn', 'dim');
btn.classList.add(s.status === 'ready' ? 'ok' : (s.status === 'waiting' || s.status === 'started' ? 'warn' : 'dim')); btn.classList.add(s.status === 'ready'
? (s.readyReason === 'timeout' ? 'warn' : 'ok')
: (s.status === 'waiting' || s.status === 'started' ? 'warn' : 'dim'));
var label = btn.querySelector('.js-def-label'); var label = btn.querySelector('.js-def-label');
var timer = btn.querySelector('.js-def-timer'); var timer = btn.querySelector('.js-def-timer');
var started = s.status === 'started'; var started = s.status === 'started';
@@ -340,12 +342,13 @@ function applyDefenseToCell(s) {
if (label) { if (label) {
label.textContent = started ? '' label.textContent = started ? ''
: (s.status == null ? '—' : (s.status == null ? '—'
: (s.status === 'ready' ? 'готова' : (s.status === 'ready'
? (s.readyReason === 'timeout' ? 'кончилось время' : 'готова')
: (s.code ? 'код ' + s.code : 'ожидает'))); : (s.code ? 'код ' + s.code : 'ожидает')));
} }
if (s.status === 'ready') { if (s.status === 'ready') {
btn.title = 'Защита: ' + defenseReasonText(s.readyReason); btn.title = 'Защита: ' + defenseReasonText(s.readyReason);
if (label) label.textContent = 'готова'; if (label) label.textContent = s.readyReason === 'timeout' ? 'кончилось время' : 'готова';
} }
} }
@@ -368,7 +371,7 @@ function syncDefenseStatuses(sessions, initial) {
var btn = defenseBtn(s.sessionId); var btn = defenseBtn(s.sessionId);
var who = (btn && btn.getAttribute('data-student-name')) || 'студент'; var who = (btn && btn.getAttribute('data-student-name')) || 'студент';
var lab = (btn && btn.getAttribute('data-lab-name')) || 'лабораторная'; var lab = (btn && btn.getAttribute('data-lab-name')) || 'лабораторная';
var reason = s.readyReason === 'timeout' ? 'время вышло' : 'нажал «Готов»'; var reason = s.readyReason === 'timeout' ? 'кончилось время' : 'нажал «Готов»';
showToast(who + ' — ' + lab + ': ' + reason + '.'); showToast(who + ' — ' + lab + ': ' + reason + '.');
} }
@@ -429,7 +432,7 @@ function startDefenseWatch() {
/* ---------- Индивидуальное задание (защита) ---------- */ /* ---------- Индивидуальное задание (защита) ---------- */
function defenseReasonText(reason) { function defenseReasonText(reason) {
if (reason === 'timeout') return 'Вышло время'; if (reason === 'timeout') return 'Кончилось время';
return 'Готов к сдаче'; return 'Готов к сдаче';
} }

View File

@@ -146,14 +146,14 @@
th:href="@{/admin/submissions/{id}/download(id=${cell.submissionId}, group=${group.name}, no=${row.studentNo}, name=${row.fullName}, attempt=${cell.submissionSeq})}">сдача ↓ <span th:text="${cell.submissionSeq}">1</span></a> th:href="@{/admin/submissions/{id}/download(id=${cell.submissionId}, group=${group.name}, no=${row.studentNo}, name=${row.fullName}, attempt=${cell.submissionSeq})}">сдача ↓ <span th:text="${cell.submissionSeq}">1</span></a>
<span th:unless="${cell.submissionId}" class="sub-dim">не сдано</span> <span th:unless="${cell.submissionId}" class="sub-dim">не сдано</span>
<button class="cell-btn st js-defense-cell" type="button" <button class="cell-btn st js-defense-cell" type="button"
th:classappend="${cell.defenseStatus == null} ? 'dim' : (${cell.defenseStatus == 'ready'} ? 'ok' : 'warn')" th:classappend="${cell.defenseStatus == null} ? 'dim' : (${cell.defenseStatus == 'ready'} ? (${cell.defenseReadyReason == 'timeout'} ? 'warn' : 'ok') : 'warn')"
th:attr="data-student=${row.studentId},data-student-name=${row.fullName},data-lab=${cell.labId},data-lab-name='ЛР ' + ${cell.labNumber},data-md=${cell.defenseAssignmentMd},data-session=${cell.defenseSessionId},data-status=${cell.defenseStatus},data-seconds=${cell.defenseSecondsLeft},data-code=${cell.defenseCode},data-reason=${cell.defenseReadyReason}" data-action="defense" th:attr="data-student=${row.studentId},data-student-name=${row.fullName},data-lab=${cell.labId},data-lab-name='ЛР ' + ${cell.labNumber},data-md=${cell.defenseAssignmentMd},data-session=${cell.defenseSessionId},data-status=${cell.defenseStatus},data-seconds=${cell.defenseSecondsLeft},data-code=${cell.defenseCode},data-reason=${cell.defenseReadyReason}" data-action="defense"
th:title="${cell.defenseStatus == null} ? 'Защита не назначена — нажмите, чтобы задать задание' : 'Защита: задание и действия'"> th:title="${cell.defenseStatus == null} ? 'Защита не назначена — нажмите, чтобы задать задание' : (${cell.defenseStatus == 'ready'} ? 'Защита: ' + (${cell.defenseReadyReason == 'timeout'} ? 'кончилось время' : 'готова') : 'Защита: задание и действия')">
<span class="cell-dim">защита:</span> <span class="cell-dim">защита:</span>
<span class="js-def-label" <span class="js-def-label"
th:text="${cell.defenseStatus == null ? '—' : (cell.defenseStatus == 'waiting' th:text="${cell.defenseStatus == null ? '—' : (cell.defenseStatus == 'waiting'
? (cell.defenseCode != null ? 'код ' + cell.defenseCode : 'ожидает') ? (cell.defenseCode != null ? 'код ' + cell.defenseCode : 'ожидает')
: (cell.defenseStatus == 'ready' ? 'готова' : ''))}">—</span> : (cell.defenseStatus == 'ready' ? (cell.defenseReadyReason == 'timeout' ? 'кончилось время' : 'готова') : ''))}">—</span>
<span th:if="${cell.defenseStatus == 'started'}" class="defense-cell-timer js-def-timer" th:data-seconds="${cell.defenseSecondsLeft}">идёт</span> <span th:if="${cell.defenseStatus == 'started'}" class="defense-cell-timer js-def-timer" th:data-seconds="${cell.defenseSecondsLeft}">идёт</span>
</button> </button>
</div> </div>

View File

@@ -108,7 +108,7 @@
</form> </form>
</div> </div>
<div th:if="${defense != null and defense.status == 'ready'}"> <div th:if="${defense != null and defense.status == 'ready'}">
<p><span class="badge" th:classappend="${defense.readyReason == 'timeout'} ? 'badge-warn' : 'badge-ok'" th:text="${defense.readyReason == 'timeout' ? 'Вышло время' : 'Готов к сдаче'}"></span></p> <p><span class="badge" th:classappend="${defense.readyReason == 'timeout'} ? 'badge-warn' : 'badge-ok'" th:text="${defense.readyReason == 'timeout' ? 'Кончилось время' : 'Готов к сдаче'}"></span></p>
<p class="text-sm text-muted">Ожидайте преподавателя с проверкой.</p> <p class="text-sm text-muted">Ожидайте преподавателя с проверкой.</p>
</div> </div>
</div> </div>