Обновление 1.0
Some checks failed
Build and Push Docker Image / test (push) Has been cancelled
Build and Push Docker Image / build (push) Has been cancelled

This commit is contained in:
brusnitsyn
2026-01-13 18:54:48 +09:00
parent bb36ef3a40
commit 76c5f6705e
7 changed files with 164 additions and 19 deletions

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Http\Resources\ArchiveInfoResource;
use App\Models\ArchiveInfo; use App\Models\ArchiveInfo;
use App\Models\Mis\SttMedicalHistory; use App\Models\Mis\SttMedicalHistory;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -35,4 +36,26 @@ class ArchiveInfoController extends Controller
return $hasCreated; return $hasCreated;
} }
public function check(Request $request)
{
$data = $request->validate([
'id' => 'required',
]);
$archive = ArchiveInfo::where('mis_history_id', $data['id'])
->orWhere('foxpro_history_id', $data['id'])
->first();
if (isset($archive)) {
return response()->json([
'id' => $archive->mis_history_id ?? $archive->foxpro_history_id,
'type' => $archive->mis_history_id ? 'mis' : 'foxpro',
]);
}
return response()->json([
'message' => 'Карты нет в архиве'
])->setStatusCode(404);
}
} }

View File

@@ -1,15 +1,21 @@
<script setup> <script setup>
import { NModal, NSelect, NSpace, NFlex, NButton, NForm, NFormItem, NInput, NDatePicker, NDivider, NSpin, NTag } from 'naive-ui' import { NModal, NSelect, NSpace, NFlex, NButton, NForm, NFormItem, NInput, NDatePicker, NDivider, NSpin, NTag } from 'naive-ui'
import ArchiveHistoryMoveModal from '../ArchiveHistoryMoveModal/Index.vue' import ArchiveHistoryMoveModal from '../ArchiveHistoryMoveModal/Index.vue'
import {computed, ref, watch} from "vue"; import {computed, h, ref, watch} from "vue";
import {useMedicalHistoryFilter} from "../../../Composables/useMedicalHistoryFilter.js"; import {useMedicalHistoryFilter} from "../../../Composables/useMedicalHistoryFilter.js";
import {useNotification} from "../../../Composables/useNotification.js"; import {useNotification} from "../../../Composables/useNotification.js";
import {useDebounceFn} from "@vueuse/core"; import {useDebounceFn} from "@vueuse/core";
import {useArchiveCard} from "../../../Stores/ArchiveCard.js";
const open = defineModel('open') const open = defineModel('open')
const {errorApi} = useNotification() const {errorApi} = useNotification()
const loading = ref(false) const loading = ref(false)
const loadingFilterPatients = ref(false)
const formRef = ref(null)
const archiveCardStore = useArchiveCard()
const isCardInArchive = computed(() => archiveCardStore.preOpenCard !== null)
const emits = defineEmits(['historyUpdated', 'closeWithoutSave', 'openArchiveCard'])
const archiveInfo = ref({ const archiveInfo = ref({
id: null, id: null,
num: null, num: null,
@@ -20,16 +26,43 @@ const archiveInfoRules = {
{ {
required: true, required: true,
validator(rule, value) { validator(rule, value) {
console.log(value) if (isCardInArchive.value) {
return false
}
if (!value) { if (!value) {
return new Error('Это поле необходимо заполнить') return false
} }
else if (!Number(value)) { else if (!Number(value)) {
return new Error('Ошибка при получении ID') return false
} }
return true return true
}, },
trigger: ['input', 'blur'] renderMessage: () => {
if (isCardInArchive.value) {
return h(
'div',
[
'Карта уже находится в архиве. ',
h(
NButton,
{
text: true,
onClick: (e) => {
e.preventDefault()
archiveCardStore.isOpenArchiveCard = true
onCloseWithoutSave()
}
},
'Перейти к карте'
)
]
)
}
return 'Это поле необходимо заполнить'
},
trigger: ['change', 'blur']
} }
], ],
num: [ num: [
@@ -47,17 +80,26 @@ const archiveInfoRules = {
} }
] ]
} }
const loadingFilterPatients = ref(false)
const formRef = ref(null)
const emits = defineEmits(['historyUpdated', 'closeWithoutSave']) const onResetArchiveInfo = (only) => {
if (only && Object.keys(only).length > 0) {
const onResetData = () => { archiveInfo.value = {
...archiveInfo.value,
...only
}
} else {
archiveInfo.value = { archiveInfo.value = {
id: null, id: null,
num: null, num: null,
post_in: null, post_in: null,
} }
}
}
const onResetData = () => {
onResetArchiveInfo()
filteredPatients.value = []
setTimeout(() => archiveCardStore.resetPreOpenCard(), 100)
} }
const onCloseWithoutSave = () => { const onCloseWithoutSave = () => {
@@ -106,6 +148,27 @@ const onSubmit = async (e) => {
} }
}) })
} }
const updateValueSearch = async (value) => {
archiveCardStore.setPreOpenCard(null)
await axios.post('/api/archive/check', {
id: value
}).then(res => {
archiveCardStore.setPreOpenCard(res.data)
}).catch(err => {
if (err.code === 404) {
archiveCardStore.resetPreOpenCard()
}
})
}
watch(() => isCardInArchive.value, (val) => {
if (val)
onResetArchiveInfo({
num: null,
post_in: null
})
})
</script> </script>
<template> <template>
@@ -126,17 +189,20 @@ const onSubmit = async (e) => {
:loading="loadingFilterPatients" :loading="loadingFilterPatients"
:options="filteredPatients" :options="filteredPatients"
v-model:value="archiveInfo.id" v-model:value="archiveInfo.id"
@update:value="(val) => updateValueSearch(val)"
@search="handleSearchCard" @search="handleSearchCard"
/> />
</NFormItem> </NFormItem>
<NFormItem size="large" label="Дата поступления карты в архив" path="post_in"> <NFormItem size="large" label="Дата поступления карты в архив" path="post_in">
<NDatePicker class="w-full" <NDatePicker class="w-full"
v-model:value="archiveInfo.post_in" v-model:value="archiveInfo.post_in"
:disabled="archiveCardStore.isSetPreOpenCard"
format="dd.MM.yyyy" format="dd.MM.yyyy"
/> />
</NFormItem> </NFormItem>
<NFormItem size="large" label="№ в архиве" path="num"> <NFormItem size="large" label="№ в архиве" path="num">
<NInput v-model:value="archiveInfo.num" /> <NInput v-model:value="archiveInfo.num"
:disabled="archiveCardStore.isSetPreOpenCard"/>
</NFormItem> </NFormItem>
</NForm> </NForm>
</NFlex> </NFlex>
@@ -147,6 +213,7 @@ const onSubmit = async (e) => {
type="primary" type="primary"
attr-type="submit" attr-type="submit"
form="formAddToArchive" form="formAddToArchive"
:disabled="archiveCardStore.isSetPreOpenCard"
@click="onSubmit"> @click="onSubmit">
Добавить карту Добавить карту
</NButton> </NButton>

View File

@@ -4,6 +4,7 @@ import ArchiveHistoryMoveModal from '../ArchiveHistoryMoveModal/Index.vue'
import {computed, ref, watch} from "vue"; import {computed, ref, watch} from "vue";
import {useMedicalHistoryFilter} from "../../../Composables/useMedicalHistoryFilter.js"; import {useMedicalHistoryFilter} from "../../../Composables/useMedicalHistoryFilter.js";
import {useNotification} from "../../../Composables/useNotification.js"; import {useNotification} from "../../../Composables/useNotification.js";
import {useArchiveCard} from "../../../Stores/ArchiveCard.js";
const open = defineModel('open') const open = defineModel('open')
const props = defineProps({ const props = defineProps({
@@ -12,6 +13,7 @@ const props = defineProps({
} }
}) })
const archiveCardStore = useArchiveCard()
const {filtersRef} = useMedicalHistoryFilter() const {filtersRef} = useMedicalHistoryFilter()
const {errorApi} = useNotification() const {errorApi} = useNotification()
const loading = ref(true) const loading = ref(true)
@@ -96,17 +98,26 @@ const columns = [
{ {
title: 'Организация', title: 'Организация',
key: 'org', key: 'org',
width: 220 width: 220,
ellipsis: {
tooltip: true
}
}, },
{ {
title: 'ФИО', title: 'ФИО',
key: 'employee_name', key: 'employee_name',
width: 180 width: 180,
ellipsis: {
tooltip: true
}
}, },
{ {
title: 'Должность', title: 'Должность',
key: 'employee_post', key: 'employee_post',
width: 120 width: 120,
ellipsis: {
tooltip: true
}
}, },
] ]
const rowProps = (row) => ({ const rowProps = (row) => ({
@@ -154,6 +165,7 @@ const onSubmit = async () => {
watch(() => props.patientInfo, async (newId) => { watch(() => props.patientInfo, async (newId) => {
if (newId) { if (newId) {
await loadPatientData() await loadPatientData()
archiveCardStore.isOpenArchiveCard = false
} }
}, { immediate: true }) }, { immediate: true })
</script> </script>
@@ -187,7 +199,7 @@ watch(() => props.patientInfo, async (newId) => {
<NButton @click="onShowArchiveHistoryModal(null)" :disabled="!patientData.can_be_issued"> <NButton @click="onShowArchiveHistoryModal(null)" :disabled="!patientData.can_be_issued">
Добавить Добавить
</NButton> </NButton>
<NDataTable :row-props="rowProps" min-height="420px" max-height="420px" :columns="columns" :data="patient?.journal" /> <NDataTable :row-props="rowProps" min-height="300px" size="small" max-height="300px" :columns="columns" :data="patient?.journal" />
</NSpace> </NSpace>
<template #action> <template #action>
<NFlex justify="end" align="center"> <NFlex justify="end" align="center">

View File

@@ -3,6 +3,7 @@ import {NDataTable, NEllipsis, NTag} from "naive-ui"
import {computed, h, reactive, ref, watch} from "vue" import {computed, h, reactive, ref, watch} from "vue"
import {useMedicalHistoryFilter} from "../../../Composables/useMedicalHistoryFilter.js"; import {useMedicalHistoryFilter} from "../../../Composables/useMedicalHistoryFilter.js";
import ArchiveHistoryModal from '../ArchiveHistoryModal/Index.vue' import ArchiveHistoryModal from '../ArchiveHistoryModal/Index.vue'
import {useArchiveCard} from "../../../Stores/ArchiveCard.js";
const props = defineProps({ const props = defineProps({
filters: { filters: {
@@ -24,6 +25,7 @@ const props = defineProps({
}) })
const { isLoading, handlePageChange, handlePageSizeChange, meta, filtersRef } = useMedicalHistoryFilter(props.filters) const { isLoading, handlePageChange, handlePageSizeChange, meta, filtersRef } = useMedicalHistoryFilter(props.filters)
const archiveCardStore = useArchiveCard()
const dataTable = ref(props.data ?? []) const dataTable = ref(props.data ?? [])
const archiveStatusColumn = (status) => { const archiveStatusColumn = (status) => {
@@ -132,6 +134,14 @@ const onUpdateHistory = ({data, patientId}) => {
watch(() => props.data, (newData) => { watch(() => props.data, (newData) => {
dataTable.value = newData dataTable.value = newData
}) })
watch(() => archiveCardStore.isOpenArchiveCard, (isOpen) => {
if (isOpen) {
selectedPatientInfo.value = Object.assign(archiveCardStore.preOpenCard)
showArchiveHistoryModal.value = true
archiveCardStore.setPreOpenCard(null)
}
})
</script> </script>
<template> <template>

View File

@@ -34,6 +34,10 @@ const onHandleSearch = (search) => {
handleSearch(search) handleSearch(search)
} }
const openArchiveCard = (card) => {
}
const handleBeforeLeave = (tabName) => { const handleBeforeLeave = (tabName) => {
handleViewTypeChange(tabName) handleViewTypeChange(tabName)
return true return true
@@ -105,7 +109,7 @@ const handleBeforeLeave = (tabName) => {
min-height="calc(100vh - 212px)" min-height="calc(100vh - 212px)"
max-height="calc(100vh - 320px)" max-height="calc(100vh - 320px)"
/> />
<ArchiveHistoryCreateModal v-model:open="ArchiveHistoryCreateModalShow" /> <ArchiveHistoryCreateModal v-model:open="ArchiveHistoryCreateModalShow" @open-archive-card="(card) => openArchiveCard(card)" />
</AppLayout> </AppLayout>
</template> </template>

View File

@@ -0,0 +1,27 @@
import {defineStore} from "pinia";
import {computed, ref} from "vue";
export const useArchiveCard = defineStore('archive-card', () => {
const preOpenCard = ref(null)
const isOpenArchiveCard = ref(false)
const isSetPreOpenCard = computed(() => preOpenCard.value !== null)
const setPreOpenCard = (card) => {
preOpenCard.value = card
}
const resetPreOpenCard = () => {
preOpenCard.value = null
}
return {
preOpenCard,
isOpenArchiveCard,
isSetPreOpenCard,
setPreOpenCard,
resetPreOpenCard
}
})

View File

@@ -31,6 +31,8 @@ Route::prefix('archive')->group(function () {
}); });
}); });
Route::post('check', [\App\Http\Controllers\ArchiveInfoController::class, 'check']);
Route::post('create', [\App\Http\Controllers\ArchiveInfoController::class, 'store']); Route::post('create', [\App\Http\Controllers\ArchiveInfoController::class, 'store']);
}); });