This commit is contained in:
Владимир Фёдоров 2026-03-26 12:27:39 +07:00
parent a895c0f910
commit aa8fe39310
3 changed files with 81 additions and 5 deletions

View File

@ -2,10 +2,10 @@
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { apiGetDays } from './client'; import { apiGetDays } from './client';
import type { Schedule } from './models'; import type { Schedule } from './models';
import { formatRussianDate, getRelativeDayName } from './date'; import { formatRussianDate, getRelativeDayName, timeAgo } from './date';
import { capitalizeFirstLetter } from './text'; import { capitalizeFirstLetter } from './text';
const schedule = ref<Schedule>({ days: [] }) const schedule = ref<Schedule>({ updateTime: "", days: [] })
onMounted(async () => { onMounted(async () => {
schedule.value = await apiGetDays() schedule.value = await apiGetDays()
@ -15,6 +15,7 @@ onMounted(async () => {
<template> <template>
<div> <div>
Обновлено: {{ timeAgo(schedule.updateTime) }}
<div v-for="day in schedule.days" :key="day.date" class="day-block"> <div v-for="day in schedule.days" :key="day.date" class="day-block">
{{ capitalizeFirstLetter(formatRussianDate(day.date)) }} {{ capitalizeFirstLetter(formatRussianDate(day.date)) }}
<span v-if="getRelativeDayName(day.date) !== ''">({{ getRelativeDayName(day.date) }})</span> <span v-if="getRelativeDayName(day.date) !== ''">({{ getRelativeDayName(day.date) }})</span>
@ -53,7 +54,5 @@ onMounted(async () => {
border-radius: 10px; border-radius: 10px;
} }
.performance-block { .performance-block {}
}
</style> </style>

View File

@ -73,3 +73,79 @@ export function getRelativeDayName(dateStr: string): string {
return ""; return "";
} }
} }
/**
* Функция для склонения слов (1 минута, 2 минуты, 5 минут)
*/
function getDeclension(number: number, titles: [string, string, string]): string {
const cases = [2, 0, 1, 1, 1, 2];
return titles[
(number % 100 > 4 && number % 100 < 20)
? 2
: cases[(number % 10 < 5) ? number % 10 : 5]
];
}
/**
* Основная функция форматирования времени
*/
export function timeAgo(goDateStr: string): string {
// 1. Парсим строку регуляркой, чтобы вытащить дату, время и смещение пояса.
// Игнорируем "m=+..." и доли секунд, так как для "5 минут назад" они не нужны.
// Группы: 1-Дата, 2-Время, 3-Часовой пояс (например +0700)
const regex = /^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})(?:\.\d+)? ([+-]\d{4})/;
const match = goDateStr.match(regex);
if (!match) {
console.error("Неверный формат даты:", goDateStr);
return goDateStr; // Возвращаем как есть в случае ошибки
}
const datePart = match[1];
const timePart = match[2];
const timezone = match[3];
// 2. Приводим к формату ISO 8601, который понимает любой браузер:
// "2026-03-26T12:11:18+0700"
const isoString = `${datePart}T${timePart}${timezone}`;
const date = new Date(isoString);
const now = new Date();
// 3. Считаем разницу в секундах
const seconds = Math.floor((now.getTime() - date.getTime()) / 1000);
// Если дата в будущем (например, как в вашем примере 2026 год)
if (seconds < 0) {
return "в будущем";
}
// 4. Логика интервалов
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (seconds < 60) {
return "только что";
}
if (minutes < 60) {
return `${minutes} ${getDeclension(minutes, ['минуту', 'минуты', 'минут'])} назад`;
}
if (hours < 24) {
return `${hours} ${getDeclension(hours, ['час', 'часа', 'часов'])} назад`;
}
if (days < 7) {
return `${days} ${getDeclension(days, ['день', 'дня', 'дней'])} назад`;
}
// Если прошло больше недели, возвращаем просто дату
// Можно использовать Intl.DateTimeFormat для красоты
return date.toLocaleDateString("ru-RU", {
day: "numeric",
month: "long",
year: "numeric"
});
}

View File

@ -1,4 +1,5 @@
export type Schedule = { export type Schedule = {
updateTime: string
days: Day[] days: Day[]
} }