Обновлен стартовый экран

Переписаны запросы для статистики, отчетов
Добавлена интеграция отчета сестры
This commit is contained in:
brusnitsyn
2026-05-28 22:10:00 +09:00
parent 90e0d04dfd
commit 739168d427
96 changed files with 6663 additions and 1465 deletions

View File

@@ -1,127 +1,114 @@
<script setup>
import {
NModal,
NList,
NListItem,
NThing,
NAvatar,
NIcon,
NText,
NDivider,
NFlex,
NButton,
NScrollbar,
NEmpty,
NDataTable,
NBadge,
NForm,
NDrawerContent,
NInput,
NSpin,
NDrawer
NModal, NDataTable, NEmpty, NSpin, NDrawer, NDrawerContent, NInput, NIcon, NTooltip, NFlex, NText
} from 'naive-ui'
import {useReportStore} from "../../../Stores/report.js";
import {TbAlertCircle, TbCheck, TbEye, TbGripVertical, TbPencil, TbTrashX, TbX} from 'vue-icons-plus/tb'
import {computed, h, ref, watch} from "vue";
import { TbEye } from 'vue-icons-plus/tb'
import { format, formatDistanceStrict } from 'date-fns'
import { ru } from 'date-fns/locale'
import { computed, h, ref, watch } from 'vue'
import TooltipColumn from '../../Report/Components/DataTableColumns/TooltipColumn.vue'
const props = defineProps({
departmentId: {
required: true
},
startAt: {
required: true
},
endAt: {
required: true
}
departmentId: { required: true },
startAt: { required: true },
endAt: { required: true },
})
const reportStore = useReportStore()
const open = defineModel('open')
const loading = ref(true)
const baseColumns = reportStore.getColumnsByKey(['num', 'fullname', 'age', 'birth_date', 'mkb.ds'])
const currentPatient = ref(null)
const showMoveDrawer = ref(false)
const columns = computed(() => {
// if (!isFillableMode.value) return baseColumns
const newColumns = []
const expandColumn = {
title: '',
width: '30',
render: (rowData) => {
return h(
NIcon,
{
onClick: () => {
currentPatient.value = rowData
showMoveDrawer.value = true
}
},
{
default: h(TbEye)
}
)
}
}
const fillableColumn = {
title: '',
key: 'fillable',
width: '20',
render: (row) => h(
NBadge,
{
dot: true,
color: (row.comment && row.comment.trim()) ? '#7fe7c4' : '#e88080'
}
)
}
newColumns.push(expandColumn)
newColumns.push(fillableColumn)
newColumns.push(...baseColumns)
return newColumns
})
const observablePatients = ref([])
const fetchUnwantedEvents = () => {
const currentPatient = ref(null)
const showDrawer = ref(false)
const columns = [
{
title: '№',
key: 'index',
width: 50,
render: (_, i) => i + 1,
},
{
title: 'ФИО',
key: 'full_name',
width: 280,
ellipsis: { tooltip: { arrow: false } },
},
{
title: 'Возраст',
key: 'age',
width: 80,
render: (row) => row.birth_date
? formatDistanceStrict(new Date(row.birth_date), new Date(), { locale: ru })
: '—',
},
{
title: 'Д/р',
key: 'birth_date',
width: 100,
render: (row) => row.birth_date ? format(new Date(row.birth_date), 'dd.MM.yyyy') : '—',
},
{
title: 'Д/п',
key: 'ingoing_date',
width: 134,
render: (row) => {
const d = row.migrations?.[0]?.ingoing_date
return d ? format(new Date(d), 'dd.MM.yyyy HH:mm') : '—'
},
},
{
title: 'Диагноз',
key: 'diagnosis',
width: 90,
render: (row) => {
const m = row.migrations?.[0]
return m?.diagnosis_code
? h(TooltipColumn, { triggerText: m.diagnosis_code, contentText: m.diagnosis_name })
: '—'
},
},
{
title: '',
key: 'actions',
width: 44,
align: 'center',
render: (row) => h(
NIcon,
{
style: 'cursor:pointer',
size: 18,
onClick: () => { currentPatient.value = row; showDrawer.value = true },
},
() => h(TbEye)
),
},
]
const fetch = () => {
loading.value = true
const data = {
status: 'observation',
startAt: props.startAt,
endAt: props.endAt,
departmentId: props.departmentId
}
axios.post('/api/mis/patients', data).then((res) => {
observablePatients.value = reportStore.addRowNumbers(res.data?.data ?? res.data ?? [])
axios.get('/api/statistics/reports/observable-patients', {
params: { startAt: props.startAt, endAt: props.endAt, departmentId: props.departmentId }
}).then((res) => {
observablePatients.value = res.data ?? []
}).finally(() => {
loading.value = false
})
}
watch(() => [props.departmentId, props.endAt, props.startAt], () => {
if (props.departmentId && props.endAt && props.startAt) {
fetchUnwantedEvents()
}
}, {
immediate: true,
deep: true
})
if (props.departmentId && props.endAt && props.startAt) fetch()
}, { immediate: true, deep: true })
</script>
<template>
<NModal v-model:show="open"
title="Пациенты на контроле"
preset="card"
:mask-closable="false"
:close-on-esc="false"
class="max-w-4xl overflow-clip h-[calc(100vh-220px)]"
id="modal-observation-patients"
<NModal
v-model:show="open"
title="Пациенты на контроле"
preset="card"
:mask-closable="false"
:close-on-esc="false"
class="max-w-5xl overflow-clip h-[calc(100vh-220px)]"
id="modal-observable-patients"
>
<template v-if="loading">
<div class="flex items-center justify-center h-full">
@@ -129,16 +116,15 @@ watch(() => [props.departmentId, props.endAt, props.startAt], () => {
</div>
</template>
<template v-else-if="observablePatients.length">
<NDataTable :columns="columns"
ref="tableRef"
:data="observablePatients"
size="small"
:loading="loading"
max-height="200"
min-height="200"
:row-key="(row, index) => row.id"
class="text-sm!">
</NDataTable>
<NDataTable
:columns="columns"
:data="observablePatients"
table-layout="fixed"
size="small"
:loading="loading"
max-height="calc(100vh - 320px)"
:row-key="(row) => row.id"
/>
</template>
<template v-else>
<div class="h-full flex items-center justify-center">
@@ -147,7 +133,7 @@ watch(() => [props.departmentId, props.endAt, props.startAt], () => {
</template>
<NDrawer
v-model:show="showMoveDrawer"
v-model:show="showDrawer"
placement="bottom"
:min-height="400"
:max-height="600"
@@ -155,10 +141,27 @@ watch(() => [props.departmentId, props.endAt, props.startAt], () => {
resizable
:trap-focus="false"
:block-scroll="false"
to="#modal-observation-patients"
to="#modal-observable-patients"
>
<NDrawerContent title="Причина постановки на контроль" closable>
<NInput type="textarea" readonly :rows="8" v-model:value="currentPatient.comment" />
<NFlex vertical :size="12">
<NInput
type="textarea"
readonly
:rows="5"
:value="currentPatient?.observable_reason"
placeholder="Причина не указана"
/>
<template v-if="currentPatient?.comment">
<NText depth="3" style="font-size:12px;">Комментарий:</NText>
<NInput
type="textarea"
readonly
:rows="4"
:value="currentPatient?.comment"
/>
</template>
</NFlex>
</NDrawerContent>
</NDrawer>
</NModal>
@@ -167,7 +170,6 @@ watch(() => [props.departmentId, props.endAt, props.startAt], () => {
<style scoped>
:deep(.n-data-table-th),
:deep(.n-data-table-td) {
white-space: nowrap !important;
font-size: var(--n-font-size);
}
</style>

View File

@@ -0,0 +1,67 @@
<script setup>
import {NFlex, NTag, NTooltip} from 'naive-ui'
import {percentType} from "../../../Utils/numbers.js";
const props = defineProps({
isTotalRow: {
type: Boolean,
default: false
},
value: {
type: [Number, String],
default: ''
},
needCompletedToPlan: {
type: [Number, String],
default: null
},
progressCompletedToPlan: {
type: [Number, String],
default: null
}
})
</script>
<template>
<NFlex align="center" justify="center" class="relative!">
<NTooltip v-if="needCompletedToPlan && !isTotalRow"
trigger="hover"
:arrow="false"
>
<template #trigger>
<NTag :type="percentType(needCompletedToPlan)"
round
:bordered="false"
size="tiny"
class="absolute! -left-1.5 bottom-2.5 text-xs"
>
{{ needCompletedToPlan }}
</NTag>
</template>
Требуется выписать для выполнения плана
</NTooltip>
<div>
{{ value }}
</div>
<NTooltip v-if="progressCompletedToPlan && !isTotalRow"
trigger="hover"
:arrow="false"
>
<template #trigger>
<NTag :type="percentType(progressCompletedToPlan)"
round
:bordered="false"
size="tiny"
class="absolute! -right-1.5 bottom-2.5 text-xs"
>
{{ progressCompletedToPlan }}%
</NTag>
</template>
Прогресс выполнения плана
</NTooltip>
</NFlex>
</template>
<style scoped>
</style>