Много чего

This commit is contained in:
brusnitsyn
2025-12-25 17:30:50 +09:00
parent c4bb7ec6f9
commit a5209f45c8
25 changed files with 1521 additions and 574 deletions

View File

@@ -16,51 +16,15 @@ export const useMedicalHistoryFilter = (initialFilters = {}) => {
page_size: initialFilters?.page_size || 50,
sort_by: initialFilters?.sort_by || 'dateextract',
sort_order: initialFilters?.sort_order || 'desc',
view_type: initialFilters?.view_type || 'si',
status: initialFilters?.status || null,
database: initialFilters?.database || 'separate', // НОВЫЙ ПАРАМЕТР: postgresql, mssql, smart, separate
})
// Метаданные для разных типов данных
const meta = computed(() => {
const cards = page.props.cards
// Для раздельного поиска
if (filtersRef.value.database === 'separate') {
return {
si: cards.si.meta || {},
mis: cards.mis.meta || {},
stats: cards.stats || {},
}
} else if (filtersRef.value.database === 'mis') {
return {
mis: cards.mis?.meta
}
} else {
return {
si: cards.si?.meta
}
}
return page.props.cards.meta
})
const isLoading = ref(false)
const databaseStats = computed(() => page.props.databaseStats || {})
// Статистика по базам
const databaseInfo = computed(() => ({
postgresql: {
count: databaseStats.value.postgresql?.total || 0,
label: 'PostgreSQL',
color: 'blue',
description: 'Основной архив'
},
mssql: {
count: databaseStats.value.mssql?.total || 0,
label: 'MSSQL',
color: 'purple',
description: 'Исторический архив'
}
}))
// Форматирование даты для URL
const formatDateForUrl = (date) => {
@@ -81,8 +45,6 @@ export const useMedicalHistoryFilter = (initialFilters = {}) => {
page_size: filtersRef.value.page_size,
sort_by: filtersRef.value.sort_by,
sort_order: filtersRef.value.sort_order,
view_type: filtersRef.value.view_type,
database: filtersRef.value.database,
status: filtersRef.value.status
}
@@ -128,10 +90,6 @@ export const useMedicalHistoryFilter = (initialFilters = {}) => {
debouncedSearch(value)
}
const handleDatabaseChange = (database) => {
applyFilters({ database, page: 1 }, false)
}
// Конвертация строки даты в timestamp для NaiveUI
const convertToTimestamp = (dateString) => {
if (!dateString) return null
@@ -186,10 +144,6 @@ export const useMedicalHistoryFilter = (initialFilters = {}) => {
applyFilters({ page_size: size, page: 1 })
}
const handleViewTypeChange = (view_type) => {
applyFilters({ view_type, page: 1 })
}
const handleSortChange = (sorter) => {
applyFilters({
sort_by: sorter.columnKey,
@@ -213,8 +167,6 @@ export const useMedicalHistoryFilter = (initialFilters = {}) => {
page_size: 15,
sort_by: 'dateextract',
sort_order: 'desc',
view_type: 'archive',
database: 'postgresql',
}
dateRange.value = [null, null]
applyFilters({}, true)
@@ -270,22 +222,6 @@ export const useMedicalHistoryFilter = (initialFilters = {}) => {
})
}
// Фильтр по базе данных
if (filtersRef.value.database) {
const dbLabel = {
postgresql: 'PostgreSQL',
mssql: 'MSSQL',
smart: 'Умный поиск',
separate: 'Раздельно'
}[filtersRef.value.database] || filtersRef.value.database
active.push({
key: 'database',
label: `База: ${dbLabel}`,
icon: 'database'
})
}
return active
})
@@ -341,12 +277,8 @@ export const useMedicalHistoryFilter = (initialFilters = {}) => {
activeFilters,
dateRange,
searchValue,
databaseInfo,
databaseStats,
// Обработчики
handleDatabaseChange,
handleViewTypeChange,
handleSearch,
handleDateRangeChange,
handlePageChange,

View File

@@ -1,5 +1,5 @@
<script setup>
import { NLayout, NH1, NLayoutSider, NFlex, NButton, NConfigProvider, ruRU, dateRuRU } from "naive-ui";
import {NLayout, NH1, NLayoutSider, NFlex, NButton, NConfigProvider, ruRU, dateRuRU, darkTheme} from "naive-ui";
import SideMenu from "./Components/SideMenu.vue";
import { generate } from '@arco-design/color'
@@ -7,17 +7,27 @@ const colors = generate('#EC6608', {
list: true,
})
const themeOverrides = {
common: {
primaryColor: colors[5],
primaryColorHover: colors[4],
primaryColorSuppl: colors[4],
primaryColorPressed: colors[6],
// common: {
// primaryColor: colors[5],
// primaryColorHover: colors[4],
// primaryColorSuppl: colors[4],
// primaryColorPressed: colors[6],
// },
Modal: {
peers: {
Dialog: {
borderRadius: '8px'
},
Card: {
borderRadius: '8px'
},
}
}
}
</script>
<template>
<NConfigProvider :theme-overrides="themeOverrides" :locale="ruRU" :date-locale="dateRuRU">
<NConfigProvider :theme="darkTheme" :theme-overrides="themeOverrides" :locale="ruRU" :date-locale="dateRuRU">
<NLayout class="h-screen">
<NLayout position="absolute" content-class="p-6 relative" :native-scrollbar="false">
<!-- <NLayoutSider-->

View File

@@ -7,7 +7,7 @@ import {useNotification} from "../../../Composables/useNotification.js";
const open = defineModel('open')
const props = defineProps({
patientId: {
patientInfo: {
type: Number,
}
})
@@ -18,10 +18,10 @@ const loading = ref(true)
const patient = ref({})
const showArchiveHistoryModal = ref(false)
const selectedArchiveHistoryId = ref(null)
const selectedArchiveHistoryType = ref(null)
const selectedArchiveHistoryType = ref(props.patientInfo.type)
const isCreateNewArchiveHistoryModal = ref(false)
const archiveInfo = ref({
id: props.patientId,
id: props.patientInfo.id,
num: null,
post_in: null,
status: null
@@ -30,7 +30,7 @@ const emits = defineEmits(['historyUpdated', 'closeWithoutSave'])
const onResetData = () => {
archiveInfo.value = {
id: props.patientId,
id: props.patientInfo.id,
num: null,
post_in: null,
status: null
@@ -47,16 +47,16 @@ const patientData = ref({
})
const loadPatientData = async () => {
if (!props.patientId) return
if (!props.patientInfo.id) return
loading.value = true
try {
await axios.get(`/api/si/patients/${props.patientId}?view_type=${filtersRef.value.view_type}`).then(res => {
await axios.get(`/api/si/patients/${props.patientInfo.id}?view_type=${props.patientInfo.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,
// historyable_type: res.data.historyable_type,
id: props.patientInfo.id,
num: null,
post_in: null,
status: null,
@@ -73,12 +73,12 @@ const loadPatientData = async () => {
const onShowArchiveHistoryModal = (id) => {
if (id === null) {
isCreateNewArchiveHistoryModal.value = true
selectedArchiveHistoryId.value = props.patientId
selectedArchiveHistoryId.value = props.patientInfo.id
} else {
isCreateNewArchiveHistoryModal.value = false
selectedArchiveHistoryId.value = id
}
selectedArchiveHistoryType.value = archiveInfo.value.historyable_type
selectedArchiveHistoryType.value = props.patientInfo.type
showArchiveHistoryModal.value = true
}
@@ -122,7 +122,7 @@ const onUpdateHistory = async ({data}) => {
}
emits('historyUpdated', {
data: updatedData,
patientId: props.patientId
patientId: props.patientInfo.id
})
}
@@ -130,14 +130,14 @@ const hasCreateNew = computed(() => archiveInfo.value === null)
const onSubmit = async () => {
try {
await axios.post(`/api/archive/histories/info/${props.patientId}`, archiveInfo.value).then(res => {
await axios.post(`/api/archive/histories/info/${props.patientInfo.id}`, archiveInfo.value).then(res => {
// onCloseWithoutSave()
const updatedData = {
status: archiveInfo.value.status,
}
emits('historyUpdated', {
data: updatedData,
patientId: props.patientId
patientId: props.patientInfo.id
})
open.value = false
})
@@ -151,7 +151,7 @@ const onSubmit = async () => {
}
// Наблюдаем за изменением patientId
watch(() => props.patientId, async (newId) => {
watch(() => props.patientInfo, async (newId) => {
if (newId) {
await loadPatientData()
}
@@ -177,6 +177,11 @@ watch(() => props.patientId, async (newId) => {
<NFormItem label="Дата поступления карты в архив">
<NDatePicker v-model:value="archiveInfo.post_in" format="dd.MM.yyyy" />
</NFormItem>
<NFormItem label="№ карты в МИС / СофтИнфо">
<NTag :bordered="false" round class="w-full justify-center">
{{ archiveInfo.mis_num }} / {{ archiveInfo.foxpro_num }}
</NTag>
</NFormItem>
</NForm>
</NFlex>
<NButton @click="onShowArchiveHistoryModal(null)" :disabled="!patientData.can_be_issued">
@@ -202,7 +207,7 @@ watch(() => props.patientId, async (newId) => {
<NSpin :show="true" />
</div>
</NModal>
<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" />
<ArchiveHistoryMoveModal @history-updated="onUpdateHistory" @close-without-save="selectedArchiveHistoryId = null" :is-create-new="isCreateNewArchiveHistoryModal" v-model:open="showArchiveHistoryModal" :type="selectedArchiveHistoryType" :archive-history-id="selectedArchiveHistoryId" />
</template>
<style scoped>

View File

@@ -17,12 +17,12 @@ import {ref, watch} from "vue";
import {router} from "@inertiajs/vue3";
const open = defineModel('open')
const props = defineProps({
type: {
type: String
},
archiveHistoryId: {
type: Number
},
activeHistoryType: {
type: String
},
isCreateNew: {
type: Boolean
}
@@ -31,8 +31,7 @@ const emits = defineEmits(['closeWithoutSave', 'historyUpdated'])
const loading = ref(false)
const archiveHistory = ref({
historyable_id: props.archiveHistoryId,
historyable_type: props.activeHistoryType,
type: props.type,
issue_at: null,
org_id: null,
return_at: null,
@@ -45,8 +44,8 @@ const orgs = ref([])
const onResetData = () => {
archiveHistory.value = {
historyable_id: props.archiveHistoryId,
historyable_type: props.activeHistoryType,
archive_info_id: props.archiveHistoryId,
type: props.type,
issue_at: null,
org_id: null,
return_at: null,
@@ -114,7 +113,7 @@ watch(() => props.archiveHistoryId, async (newId) => {
<template>
<NModal v-model:show="open" preset="card" class="max-w-2xl relative" closable @close="onCloseWithoutSave">
<template #header>
{{ archiveHistoryId === null ? 'Добавить' : 'Редактировать' }} запись выдачи
{{ isCreateNew ? 'Добавить' : 'Редактировать' }} запись выдачи
</template>
<NForm>
<NFormItem label="Дата выдачи">

View File

@@ -90,56 +90,37 @@ const columns = ref([
}
])
const showArchiveHistoryModal = ref(false)
const selectedPatientId = ref(null)
const selectedPatientInfo = ref({})
const rowProps = (row) => ({
onDblclick: () => {
selectedPatientId.value = row.id
selectedPatientInfo.value = {id: row.id, type: row.history_type}
showArchiveHistoryModal.value = true
}
})
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
}
return {
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 onCloseWithoutSave = () => {
selectedPatientId.value = null
selectedPatientInfo.value = null
}
const onUpdateHistory = ({data, patientId}) => {
console.log(data)
if (dataTable.value.length > 0) {
let needUpdateItem = dataTable.value.findIndex(itm => itm.id === patientId)
dataTable.value[needUpdateItem] = {
@@ -156,7 +137,7 @@ watch(() => props.data, (newData) => {
<template>
<NDataTable remote striped :loading="isLoading" :row-props="rowProps" :columns="columns" :pagination="pagination" :max-height="maxHeight" size="small" :min-height="minHeight" :data="dataTable" />
<ArchiveHistoryModal v-model:open="showArchiveHistoryModal" :patient-id="selectedPatientId" @history-updated="onUpdateHistory" @close-without-save="onCloseWithoutSave" />
<ArchiveHistoryModal v-model:open="showArchiveHistoryModal" :patient-info="selectedPatientInfo" @history-updated="onUpdateHistory" @close-without-save="onCloseWithoutSave" />
</template>
<style scoped>

View File

@@ -2,10 +2,8 @@
import AppLayout from "../../Layouts/AppLayout.vue"
import TableCards from './DataTable/Index.vue'
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";
import {computed, ref} from "vue";
import {ref} from "vue";
const props = defineProps({
cards: {
@@ -63,14 +61,7 @@ const handleBeforeLeave = (tabName) => {
</NFlex>
</NSpace>
</template>
<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>
<TableCards :filters="filters" :data="cards.data" :meta="cards.meta" min-height="calc(100vh - 212px)" max-height="calc(100vh - 320px)" />
</AppLayout>
</template>