reports/frontend/src/App.vue

152 lines
3.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { fetchTeams } from './api'
import type { Team } from './types'
import TeamSidebar from './components/TeamSidebar.vue'
import SprintTable from './components/SprintTable.vue'
const teams = ref<Team[]>([])
const selectedTeamId = ref<number | null>(null)
const loadingTeams = ref(true)
const teamsError = ref<string | null>(null)
onMounted(async () => {
try {
teams.value = await fetchTeams()
if (teams.value.length > 0) {
selectedTeamId.value = teams.value[0].id
}
} catch (error) {
teamsError.value = error instanceof Error ? error.message : 'Не удалось загрузить команды'
} finally {
loadingTeams.value = false
}
})
function selectTeam(teamId: number) {
selectedTeamId.value = teamId
}
const selectedTeam = computed(
() => teams.value.find((team) => team.id === selectedTeamId.value) ?? null,
)
</script>
<template>
<div class="layout">
<aside class="sidebar">
<div class="sidebar__header">
<h1 class="sidebar__title">Команды</h1>
</div>
<div v-if="loadingTeams" class="sidebar__state">Загрузка...</div>
<div v-else-if="teamsError" class="sidebar__state sidebar__state--error">{{ teamsError }}</div>
<TeamSidebar
v-else
:teams="teams"
:selected-team-id="selectedTeamId"
@select="selectTeam"
/>
</aside>
<main class="main">
<header class="main__header">
<h2 class="main__title">
{{ selectedTeam?.name ?? 'Сводка по спринтам' }}
</h2>
<p class="main__subtitle">Спринты отсортированы по дате начала</p>
</header>
<SprintTable v-if="selectedTeamId !== null" :team-id="selectedTeamId" />
<div v-else class="main__empty">Выберите команду в сайдбаре</div>
</main>
</div>
</template>
<style scoped>
.layout {
display: grid;
grid-template-columns: 240px 1fr;
min-height: 100vh;
background: #23272a;
}
.sidebar {
position: relative;
display: flex;
flex-direction: column;
padding: 8px 0 16px;
background: #1e2226;
border-right: 0.5px solid rgba(255, 255, 255, 0.06);
}
.sidebar__header {
padding: 12px 16px 4px;
}
.sidebar__title {
margin: 0;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: rgba(235, 235, 245, 0.55);
}
.sidebar__state {
padding: 8px 16px;
font-size: 13px;
color: rgba(235, 235, 245, 0.45);
}
.sidebar__state--error {
color: #ff6961;
}
.main {
padding: 28px 36px;
overflow-x: auto;
background: #23272a;
}
.main__header {
margin-bottom: 24px;
}
.main__title {
margin: 0 0 4px;
font-size: 1.625rem;
font-weight: 600;
letter-spacing: -0.02em;
color: #f5f5f7;
}
.main__subtitle {
margin: 0;
color: rgba(235, 235, 245, 0.55);
font-size: 0.875rem;
}
.main__empty {
color: rgba(235, 235, 245, 0.45);
padding: 48px 0;
text-align: center;
font-size: 0.9375rem;
}
@media (max-width: 900px) {
.layout {
grid-template-columns: 1fr;
}
.sidebar {
border-right: none;
border-bottom: 0.5px solid rgba(255, 255, 255, 0.06);
}
.main {
padding: 24px 20px;
}
}
</style>