298 lines
12 KiB
Vue
298 lines
12 KiB
Vue
<script setup lang="ts">
|
||
import { Form, Head } from '@inertiajs/vue3';
|
||
import { Building2, FolderPlus, Plus } from 'lucide-vue-next';
|
||
import InputError from '@/components/InputError.vue';
|
||
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 {
|
||
Select,
|
||
SelectContent,
|
||
SelectItem,
|
||
SelectTrigger,
|
||
SelectValue,
|
||
} from '@/components/ui/select';
|
||
import { index, store as storeDepartment } from '@/routes/references/departments';
|
||
import { store as storeDepartmentProfile } from '@/routes/references/department-profiles';
|
||
import type { Department, DepartmentProfile, Team } from '@/types';
|
||
|
||
type Props = {
|
||
currentTeam?: Team | null;
|
||
departmentProfiles: DepartmentProfile[];
|
||
departments: Department[];
|
||
};
|
||
|
||
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">
|
||
<div class="flex flex-col gap-2">
|
||
<Heading
|
||
title="Отделения"
|
||
description="Управляйте профилями отделений и создавайте сами отделения в одном разделе."
|
||
/>
|
||
</div>
|
||
|
||
<div class="grid gap-6 xl:grid-cols-[minmax(0,0.95fr)_minmax(0,1.05fr)]">
|
||
<Card class="border-sidebar-border/70">
|
||
<CardHeader>
|
||
<CardTitle class="flex items-center gap-2 text-base">
|
||
<FolderPlus class="h-4 w-4" />
|
||
Создать профиль отделения
|
||
</CardTitle>
|
||
<CardDescription>
|
||
Профиль используется как категория, к которой
|
||
привязывается отделение.
|
||
</CardDescription>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<Form
|
||
v-bind="
|
||
props.currentTeam
|
||
? storeDepartmentProfile.form(
|
||
props.currentTeam.slug,
|
||
)
|
||
: undefined
|
||
"
|
||
class="space-y-4"
|
||
v-slot="{ errors, processing }"
|
||
>
|
||
<div class="grid gap-2">
|
||
<Label for="department-profile-name">
|
||
Название профиля
|
||
</Label>
|
||
<Input
|
||
id="department-profile-name"
|
||
name="name"
|
||
data-test="department-profile-name"
|
||
placeholder="Например, Клинический профиль"
|
||
required
|
||
/>
|
||
<InputError :message="errors.name" />
|
||
</div>
|
||
|
||
<Button
|
||
type="submit"
|
||
data-test="department-profile-submit"
|
||
:disabled="processing"
|
||
class="w-full sm:w-auto"
|
||
>
|
||
<Plus class="h-4 w-4" />
|
||
Создать профиль
|
||
</Button>
|
||
</Form>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card class="border-sidebar-border/70">
|
||
<CardHeader>
|
||
<CardTitle class="flex items-center gap-2 text-base">
|
||
<Building2 class="h-4 w-4" />
|
||
Создать отделение
|
||
</CardTitle>
|
||
<CardDescription>
|
||
Укажите название, профиль и статус активности для
|
||
нового отделения.
|
||
</CardDescription>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<Form
|
||
v-bind="
|
||
props.currentTeam
|
||
? storeDepartment.form(props.currentTeam.slug)
|
||
: undefined
|
||
"
|
||
class="space-y-4"
|
||
v-slot="{ errors, processing }"
|
||
>
|
||
<div class="grid gap-2">
|
||
<Label for="department-name">Название отделения</Label>
|
||
<Input
|
||
id="department-name"
|
||
name="name"
|
||
data-test="department-name"
|
||
placeholder="Например, Приемное отделение"
|
||
required
|
||
/>
|
||
<InputError :message="errors.name" />
|
||
</div>
|
||
|
||
<div class="grid gap-2">
|
||
<Label for="department-profile">Профиль</Label>
|
||
<Select
|
||
name="department_profile_id"
|
||
data-test="department-profile-id"
|
||
>
|
||
<SelectTrigger
|
||
id="department-profile"
|
||
class="w-full"
|
||
>
|
||
<SelectValue
|
||
placeholder="Выберите профиль отделения"
|
||
/>
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem
|
||
v-for="departmentProfile in departmentProfiles"
|
||
:key="departmentProfile.id"
|
||
:value="String(departmentProfile.id)"
|
||
>
|
||
{{ departmentProfile.name }}
|
||
</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
<InputError
|
||
:message="errors.department_profile_id"
|
||
/>
|
||
</div>
|
||
|
||
<div class="grid gap-2">
|
||
<Label for="department-status">Статус</Label>
|
||
<Select
|
||
name="is_active"
|
||
default-value="1"
|
||
data-test="department-is-active"
|
||
>
|
||
<SelectTrigger
|
||
id="department-status"
|
||
class="w-full"
|
||
>
|
||
<SelectValue placeholder="Выберите статус" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="1">Активно</SelectItem>
|
||
<SelectItem value="0">Неактивно</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
<InputError :message="errors.is_active" />
|
||
</div>
|
||
|
||
<Button
|
||
type="submit"
|
||
data-test="department-submit"
|
||
:disabled="processing || departmentProfiles.length === 0"
|
||
class="w-full sm:w-auto"
|
||
>
|
||
<Plus class="h-4 w-4" />
|
||
Создать отделение
|
||
</Button>
|
||
</Form>
|
||
|
||
<p
|
||
v-if="departmentProfiles.length === 0"
|
||
class="mt-3 text-sm text-muted-foreground"
|
||
>
|
||
Сначала создайте хотя бы один профиль отделения.
|
||
</p>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
|
||
<div class="grid gap-6 xl:grid-cols-2">
|
||
<Card class="border-sidebar-border/70">
|
||
<CardHeader>
|
||
<CardTitle>Профили отделений</CardTitle>
|
||
<CardDescription>
|
||
Всего профилей: {{ departmentProfiles.length }}
|
||
</CardDescription>
|
||
</CardHeader>
|
||
<CardContent class="space-y-3">
|
||
<div
|
||
v-for="departmentProfile in departmentProfiles"
|
||
:key="departmentProfile.id"
|
||
class="flex items-center justify-between rounded-lg border px-4 py-3"
|
||
>
|
||
<div>
|
||
<p class="font-medium">
|
||
{{ departmentProfile.name }}
|
||
</p>
|
||
<p class="text-sm text-muted-foreground">
|
||
Отделений: {{
|
||
departmentProfile.departmentsCount
|
||
}}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<p
|
||
v-if="departmentProfiles.length === 0"
|
||
class="py-6 text-center text-sm text-muted-foreground"
|
||
>
|
||
Профили отделений пока не созданы.
|
||
</p>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card class="border-sidebar-border/70">
|
||
<CardHeader>
|
||
<CardTitle>Список отделений</CardTitle>
|
||
<CardDescription>
|
||
Всего отделений: {{ departments.length }}
|
||
</CardDescription>
|
||
</CardHeader>
|
||
<CardContent class="space-y-3">
|
||
<div
|
||
v-for="department in departments"
|
||
:key="department.id"
|
||
class="flex items-center justify-between rounded-lg border px-4 py-3"
|
||
>
|
||
<div>
|
||
<p class="font-medium">{{ department.name }}</p>
|
||
<p class="text-sm text-muted-foreground">
|
||
Профиль:
|
||
{{ department.departmentProfile.name }}
|
||
</p>
|
||
</div>
|
||
|
||
<Badge
|
||
:variant="
|
||
department.isActive ? 'default' : 'secondary'
|
||
"
|
||
>
|
||
{{
|
||
department.isActive
|
||
? 'Активно'
|
||
: 'Неактивно'
|
||
}}
|
||
</Badge>
|
||
</div>
|
||
|
||
<p
|
||
v-if="departments.length === 0"
|
||
class="py-6 text-center text-sm text-muted-foreground"
|
||
>
|
||
Отделения пока не созданы.
|
||
</p>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</div>
|
||
</template>
|