Files
onboard/resources/js/Pages/Report/Index.vue
brusnitsyn 739168d427 Обновлен стартовый экран
Переписаны запросы для статистики, отчетов
Добавлена интеграция отчета сестры
2026-05-28 22:10:00 +09:00

302 lines
11 KiB
Vue

<script setup>
import AppLayout from "../../Layouts/AppLayout.vue";
import {useReportStore} from "../../Stores/report.js";
import {onMounted, ref, watch, provide} from "vue";
import {useAuthStore} from "../../Stores/auth.js";
import {
NFormItem,
NFlex,
NInputNumber,
NTabPane,
NTabs,
NTag,
NRow, NCol, NDivider, NButton, NSpace
} from "naive-ui";
import DatePickerQuery from "../../Components/DatePickerQuery.vue";
import AppPanel from "../../Components/AppPanel.vue";
import AppContainer from "../../Components/AppContainer.vue";
import ReportWidget from "./Components/ReportWidget.vue";
import {router} from "@inertiajs/vue3";
import HeaderWidget from "./Components/HeaderWidget.vue";
import DutyPatientsPane from "./Components/DutyPatientsPane.vue";
import NursePatientsPane from "./Components/NursePatientsPane.vue";
import OperationWidget from "./Components/Widgets/OperationWidget.vue";
import LoadedWidget from "./Components/Widgets/LoadedWidget.vue";
import UnwantedEventModal from "./Components/Modals/UnwantedEventModal.vue";
import RecipientWidget from "./Components/Widgets/RecipientWidget.vue";
const props = defineProps({
department: {
type: Object,
default: {}
},
report: {
type: Object,
default: {}
},
metrikaItems: {
type: Array,
default: []
},
canSaveReport: Boolean,
canEditPastReport: Boolean,
canSaveNurseReport: Boolean,
stats: {
type: Object,
default: () => ({
duty: {
beds: 0,
loaded: 0,
current: 0,
urgent: 0,
discharged: 0,
},
nurse: {
current: 0,
urgent: 0,
discharged: 0,
},
})
},
latestReport: {
type: Object,
default: () => ({ })
},
patients: {
type: Array,
default: () => ([])
},
nursePatients: {
type: Array,
default: () => ([])
},
dates: {
type: Array,
default: []
},
selectedUserId: {
type: Number,
default: null
},
selectedDepartmentId: {
type: Number,
default: null
}
})
const reportStore = useReportStore()
const authStore = useAuthStore()
const userDepartment = authStore.userDepartment
const patientCollection = ref({...props.patients})
const nursePatientCollection = ref({...props.nursePatients})
const latestReportObj = ref(props.latestReport ?? {
unwanted_events: []
})
const loading = ref(false)
const showUnwantedEventModal = ref(false)
const reportForm = ref({
recipient: props.stats.duty.recipient,
discharged: props.stats.duty.discharged,
current: props.stats.duty.current,
staff: 0,
observables: []
})
const updateReportForm = (form) => {
reportForm.value = {
...reportForm.value,
...form
}
}
const updateUnwantedEvents = (unwanted_events) => {
reportForm.value = {
...reportForm.value,
unwanted_events
}
latestReportObj.value = {
...latestReportObj.value,
unwanted_events
}
}
// Прокидываем reportForm всем потомкам
provide('reportForm', {
reportForm,
updateReportForm
})
const submit = () => {
const queryString = window.location.search;
const params = new URLSearchParams(queryString);
const url = new URL(`${window.location.origin}/duty/report/save`)
const startAt = params.get('startAt')
const endAt = params.get('endAt')
if (startAt && startAt !== 'null') url.searchParams.append('startAt', startAt)
if (endAt && endAt !== 'null') url.searchParams.append('endAt', endAt)
router.post(url.toString(), {
...reportForm.value,
userId: props.selectedUserId,
departmentId: props.selectedDepartmentId,
}, {
onSuccess: () => {
alert('Сохранено')
}
})
}
const onShowUnwantedEventModal = () => {
showUnwantedEventModal.value = true
}
const addObservablePatient = (observable) => {
const collection = patientCollection.value.data
const item = collection.find(obs => obs.id === observable.id)
if (item) {
item.in_observable = true
item.observable = { observable_reason: observable.observable_reason }
}
}
const removeObservablePatient = (patient) => {
const collection = patientCollection.value.data
const item = collection.find(p => p.id === patient.id)
if (item) {
item.in_observable = false
}
}
const syncPageProps = (pageProps = props) => {
reportStore.initializeFromPage(pageProps)
patientCollection.value = {...pageProps.patients}
nursePatientCollection.value = {...pageProps.nursePatients}
latestReportObj.value = pageProps.latestReport ?? { unwanted_events: [] }
reportForm.value = {
...reportForm.value,
recipient: pageProps.stats.duty.recipient,
discharged: pageProps.stats.duty.discharged,
current: pageProps.stats.duty.current,
}
}
onMounted(syncPageProps)
watch(() => props, (newProps) => {
syncPageProps(newProps)
}, {
deep: true,
immediate: true
})
</script>
<template>
<AppLayout>
<!-- <template #headerSuffix>-->
<!-- <StatisticRecipientPlanOfYear :plan="reportStore.reportInfo.department.recipientPlanOfYear" :progress="reportStore.reportInfo.department.progressPlanOfYear" />-->
<!-- </template>-->
<!-- <ReportForm :mode />-->
<AppContainer>
<AppPanel>
<NFlex justify="space-between" align="center">
<NSpace>
<NTag type="info" :bordered="false">
{{ department.name_full }}
</NTag>
<NTag v-if="props.latestReport" type="warning" :bordered="false">
Отчет создан: {{ `${props.latestReport.doctor.FAM_V} ${props.latestReport.doctor.IM_V} ${props.latestReport.doctor.OT_V}` }}
</NTag>
</NSpace>
<DatePickerQuery :date="dates" :is-head-or-admin="true" class="text-lg!" />
</NFlex>
<NDivider dashed class="my-4! mt-3!" />
<NRow class="grow space-x-2 h-[82.78px]">
<NCol :span="3">
<HeaderWidget label="Коек"
:counter="stats.duty.beds" />
</NCol>
<NCol :span="3">
<LoadedWidget :counter="stats.duty.loaded" />
</NCol>
<NCol :span="3">
<RecipientWidget :beds="stats.duty.beds"
:duty-current="stats.duty.current"
:nurse-current="stats.nurse.current"
/>
</NCol>
<NCol :span="3">
<HeaderWidget label="Поступило"
is-double-counter
:counter="stats.duty.recipient"
:counter-suffix="stats.nurse.recipient"
/>
</NCol>
<NCol :span="3">
<HeaderWidget label="Выбыло"
is-double-counter
:counter="stats.duty.discharged"
:counter-suffix="stats.nurse.discharged"
/>
</NCol>
</NRow>
</AppPanel>
<div class="grid grid-cols-[1fr_auto] gap-x-2">
<AppPanel>
<NFlex align="center" :wrap="false">
<NFormItem label="Поступило" :show-feedback="false">
<NInputNumber :disabled="!canSaveReport" :min="0" v-model:value="reportForm.recipient" />
</NFormItem>
<NFormItem label="Выбыло" :show-feedback="false">
<NInputNumber :disabled="!canSaveReport" :min="0" v-model:value="reportForm.discharged" />
</NFormItem>
<NFormItem label="Состоит" :show-feedback="false">
<NInputNumber :disabled="!canSaveReport" :min="0" v-model:value="reportForm.current" />
</NFormItem>
<NFormItem label="Мед. персонал" :show-feedback="false">
<NInputNumber :disabled="!canSaveReport" :min="0" v-model:value="reportForm.staff" />
</NFormItem>
</NFlex>
</AppPanel>
<NFlex :wrap="false" :size="8">
<ReportWidget :counter="stats.duty.deceased">
Умерло
</ReportWidget>
<ReportWidget :counter="stats.duty.deceased">
<NSpace vertical :size="1">
<div>Летальность</div>
<div>%</div>
</NSpace>
</ReportWidget>
<OperationWidget :planned="stats.duty.surgical_planned" :urgent="stats.duty.surgical_urgent" />
</NFlex>
</div>
<AppPanel>
<NTabs type="segment">
<NTabPane name="mis" tab="МИС" display-directive="show">
<DutyPatientsPane :patients="patientCollection" :nurse-patients="nursePatientCollection" @create-observable="addObservablePatient" @remove-observable="removeObservablePatient" />
</NTabPane>
<NTabPane name="nurse" tab="Журнал пациентов" display-directive="show">
<NursePatientsPane :patients="nursePatientCollection" />
</NTabPane>
</NTabs>
</AppPanel>
<AppPanel>
<NFlex justify="space-between">
<NButton v-if="props.canSaveReport || props.canEditPastReport"
secondary type="error" :loading="loading" @click="onShowUnwantedEventModal">
Нежелательные события ({{ latestReportObj.unwanted_events?.length ?? 0 }})
</NButton>
<NButton v-if="props.canSaveReport" secondary @click="submit" :loading="loading">
Сохранить отчет
</NButton>
</NFlex>
</AppPanel>
</AppContainer>
<UnwantedEventModal v-model:show="showUnwantedEventModal" :can-save-report="props.canSaveReport" :report="latestReportObj" @onSubmit="updateUnwantedEvents" />
</AppLayout>
</template>