Модуль отчетов

This commit is contained in:
brusnitsyn
2026-06-21 23:40:55 +09:00
parent f163b95663
commit bd2cc24b98
27 changed files with 2781 additions and 3 deletions

View File

@@ -0,0 +1,135 @@
<script setup>
import {
NButton, NFlex, NForm, NFormItem, NInput, NSelect,
NText, NDynamicInput, NAlert, NTag,
} from 'naive-ui'
import {
TbReportAnalytics, TbLayoutDashboard,
} from 'vue-icons-plus/tb'
import AppLayout from '../../../Layouts/AppLayout.vue'
import AppContainer from '../../../Components/AppContainer.vue'
import SectionCard from '../../../Components/SectionCard.vue'
import PageBanner from '../../../Components/PageBanner.vue'
import SectionEditor from './Components/SectionEditor.vue'
import { useForm, Link, usePage } from '@inertiajs/vue3'
import { computed } from 'vue'
const props = defineProps({
template: { type: Object, default: null },
sources: { type: Array, default: () => [] },
})
const page = usePage()
const flash = computed(() => page.props.flash ?? {})
const isEdit = computed(() => !!props.template)
const createSection = () => ({
source: props.sources[0]?.key ?? null,
title: '',
columns: [],
filters: [],
})
const form = useForm({
name: props.template?.name ?? '',
sections: props.template?.sections?.length ? props.template.sections : [createSection()],
required_permissions: props.template?.requiredPermissions ?? [],
})
const visibilityOptions = [
{ label: 'Дежурный врач', value: 'report.view' },
{ label: 'Старшая медсестра', value: 'nurse.report.view' },
]
const submit = () => {
if (isEdit.value) {
form.put(`/admin/report-templates/${props.template.id}`)
} else {
form.post('/admin/report-templates/new')
}
}
</script>
<template>
<AppLayout>
<AppContainer>
<NAlert v-if="flash.success" type="success" closable style="margin-bottom: 4px;">
{{ flash.success }}
</NAlert>
<PageBanner
:title="isEdit ? template.name : 'Новый шаблон отчёта'"
:icon="TbReportAnalytics"
:color="isEdit ? null : 'default'"
:breadcrumbs="[
{ label: 'Администратор', href: '/admin', icon: TbLayoutDashboard, tag: Link },
{ label: 'Шаблоны отчётов', href: '/admin/report-templates', icon: TbReportAnalytics, tag: Link },
]"
>
<template #meta>
<NText depth="3" style="font-size: 13px;">
{{ isEdit ? 'Редактирование шаблона' : 'Название → секции с данными → кому виден' }}
</NText>
</template>
<template #actions>
<NButton :tag="Link" href="/admin/report-templates">Отмена</NButton>
<NButton type="primary" :loading="form.processing" @click="submit">
{{ isEdit ? 'Сохранить' : 'Создать шаблон' }}
</NButton>
</template>
</PageBanner>
<NFlex vertical :size="16">
<SectionCard title="1 · Название и видимость">
<NFlex :size="16" :wrap="true">
<NForm label-placement="top" style="flex: 2; min-width: 280px;">
<NFormItem label="Название отчёта" :feedback="form.errors.name" :validation-status="form.errors.name ? 'error' : undefined" style="margin-bottom: 0;">
<NInput v-model:value="form.name" placeholder="Например: Сводка по отделению" />
</NFormItem>
</NForm>
<NForm label-placement="top" style="flex: 1; min-width: 280px;">
<NFormItem label="Кому виден отчёт" style="margin-bottom: 0;">
<NSelect
v-model:value="form.required_permissions"
:options="visibilityOptions"
multiple
placeholder="Все с доступом к отчётам"
clearable
/>
</NFormItem>
</NForm>
</NFlex>
<NText depth="3" style="font-size: 12px; display: block; margin-top: 4px;">
Ничего не выбрано отчёт увидят все, у кого есть доступ к разделу «Отчёты»
</NText>
</SectionCard>
<SectionCard title="2 · Секции с данными">
<NText v-if="form.errors.sections" type="error" style="display: block; margin-bottom: 8px; font-size: 12px;">
{{ form.errors.sections }}
</NText>
<NDynamicInput
v-model:value="form.sections"
:on-create="createSection"
item-style="margin-bottom: 16px; padding-bottom: 16px; border-bottom: 1px solid var(--n-border-color, rgba(255,255,255,.08));"
>
<template #default="{ index, value }">
<NFlex vertical :size="8" style="width: 100%;">
<NTag size="small" round :bordered="false">Секция {{ index + 1 }}</NTag>
<SectionEditor :section="value" :sources="sources" />
</NFlex>
</template>
<template #create-button-default>
Добавить секцию
</template>
</NDynamicInput>
</SectionCard>
</NFlex>
</AppContainer>
</AppLayout>
</template>