Redesign B3 bordeaux + finish lab-page rework

- Lab page is now read-only with a settings screen for levels/variants;
  variant issuance moved to a large modal on the group page (assign-fragment).
- Header: bordeaux logo and 2px accent underline, bordeaux login/logout/theme
  buttons; smaller radii across the UI; filled secondary/danger buttons.
- Includes prior agent work (login backoff, no-cache pages, API timeouts,
  content tweaks) and fixes (variant usage Map.values, import order).
- Bump static asset version to v=9.
This commit is contained in:
2026-10-02 15:41:16 +03:00
parent 7a781fea33
commit 556fdf3b5e
67 changed files with 3019 additions and 653 deletions

View File

@@ -46,8 +46,8 @@
<tr th:each="s : ${submissions}">
<td th:text="${s.seq}">1</td>
<td class="text-muted" th:text="${s.createdAt}"></td>
<td class="font-mono text-sm"><span th:each="f : ${s.files}" th:text="${f}"></span></td>
<td><a class="btn btn-secondary btn-sm" th:href="'/student/submissions/' + ${s.id} + '/download'">Скачать</a></td>
<td class="font-mono text-sm" th:text="${#strings.listJoin(s.files, ', ')}">main.c</td>
<td><a class="btn btn-secondary" th:href="'/student/submissions/' + ${s.id} + '/download'">Скачать</a></td>
</tr>
<tr th:if="${#lists.isEmpty(submissions)}"><td colspan="4" class="empty">Нет сдач.</td></tr>
</tbody>
@@ -89,7 +89,8 @@
<form class="inline-form" th:action="@{/student/defenses/start}" method="post">
<input type="hidden" name="_csrf" th:value="${csrfToken}">
<input type="hidden" name="labId" th:value="${lab.id}">
<input class="input input-sm" name="code" placeholder="6-значный код" maxlength="6" pattern="[0-9]{6}" required>
<input class="input" name="code" placeholder="6-значный код" maxlength="6" pattern="[0-9]{6}"
inputmode="numeric" autocomplete="one-time-code" required>
<button class="btn btn-primary" type="submit">Приступить к защите</button>
</form>
</th:block>
@@ -97,7 +98,8 @@
<p class="text-sm defense-timer" th:attr="data-seconds=${defense.secondsLeft},data-lab=${lab.id}"></p>
<h3 class="group-title">Ваше индивидуальное задание</h3>
<div class="md-body" th:utext="${defense.assignmentHtml}"></div>
<form class="mt-4" th:action="'/student/defenses/' + ${defense.id} + '/finish?labId=' + ${lab.id}" method="post">
<form class="mt-4" th:action="'/student/defenses/' + ${defense.id} + '/finish?labId=' + ${lab.id}" method="post"
onsubmit="return confirm('Завершить защиту? Продолжить её будет нельзя — дождитесь преподавателя.')">
<input type="hidden" name="_csrf" th:value="${csrfToken}">
<button class="btn btn-primary" type="submit">Готов к сдаче</button>
</form>
@@ -107,7 +109,7 @@
<p class="text-sm text-muted">Ожидайте преподавателя с проверкой.</p>
</div>
</div>
<script src="/js/defense-timer.js"></script>
<script th:src="@{/js/defense-timer.js(v='9')}" defer></script>
</div>
</body>
</html>