From e56b577772c88777096047c957f97926b02a1982 Mon Sep 17 00:00:00 2001 From: Sergey Karmanov Date: Sun, 24 May 2026 21:32:22 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/admin/CreateLectureModal.vue | 328 ++++++++++++++++++ .../src/views/admin/AdminLecturesView.vue | 207 ++--------- .../views/teacher/TeacherDashboardView.vue | 2 +- 3 files changed, 360 insertions(+), 177 deletions(-) create mode 100644 frontend/src/components/admin/CreateLectureModal.vue diff --git a/frontend/src/components/admin/CreateLectureModal.vue b/frontend/src/components/admin/CreateLectureModal.vue new file mode 100644 index 0000000..76651cf --- /dev/null +++ b/frontend/src/components/admin/CreateLectureModal.vue @@ -0,0 +1,328 @@ + + + + + diff --git a/frontend/src/views/admin/AdminLecturesView.vue b/frontend/src/views/admin/AdminLecturesView.vue index 3d389a7..8ee7f85 100644 --- a/frontend/src/views/admin/AdminLecturesView.vue +++ b/frontend/src/views/admin/AdminLecturesView.vue @@ -14,6 +14,7 @@ import type { import GlassCard from '@/components/ui/GlassCard.vue' import DataTable from '@/components/ui/DataTable.vue' import EmptyState from '@/components/ui/EmptyState.vue' +import CreateLectureModal from '@/components/admin/CreateLectureModal.vue' type TabKey = 'lectures' | 'courses' | 'rooms' | 'tags' type TabConfig = { @@ -34,19 +35,7 @@ const syncError = ref('') const syncErrorDetails = ref([]) const syncStatus = ref(null) const syncResult = ref(null) -const creatingDummyLecture = ref(false) -const dummyTimeOptions = [ - { label: 'Через 3ч 5м', minutes: 185 }, - { label: 'Через 1ч 5м', minutes: 65 }, - { label: 'Через 5м', minutes: 5 }, -] -const dummyLectureForm = ref({ - title: 'Фиктивная лекция для проверки уведомлений', - offsetMinutes: 185, - durationMinutes: 60, - maxEnrollments: 100, - courseId: null as number | null, -}) +const isCreateLectureModalOpen = ref(false) const addToast = inject('addToast') as | ((message: string, type?: 'success' | 'error' | 'info') => void) | undefined @@ -197,60 +186,14 @@ async function loadData() { loading.value = false } -function getDummyLectureCourseId() { - const selectedCourseId = dummyLectureForm.value.courseId - if (selectedCourseId && courses.value.some((course) => course.id === selectedCourseId)) - return selectedCourseId - return courses.value[0]?.id ?? null +async function handleLectureCreated(lecture: LectureDto) { + lectures.value = [lecture, ...lectures.value] + activeTab.value = 'lectures' + await loadData() } -async function createDummyLecture() { - const courseId = getDummyLectureCourseId() - const title = dummyLectureForm.value.title.trim() - const durationMinutes = Math.max(5, Number(dummyLectureForm.value.durationMinutes) || 60) - const maxEnrollments = Math.max(1, Number(dummyLectureForm.value.maxEnrollments) || 100) - - if (!courseId) { - addToast?.('Нужен хотя бы один курс, чтобы создать фиктивную лекцию.', 'error') - activeTab.value = 'courses' - return - } - if (!title) { - addToast?.('Укажите название фиктивной лекции.', 'error') - return - } - - creatingDummyLecture.value = true - try { - const location = locations.value[0] - const startsAt = new Date(Date.now() + dummyLectureForm.value.offsetMinutes * 60_000) - const endsAt = new Date(startsAt.getTime() + durationMinutes * 60_000) - const createdLecture = await lecturesApi.create({ - courseId, - teacherId: null, - locationId: location?.id ?? null, - title, - description: - 'Фиктивная лекция создана из админки для проверки системы отзывов и напоминаний о начале лекции.', - format: location ? 'Offline' : 'Online', - startsAt: startsAt.toISOString(), - endsAt: endsAt.toISOString(), - isOpen: true, - maxEnrollments, - onlineUrl: null, - }) - - lectures.value = [createdLecture, ...lectures.value] - activeTab.value = 'lectures' - addToast?.(`Фиктивная лекция создана: ${startsAt.toLocaleString('ru-RU')}.`, 'success') - await loadData() - } catch (err) { - const message = err instanceof Error ? err.message : 'Не удалось создать фиктивную лекцию.' - const details = extractApiErrorDetails(err) - addToast?.(details.length ? `${message}: ${details.join('; ')}` : message, 'error') - } finally { - creatingDummyLecture.value = false - } +function handleLectureMissingCourse() { + activeTab.value = 'courses' } async function refreshSyncStatus() { @@ -345,9 +288,14 @@ onMounted(() => {

Управление лекциями и справочниками

- +
+ + +
@@ -374,80 +322,6 @@ onMounted(() => { - -
-
-
Фиктивная лекция
-
Для ручной проверки отзывов и уведомлений
-
-
- -
- - - - -
- -
- - - - -
- - -
- -
- Лекция создаётся открытой для записи. Аудитория подставится автоматически, если она уже - есть в справочнике. -
- -
- -
-
-
-
@@ -511,6 +385,15 @@ onMounted(() => {
+ +
@@ -527,6 +410,12 @@ onMounted(() => { gap: 12px; flex-wrap: wrap; } +.header-actions { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; +} .tabs { display: inline-flex; width: fit-content; @@ -574,40 +463,6 @@ onMounted(() => { gap: 10px; flex-wrap: wrap; } -.time-options { - display: flex; - gap: 8px; - flex-wrap: wrap; -} -.time-option { - border: 1px solid var(--color-border-glass); - border-radius: 999px; - padding: 8px 12px; - background: var(--color-white-a72); - color: var(--color-text-secondary); - cursor: pointer; -} -.time-option.active { - background: var(--color-primary-a18); - border-color: var(--color-primary-light); - color: var(--color-primary-dark); - font-weight: 600; -} -.dummy-fields { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); - gap: 10px; -} -.dummy-fields label { - display: flex; - flex-direction: column; - gap: 6px; -} -.dummy-note { - font-size: 12px; - color: var(--color-text-secondary); - line-height: 1.4; -} .type-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); diff --git a/frontend/src/views/teacher/TeacherDashboardView.vue b/frontend/src/views/teacher/TeacherDashboardView.vue index 92c12cd..1544536 100644 --- a/frontend/src/views/teacher/TeacherDashboardView.vue +++ b/frontend/src/views/teacher/TeacherDashboardView.vue @@ -49,7 +49,7 @@ watch(() => auth.user?.id, fetchTeacherLectures)
Заметность за пределами направления
- {{ visibility }}% студентов из других институтов Цель 50% + {{ visibility }}% студентов из других институтов