* вывод данных из отчетов для ролей адм и зав * поправил ширину стобцов ввода * добавил календарь на страницу статистики * переделал календарь у заведующего на странице отчета * добавил и привязал метрики в статистику
213 lines
6.5 KiB
Vue
213 lines
6.5 KiB
Vue
<script setup>
|
||
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()
|
||
const {timestampCurrentRange} = storeToRefs(reportStore)
|
||
|
||
// Текущее время для обновления
|
||
const currentTime = ref(Date.now())
|
||
|
||
// Проверяем, является ли дата сегодняшней
|
||
const isToday = (timestamp) => {
|
||
const date = new Date(timestamp)
|
||
const today = new Date()
|
||
|
||
return date.getDate() === today.getDate() &&
|
||
date.getMonth() === today.getMonth() &&
|
||
date.getFullYear() === today.getFullYear()
|
||
}
|
||
|
||
// Функция для форматирования с заглавной буквой
|
||
const formatDateWithCapital = (timestamp) => {
|
||
const date = new Date(timestamp)
|
||
// Форматируем дату на русском
|
||
const formatted = date.toLocaleDateString('ru-RU', {
|
||
weekday: 'long',
|
||
year: 'numeric',
|
||
month: 'long',
|
||
day: 'numeric'
|
||
})
|
||
// Делаем первую букву заглавной
|
||
return formatted.charAt(0).toUpperCase() + formatted.slice(1)
|
||
}
|
||
|
||
const themeOverride = computed(() => {
|
||
if (authStore.isDoctor) {
|
||
return {
|
||
peers: {
|
||
Input: {
|
||
border: '',
|
||
borderHover: '',
|
||
borderFocus: '',
|
||
boxShadowFocus: '',
|
||
color: '',
|
||
colorFocus: '',
|
||
fontSizeMedium: '22px',
|
||
fontWeight: '500'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
})
|
||
|
||
// Используем кастомную функцию форматирования
|
||
const formatComputed = computed(() => {
|
||
const baseFormat = "dd.MM.yyyy"
|
||
|
||
if (authStore.isDoctor) {
|
||
// Возвращаем функцию форматирования вместо строки
|
||
return formatDateWithCapital(modelComputed.value)
|
||
}
|
||
|
||
return baseFormat
|
||
})
|
||
|
||
const typeComputed = computed(() => authStore.isDoctor ? 'date' : 'daterange')
|
||
|
||
const modelComputed = computed({
|
||
get: () => {
|
||
const value = reportStore.timestampCurrentRange
|
||
|
||
if (authStore.isDoctor) {
|
||
if (Array.isArray(value)) {
|
||
const doctorTimestamp = value[1]
|
||
|
||
// Если выбрана сегодняшняя дата - показываем текущее время
|
||
if (isToday(doctorTimestamp)) {
|
||
return currentTime.value
|
||
}
|
||
// Иначе показываем выбранную дату (без обновления)
|
||
return doctorTimestamp
|
||
}
|
||
return value
|
||
}
|
||
|
||
if (Array.isArray(value)) {
|
||
return value
|
||
} else {
|
||
return [value, value]
|
||
}
|
||
},
|
||
set: (value) => {
|
||
if (Array.isArray(value)) {
|
||
reportStore.timestampCurrentRange = value
|
||
} else {
|
||
reportStore.timestampCurrentRange = [value, value]
|
||
}
|
||
|
||
const queryString = window.location.search
|
||
const params = new URLSearchParams(queryString)
|
||
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 = []
|
||
|
||
if (authStore.isDoctor) {
|
||
baseClasses.push('w-[400px]')
|
||
baseClasses.push('text-end')
|
||
} else {
|
||
baseClasses.push('max-w-[280px]')
|
||
}
|
||
|
||
return baseClasses
|
||
})
|
||
|
||
const showCalendar = ref(false)
|
||
</script>
|
||
|
||
<template>
|
||
<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) {
|
||
position: absolute;
|
||
pointer-events: none;
|
||
}
|
||
</style>
|