- progress: submissions table+V4; SubmissionService (deadline-gated submit,
unlimited resubmits, per-student history, zip download); files on disk
data/submissions/{student}/{lab}/{seq}/
- student API: POST submit (multipart), GET me submissions, download; admin
GET lab submissions + admin download (zip pack)
- progress enrich(): labId in MeAssignment; web DTO aligned
- web: /student dashboard (avg/best/worst cards), /student/labs cards,
/student/labs/{id}: condition md, variant block, submit form, history;
'Лабораторные' link in nav for students
- admin: submissions column on lab assignment table + download link
- fixed long-standing template bug: broken @{} expression (missing }) in
admin/lab and student/lab
48 lines
2.5 KiB
HTML
48 lines
2.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ru" xmlns:th="http://www.thymeleaf.org" th:fragment="layout(title, content)">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title th:replace="${title}">LMS</title>
|
|
<link rel="icon" type="image/svg+xml" th:href="@{/favicon.svg}">
|
|
<link rel="stylesheet" th:href="@{/css/app.css}">
|
|
<script th:src="@{/js/htmx.min.js}" defer></script>
|
|
<script>
|
|
(function(){ var t = localStorage.getItem('lms-theme') || 'light'; document.documentElement.setAttribute('data-theme', t); })();
|
|
function toggleTheme(){ var e=document.documentElement; var t=e.getAttribute('data-theme')==='dark'?'light':'dark'; e.setAttribute('data-theme',t); localStorage.setItem('lms-theme',t); }
|
|
function openModal(id){ var d=document.getElementById(id); if(d) d.showModal(); }
|
|
function closeModal(id){ var d=document.getElementById(id); if(d) d.close(); }
|
|
function openModalData(btn){ openModal(btn.dataset.modal); }
|
|
function closeModalData(btn){ closeModal(btn.dataset.modal); }
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div class="page">
|
|
<header class="page-header">
|
|
<div class="page-header-inner">
|
|
<a th:href="@{/}" class="logo">LMS</a>
|
|
<nav class="nav">
|
|
<a th:href="@{/learn}" class="nav-link">Материалы</a>
|
|
<th:block th:if="${currentUser != null}">
|
|
<a th:if="${currentUser.admin}" th:href="@{/admin/groups}" class="nav-link">Группы</a>
|
|
<a th:if="${currentUser.admin}" th:href="@{/admin/labs}" class="nav-link">Лабораторные</a>
|
|
<a th:unless="${currentUser.admin}" th:href="@{/student/labs}" class="nav-link">Лабораторные</a>
|
|
<span class="nav-sep" th:text="${currentUser.name}">—</span>
|
|
</th:block>
|
|
<button onclick="toggleTheme()" class="btn btn-secondary btn-sm">☀/🌙</button>
|
|
<form th:if="${currentUser != null}" th:action="@{/logout}" method="post">
|
|
<button class="btn btn-secondary" type="submit">Выйти</button>
|
|
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
|
</form>
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
<main class="page-main">
|
|
<th:block th:replace="${content}" />
|
|
</main>
|
|
<footer class="page-footer">
|
|
LMS v0.1.2
|
|
</footer>
|
|
</div>
|
|
</body>
|
|
</html> |