* блокировка изменения отчета для врача
* вывод данных из отчетов для ролей адм и зав * поправил ширину стобцов ввода * добавил календарь на страницу статистики * переделал календарь у заведующего на странице отчета * добавил и привязал метрики в статистику
This commit is contained in:
117
resources/js/Components/DatePickerQuery.vue
Normal file
117
resources/js/Components/DatePickerQuery.vue
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -22,7 +22,11 @@ const themeOverrides = {
|
||||
<NLayout position="absolute">
|
||||
|
||||
<NLayoutHeader style="height: 48px;" bordered>
|
||||
<AppHeader />
|
||||
<AppHeader>
|
||||
<template #headerExtra>
|
||||
<slot name="headerExtra" />
|
||||
</template>
|
||||
</AppHeader>
|
||||
</NLayoutHeader>
|
||||
|
||||
<NLayout has-sider position="absolute" class="top-12!" content-class="relative" :native-scrollbar="false">
|
||||
|
||||
@@ -4,13 +4,21 @@ import ReportSelectDate from "../../Components/ReportSelectDate.vue";
|
||||
import AppUserButton from "./AppUserButton.vue";
|
||||
import {Link} from "@inertiajs/vue3";
|
||||
import AppHeaderRole from "./AppHeaderRole.vue";
|
||||
import {computed, useSlots} from "vue";
|
||||
|
||||
const slots = useSlots()
|
||||
const hasHeaderExtra = computed(() => !!slots.headerExtra)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid grid-cols-[auto_1fr_auto] px-4 w-full h-full">
|
||||
<NButton :tag="Link" text href="/">
|
||||
Метрика
|
||||
</NButton>
|
||||
<NSpace align="center">
|
||||
<NButton :tag="Link" text href="/">
|
||||
Метрика
|
||||
</NButton>
|
||||
<NDivider v-if="hasHeaderExtra" vertical />
|
||||
<slot name="headerExtra" />
|
||||
</NSpace>
|
||||
<div></div>
|
||||
<AppUserButton />
|
||||
</div>
|
||||
|
||||
@@ -54,7 +54,7 @@ const reportButtonType = computed(() => authStore.isDoctor ? 'button' : Link)
|
||||
/>
|
||||
<StartButton title="Статистика моего отделения"
|
||||
:description="`Ваше отделение в системе: ${authStore.userDepartment.name_short}`"
|
||||
:href="`/statistic?sent_at=${reportStore.timestampCurrentRange}&groupId=1`"
|
||||
:href="`/statistic`"
|
||||
:icon="TbChartTreemap"
|
||||
/>
|
||||
<StartButton title="Выйти из системы"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { NFlex, NButton } from 'naive-ui'
|
||||
import { NFlex, NAlert, NButton } from 'naive-ui'
|
||||
import ReportHeader from "./ReportHeader.vue";
|
||||
import ReportFormInput from "./ReportFormInput.vue";
|
||||
import ReportSection from "./ReportSection.vue";
|
||||
@@ -28,6 +28,9 @@ const onSubmit = () => {
|
||||
|
||||
<template>
|
||||
<NFlex vertical class="max-w-6xl mx-auto mt-6 mb-4 w-full">
|
||||
<NAlert type="warning" v-if="reportStore.reportInfo.report?.message">
|
||||
{{ reportStore.reportInfo.report.message }}
|
||||
</NAlert>
|
||||
<ReportHeader :mode="mode" />
|
||||
|
||||
<ReportFormInput />
|
||||
|
||||
@@ -5,6 +5,7 @@ import {useAuthStore} from "../../../Stores/auth.js";
|
||||
|
||||
const reportStore = useReportStore()
|
||||
const authStore = useAuthStore()
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -66,4 +67,8 @@ const authStore = useAuthStore()
|
||||
:deep(.n-statistic-value) {
|
||||
@apply flex justify-center items-center;
|
||||
}
|
||||
|
||||
:deep(.n-input-wrapper) {
|
||||
width: 120px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -66,7 +66,7 @@ const currentDate = computed(() => {
|
||||
</NSpace>
|
||||
|
||||
<div class="col-3 w-full">
|
||||
<ReportSelectDate />
|
||||
<ReportSelectDate :is-one-day="reportStore.reportInfo.report?.isOneDay"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ const isReadonlyMode = computed(() => props.mode.toLowerCase() === 'readonly')
|
||||
|
||||
<template>
|
||||
<NCard>
|
||||
<NCollapse>
|
||||
<NCollapse v-model:expanded-names="reportStore.openedCollapsible">
|
||||
<NCollapseItem name="1">
|
||||
<template #header>
|
||||
<ReportSectionHeader title="Планово" status="plan" />
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
<script setup>
|
||||
import {NDataTable} from 'naive-ui'
|
||||
import {NDataTable, NFlex, NText, NDatePicker} from 'naive-ui'
|
||||
import AppLayout from "../../Layouts/AppLayout.vue";
|
||||
import {ref} from "vue";
|
||||
import {h, ref} from "vue";
|
||||
import DatePickerQuery from "../../Components/DatePickerQuery.vue";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: []
|
||||
},
|
||||
isHeadOrAdmin: {
|
||||
type: Boolean
|
||||
},
|
||||
date: {
|
||||
type: [Number, Array]
|
||||
},
|
||||
isOneDay: {
|
||||
type: Boolean
|
||||
}
|
||||
})
|
||||
|
||||
@@ -15,7 +25,17 @@ const columns = ref([
|
||||
title: 'Отделение',
|
||||
key: 'department',
|
||||
width: 240,
|
||||
titleAlign: 'center'
|
||||
titleAlign: 'center',
|
||||
colSpan: (row) => row.colspan,
|
||||
render(row) {
|
||||
if (row.isGroupHeader) {
|
||||
return h(NFlex, {
|
||||
align: "center",
|
||||
justify: "center"
|
||||
}, h(NText, { style: 'font-weight: 600;' }, row.groupName))
|
||||
}
|
||||
return row.department
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Кол-во коек',
|
||||
@@ -24,42 +44,35 @@ const columns = ref([
|
||||
titleAlign: 'center',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'Состояло',
|
||||
key: '',
|
||||
width: 84,
|
||||
titleAlign: 'center',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'Поступило',
|
||||
key: 'received',
|
||||
key: 'recipients',
|
||||
titleAlign: 'center',
|
||||
children: [
|
||||
{
|
||||
title: 'Всего',
|
||||
key: 'all',
|
||||
key: 'recipients.all',
|
||||
width: 60,
|
||||
titleAlign: 'center',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'План',
|
||||
key: 'plan',
|
||||
key: 'recipients.plan',
|
||||
width: 60,
|
||||
titleAlign: 'center',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'Экстр',
|
||||
key: 'emergency',
|
||||
key: 'recipients.emergency',
|
||||
width: 60,
|
||||
titleAlign: 'center',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'Перевод',
|
||||
key: '',
|
||||
key: 'recipients.transferred',
|
||||
width: 84,
|
||||
titleAlign: 'center',
|
||||
align: 'center'
|
||||
@@ -68,7 +81,7 @@ const columns = ref([
|
||||
},
|
||||
{
|
||||
title: 'Выбыло',
|
||||
key: 'leave',
|
||||
key: 'outcome',
|
||||
width: 84,
|
||||
titleAlign: 'center',
|
||||
align: 'center'
|
||||
@@ -89,30 +102,46 @@ const columns = ref([
|
||||
},
|
||||
{
|
||||
title: 'Операции',
|
||||
key: '',
|
||||
key: 'surgical',
|
||||
titleAlign: 'center',
|
||||
children: [
|
||||
{
|
||||
title: 'Э',
|
||||
key: '',
|
||||
key: 'surgical.emergency',
|
||||
width: 60,
|
||||
titleAlign: 'center',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: 'П',
|
||||
key: '',
|
||||
key: 'surgical.plan',
|
||||
width: 60,
|
||||
titleAlign: 'center',
|
||||
align: 'center'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Умерло',
|
||||
key: 'deceased',
|
||||
width: 84,
|
||||
titleAlign: 'center',
|
||||
align: 'center'
|
||||
},
|
||||
])
|
||||
|
||||
const rowProps = (row) => {
|
||||
if (row.isGroupHeader) return {
|
||||
style: `--n-merged-td-color: var(--n-merged-th-color)`
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout>
|
||||
<template #headerExtra>
|
||||
<DatePickerQuery :is-head-or-admin="isHeadOrAdmin" :date="date" :is-one-day="isOneDay" />
|
||||
</template>
|
||||
<NDataTable :columns="columns"
|
||||
:data="data"
|
||||
size="small"
|
||||
@@ -120,6 +149,7 @@ const columns = ref([
|
||||
striped
|
||||
min-height="calc(100vh - 48px - 70px)"
|
||||
max-height="calc(100vh - 48px - 70px)"
|
||||
:row-props="rowProps"
|
||||
>
|
||||
|
||||
</NDataTable>
|
||||
|
||||
@@ -23,6 +23,9 @@ export const useReportStore = defineStore('reportStore', () => {
|
||||
|
||||
const dataOnReport = ref(null)
|
||||
|
||||
// Открытие collapse из ReportSectionItem
|
||||
const openedCollapsible = ref([])
|
||||
|
||||
const reportInfo = ref({
|
||||
userId: null
|
||||
})
|
||||
@@ -85,6 +88,7 @@ export const useReportStore = defineStore('reportStore', () => {
|
||||
unwantedEvents: unwantedEvents.value,
|
||||
dates: timestampCurrentRange.value,
|
||||
userId: reportInfo.value.userId,
|
||||
reportId: reportInfo.value.report.report_id,
|
||||
...assignForm
|
||||
}
|
||||
|
||||
@@ -122,7 +126,7 @@ export const useReportStore = defineStore('reportStore', () => {
|
||||
|
||||
reportForm.value.metrika_item_3 = reportInfo.value.department?.recipientCount
|
||||
reportForm.value.metrika_item_7 = reportInfo.value.department?.extractCount
|
||||
reportForm.value.metrika_item_8 = reportInfo.value.department?.currentCounts
|
||||
reportForm.value.metrika_item_8 = reportInfo.value.department?.currentCount
|
||||
|
||||
reportForm.value.metrika_item_9 = reportInfo.value.department?.deadCount
|
||||
reportForm.value.metrika_item_10 = reportInfo.value.department?.surgicalCount[1]
|
||||
@@ -143,6 +147,13 @@ export const useReportStore = defineStore('reportStore', () => {
|
||||
const getDataOnReportDate = async (dateRange) => {
|
||||
isLoadReportInfo.value = true
|
||||
timestampCurrentRange.value = dateRange
|
||||
openedCollapsible.value = []
|
||||
patientsData.value = {
|
||||
plan: [],
|
||||
emergency: [],
|
||||
observation: [],
|
||||
outcome: []
|
||||
}
|
||||
const queryParams = {
|
||||
userId: reportInfo.value.userId,
|
||||
startAt: timestampCurrentRange.value[0],
|
||||
@@ -185,6 +196,7 @@ export const useReportStore = defineStore('reportStore', () => {
|
||||
reportForm,
|
||||
departmentUsers,
|
||||
unwantedEvents,
|
||||
openedCollapsible,
|
||||
|
||||
getColumnsByKey,
|
||||
getDataOnReportDate,
|
||||
|
||||
46
resources/js/Utils/dateFormatter.js
Normal file
46
resources/js/Utils/dateFormatter.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import { format } from 'date-fns'
|
||||
import { ru } from 'date-fns/locale'
|
||||
|
||||
/**
|
||||
* Делает первую букву строки заглавной
|
||||
*/
|
||||
const capitalizeFirst = (str) => {
|
||||
if (!str) return ''
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Форматирует дату по-русски: "Вторник, 3 февраля 2026 г."
|
||||
*/
|
||||
export const formatRussianDate = (date) => {
|
||||
if (!date) return ''
|
||||
|
||||
const formatted = format(new Date(date), 'EEEE, d MMMM yyyy г.', { locale: ru })
|
||||
return capitalizeFirst(formatted)
|
||||
}
|
||||
|
||||
/**
|
||||
* Форматирует диапазон дат по-русски:
|
||||
* "С понедельника, 2 февраля 2026 г. по вторник, 3 февраля 2026 г."
|
||||
*/
|
||||
export const formatRussianDateRange = (dateRange) => {
|
||||
if (!dateRange || !Array.isArray(dateRange) || dateRange.length < 2) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const [startDate, endDate] = dateRange
|
||||
|
||||
if (!startDate || !endDate) return ''
|
||||
|
||||
const formattedStart = format(new Date(startDate), 'd MMMM yyyy г.', { locale: ru })
|
||||
const formattedEnd = format(new Date(endDate), 'd MMMM yyyy г.', { locale: ru })
|
||||
|
||||
return `С ${formattedStart.toLowerCase()} по ${formattedEnd.toLowerCase()}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Для совместимости со старым кодом
|
||||
*/
|
||||
export const formatDateWithCapital = (date) => {
|
||||
return formatRussianDate(date)
|
||||
}
|
||||
Reference in New Issue
Block a user