This commit is contained in:
brusnitsyn
2026-02-20 17:28:16 +09:00
parent 94e374c32b
commit 52a80ccd3b
41 changed files with 2555 additions and 206 deletions

View File

@@ -18,9 +18,11 @@ const authStore = useAuthStore()
const reportStore = useReportStore()
const onSubmit = () => {
reportStore.sendReportForm({
departmentId: authStore.userDepartment.department_id
reportStore.reportFormRef?.validate((errors) => {
if (!errors) reportStore.sendReportForm()
else window.$message.error('Ошибка отправки отчета')
})
// reportStore.sendReportForm()
}

View File

@@ -2,16 +2,42 @@
import {NCard, NSkeleton, NSpace, NFlex, NFormItem, NForm, NInputNumber, NStatistic} from "naive-ui";
import {useReportStore} from "../../../Stores/report.js";
import {useAuthStore} from "../../../Stores/auth.js";
import {computed, onMounted, ref, watch} from "vue";
const reportStore = useReportStore()
const authStore = useAuthStore()
const formRef = ref()
const rules = computed(() => {
const rawRules = {}
for (const metrika of reportStore.reportInfo.metrikaItems) {
const rule = {}
rule.required = metrika.is_required
rule.trigger = ['input', 'blur']
if (metrika.data_type === 'integer') {
rule.validator = (rule, value) => {
if (!/^\d*$/.test(value)) {
return new Error()
}
return true
}
}
rawRules[`metrika_item_${metrika.metrika_item_id}`] = rule
}
return rawRules
})
watch(() => formRef.value, (nv) => {
reportStore.reportFormRef = nv
})
</script>
<template>
<div class="grid grid-cols-[1fr_auto] gap-x-3">
<NCard v-if="reportStore.reportInfo?.report?.isActiveSendButton">
<NForm>
<NCard>
<NForm ref="formRef" :model="reportStore.reportForm" :disabled="!reportStore.reportInfo?.report?.isActiveSendButton" :rules="rules">
<template v-if="reportStore.isLoadReportInfo">
<NFlex>
<NSkeleton class="rounded-md w-[246px]! h-[65px]!" />
@@ -22,9 +48,9 @@ const authStore = useAuthStore()
<NFlex v-else justify="space-between" align="center">
<NSpace>
<template v-for="metrikaItem in reportStore.reportInfo?.metrikaItems">
<NFormItem :label="metrikaItem.name" :show-feedback="false">
<NFormItem :label="metrikaItem.name" :show-feedback="false" :required="metrikaItem.is_required" :path="`metrika_item_${metrikaItem.metrika_item_id}`">
<NInputNumber v-model:value="reportStore.reportForm[`metrika_item_${metrikaItem.metrika_item_id}`]"
:default-value="metrikaItem.default_value" />
:default-value="metrikaItem.default_value" min="0" />
</NFormItem>
</template>
</NSpace>
@@ -39,6 +65,19 @@ const authStore = useAuthStore()
<NStatistic label="Умерло" :value="reportStore.reportInfo?.department?.deadCount" />
</div>
</NCard>
<NCard class="min-w-[120px] max-w-[120px] min-h-[100px] max-h-[102px] h-full"
style="--n-padding-top: 0; --n-padding-bottom: 0; --n-padding-left: 8px; --n-padding-right: 8px;">
<div class="w-full h-full flex flex items-center justify-center">
<NStatistic :value="reportStore.reportInfo.department.percentDead">
<template #label>
<div class="flex flex-col">
<span>Летальность</span>
<span>%</span>
</div>
</template>
</NStatistic>
</div>
</NCard>
<NCard class="min-w-[120px] max-w-[120px] min-h-[100px] max-h-[102px] h-full"
style="--n-padding-top: 0; --n-padding-bottom: 0; --n-padding-left: 8px; --n-padding-right: 8px;">
<div class="w-full h-full flex flex items-center justify-center">

View File

@@ -58,11 +58,11 @@ const currentDate = computed(() => {
<div class="grid grid-cols-[auto_1fr_auto] items-center">
<NSpace align="center">
<NTag v-if="isFillableMode" type="info" :bordered="false">
{{ authStore.userDepartment.name_full }}
{{ reportStore.reportInfo.department.department_name }}
</NTag>
<DepartmentSelect v-if="isReadonlyMode" />
<NTag v-if="reportStore.reportInfo?.report?.userName" type="warning">
Ответственный: {{ reportStore.reportInfo?.report.userName }}
<NTag v-if="reportStore.reportInfo.report.userName" type="warning">
Ответственный: {{ reportStore.reportInfo.report.userName }}
</NTag>
</NSpace>

View File

@@ -23,7 +23,8 @@ const fetchPatientCount = async () => {
const data = {
status: props.status,
startAt: reportStore.timestampCurrentRange[0],
endAt: reportStore.timestampCurrentRange[1]
endAt: reportStore.timestampCurrentRange[1],
departmentId: reportStore.reportInfo.department.department_id
}
await axios.post('/api/mis/patients/count', data).then((res) => {
countPatient.value = res.data

View File

@@ -229,6 +229,7 @@ const fetchPatients = async () => {
status: props.status,
startAt: reportStore.timestampCurrentRange[0],
endAt: reportStore.timestampCurrentRange[1],
departmentId: reportStore.reportInfo.department.department_id
}
await axios.post('/api/mis/patients', data).then((res) => {
patientsData.value[props.status] = reportStore.addRowNumbers(res.data)

View File

@@ -1,56 +1,139 @@
<script setup>
import { NSelect, NModal, NForm, NFormItem, NButton } from 'naive-ui'
import { NSelect, NModal, NForm, NFormItem, NButton, NAlert } from 'naive-ui'
import {useReportStore} from "../../../Stores/report.js";
import {computed, onMounted, ref} from "vue";
import {router} from "@inertiajs/vue3";
import {computed, onMounted, ref, watch} from "vue";
import {router, Link} from "@inertiajs/vue3";
import {useDebounceFn} from "@vueuse/core";
const show = defineModel('show')
const reportStore = useReportStore()
const formRef = ref()
const users = computed(() => reportStore.departmentUsers.map(itm => ({
const rawUsers = ref([])
const rawDepartments = ref([])
const reportExists = ref(false)
const existingReportId = ref(null)
const users = computed(() => rawUsers.value.map(itm => ({
label: `${itm.FAM_V} ${itm.IM_V} ${itm.OT_V}`,
value: itm.LPUDoctorID
})))
const departments = computed(() => rawDepartments.value.map(itm => ({
label: itm.name_short,
value: itm.department_id
})))
const fetchUsers = () => {
axios.get('/api/mis/department-users')
.then((res) => {
reportStore.departmentUsers = res.data
rawUsers.value = res.data
})
}
const fetchDepartments = () => {
axios.get('/api/app/departments')
.then((res) => {
rawDepartments.value = res.data
})
}
const checkReportExists = async (userId, departmentId) => {
if (!userId || !departmentId) {
reportExists.value = false;
existingReportId.value = null;
return;
}
try {
await axios.get(`/api/report/check`, {
params: {
department_id: departmentId,
}
}).then(res => {
reportExists.value = res.data.exists;
existingReportId.value = res.data.report_id || null;
});
} catch (error) {
console.error('Ошибка при проверке отчета:', error);
reportExists.value = false;
existingReportId.value = null;
} finally {
}
}
// Дебаунс функция
const debouncedCheck = useDebounceFn((userId, departmentId) => {
checkReportExists(userId, departmentId);
}, 300);
// Автоматическая проверка при изменении любого из полей
watch(
() => [reportStore.reportInfo.userId, reportStore.reportInfo.departmentId],
([newUserId, newDepartmentId], [oldUserId, oldDepartmentId]) => {
// Проверяем, что оба поля заполнены и корректны
const userIdValid = newUserId && Number.isInteger(Number(newUserId));
const departmentIdValid = newDepartmentId && Number.isInteger(Number(newDepartmentId));
if (userIdValid && departmentIdValid) {
debouncedCheck(newUserId, newDepartmentId);
} else {
reportExists.value = false;
existingReportId.value = null;
}
},
{ deep: true }
);
const rules = {
userId: {
required: true,
validator: (rule, value) => {
if (Number.isInteger(value)) return true
return false
return Number.isInteger(value) ?? false
},
trigger: ['change', 'blur'],
message: 'Выберите ответственного'
}
},
departmentId: {
required: true,
validator: (rule, value) => {
return Number.isInteger(value) ?? false
},
trigger: ['change', 'blur'],
message: 'Выберите отделение'
},
}
onMounted(() => {
reportStore.reportInfo.userId = null
reportStore.reportInfo.departmentId = null
fetchUsers()
fetchDepartments()
})
const onSubmit = (e) => {
e.preventDefault()
formRef.value?.validate((errors) => {
if (!errors) {
router.visit(`/report?userId=${reportStore.reportInfo.userId}`)
if (reportExists.value) return
router.visit(`/report`, {
data: {
userId: reportStore.reportInfo.userId,
departmentId: reportStore.reportInfo.departmentId
}
})
}
else {
window.$message.warning('Заполните выделенные поля')
}
})
}
const onAfterLeave = () => {
reportStore.reportInfo.userId = null
reportStore.reportInfo.departmentId = null
reportExists.value = false
existingReportId.value = null
}
</script>
@@ -68,12 +151,25 @@ const onAfterLeave = () => {
filterable
/>
</NFormItem>
<NFormItem label="Выберите отделение" path="departmentId">
<NSelect :options="departments"
v-model:value="reportStore.reportInfo.departmentId"
filterable
/>
</NFormItem>
</NForm>
<NAlert v-if="reportExists" type="warning">
Сводная уже создана.
<NButton :tag="Link" text :href="`/report?userId=${reportStore.reportInfo.userId}&departmentId=${reportStore.reportInfo.departmentId}`">
Перейти
</NButton>
</NAlert>
<template #action>
<NButton form-id="select-user-form"
type="primary"
block
@click="onSubmit">
@click="onSubmit"
:disabled="reportExists">
Перейти к заполнению сводной
</NButton>
</template>