* исправление подсчета операций пациентов

* поправил поле выбора даты
* добавил индикатор в контроле
* окно выбора пользователя для сводной
* привязка окна для ввода причины контроля
* добавил привязку историй пациентов для просмотра статистики по дням
* поправил фиксацию фио ответственного, убрал при диапазоне
* отключение ролей адм и зав от реплики
This commit is contained in:
brusnitsyn
2026-01-30 17:26:16 +09:00
parent 87e21f0e08
commit 2805e5e4bc
21 changed files with 836 additions and 156 deletions

View File

@@ -34,7 +34,7 @@ const onSubmit = () => {
<ReportSection label="Планово" />
<NButton v-if="reportStore.reportInfo?.report.isActiveSendButton" secondary size="large" @click="onSubmit">
<NButton v-if="reportStore.reportInfo?.report?.isActiveSendButton" secondary size="large" @click="onSubmit">
Сохранить отчет
</NButton>
</NFlex>

View File

@@ -9,7 +9,7 @@ const authStore = useAuthStore()
<template>
<div class="grid grid-cols-[1fr_auto] gap-x-3">
<NCard v-if="reportStore.reportInfo?.report.isActiveSendButton">
<NCard v-if="reportStore.reportInfo?.report?.isActiveSendButton">
<NForm>
<template v-if="reportStore.isLoadReportInfo">
<NFlex>
@@ -35,13 +35,13 @@ const authStore = useAuthStore()
style="--n-padding-top: 0; --n-padding-left: 0; --n-padding-bottom: 0; --n-padding-right: 0;"
>
<div class="w-full h-full flex flex items-center justify-center">
<NStatistic label="Умерло" :value="reportStore.reportInfo?.department.deadCount" />
<NStatistic label="Умерло" :value="reportStore.reportInfo?.department?.deadCount" />
</div>
</NCard>
<NCard class="min-w-[120px] max-w-[120px] min-h-[100px] max-h-[102px] h-full"
style="--n-padding-top: 0; --n-padding-bottom: 0; --n-padding-left: 8px; --n-padding-right: 8px;">
<div class="w-full h-full flex flex items-center justify-center">
<NStatistic :value="reportStore.reportInfo?.department.surgicalCount[1]">
<NStatistic :value="reportStore.reportInfo?.department?.surgicalCount[1]">
<template #label>
<div class="flex flex-col">
<span>Операций</span>
@@ -49,7 +49,7 @@ const authStore = useAuthStore()
</div>
</template>
<template #suffix>
/ {{ reportStore.reportInfo?.department.surgicalCount[0] }}
/ {{ reportStore.reportInfo?.department?.surgicalCount[0] }}
</template>
</NStatistic>
</div>

View File

@@ -1,5 +1,5 @@
<script setup>
import {NSkeleton, NStatistic, NRow, NCol, NCard, NButton, NTag, NDatePicker, NFlex, NSelect, NText, NH2} from "naive-ui";
import {NSkeleton, NStatistic, NRow, NCol, NSpace, NCard, NButton, NTag, NDatePicker, NFlex, NSelect, NText, NH2} from "naive-ui";
import {computed, ref} from "vue";
import {format} from "date-fns";
import {useNow} from "@vueuse/core";
@@ -55,10 +55,15 @@ const currentDate = computed(() => {
<NCard>
<NFlex vertical>
<div class="grid grid-cols-[auto_1fr_auto] items-center">
<NTag v-if="isFillableMode" type="info" :bordered="false">
{{ authStore.userDepartment.name_full }}
</NTag>
<DepartmentSelect v-if="isReadonlyMode" />
<NSpace align="center">
<NTag v-if="isFillableMode" type="info" :bordered="false">
{{ authStore.userDepartment.name_full }}
</NTag>
<DepartmentSelect v-if="isReadonlyMode" />
<NTag v-if="reportStore.reportInfo?.userName" type="warning">
Ответственный: {{ reportStore.reportInfo?.userName }}
</NTag>
</NSpace>
<div class="col-3 w-full">
<ReportSelectDate />
@@ -71,7 +76,7 @@ const currentDate = computed(() => {
<NStatistic label="Коек">
<template #default>
<NSkeleton v-if="reportStore.isLoadReportInfo" round class="w-[70px]! mt-2 h-[29px]!" />
<span v-else>{{ reportStore.reportInfo?.department.beds }}</span>
<span v-else>{{ reportStore.reportInfo?.department?.beds }}</span>
</template>
</NStatistic>
</NCol>
@@ -79,7 +84,7 @@ const currentDate = computed(() => {
<NStatistic label="Загруженность">
<template #default>
<NSkeleton v-if="reportStore.isLoadReportInfo" round class="w-[70px]! mt-2 h-[29px]!" />
<span v-else>{{ reportStore.reportInfo?.department.percentLoadedBeds }}%</span>
<span v-else>{{ reportStore.reportInfo?.department?.percentLoadedBeds }}%</span>
</template>
</NStatistic>
</NCol>
@@ -87,7 +92,7 @@ const currentDate = computed(() => {
<NStatistic label="Поступило">
<template #default>
<NSkeleton v-if="reportStore.isLoadReportInfo" round class="w-[70px]! mt-2 h-[29px]!" />
<span v-else>{{ reportStore.reportInfo?.department.recipientCount }}</span>
<span v-else>{{ reportStore.reportInfo?.department?.recipientCount }}</span>
</template>
</NStatistic>
</NCol>
@@ -95,7 +100,7 @@ const currentDate = computed(() => {
<NStatistic label="Выбыло">
<template #default>
<NSkeleton v-if="reportStore.isLoadReportInfo" round class="w-[70px]! mt-2 h-[29px]!" />
<span v-else>{{ reportStore.reportInfo?.department.extractCount }}</span>
<span v-else>{{ reportStore.reportInfo?.department?.extractCount }}</span>
</template>
</NStatistic>
</NCol>
@@ -103,7 +108,7 @@ const currentDate = computed(() => {
<NStatistic label="Состоит">
<template #default>
<NSkeleton v-if="reportStore.isLoadReportInfo" round class="w-[70px]! mt-2 h-[29px]!" />
<span v-else>{{ reportStore.reportInfo?.department.currentCount }}</span>
<span v-else>{{ reportStore.reportInfo?.department?.currentCount }}</span>
</template>
</NStatistic>
</NCol>

View File

@@ -47,7 +47,7 @@ const isReadonlyMode = computed(() => props.mode.toLowerCase() === 'readonly')
<ReportSectionHeader title="Планово" status="plan" />
</template>
<ReportSectionItem status="plan"
:accent-ids="reportStore.reportInfo?.department.recipientIds"
:accent-ids="reportStore.reportInfo?.department?.recipientIds"
is-draggable
@item-dragged="handleItemDragged"
/>
@@ -57,7 +57,7 @@ const isReadonlyMode = computed(() => props.mode.toLowerCase() === 'readonly')
<ReportSectionHeader title="Экстренно" status="emergency" />
</template>
<ReportSectionItem status="emergency"
:accent-ids="reportStore.reportInfo?.department.recipientIds"
:accent-ids="reportStore.reportInfo?.department?.recipientIds"
is-draggable
@item-dragged="handleItemDragged"
/>

View File

@@ -1,10 +1,10 @@
<script setup>
import {NIcon, NText, NDataTable, NButton, NTabs, NTabPane} from "naive-ui";
import {NIcon, NText, NDataTable, NButton, NBadge, NTabs, NTabPane} from "naive-ui";
import {useReportStore} from "../../../Stores/report.js";
import {computed, h, onMounted, ref, watch} from "vue";
import { VueDraggableNext } from 'vue-draggable-next'
import {storeToRefs} from "pinia";
import {TbGripVertical} from "vue-icons-plus/tb";
import {TbGripVertical, TbEye} from "vue-icons-plus/tb";
import MoveModalComment from "./MoveModalComment.vue";
const props = defineProps({
@@ -49,6 +49,7 @@ const data = ref([])
const isLoading = ref(true)
const showMoveModal = ref(false)
const latestDropItem = ref(null)
const activePatient = ref(null)
// Добавляем drag колонку если режим fillable
const columns = computed(() => {
@@ -100,22 +101,40 @@ const columns = computed(() => {
}
const expandColumn = {
type: 'expand',
renderExpand: (rowData) => {
title: '',
width: '30',
render: (rowData) => {
return h(
NText,
NIcon,
{
class: 'max-w-full break-words whitespace-normal'
onClick: () => {
latestDropItem.value = rowData
showMoveModal.value = true
}
},
{
default: rowData.comment ?? 'Причина наблюдения не указана'
default: h(TbEye)
}
)
}
}
const fillableColumn = {
title: '',
key: 'fillable',
width: '20',
render: (row) => h(
NBadge,
{
dot: true,
color: (row.comment && row.comment.trim()) ? '#7fe7c4' : '#e88080'
}
)
}
if (props.status === 'observation') {
newColumns.push(expandColumn)
newColumns.push(fillableColumn)
}
if (props.isDraggable) newColumns.push(dragColumn)

View File

@@ -0,0 +1,82 @@
<script setup>
import { NSelect, NModal, NForm, NFormItem, NButton } from 'naive-ui'
import {useReportStore} from "../../../Stores/report.js";
import {computed, onMounted, ref} from "vue";
import {router} from "@inertiajs/vue3";
const show = defineModel('show')
const reportStore = useReportStore()
const formRef = ref()
const users = computed(() => reportStore.departmentUsers.map(itm => ({
label: `${itm.FAM_V} ${itm.IM_V} ${itm.OT_V}`,
value: itm.LPUDoctorID
})))
const fetchUsers = () => {
axios.get('/api/mis/department-users')
.then((res) => {
reportStore.departmentUsers = res.data
})
}
const rules = {
userId: {
required: true,
validator: (rule, value) => {
if (Number.isInteger(value)) return true
return false
},
trigger: ['change', 'blur'],
message: 'Выберите ответственного'
}
}
onMounted(() => {
reportStore.reportInfo.userId = null
fetchUsers()
})
const onSubmit = (e) => {
e.preventDefault()
formRef.value?.validate((errors) => {
if (!errors) {
router.visit(`/report?userId=${reportStore.reportInfo.userId}`)
}
else {
}
})
}
const onAfterLeave = () => {
reportStore.reportInfo.userId = null
}
</script>
<template>
<NModal v-model:show="show"
preset="card"
class="max-w-[420px]"
:mask-closable="false"
@before-leave="onAfterLeave"
>
<NForm id="select-user-form" ref="formRef" :model="reportStore.reportInfo" :rules="rules">
<NFormItem label="Выберите ответственного" path="userId">
<NSelect :options="users" v-model:value="reportStore.reportInfo.userId" />
</NFormItem>
</NForm>
<template #action>
<NButton form-id="select-user-form"
type="primary"
block
@click="onSubmit">
Перейти к заполнению сводной
</NButton>
</template>
</NModal>
</template>
<style scoped>
</style>

View File

@@ -8,10 +8,18 @@ import {useAuthStore} from "../../Stores/auth.js";
const reportStore = useReportStore()
const authStore = useAuthStore()
onMounted(async () => {
await reportStore.getReportInfo()
onMounted(() => {
const queryString = window.location.search
const params = new URLSearchParams(queryString)
const userId = params.get('userId')
reportStore.reportInfo.userId = userId
reportStore.getReportInfo()
})
// reportStore.getReportInfo()
const mode = computed(() => {
if (authStore.isHeadOfDepartment)
return 'readonly'