* добавил исход спец контингенту

* оптимизация обновления при редактировании спец контингента
* добавил поддержку заключительных диагнозов
* изменил определение законченной операции
* добавил поддержку исхода операции
* добавил определение отмены для операции через назначение
* работа над диапазонами календарей, подсчет статистики
* добавил статусы отчетов и подкорректировал привязку спец контингента к отчету
* добавил новые сервисы для будущего кеширования
* частичное разделение логики подсчета пациентов
This commit is contained in:
brusnitsyn
2026-04-22 20:35:39 +09:00
parent 2041ab54ea
commit 719eb1403f
39 changed files with 1458 additions and 763 deletions

View File

@@ -27,6 +27,8 @@ const form = reactive({
birth_date: null,
admitted_at: null,
patient_kind: 'plan',
manual_status: 'current',
outcome_at: null,
diagnosis_code: '',
diagnosis_name: '',
})
@@ -56,6 +58,12 @@ const patientKindOptions = [
{label: 'Экстренно', value: 'emergency'},
]
const manualStatusOptions = [
{label: 'Состоит', value: 'current'},
{label: 'Выписан', value: 'discharged'},
{label: 'Умер', value: 'deceased'},
]
const normalizeSpaces = (value) => value.replace(/\s+/g, ' ').trim()
const pad = (value) => String(value).padStart(2, '0')
const formatLocalDate = (timestamp) => {
@@ -76,6 +84,11 @@ const parseDateToTimestamp = (value) => {
}
const parseDateTimeToTimestamp = (value) => {
if (!value) return null
const nativeDate = new Date(value)
if (!Number.isNaN(nativeDate.getTime())) {
return nativeDate.getTime()
}
const [datePart, timePart] = String(value).split(' ')
const dateTimestamp = parseDateToTimestamp(datePart)
if (!dateTimestamp) return null
@@ -90,6 +103,8 @@ const hydrateForm = () => {
form.birth_date = parseDateToTimestamp(props.patient?.birth_date)
form.admitted_at = parseDateTimeToTimestamp(props.patient?.admitted_at)
form.patient_kind = props.patient?.patient_kind ?? 'plan'
form.manual_status = props.patient?.outcome_type ?? 'current'
form.outcome_at = parseDateTimeToTimestamp(props.patient?.outcome_date)
form.diagnosis_code = props.patient?.mkb?.ds ?? ''
form.diagnosis_name = props.patient?.mkb?.name ?? ''
@@ -179,11 +194,21 @@ const submit = async () => {
birth_date: formatLocalDate(form.birth_date),
admitted_at: form.admitted_at ? formatLocalDateTime(form.admitted_at) : null,
patient_kind: form.patient_kind,
manual_status: form.manual_status,
outcome_at: form.manual_status === 'current'
? null
: (form.outcome_at ? formatLocalDateTime(form.outcome_at) : null),
diagnosis_code: form.diagnosis_code ? normalizeSpaces(form.diagnosis_code).toUpperCase() : null,
diagnosis_name: form.diagnosis_name ? normalizeSpaces(form.diagnosis_name) : null,
},
{
reloadStatuses: [props.sourceStatus, `special-${form.patient_kind}`],
reloadStatuses: [
props.sourceStatus,
`special-${form.patient_kind}`,
'special-outcome-discharged',
'special-outcome-deceased',
'special-outcome-transferred',
],
}
)
@@ -204,12 +229,18 @@ const submit = async () => {
<NFormItem label="Тип пациента" path="patient_kind">
<NSelect v-model:value="form.patient_kind" :options="patientKindOptions" />
</NFormItem>
<NFormItem label="Статус">
<NSelect v-model:value="form.manual_status" :options="manualStatusOptions" />
</NFormItem>
<NFormItem label="Дата рождения" path="birth_date">
<NDatePicker v-model:value="form.birth_date" type="date" class="w-full" />
</NFormItem>
<NFormItem label="Дата и время поступления">
<NDatePicker v-model:value="form.admitted_at" type="datetime" class="w-full" clearable />
</NFormItem>
<NFormItem v-if="form.manual_status !== 'current'" label="Дата и время исхода">
<NDatePicker v-model:value="form.outcome_at" type="datetime" class="w-full" clearable />
</NFormItem>
<NFormItem label="Диагноз (МКБ)">
<NSelect
v-model:value="form.diagnosis_code"

View File

@@ -134,6 +134,10 @@ const submit = async () => {
try {
await reportStore.createManualPatient({
departmentId: reportStore.reportInfo.department.department_id,
report_id: reportStore.reportInfo?.report?.report_id ?? null,
startAt: reportStore.reportInfo?.dates?.startAt,
endAt: reportStore.reportInfo?.dates?.endAt,
user_id: reportStore.reportInfo?.report?.userId ?? null,
full_name: normalizeSpaces(form.full_name),
birth_date: formatLocalDate(form.birth_date),
patient_kind: props.patientKind,

View File

@@ -25,23 +25,44 @@ const onSubmit = () => {
// reportStore.sendReportForm()
}
const onPublish = () => {
reportStore.reportFormRef?.validate((errors) => {
if (!errors) reportStore.sendReportForm({ status: 'submitted' })
else window.$message.error('Ошибка отправки отчета')
})
}
</script>
<template>
<NFlex vertical class="max-w-6xl mx-auto mt-6 mb-4 w-full">
<NAlert type="warning" v-if="reportStore.reportInfo.report?.message">
{{ reportStore.reportInfo.report.message }}
</NAlert>
<NFlex v-if="reportStore.reportInfo.report?.message || reportStore.reportInfo.report?.statusMessage" :size="12">
<NAlert class="flex-1" type="warning" v-if="reportStore.reportInfo.report?.message">
{{ reportStore.reportInfo.report.message }}
</NAlert>
<NAlert class="flex-1" type="info" v-if="reportStore.reportInfo.report?.statusMessage">
{{ reportStore.reportInfo.report.statusMessage }}
</NAlert>
</NFlex>
<ReportHeader :mode="mode" />
<ReportFormInput />
<ReportSection label="Планово" />
<NButton v-if="reportStore.reportInfo?.report?.isActiveSendButton" secondary size="large" @click="onSubmit">
Сохранить отчет
</NButton>
<NFlex v-if="reportStore.reportInfo?.report?.isActiveSendButton" :size="12">
<NButton secondary size="large" @click="onSubmit">
Сохранить отчет
</NButton>
<NButton
v-if="reportStore.reportInfo?.report?.canPublish || !reportStore.reportInfo?.report?.report_id"
type="primary"
size="large"
@click="onPublish"
>
Опубликовать
</NButton>
</NFlex>
</NFlex>
</template>

View File

@@ -217,14 +217,6 @@ watch(
</NAlert>
</NFlex>
</NCollapseItem>
<NCollapseItem name="4">
<template #header>
<ReportSectionHeader title="Находятся в реанимации" status="special-reanimation" />
</template>
<ReportSectionItem status="special-reanimation"
:enabled="activeRootTab === 'special' && reportStore.openedCollapsible.includes('4')"
/>
</NCollapseItem>
<NCollapseItem name="5">
<template #header>
<ReportSectionHeader title="Выбывшие" status="special-outcome" />

View File

@@ -18,7 +18,7 @@ import {
import {useReportStore} from "../../../Stores/report.js";
import {computed, h, ref, watch} from "vue";
import {storeToRefs} from "pinia";
import {TbEye, TbExternalLink, TbPencil} from "vue-icons-plus/tb";
import {TbEye, TbExternalLink, TbPencil, TbTrash} from "vue-icons-plus/tb";
import MoveModalComment from "./MoveModalComment.vue";
import OperationInfoModal from "./OperationInfoModal.vue";
import ManualPatientOutcomeModal from "./ManualPatientOutcomeModal.vue";
@@ -90,7 +90,11 @@ const activePatient = ref(null)
const hasDisabledEdit = computed(() => {
return !Boolean(reportStore.reportInfo?.report?.isActiveSendButton)
})
const canEditSpecial = computed(() => isSpecialStatus.value && !hasDisabledEdit.value)
const canEditSpecial = computed(() => (
isSpecialStatus.value
&& !hasDisabledEdit.value
&& baseStatus.value !== 'observation'
))
const statusState = computed(() => statusStates.value[props.status] ?? {
page: 1,
perPage: 20,
@@ -214,7 +218,7 @@ const columns = computed(() => {
}
},
[
'Снять с наблюдения'
h(NIcon, {size: '16'}, h(TbTrash))
]
)
}

View File

@@ -0,0 +1,29 @@
<script setup>
import AppLayout from "../Layouts/AppLayout.vue"
import AppPanel from "../Components/AppPanel.vue";
import AppGridItem from "../Components/AppGridItem.vue";
import AppGrid from "../Components/AppGrid.vue";
import {NGi} from 'naive-ui'
</script>
<template>
<AppLayout>
<AppGrid cols="5">
<NGi>
<AppPanel header="Текст" header-include-body>
panel
</AppPanel>
</NGi>
<NGi>
<AppPanel header="Текст" header-include-body>
panel
</AppPanel>
</NGi>
</AppGrid>
</AppLayout>
</template>
<style scoped>
</style>