first commit
This commit is contained in:
208
resources/js/pages/reports/periods/Index.vue
Normal file
208
resources/js/pages/reports/periods/Index.vue
Normal file
@@ -0,0 +1,208 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user