209 lines
8.4 KiB
Vue
209 lines
8.4 KiB
Vue
<script setup lang="ts">
|
||
import { Form, Head } from '@inertiajs/vue3';
|
||
import Heading from '@/components/Heading.vue';
|
||
import { Badge } from '@/components/ui/badge';
|
||
import { Button } from '@/components/ui/button';
|
||
import {
|
||
Card,
|
||
CardContent,
|
||
CardDescription,
|
||
CardHeader,
|
||
CardTitle,
|
||
} from '@/components/ui/card';
|
||
import { Input } from '@/components/ui/input';
|
||
import { Label } from '@/components/ui/label';
|
||
import { index as analysisIndex } from '@/routes/reports/analysis';
|
||
import { approve, index, store } from '@/routes/reports/periods';
|
||
import type { ReportPeriodSummary, Team } from '@/types';
|
||
|
||
type Props = {
|
||
currentTeam?: Team | null;
|
||
periods: ReportPeriodSummary[];
|
||
months: Array<{ value: number; label: string }>;
|
||
years: number[];
|
||
};
|
||
|
||
const props = defineProps<Props>();
|
||
|
||
defineOptions({
|
||
layout: (props: { currentTeam?: Team | null }) => ({
|
||
breadcrumbs: [
|
||
{
|
||
title: 'Отчеты',
|
||
href: props.currentTeam ? index(props.currentTeam.slug) : '/',
|
||
},
|
||
{
|
||
title: 'Периоды',
|
||
href: props.currentTeam ? index(props.currentTeam.slug) : '/',
|
||
},
|
||
],
|
||
}),
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<Head title="Периоды отчетов" />
|
||
|
||
<div class="flex flex-col gap-6">
|
||
<Heading
|
||
title="Периоды отчетов"
|
||
description="Создавайте месяцы учета, управляйте их статусом и подготавливайте основу для модулей ввода и анализа."
|
||
/>
|
||
|
||
<div class="grid gap-6 xl:grid-cols-[minmax(0,0.8fr)_minmax(0,1.2fr)]">
|
||
<Card class="border-sidebar-border/70">
|
||
<CardHeader>
|
||
<CardTitle>Создать период</CardTitle>
|
||
<CardDescription>
|
||
Новый период создается в статусе черновика и доступен
|
||
для ввода данных.
|
||
</CardDescription>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<Form
|
||
v-if="props.currentTeam"
|
||
v-bind="store.form(props.currentTeam.slug)"
|
||
class="space-y-4"
|
||
v-slot="{ errors, processing }"
|
||
>
|
||
<div class="grid gap-2">
|
||
<Label for="report-period-year">Год</Label>
|
||
<select
|
||
id="report-period-year"
|
||
name="year"
|
||
class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
|
||
>
|
||
<option
|
||
v-for="year in years"
|
||
:key="year"
|
||
:value="year"
|
||
>
|
||
{{ year }}
|
||
</option>
|
||
</select>
|
||
<p
|
||
v-if="errors.year"
|
||
class="text-sm text-destructive"
|
||
>
|
||
{{ errors.year }}
|
||
</p>
|
||
</div>
|
||
|
||
<div class="grid gap-2">
|
||
<Label for="report-period-month">Месяц</Label>
|
||
<select
|
||
id="report-period-month"
|
||
name="month"
|
||
class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
|
||
>
|
||
<option
|
||
v-for="month in months"
|
||
:key="month.value"
|
||
:value="month.value"
|
||
>
|
||
{{ month.label }}
|
||
</option>
|
||
</select>
|
||
<p
|
||
v-if="errors.month"
|
||
class="text-sm text-destructive"
|
||
>
|
||
{{ errors.month }}
|
||
</p>
|
||
</div>
|
||
|
||
<Button type="submit" :disabled="processing">
|
||
Создать период
|
||
</Button>
|
||
</Form>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card class="border-sidebar-border/70">
|
||
<CardHeader>
|
||
<CardTitle>Периоды команды</CardTitle>
|
||
<CardDescription>
|
||
Всего периодов: {{ periods.length }}
|
||
</CardDescription>
|
||
</CardHeader>
|
||
<CardContent class="space-y-3">
|
||
<div
|
||
v-for="period in periods"
|
||
:key="period.id"
|
||
class="flex flex-col gap-3 rounded-lg border px-4 py-4 md:flex-row md:items-center md:justify-between"
|
||
>
|
||
<div class="space-y-1">
|
||
<p class="font-medium">{{ period.label }}</p>
|
||
<p class="text-sm text-muted-foreground">
|
||
Обновлен: {{
|
||
period.updatedAt
|
||
? new Date(period.updatedAt).toLocaleString(
|
||
'ru-RU',
|
||
)
|
||
: 'нет данных'
|
||
}}
|
||
</p>
|
||
</div>
|
||
|
||
<div class="flex flex-wrap items-center gap-2">
|
||
<Badge
|
||
:variant="
|
||
period.isEditable ? 'default' : 'secondary'
|
||
"
|
||
>
|
||
{{ period.statusLabel }}
|
||
</Badge>
|
||
|
||
<Button
|
||
v-if="props.currentTeam"
|
||
as-child
|
||
variant="outline"
|
||
size="sm"
|
||
>
|
||
<a
|
||
:href="
|
||
analysisIndex(props.currentTeam.slug, {
|
||
query: { period: period.id },
|
||
}).url
|
||
"
|
||
>
|
||
Открыть анализ
|
||
</a>
|
||
</Button>
|
||
|
||
<Form
|
||
v-if="
|
||
props.currentTeam &&
|
||
period.isEditable
|
||
"
|
||
v-bind="
|
||
approve.form([
|
||
props.currentTeam.slug,
|
||
period.id,
|
||
])
|
||
"
|
||
v-slot="{ processing }"
|
||
>
|
||
<Button
|
||
type="submit"
|
||
size="sm"
|
||
:disabled="processing"
|
||
>
|
||
Утвердить
|
||
</Button>
|
||
</Form>
|
||
</div>
|
||
</div>
|
||
|
||
<p
|
||
v-if="periods.length === 0"
|
||
class="py-6 text-center text-sm text-muted-foreground"
|
||
>
|
||
Периоды еще не созданы.
|
||
</p>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</div>
|
||
</template>
|