* блокировка изменения отчета для врача

* вывод данных из отчетов для ролей адм и зав
* поправил ширину стобцов ввода
* добавил календарь на страницу статистики
* переделал календарь у заведующего на странице отчета
* добавил и привязал метрики в статистику
This commit is contained in:
brusnitsyn
2026-02-03 17:03:37 +09:00
parent 2805e5e4bc
commit 9ee33bc517
20 changed files with 889 additions and 159 deletions

View File

@@ -0,0 +1,117 @@
<script setup>
import {NDatePicker, NIcon, } from 'naive-ui'
import {computed, onMounted, ref, watch} from "vue";
import {router} from "@inertiajs/vue3";
import {TbCalendar} from 'vue-icons-plus/tb'
import {formatRussianDate, formatRussianDateRange} from "../Utils/dateFormatter.js";
const props = defineProps({
// Пользователь с ролью админ или зав
isHeadOrAdmin: {
type: Boolean,
default: false
},
date: {
type: [Number, Array]
},
isOneDay: {
type: Boolean
}
})
const isUseDateRange = computed(() => props.isHeadOrAdmin)
const datePicker = ref()
const showCalendar = ref(false)
const dateType = computed(() => {
if (isUseDateRange.value) return 'daterange'
return 'date'
})
const queryDate = ref([null, null])
const modelValue = ref(props.date)
const setQueryDate = () => {
router.reload({
data: {
startAt: queryDate.value[0],
endAt: queryDate.value[1]
}
})
}
// Форматированное значение для отображения
const formattedValue = computed(() => {
const value = modelValue.value
if (props.isHeadOrAdmin) {
if (props.isOneDay) {
const dateToFormat = Array.isArray(value) ? value[1] : value
return formatRussianDate(dateToFormat)
} else if (Array.isArray(value) && value.length >= 2 && value[0] && value[1]) { // Для админа - диапазон дат
return formatRussianDateRange(value)
}
// Если что-то пошло не так, форматируем как одиночную дату
if (value) {
const dateToFormat = Array.isArray(value) ? value[0] : value
return formatRussianDate(dateToFormat)
}
return ''
} else {
// Для врача - одиночная дата
let dateToFormat
if (Array.isArray(value)) {
dateToFormat = value[1] || value[0]
} else {
dateToFormat = value
}
// Если выбрана сегодняшняя дата - показываем текущее время
if (dateToFormat) {
return formatRussianDate(dateToFormat)
}
return ''
}
})
watch(() => modelValue.value, (newVal) => {
if (isUseDateRange.value) {
queryDate.value = newVal
} else {
queryDate.value = [newVal, newVal]
}
setQueryDate()
})
</script>
<template>
<div class="relative inline-flex items-center">
<div v-if="formattedValue" class="font-medium leading-3 cursor-pointer" @click="showCalendar = true">
{{ formattedValue }}
</div>
<NDatePicker v-model:value="modelValue"
v-model:show="showCalendar"
ref="datePicker"
class="opacity-0 absolute! inset-x-0 bottom-full -translate-y-1/2"
placement="top-start"
input-readonly
bind-calendar-months
update-value-on-close
:type="dateType" />
<div class="cursor-pointer p-2 flex items-center justify-center" @click="showCalendar = true">
<NIcon size="20">
<TbCalendar />
</NIcon>
</div>
</div>
</template>
<style scoped>
:deep(.n-input) {
position: absolute;
pointer-events: none;
}
</style>

View File

@@ -1,9 +1,17 @@
<script setup>
import {NDatePicker} from 'naive-ui'
import {NDatePicker, NIcon} from 'naive-ui'
import {storeToRefs} from "pinia";
import {useReportStore} from "../Stores/report.js";
import {useAuthStore} from "../Stores/auth.js";
import {computed, ref, onMounted, onUnmounted} from "vue";
import {TbCalendar} from "vue-icons-plus/tb";
import {formatRussianDate, formatRussianDateRange} from "../Utils/dateFormatter.js";
const props = defineProps({
isOneDay: {
type: Boolean
}
})
const reportStore = useReportStore()
const authStore = useAuthStore()
@@ -12,22 +20,6 @@ const {timestampCurrentRange} = storeToRefs(reportStore)
// Текущее время для обновления
const currentTime = ref(Date.now())
// Обновляем время каждую секунду
let intervalId = null
onMounted(() => {
if (authStore.isDoctor) {
intervalId = setInterval(() => {
currentTime.value = Date.now()
}, 1000)
}
})
onUnmounted(() => {
if (intervalId) {
clearInterval(intervalId)
}
})
// Проверяем, является ли дата сегодняшней
const isToday = (timestamp) => {
const date = new Date(timestamp)
@@ -121,11 +113,46 @@ const modelComputed = computed({
const userId = params.get('userId')
reportStore.reportInfo.userId = userId
reportStore.getDataOnReportDate(reportStore.timestampCurrentRange)
}
})
const formattedValue = computed(() => {
const value = reportStore.timestampCurrentRange
if (authStore.isHeadOfDepartment || authStore.isAdmin) {
if (props.isOneDay) {
const dateToFormat = Array.isArray(value) ? value[1] : value
return formatRussianDate(dateToFormat)
} else if (Array.isArray(value) && value.length >= 2 && value[0] && value[1]) { // Для админа - диапазон дат
return formatRussianDateRange(value)
}
// Если что-то пошло не так, форматируем как одиночную дату
if (value) {
const dateToFormat = Array.isArray(value) ? value[0] : value
return formatRussianDate(dateToFormat)
}
return ''
} else {
// Для врача - одиночная дата
let dateToFormat
if (Array.isArray(value)) {
dateToFormat = value[1] || value[0]
} else {
dateToFormat = value
}
// Если выбрана сегодняшняя дата - показываем текущее время
if (dateToFormat) {
return formatRussianDate(dateToFormat)
}
return ''
}
})
const classComputed = computed(() => {
const baseClasses = []
@@ -138,28 +165,48 @@ const classComputed = computed(() => {
return baseClasses
})
const showCalendar = ref(false)
</script>
<template>
<NDatePicker
:theme-overrides="themeOverride"
v-model:value="modelComputed"
:class="classComputed"
:format="formatComputed"
:type="typeComputed"
placement="top-end"
input-readonly
bind-calendar-months
update-value-on-close
/>
<div class="relative inline-flex items-center">
<div v-if="formattedValue" class="text-lg font-medium leading-3 cursor-pointer" @click="showCalendar = true">
{{ formattedValue }}
</div>
<NDatePicker v-model:value="modelComputed"
v-model:show="showCalendar"
ref="datePicker"
class="opacity-0 absolute! inset-x-0 bottom-full -translate-y-1/2"
placement="top-start"
input-readonly
bind-calendar-months
update-value-on-close
:type="typeComputed" />
<div class="cursor-pointer p-2 flex items-center justify-center" @click="showCalendar = true">
<NIcon size="20">
<TbCalendar />
</NIcon>
</div>
</div>
<!-- <NDatePicker-->
<!-- :theme-overrides="themeOverride"-->
<!-- v-model:value="modelComputed"-->
<!-- :class="classComputed"-->
<!-- :format="formatComputed"-->
<!-- :type="typeComputed"-->
<!-- placement="top-end"-->
<!-- input-readonly-->
<!-- bind-calendar-months-->
<!-- update-value-on-close-->
<!-- />-->
</template>
<style scoped>
:deep(.n-input__suffix) {
margin-left: 12px;
}
:deep(.n-input),
:deep(.n-input__input-el) {
cursor: pointer !important;
:deep(.n-input) {
position: absolute;
pointer-events: none;
}
</style>