Много всего

This commit is contained in:
brusnitsyn
2025-12-12 17:10:05 +09:00
parent 54f36e91fa
commit 98e9f8b52e
25 changed files with 1118 additions and 145 deletions

View File

@@ -1,7 +1,8 @@
<script setup>
import { NModal, NDataTable, NSpace, NFlex, NButton, NForm, NFormItem, NInput, NDatePicker, NDivider, NSwitch, NTag } from 'naive-ui'
import ArchiveHistoryMoveModal from '../ArchiveHistoryMoveModal/Index.vue'
import {ref, watch} from "vue";
import {computed, ref, watch} from "vue";
import {useMedicalHistoryFilter} from "../../../Composables/useMedicalHistoryFilter.js";
const open = defineModel('open')
const props = defineProps({
@@ -10,10 +11,29 @@ const props = defineProps({
}
})
const {filtersRef} = useMedicalHistoryFilter()
const loading = ref(true)
const patient = ref({})
const showArchiveHistoryModal = ref(false)
const selectedArchiveHistoryId = ref(null)
const selectedArchiveHistoryType = ref(null)
const isCreateNewArchiveHistoryModal = ref(false)
const archiveInfo = ref({
id: props.patientId,
num: null,
post_in: null,
status: null
})
const emits = defineEmits(['historyUpdated'])
const onResetData = () => {
archiveInfo.value = {
id: props.patientId,
num: null,
post_in: null,
status: null
}
}
const patientData = ref({
@@ -25,9 +45,16 @@ const loadPatientData = async () => {
loading.value = true
try {
axios.get(`/api/si/patients/${props.patientId}`).then(res => {
axios.get(`/api/si/patients/${props.patientId}?view_type=${filtersRef.value.view_type}`).then(res => {
patient.value = res.data
patientData.value = res.data.info
archiveInfo.value = res.data.archiveInfo ?? {
historyable_type: res.data.historyable_type,
id: props.patientId,
num: null,
post_in: null,
status: null,
}
})
} catch (error) {
// message.error('Ошибка при загрузке данных пациента')
@@ -38,7 +65,14 @@ const loadPatientData = async () => {
}
const onShowArchiveHistoryModal = (id) => {
selectedArchiveHistoryId.value = id
if (id === null) {
isCreateNewArchiveHistoryModal.value = true
selectedArchiveHistoryId.value = props.patientId
} else {
isCreateNewArchiveHistoryModal.value = false
selectedArchiveHistoryId.value = id
}
selectedArchiveHistoryType.value = archiveInfo.value.historyable_type
showArchiveHistoryModal.value = true
}
@@ -75,6 +109,30 @@ const rowProps = (row) => ({
}
})
const onUpdateHistory = (updatedData) => {
loadPatientData()
}
const hasCreateNew = computed(() => archiveInfo.value === null)
const onSubmit = async () => {
try {
await axios.post(`/api/archive/histories/info/${props.patientId}`, archiveInfo.value).then(res => {
// onCloseWithoutSave()
emits('historyUpdated', {
type: hasCreateNew.value ? 'created' : 'updated',
data: res.data,
patientId: props.patientId
})
})
} catch (error) {
console.error(error)
} finally {
loading.value = false
}
}
// Наблюдаем за изменением patientId
watch(() => props.patientId, (newId) => {
if (newId) {
@@ -92,19 +150,19 @@ watch(() => props.patientId, (newId) => {
<NFlex inline justify="space-between" align="center" :wrap="false">
<NForm inline :show-feedback="false">
<NFormItem label="Статус карты">
<NTag :type="patient.archiveInfo?.status?.variant ?? 'error'" :bordered="false" round>
{{ patient.archiveInfo?.status?.text ?? 'Нет в архиве' }}
<NTag :type="archiveInfo.status?.variant ?? 'error'" :bordered="false" round>
{{ archiveInfo.status?.text ?? 'Нет в архиве' }}
</NTag>
</NFormItem>
<NFormItem label="№ в архиве">
<NInput v-model:value="patientData.narhiv" />
<NInput v-model:value="archiveInfo.num" />
</NFormItem>
<NFormItem label="Дата поступления карты в архив">
<NDatePicker v-model:value="patientData.datearhiv" format="dd.MM.yyyy" />
<NDatePicker v-model:value="archiveInfo.post_in" format="dd.MM.yyyy" />
</NFormItem>
</NForm>
</NFlex>
<NButton @click="onShowArchiveHistoryModal(null)">
<NButton @click="onShowArchiveHistoryModal(null)" :disabled="!patientData.can_be_issued">
Добавить
</NButton>
<NDataTable :row-props="rowProps" min-height="420px" max-height="420px" :columns="columns" :data="patient?.journal" />
@@ -116,14 +174,14 @@ watch(() => props.patientId, (newId) => {
Закрыть без сохранения
</NButton>
<NDivider vertical />
<NButton secondary type="primary">
<NButton secondary type="primary" @click="onSubmit">
Сохранить
</NButton>
</NSpace>
</NFlex>
</template>
</NModal>
<ArchiveHistoryMoveModal @close-without-save="selectedArchiveHistoryId = null" v-model:open="showArchiveHistoryModal" :archive-history-id="selectedArchiveHistoryId" />
<ArchiveHistoryMoveModal @history-updated="onUpdateHistory" @close-without-save="selectedArchiveHistoryId = null" :is-create-new="isCreateNewArchiveHistoryModal" v-model:open="showArchiveHistoryModal" :active-history-type="selectedArchiveHistoryType" :archive-history-id="selectedArchiveHistoryId" />
</template>
<style scoped>

View File

@@ -1,17 +1,25 @@
<script setup>
import {NButton, NDatePicker, NDivider, NFlex, NForm, NFormItem, NInput, NModal, NSpace, NSwitch, NSelect} from "naive-ui";
import {ref, watch} from "vue";
import {router} from "@inertiajs/vue3";
const open = defineModel('open')
const props = defineProps({
archiveHistoryId: {
type: Number
},
activeHistoryType: {
type: String
},
isCreateNew: {
type: Boolean
}
})
const emits = defineEmits(['closeWithoutSave'])
const emits = defineEmits(['closeWithoutSave', 'historyUpdated'])
const loading = ref(false)
const archiveHistory = ref({
historyable_id: props.archiveHistoryId,
historyable_type: props.activeHistoryType,
issue_at: null,
org_id: null,
return_at: null,
@@ -25,6 +33,7 @@ const orgs = ref([])
const onResetData = () => {
archiveHistory.value = {
historyable_id: props.archiveHistoryId,
historyable_type: props.activeHistoryType,
issue_at: null,
org_id: null,
return_at: null,
@@ -59,9 +68,19 @@ const loadArchiveHistoryData = async () => {
const submit = () => {
try {
axios.post('/api/archive/histories/move', archiveHistory.value).then(res => {
const url = props.isCreateNew
? '/api/archive/histories/move'
: `/api/archive/histories/move/${archiveHistory.value.id}`
axios.post(url, archiveHistory.value).then(res => {
onCloseWithoutSave()
emits('historyUpdated', {
type: props.isCreateNew ? 'created' : 'updated',
data: res.data,
historyId: archiveHistory.value.id
})
})
} catch (error) {
console.error(error)
} finally {
@@ -71,7 +90,7 @@ const submit = () => {
// Наблюдаем за изменением archiveHistoryId
watch(() => props.archiveHistoryId, async (newId) => {
if (newId) {
if (!props.isCreateNew) {
await loadArchiveHistoryData()
} else {
onResetData()

View File

@@ -23,7 +23,7 @@ const props = defineProps({
},
})
const { isLoading, handlePageChange, handlePageSizeChange, meta } = useMedicalHistoryFilter(props.filters)
const { isLoading, handlePageChange, handlePageSizeChange, meta, filtersRef } = useMedicalHistoryFilter(props.filters)
const archiveStatusColumn = (status) => {
const tagType = status?.variant ?? 'error'
@@ -97,21 +97,41 @@ const rowProps = (row) => ({
}
})
const pagination = computed(() => ({
page: meta.value.current_page || 1,
pageCount: meta.value.last_page || 1,
pageSize: meta.value.per_page || 15,
itemCount: meta.value.total || 0,
pageSizes: [15, 50, 100],
showSizePicker: true,
prefix({ itemCount }) {
return `Всего карт ${itemCount}.`
},
onUpdatePage: (page) => {
handlePageChange(page)
},
onUpdatePageSize: handlePageSizeChange
}))
const pagination = computed(() => {
if (filtersRef.value.view_type === 'si') {
return {
page: meta.value.si.current_page || 1,
pageCount: meta.value.si.last_page || 1,
pageSize: meta.value.si.per_page || 15,
itemCount: meta.value.si.total || 0,
pageSizes: [15, 50, 100],
showSizePicker: true,
prefix({ itemCount }) {
return `Всего карт ${itemCount}.`
},
onUpdatePage: (page) => {
handlePageChange(page)
},
onUpdatePageSize: handlePageSizeChange
}
} else {
return {
page: meta.value.mis.current_page || 1,
pageCount: meta.value.mis.last_page || 1,
pageSize: meta.value.mis.per_page || 15,
itemCount: meta.value.mis.total || 0,
pageSizes: [15, 50, 100],
showSizePicker: true,
prefix({ itemCount }) {
return `Всего карт ${itemCount}.`
},
onUpdatePage: (page) => {
handlePageChange(page)
},
onUpdatePageSize: handlePageSizeChange
}
}
})
</script>
<template>

View File

@@ -1,7 +1,7 @@
<script setup>
import AppLayout from "../../Layouts/AppLayout.vue"
import TableCards from './DataTable/Index.vue'
import { NInput, NFlex, NDivider, NDatePicker, NSpace, NRadioGroup, NRadioButton, NH1 } from 'naive-ui'
import { NInput, NFlex, NDivider, NDatePicker, NSpace, NFormItem, NRadioButton, NH1, NTabs, NTabPane, NSelect } from 'naive-ui'
import {useMedicalHistory} from "../../Composables/useMedicalHistory.js";
import {useDebounceFn} from "@vueuse/core";
import {useMedicalHistoryFilter} from "../../Composables/useMedicalHistoryFilter.js";
@@ -12,6 +12,10 @@ const props = defineProps({
type: Array,
default: []
},
statuses: {
type: Array,
default: []
},
filters: {
type: Array,
default: []
@@ -20,35 +24,56 @@ const props = defineProps({
const {
isLoading, applyFilters, filtersRef, handleSearch, dateRange,
handleDateRangeChange, handleViewTypeChange
handleDateRangeChange, handleViewTypeChange, handleStatusChange
} = useMedicalHistoryFilter(props.filters)
const viewType = ref('archive')
const handleBeforeLeave = (tabName) => {
handleViewTypeChange(tabName)
return true
}
</script>
<template>
<AppLayout>
<template #header>
<NSpace vertical>
<NH1 class="!my-0 mb-5">
Архив
</NH1>
<NRadioGroup v-model:value="viewType" @update:value="val => handleViewTypeChange(val)">
<NRadioButton value="archive">Архив</NRadioButton>
<NRadioButton value="mis">МИС</NRadioButton>
<NRadioButton value="softinfo">СофтИнфо</NRadioButton>
</NRadioGroup>
<!-- <NH1 class="!my-0 mb-5">-->
<!-- Архив-->
<!-- </NH1>-->
<!-- <NRadioGroup v-model:value="viewType" @update:value="val => handleViewTypeChange(val)">-->
<!-- <NRadioButton value="archive">Архив</NRadioButton>-->
<!-- <NRadioButton value="mis">МИС</NRadioButton>-->
<!-- <NRadioButton value="softinfo">СофтИнфо</NRadioButton>-->
<!-- </NRadioGroup>-->
<NFlex class="pb-4" align="center" :wrap="false">
<NInput placeholder="Поиск по ФИО, № карты" @update:value="val => handleSearch(val)"/>
<NFormItem class="w-[720px]" label="Поиск" :show-feedback="false">
<NInput placeholder="Поиск по ФИО, № карты" @update:value="val => handleSearch(val)" size="large" />
</NFormItem>
<NDivider vertical />
<NDatePicker v-model:value="dateRange" @update:value="handleDateRangeChange" type="daterange" clearable format="dd.MM.yyyy" start-placeholder="Дата выписки с" end-placeholder="по" />
<NFormItem class="w-[340px]" label="Дата выписки" :show-feedback="false">
<NDatePicker v-model:value="dateRange" @update:value="handleDateRangeChange" type="daterange" clearable format="dd.MM.yyyy" start-placeholder="Дата выписки с" end-placeholder="по" size="large" />
</NFormItem>
<NFormItem class="w-[340px]" label="Статус карты" :show-feedback="false">
<NSelect :options="statuses" @update:value="val => handleStatusChange(val)" clearable size="large" />
</NFormItem>
</NFlex>
</NSpace>
</template>
<TableCards :filters="filters" :data="cards.data" :meta="cards.meta" min-height="calc(100vh - 277px)" max-height="calc(100vh - 320px)" />
<NTabs :value="filtersRef.view_type" type="segment" animated @before-leave="handleBeforeLeave">
<NTabPane name="si" :tab="`СофтИнфо (${cards.si?.meta.total})`">
<TableCards :filters="filters" :data="cards.si?.data" :meta="cards.si?.meta" min-height="calc(100vh - 286px)" max-height="calc(100vh - 320px)" />
</NTabPane>
<NTabPane name="mis" :tab="`МИС (${cards.mis?.meta.total})`">
<TableCards :filters="filters" :data="cards.mis?.data" :meta="cards.mis?.meta" min-height="calc(100vh - 286px)" max-height="calc(100vh - 320px)" />
</NTabPane>
</NTabs>
</AppLayout>
</template>
<style scoped>
:deep(.n-tabs .n-tabs-nav) {
max-width: 420px;
}
</style>