Dev #11

Merged
serega404 merged 87 commits from dev into main 2026-05-25 03:22:55 +03:00
10 changed files with 29 additions and 23 deletions
Showing only changes of commit 5a1ddb82e6 - Show all commits
+1 -1
View File
@@ -73,7 +73,7 @@ export function mapApiLecture(lecture: LectureDto): Lecture {
time: startsAt.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }), time: startsAt.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }),
duration, duration,
building: lecture.format === 'Online' ? 'Онлайн' : locationName, building: lecture.format === 'Online' ? 'Онлайн' : locationName,
room: lecture.format === 'Online' ? undefined : locationName, room: undefined,
format: lecture.format === 'Online' ? 'online' : 'offline', format: lecture.format === 'Online' ? 'online' : 'offline',
totalSeats, totalSeats,
enrolledSeats: enrolled, enrolledSeats: enrolled,
+1 -1
View File
@@ -217,7 +217,7 @@ input, textarea, select {
font-weight: 600; font-weight: 600;
white-space: nowrap; white-space: nowrap;
} }
.badge-green { color: #15803D; border: 1.5px solid rgba(34,197,94,0.3); } .badge-green { color: #15803D; border: 1.3px solid rgba(34,197,94,0.3); }
.badge-blue { background: rgba(6,182,212,0.15); color: #0E7490; border: 1px solid rgba(6,182,212,0.3); } .badge-blue { background: rgba(6,182,212,0.15); color: #0E7490; border: 1px solid rgba(6,182,212,0.3); }
.badge-orange { background: rgba(251,146,60,0.15); color: #C2410C; border: 1px solid rgba(251,146,60,0.3); } .badge-orange { background: rgba(251,146,60,0.15); color: #C2410C; border: 1px solid rgba(251,146,60,0.3); }
.badge-gray { background: rgba(100,116,139,0.1); color: #64748B; border: 1px solid rgba(100,116,139,0.2); } .badge-gray { background: rgba(100,116,139,0.1); color: #64748B; border: 1px solid rgba(100,116,139,0.2); }
+9 -3
View File
@@ -50,9 +50,15 @@ function goDetail() {
<h3 class="card-title">{{ lecture.title }}</h3> <h3 class="card-title">{{ lecture.title }}</h3>
<div class="card-teacher"> <div class="card-teacher">
<AppIcon class="teacher-icon" icon="user" :size="16" /> <template v-if="lecture.teacher && lecture.teacher !== 'Преподаватель уточняется'">
<span>{{ lecture.teacher }}</span> <AppIcon class="teacher-icon" icon="user" :size="16" />
<span class="text-secondary">· {{ lecture.institute }}</span> <span>{{ lecture.teacher }}</span>
<span class="text-secondary">{{ lecture.institute }}</span>
</template>
<template v-else>
<AppIcon class="teacher-icon" icon="building" :size="16" />
<span class="text-secondary">{{ lecture.institute }}</span>
</template>
</div> </div>
<div class="card-meta"> <div class="card-meta">
+3 -3
View File
@@ -222,10 +222,10 @@ function isRegistered(id: string) {
<div class="text-secondary text-sm">{{ row.tags.join(' ') }}</div> <div class="text-secondary text-sm">{{ row.tags.join(' ') }}</div>
</template> </template>
<template #date="{ row }"> <template #date="{ row }">
{{ new Date(row.date).toLocaleDateString('ru-RU') }} · {{ row.time }} {{ new Date(row.date).toLocaleDateString('ru-RU') }} {{ row.time }}
</template> </template>
<template #place="{ row }"> <template #place="{ row }">
{{ row.building }} {{ row.room ? `· ауд. ${row.room}` : '' }} {{ row.building }} {{ row.room ? `ауд. ${row.room}` : '' }}
</template> </template>
<template #seats="{ row }"> <template #seats="{ row }">
<span :class="row.freeSeats === 0 ? 'badge badge-gray' : 'badge badge-green'"> <span :class="row.freeSeats === 0 ? 'badge badge-gray' : 'badge badge-green'">
@@ -251,7 +251,7 @@ function isRegistered(id: string) {
<div class="calendar-items"> <div class="calendar-items">
<div v-for="l in items" :key="l.id" class="calendar-item"> <div v-for="l in items" :key="l.id" class="calendar-item">
<div class="calendar-title">{{ l.title }}</div> <div class="calendar-title">{{ l.title }}</div>
<div class="calendar-meta">{{ l.time }} · {{ l.building }} {{ l.room ? `· ауд. ${l.room}` : '' }}</div> <div class="calendar-meta">{{ l.time }} {{ l.building }} {{ l.room ? `ауд. ${l.room}` : '' }}</div>
<button class="btn-secondary btn-sm">Подробнее</button> <button class="btn-secondary btn-sm">Подробнее</button>
</div> </div>
</div> </div>
+1 -1
View File
@@ -24,7 +24,7 @@ const userMetaLine = computed(() => {
const parts: string[] = [] const parts: string[] = []
if (user.value.institute) parts.push(user.value.institute) if (user.value.institute) parts.push(user.value.institute)
if (user.value.direction) parts.push(user.value.direction) if (user.value.direction) parts.push(user.value.direction)
if (user.value.year !== null && user.value.year !== undefined) parts.push(`${user.value.year} курс`) if (Number.isFinite(user.value.year) && (user.value.year as number) > 0) parts.push(`${user.value.year} курс`)
return parts.join(' · ') return parts.join(' · ')
}) })
const nextLecture = computed(() => lectures.registeredLectures[0] ?? lectures.all[0]) const nextLecture = computed(() => lectures.registeredLectures[0] ?? lectures.all[0])
@@ -63,14 +63,14 @@ onMounted(async () => {
<GlassCard> <GlassCard>
<div class="info-section"> <div class="info-section">
<h3>Преподаватель</h3> <h3>Преподаватель</h3>
<div class="info-value">{{ lecture.teacher }} · {{ lecture.teacherTitle }}</div> <div class="info-value">{{ lecture.teacher }}<span v-if="lecture.teacherTitle"> {{ lecture.teacherTitle }}</span></div>
<div class="info-sub">{{ lecture.department }}, {{ lecture.institute }}</div> <div class="info-sub">{{ [lecture.department, lecture.institute].filter(Boolean).join(', ') }}</div>
</div> </div>
<div class="info-section"> <div class="info-section">
<h3>Детали занятия</h3> <h3>Детали занятия</h3>
<div class="info-value">📅 {{ new Date(lecture.date).toLocaleDateString('ru-RU') }} · {{ lecture.time }}</div> <div class="info-value">{{ new Date(lecture.date).toLocaleDateString('ru-RU') }} {{ lecture.time }}</div>
<div class="info-sub">Длительность: {{ lecture.duration }} мин</div> <div class="info-sub">Длительность: {{ lecture.duration }} мин</div>
<div class="info-sub">Локация: {{ lecture.building }} {{ lecture.room ? `· ауд. ${lecture.room}` : '' }}</div> <div class="info-sub">Локация: {{ lecture.building }} {{ lecture.room ? `ауд. ${lecture.room}` : '' }}</div>
</div> </div>
<div class="info-section"> <div class="info-section">
<h3>Места</h3> <h3>Места</h3>
@@ -93,7 +93,7 @@ onMounted(async () => {
</p> </p>
<div class="reviews" v-if="reviews.length"> <div class="reviews" v-if="reviews.length">
<div v-for="review in reviews" :key="review.id" class="review"> <div v-for="review in reviews" :key="review.id" class="review">
<div class="review-head">{{ review.userName }} · {{ review.sentiment }}</div> <div class="review-head">{{ review.userName }} {{ review.sentiment }}</div>
<div class="review-body">{{ review.text }}</div> <div class="review-body">{{ review.text }}</div>
</div> </div>
</div> </div>
@@ -57,8 +57,8 @@ async function confirmCancel() {
<GlassCard v-for="item in upcoming" :key="item.id" class="lecture-row"> <GlassCard v-for="item in upcoming" :key="item.id" class="lecture-row">
<div> <div>
<div class="lecture-title">{{ item.title }}</div> <div class="lecture-title">{{ item.title }}</div>
<div class="lecture-meta">📅 {{ new Date(item.date).toLocaleDateString('ru-RU') }} · {{ item.time }}</div> <div class="lecture-meta">{{ new Date(item.date).toLocaleDateString('ru-RU') }} {{ item.time }}</div>
<div class="lecture-meta">🏛 {{ item.building }} {{ item.room ? `· ауд. ${item.room}` : '' }}</div> <div class="lecture-meta">{{ item.building }} {{ item.room ? `ауд. ${item.room}` : '' }}</div>
</div> </div>
<div class="lecture-actions"> <div class="lecture-actions">
<StatusBadge status="registered" /> <StatusBadge status="registered" />
@@ -73,8 +73,8 @@ async function confirmCancel() {
<GlassCard v-for="item in history" :key="item.id" class="lecture-row"> <GlassCard v-for="item in history" :key="item.id" class="lecture-row">
<div> <div>
<div class="lecture-title">{{ item.title }}</div> <div class="lecture-title">{{ item.title }}</div>
<div class="lecture-meta">📅 {{ new Date(item.date).toLocaleDateString('ru-RU') }} · {{ item.time }}</div> <div class="lecture-meta">{{ new Date(item.date).toLocaleDateString('ru-RU') }} {{ item.time }}</div>
<div class="lecture-meta">🏛 {{ item.building }} {{ item.room ? `· ауд. ${item.room}` : '' }}</div> <div class="lecture-meta">{{ item.building }} {{ item.room ? `ауд. ${item.room}` : '' }}</div>
</div> </div>
<div class="lecture-actions"> <div class="lecture-actions">
<StatusBadge :status="item.status ?? 'completed'" /> <StatusBadge :status="item.status ?? 'completed'" />
+2 -2
View File
@@ -17,12 +17,12 @@ const userMetaLine = computed(() => {
const parts: string[] = [] const parts: string[] = []
if (user.value.institute) parts.push(user.value.institute) if (user.value.institute) parts.push(user.value.institute)
if (user.value.direction) parts.push(user.value.direction) if (user.value.direction) parts.push(user.value.direction)
return parts.join(' · ') return parts.join(' ')
}) })
const userYearLine = computed(() => { const userYearLine = computed(() => {
const year = user.value.year const year = user.value.year
return year === null || year === undefined ? '' : `${year} курс` return Number.isFinite(year) && year > 0 ? `${year} курс` : ''
}) })
const interestTags = ref([ const interestTags = ref([
{ label: '#ML', active: true }, { label: '#ML', active: true },
@@ -46,7 +46,7 @@ onMounted(() => {
<div class="section-title">Заметность за пределами направления</div> <div class="section-title">Заметность за пределами направления</div>
<div class="visibility"> <div class="visibility">
<div class="visibility-meta"> <div class="visibility-meta">
{{ visibility }}% студентов из других институтов · Цель 50% {{ visibility }}% студентов из других институтов Цель 50%
</div> </div>
<ProgressBar :value="visibility" :max="100" /> <ProgressBar :value="visibility" :max="100" />
</div> </div>
@@ -59,7 +59,7 @@ onMounted(() => {
<div class="upcoming-item" v-for="l in upcoming" :key="l.id"> <div class="upcoming-item" v-for="l in upcoming" :key="l.id">
<div> <div>
<div class="upcoming-title">{{ l.title }}</div> <div class="upcoming-title">{{ l.title }}</div>
<div class="upcoming-meta">📅 {{ new Date(l.date).toLocaleDateString('ru-RU') }} · {{ l.time }}</div> <div class="upcoming-meta">{{ new Date(l.date).toLocaleDateString('ru-RU') }} {{ l.time }}</div>
<div class="upcoming-meta">Записалось {{ l.enrolledSeats }} студентов</div> <div class="upcoming-meta">Записалось {{ l.enrolledSeats }} студентов</div>
</div> </div>
<button class="btn-secondary btn-sm" @click="router.push('/teacher/lectures')">Управлять</button> <button class="btn-secondary btn-sm" @click="router.push('/teacher/lectures')">Управлять</button>
@@ -22,7 +22,7 @@ const rows = computed(() => {
return (owned.length ? owned : lecturesStore.all).map(l => ({ return (owned.length ? owned : lecturesStore.all).map(l => ({
id: l.id, id: l.id,
title: l.title, title: l.title,
date: `${new Date(l.date).toLocaleDateString('ru-RU')} · ${l.time}`, date: `${new Date(l.date).toLocaleDateString('ru-RU')} ${l.time}`,
status: l.status ?? 'upcoming', status: l.status ?? 'upcoming',
stats: `${l.enrolledSeats} / — / ${l.reviewCount}`, stats: `${l.enrolledSeats} / — / ${l.reviewCount}`,
})) }))