🎨 Добавлен полный редактор стилей и поле image_url для туров
✨ Новые функции: - Поле image_url в модели туров для изменения изображений через админ-панель - Расширенная модель настроек сайта с категориями: colors, typography, images, effects, layout - Динамический CSS генератор на основе настроек (/dynamic-styles.css) - API для управления настройками сайта (/api/site-settings) 🎯 Редактор стилей: - Управление цветами (основные, акцентные, текст, фон) - Настройка типографики (шрифты, размеры, межстрочный интервал) - Управление изображениями (фоны, логотипы, фавикон) - Эффекты (прозрачность, тени, размытие, скругления) - Макет (высота секций, размеры контейнеров) - Пользовательский CSS код 🛠️ Техническая реализация: - SiteSettingsHelper с кешированием для производительности - CSS переменные для динамического изменения стилей - Автоматическая миграция базы данных - Интеграция с AdminJS для удобного управления - Загрузка настроек в шаблоны для доступности 📊 База данных: - Расширена таблица site_settings (добавлено поле category) - Новые типы настроек: color, file - 27 предустановленных настроек для полного контроля над дизайном - Автоматическое применение миграций при старте приложения
This commit is contained in:
@@ -42,6 +42,7 @@ const Routes = sequelize.define('routes', {
|
||||
price: { type: DataTypes.DECIMAL(10, 2) },
|
||||
duration: { type: DataTypes.INTEGER },
|
||||
max_group_size: { type: DataTypes.INTEGER },
|
||||
image_url: { type: DataTypes.STRING },
|
||||
is_featured: { type: DataTypes.BOOLEAN, defaultValue: false },
|
||||
is_active: { type: DataTypes.BOOLEAN, defaultValue: true },
|
||||
created_at: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
|
||||
@@ -187,6 +188,20 @@ const Holidays = sequelize.define('holidays', {
|
||||
tableName: 'holidays'
|
||||
});
|
||||
|
||||
// Модель настроек сайта
|
||||
const SiteSettings = sequelize.define('site_settings', {
|
||||
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
|
||||
setting_key: { type: DataTypes.STRING, allowNull: false, unique: true },
|
||||
setting_value: { type: DataTypes.TEXT },
|
||||
setting_type: { type: DataTypes.ENUM('text', 'number', 'boolean', 'json', 'color', 'file'), defaultValue: 'text' },
|
||||
description: { type: DataTypes.TEXT },
|
||||
category: { type: DataTypes.STRING, defaultValue: 'general' },
|
||||
updated_at: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }
|
||||
}, {
|
||||
timestamps: false,
|
||||
tableName: 'site_settings'
|
||||
});
|
||||
|
||||
// Определение связей между моделями
|
||||
Guides.hasOne(GuideSchedules, { foreignKey: 'guide_id' });
|
||||
GuideSchedules.belongsTo(Guides, { foreignKey: 'guide_id' });
|
||||
@@ -222,8 +237,8 @@ const adminJsOptions = {
|
||||
options: {
|
||||
parent: { name: 'Контент', icon: 'DocumentText' },
|
||||
listProperties: ['id', 'title', 'type', 'price', 'duration', 'is_active', 'created_at'],
|
||||
editProperties: ['title', 'description', 'content', 'type', 'difficulty_level', 'price', 'duration', 'max_group_size', 'is_featured', 'is_active'],
|
||||
showProperties: ['id', 'title', 'description', 'content', 'type', 'difficulty_level', 'price', 'duration', 'max_group_size', 'is_featured', 'is_active', 'created_at', 'updated_at'],
|
||||
editProperties: ['title', 'description', 'content', 'type', 'difficulty_level', 'price', 'duration', 'max_group_size', 'image_url', 'is_featured', 'is_active'],
|
||||
showProperties: ['id', 'title', 'description', 'content', 'type', 'difficulty_level', 'price', 'duration', 'max_group_size', 'image_url', 'is_featured', 'is_active', 'created_at', 'updated_at'],
|
||||
filterProperties: ['title', 'type', 'is_active'],
|
||||
properties: {
|
||||
title: {
|
||||
@@ -263,6 +278,10 @@ const adminJsOptions = {
|
||||
type: 'number',
|
||||
isRequired: true,
|
||||
},
|
||||
image_url: {
|
||||
type: 'string',
|
||||
description: 'URL изображения тура (например: /images/tours/seoul-1.jpg)'
|
||||
},
|
||||
is_featured: { type: 'boolean' },
|
||||
is_active: { type: 'boolean' },
|
||||
created_at: {
|
||||
@@ -633,6 +652,58 @@ const adminJsOptions = {
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
resource: SiteSettings,
|
||||
options: {
|
||||
parent: { name: 'Администрирование', icon: 'Settings' },
|
||||
listProperties: ['id', 'setting_key', 'setting_value', 'category', 'updated_at'],
|
||||
editProperties: ['setting_key', 'setting_value', 'setting_type', 'description', 'category'],
|
||||
showProperties: ['id', 'setting_key', 'setting_value', 'setting_type', 'description', 'category', 'updated_at'],
|
||||
filterProperties: ['setting_key', 'category', 'setting_type'],
|
||||
properties: {
|
||||
setting_key: {
|
||||
isTitle: true,
|
||||
isRequired: true,
|
||||
description: 'Уникальный ключ настройки (например: primary_color, hero_background_url)'
|
||||
},
|
||||
setting_value: {
|
||||
type: 'textarea',
|
||||
isRequired: true,
|
||||
description: 'Значение настройки (цвет в HEX, URL изображения, текст и т.д.)'
|
||||
},
|
||||
setting_type: {
|
||||
availableValues: [
|
||||
{ value: 'text', label: 'Текст' },
|
||||
{ value: 'number', label: 'Число' },
|
||||
{ value: 'boolean', label: 'Да/Нет' },
|
||||
{ value: 'json', label: 'JSON' },
|
||||
{ value: 'color', label: 'Цвет (HEX)' },
|
||||
{ value: 'file', label: 'Файл/URL' }
|
||||
],
|
||||
isRequired: true
|
||||
},
|
||||
description: {
|
||||
type: 'textarea',
|
||||
description: 'Описание назначения этой настройки'
|
||||
},
|
||||
category: {
|
||||
availableValues: [
|
||||
{ value: 'general', label: 'Общие' },
|
||||
{ value: 'theme', label: 'Тема и стили' },
|
||||
{ value: 'colors', label: 'Цвета' },
|
||||
{ value: 'typography', label: 'Типографика' },
|
||||
{ value: 'images', label: 'Изображения' },
|
||||
{ value: 'effects', label: 'Эффекты' },
|
||||
{ value: 'layout', label: 'Макет' }
|
||||
],
|
||||
defaultValue: 'general'
|
||||
},
|
||||
updated_at: {
|
||||
isVisible: { list: true, filter: true, show: true, edit: false },
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
],
|
||||
rootPath: '/admin',
|
||||
|
||||
Reference in New Issue
Block a user