🎨 UI улучшения: - Уменьшена высота синих панелей с 100vh до 70vh на главной - Добавлен класс .compact (25vh) для всех остальных страниц - Улучшена адаптивность для мобильных устройств - Обновлены все шаблоны с hero секциями 🚀 Инфраструктура: - Автоматическая инициализация базы данных при деплое - Улучшены мокапные данные (больше отзывов, бронирований, сообщений) - Добавлены настройки сайта в базу данных - Создан скрипт автоматического деплоя deploy.sh 📦 Система сборки: - Обновлен .gitignore с полным покрытием файлов - Добавлена папка для загрузок с .gitkeep - Улучшен README с инструкциями по запуску - ES модули для инициализации базы данных 🐛 Исправления: - Совместимость с ES модулями в Node.js - Правильная обработка ошибок инициализации БД - Корректные SQL запросы для PostgreSQL
106 lines
4.0 KiB
JavaScript
106 lines
4.0 KiB
JavaScript
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(); |