✨ Компактные hero секции и улучшенная инициализация БД
🎨 UI улучшения: - Уменьшена высота синих панелей с 100vh до 70vh на главной - Добавлен класс .compact (25vh) для всех остальных страниц - Улучшена адаптивность для мобильных устройств - Обновлены все шаблоны с hero секциями 🚀 Инфраструктура: - Автоматическая инициализация базы данных при деплое - Улучшены мокапные данные (больше отзывов, бронирований, сообщений) - Добавлены настройки сайта в базу данных - Создан скрипт автоматического деплоя deploy.sh 📦 Система сборки: - Обновлен .gitignore с полным покрытием файлов - Добавлена папка для загрузок с .gitkeep - Улучшен README с инструкциями по запуску - ES модули для инициализации базы данных 🐛 Исправления: - Совместимость с ES модулями в Node.js - Правильная обработка ошибок инициализации БД - Корректные SQL запросы для PostgreSQL
This commit is contained in:
106
database/run-migration.js
Normal file
106
database/run-migration.js
Normal file
@@ -0,0 +1,106 @@
|
||||
import pool from '../src/config/database.js';
|
||||
|
||||
const migrateRatingSystem = async () => {
|
||||
try {
|
||||
console.log('🔄 Выполняю миграцию для системы рейтингов...');
|
||||
|
||||
// Создание таблицы ratings
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS ratings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_ip VARCHAR(45) NOT NULL,
|
||||
target_id INTEGER NOT NULL,
|
||||
target_type VARCHAR(20) NOT NULL CHECK (target_type IN ('route', 'guide', 'article')),
|
||||
rating INTEGER NOT NULL CHECK (rating IN (1, -1)),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(user_ip, target_id, target_type)
|
||||
);
|
||||
`);
|
||||
|
||||
// Создание таблицы guide_schedules
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS guide_schedules (
|
||||
id SERIAL PRIMARY KEY,
|
||||
guide_id INTEGER NOT NULL REFERENCES guides(id) ON DELETE CASCADE,
|
||||
monday BOOLEAN DEFAULT true,
|
||||
tuesday BOOLEAN DEFAULT true,
|
||||
wednesday BOOLEAN DEFAULT true,
|
||||
thursday BOOLEAN DEFAULT true,
|
||||
friday BOOLEAN DEFAULT true,
|
||||
saturday BOOLEAN DEFAULT false,
|
||||
sunday BOOLEAN DEFAULT false,
|
||||
start_time TIME DEFAULT '09:00',
|
||||
end_time TIME DEFAULT '18:00',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(guide_id)
|
||||
);
|
||||
`);
|
||||
|
||||
// Создание таблицы holidays
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS holidays (
|
||||
id SERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
type VARCHAR(20) NOT NULL CHECK (type IN ('public', 'guide_personal')),
|
||||
guide_id INTEGER REFERENCES guides(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(date, guide_id)
|
||||
);
|
||||
`);
|
||||
|
||||
// Добавление колонок в bookings (если не существуют)
|
||||
try {
|
||||
await pool.query('ALTER TABLE bookings ADD COLUMN guide_id INTEGER REFERENCES guides(id);');
|
||||
} catch (e) {
|
||||
console.log('Колонка guide_id уже существует');
|
||||
}
|
||||
|
||||
try {
|
||||
await pool.query('ALTER TABLE bookings ADD COLUMN route_id INTEGER REFERENCES routes(id);');
|
||||
} catch (e) {
|
||||
console.log('Колонка route_id уже существует');
|
||||
}
|
||||
|
||||
// Создание индексов
|
||||
await pool.query('CREATE INDEX IF NOT EXISTS idx_ratings_target ON ratings(target_type, target_id);');
|
||||
await pool.query('CREATE INDEX IF NOT EXISTS idx_ratings_user_ip ON ratings(user_ip);');
|
||||
await pool.query('CREATE INDEX IF NOT EXISTS idx_bookings_date ON bookings(preferred_date);');
|
||||
await pool.query('CREATE INDEX IF NOT EXISTS idx_bookings_guide ON bookings(guide_id);');
|
||||
await pool.query('CREATE INDEX IF NOT EXISTS idx_holidays_date ON holidays(date);');
|
||||
|
||||
// Функция для подсчета рейтинга
|
||||
await pool.query(`
|
||||
CREATE OR REPLACE FUNCTION calculate_rating(target_type_param VARCHAR, target_id_param INTEGER)
|
||||
RETURNS TABLE(
|
||||
likes_count BIGINT,
|
||||
dislikes_count BIGINT,
|
||||
total_votes BIGINT,
|
||||
rating_percentage NUMERIC(5,2)
|
||||
) AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT
|
||||
COUNT(CASE WHEN rating = 1 THEN 1 END) as likes_count,
|
||||
COUNT(CASE WHEN rating = -1 THEN 1 END) as dislikes_count,
|
||||
COUNT(*) as total_votes,
|
||||
CASE
|
||||
WHEN COUNT(*) = 0 THEN 0
|
||||
ELSE ROUND((COUNT(CASE WHEN rating = 1 THEN 1 END)::NUMERIC / COUNT(*)::NUMERIC) * 100, 2)
|
||||
END as rating_percentage
|
||||
FROM ratings
|
||||
WHERE target_type = target_type_param AND target_id = target_id_param;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
`);
|
||||
|
||||
console.log('✅ Миграция выполнена успешно!');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка миграции:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
migrateRatingSystem();
|
||||
Reference in New Issue
Block a user