AdminLTE3

This commit is contained in:
2025-10-26 22:14:47 +09:00
parent 291fc63a4c
commit 9974811a3e
226 changed files with 88284 additions and 3406 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,496 @@
const express = require('express');
const router = express.Router();
const multer = require('multer');
const path = require('path');
const { Portfolio, Service, Contact, User } = require('../../models');
// Multer configuration for file uploads
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/uploads/');
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (file.mimetype.startsWith('image/')) {
cb(null, true);
} else {
cb(new Error('Only image files are allowed!'), false);
}
},
limits: {
fileSize: 10 * 1024 * 1024 // 10MB
}
});
// Authentication middleware
const requireAuth = (req, res, next) => {
if (!req.session.user) {
return res.status(401).json({ success: false, message: 'Authentication required' });
}
next();
};
// Portfolio API Routes
router.post('/portfolio', requireAuth, upload.array('images', 10), async (req, res) => {
try {
const {
title,
shortDescription,
description,
category,
clientName,
projectUrl,
githubUrl,
technologies,
featured,
isPublished
} = req.body;
// Process uploaded images
const images = req.files ? req.files.map((file, index) => ({
url: `/uploads/${file.filename}`,
alt: `${title} image ${index + 1}`,
isPrimary: index === 0
})) : [];
// Parse technologies
let techArray = [];
if (technologies) {
try {
techArray = JSON.parse(technologies);
} catch (e) {
techArray = technologies.split(',').map(t => t.trim());
}
}
const portfolio = await Portfolio.create({
title,
shortDescription,
description,
category,
clientName,
projectUrl: projectUrl || null,
githubUrl: githubUrl || null,
technologies: techArray,
images,
featured: featured === 'on',
isPublished: isPublished === 'on',
status: 'completed',
publishedAt: isPublished === 'on' ? new Date() : null
});
res.json({ success: true, portfolio });
} catch (error) {
console.error('Portfolio creation error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.patch('/portfolio/:id', requireAuth, upload.array('images', 10), async (req, res) => {
try {
const portfolio = await Portfolio.findByPk(req.params.id);
if (!portfolio) {
return res.status(404).json({ success: false, message: 'Portfolio not found' });
}
const updates = { ...req.body };
// Handle checkboxes
updates.featured = updates.featured === 'on';
updates.isPublished = updates.isPublished === 'on';
// Process technologies
if (updates.technologies) {
try {
updates.technologies = JSON.parse(updates.technologies);
} catch (e) {
updates.technologies = updates.technologies.split(',').map(t => t.trim());
}
}
// Process new images
if (req.files && req.files.length > 0) {
const newImages = req.files.map((file, index) => ({
url: `/uploads/${file.filename}`,
alt: `${updates.title || portfolio.title} image ${index + 1}`,
isPrimary: index === 0 && (!portfolio.images || portfolio.images.length === 0)
}));
updates.images = [...(portfolio.images || []), ...newImages];
}
await portfolio.update(updates);
res.json({ success: true, portfolio });
} catch (error) {
console.error('Portfolio update error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.delete('/portfolio/:id', requireAuth, async (req, res) => {
try {
const portfolio = await Portfolio.findByPk(req.params.id);
if (!portfolio) {
return res.status(404).json({ success: false, message: 'Portfolio not found' });
}
await portfolio.destroy();
res.json({ success: true });
} catch (error) {
console.error('Portfolio deletion error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
// Services API Routes
router.post('/services', requireAuth, async (req, res) => {
try {
const {
name,
description,
shortDescription,
icon,
category,
features,
pricing,
estimatedTime,
isActive,
featured,
tags
} = req.body;
// Parse arrays
let featuresArray = [];
let tagsArray = [];
let pricingObj = {};
if (features) {
try {
featuresArray = JSON.parse(features);
} catch (e) {
featuresArray = features.split(',').map(f => f.trim());
}
}
if (tags) {
try {
tagsArray = JSON.parse(tags);
} catch (e) {
tagsArray = tags.split(',').map(t => t.trim());
}
}
if (pricing) {
try {
pricingObj = JSON.parse(pricing);
} catch (e) {
pricingObj = { basePrice: pricing };
}
}
const service = await Service.create({
name,
description,
shortDescription,
icon,
category,
features: featuresArray,
pricing: pricingObj,
estimatedTime,
isActive: isActive === 'on',
featured: featured === 'on',
tags: tagsArray
});
res.json({ success: true, service });
} catch (error) {
console.error('Service creation error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.put('/services/:id', requireAuth, async (req, res) => {
try {
const service = await Service.findByPk(req.params.id);
if (!service) {
return res.status(404).json({ success: false, message: 'Service not found' });
}
const {
name,
description,
shortDescription,
icon,
category,
features,
pricing,
estimatedTime,
isActive,
featured,
tags,
order,
seo
} = req.body;
// Parse arrays and objects
let featuresArray = [];
let tagsArray = [];
let pricingObj = {};
let seoObj = {};
if (features) {
if (Array.isArray(features)) {
featuresArray = features;
} else {
try {
featuresArray = JSON.parse(features);
} catch (e) {
featuresArray = features.split(',').map(f => f.trim());
}
}
}
if (tags) {
if (Array.isArray(tags)) {
tagsArray = tags;
} else {
try {
tagsArray = JSON.parse(tags);
} catch (e) {
tagsArray = tags.split(',').map(t => t.trim());
}
}
}
if (pricing) {
if (typeof pricing === 'object') {
pricingObj = pricing;
} else {
try {
pricingObj = JSON.parse(pricing);
} catch (e) {
pricingObj = { basePrice: pricing };
}
}
}
if (seo) {
if (typeof seo === 'object') {
seoObj = seo;
} else {
try {
seoObj = JSON.parse(seo);
} catch (e) {
seoObj = {};
}
}
}
const updateData = {
name,
description,
shortDescription,
icon,
category,
features: featuresArray,
pricing: pricingObj,
estimatedTime,
isActive: Boolean(isActive),
featured: Boolean(featured),
tags: tagsArray,
order: order ? parseInt(order) : 0,
seo: seoObj
};
// Remove undefined values
Object.keys(updateData).forEach(key => {
if (updateData[key] === undefined) {
delete updateData[key];
}
});
await service.update(updateData);
res.json({ success: true, service });
} catch (error) {
console.error('Service update error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.delete('/services/:id', requireAuth, async (req, res) => {
try {
const service = await Service.findByPk(req.params.id);
if (!service) {
return res.status(404).json({ success: false, message: 'Service not found' });
}
await service.destroy();
res.json({ success: true });
} catch (error) {
console.error('Service deletion error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
// Contacts API Routes
router.patch('/contacts/:id', requireAuth, async (req, res) => {
try {
const contact = await Contact.findByPk(req.params.id);
if (!contact) {
return res.status(404).json({ success: false, message: 'Contact not found' });
}
await contact.update(req.body);
res.json({ success: true, contact });
} catch (error) {
console.error('Contact update error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.delete('/contacts/:id', requireAuth, async (req, res) => {
try {
const contact = await Contact.findByPk(req.params.id);
if (!contact) {
return res.status(404).json({ success: false, message: 'Contact not found' });
}
await contact.destroy();
res.json({ success: true });
} catch (error) {
console.error('Contact deletion error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
// Telegram notification for contact
router.post('/contacts/:id/telegram', requireAuth, async (req, res) => {
try {
const contact = await Contact.findByPk(req.params.id);
if (!contact) {
return res.status(404).json({ success: false, message: 'Contact not found' });
}
// Send Telegram notification
const telegramService = require('../../services/telegram');
const result = await telegramService.sendContactNotification(contact);
if (result.success) {
res.json({ success: true });
} else {
res.status(500).json({ success: false, message: result.message || result.error });
}
} catch (error) {
console.error('Telegram notification error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
// Test Telegram connection
router.post('/telegram/test', requireAuth, async (req, res) => {
try {
const { botToken, chatId } = req.body;
// Temporarily set up telegram service with provided credentials
const axios = require('axios');
// Test bot info
const botResponse = await axios.get(`https://api.telegram.org/bot${botToken}/getMe`);
// Test sending a message
const testMessage = '✅ Telegram bot подключен успешно!\n\nЭто тестовое сообщение от SmartSolTech Admin Panel.';
await axios.post(`https://api.telegram.org/bot${botToken}/sendMessage`, {
chat_id: chatId,
text: testMessage,
parse_mode: 'Markdown'
});
res.json({
success: true,
bot: botResponse.data.result,
message: 'Test message sent successfully'
});
} catch (error) {
console.error('Telegram test error:', error);
let message = 'Connection failed';
if (error.response?.data?.description) {
message = error.response.data.description;
} else if (error.message) {
message = error.message;
}
res.status(400).json({ success: false, message });
}
});
// Settings API
const { SiteSettings } = require('../../models');
router.get('/settings', requireAuth, async (req, res) => {
try {
const settings = await SiteSettings.findOne() || {};
res.json({ success: true, settings });
} catch (error) {
console.error('Settings fetch error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.post('/settings', requireAuth, upload.fields([
{ name: 'logo', maxCount: 1 },
{ name: 'favicon', maxCount: 1 }
]), async (req, res) => {
try {
let settings = await SiteSettings.findOne();
if (!settings) {
settings = await SiteSettings.create({});
}
const updates = {};
// Handle nested objects
Object.keys(req.body).forEach(key => {
if (key.includes('.')) {
const [parent, child] = key.split('.');
if (!updates[parent]) updates[parent] = {};
updates[parent][child] = req.body[key];
} else {
updates[key] = req.body[key];
}
});
// Handle file uploads
if (req.files.logo) {
updates.logo = `/uploads/${req.files.logo[0].filename}`;
}
if (req.files.favicon) {
updates.favicon = `/uploads/${req.files.favicon[0].filename}`;
}
// Update existing settings with new values
Object.keys(updates).forEach(key => {
if (typeof updates[key] === 'object' && updates[key] !== null) {
settings[key] = { ...settings[key], ...updates[key] };
} else {
settings[key] = updates[key];
}
});
await settings.save();
res.json({ success: true, settings });
} catch (error) {
console.error('Settings update error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
module.exports = router;

View File

@@ -0,0 +1,496 @@
const express = require('express');
const router = express.Router();
const multer = require('multer');
const path = require('path');
const { Portfolio, Service, Contact, User } = require('../../models');
// Multer configuration for file uploads
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/uploads/');
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (file.mimetype.startsWith('image/')) {
cb(null, true);
} else {
cb(new Error('Only image files are allowed!'), false);
}
},
limits: {
fileSize: 10 * 1024 * 1024 // 10MB
}
});
// Authentication middleware
const requireAuth = (req, res, next) => {
if (!req.session.user) {
return res.status(401).json({ success: false, message: 'Authentication required' });
}
next();
};
// Portfolio API Routes
router.post('/portfolio', requireAuth, upload.array('images', 10), async (req, res) => {
try {
const {
title,
shortDescription,
description,
category,
clientName,
projectUrl,
githubUrl,
technologies,
featured,
isPublished
} = req.body;
// Process uploaded images
const images = req.files ? req.files.map((file, index) => ({
url: `/uploads/${file.filename}`,
alt: `${title} image ${index + 1}`,
isPrimary: index === 0
})) : [];
// Parse technologies
let techArray = [];
if (technologies) {
try {
techArray = JSON.parse(technologies);
} catch (e) {
techArray = technologies.split(',').map(t => t.trim());
}
}
const portfolio = await Portfolio.create({
title,
shortDescription,
description,
category,
clientName,
projectUrl: projectUrl || null,
githubUrl: githubUrl || null,
technologies: techArray,
images,
featured: featured === 'on',
isPublished: isPublished === 'on',
status: 'completed',
publishedAt: isPublished === 'on' ? new Date() : null
});
res.json({ success: true, portfolio });
} catch (error) {
console.error('Portfolio creation error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.patch('/portfolio/:id', requireAuth, upload.array('images', 10), async (req, res) => {
try {
const portfolio = await Portfolio.findByPk(req.params.id);
if (!portfolio) {
return res.status(404).json({ success: false, message: 'Portfolio not found' });
}
const updates = { ...req.body };
// Handle checkboxes
updates.featured = updates.featured === 'on';
updates.isPublished = updates.isPublished === 'on';
// Process technologies
if (updates.technologies) {
try {
updates.technologies = JSON.parse(updates.technologies);
} catch (e) {
updates.technologies = updates.technologies.split(',').map(t => t.trim());
}
}
// Process new images
if (req.files && req.files.length > 0) {
const newImages = req.files.map((file, index) => ({
url: `/uploads/${file.filename}`,
alt: `${updates.title || portfolio.title} image ${index + 1}`,
isPrimary: index === 0 && (!portfolio.images || portfolio.images.length === 0)
}));
updates.images = [...(portfolio.images || []), ...newImages];
}
await portfolio.update(updates);
res.json({ success: true, portfolio });
} catch (error) {
console.error('Portfolio update error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.delete('/portfolio/:id', requireAuth, async (req, res) => {
try {
const portfolio = await Portfolio.findByPk(req.params.id);
if (!portfolio) {
return res.status(404).json({ success: false, message: 'Portfolio not found' });
}
await portfolio.destroy();
res.json({ success: true });
} catch (error) {
console.error('Portfolio deletion error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
// Services API Routes
router.post('/services', requireAuth, async (req, res) => {
try {
const {
name,
description,
shortDescription,
icon,
category,
features,
pricing,
estimatedTime,
isActive,
featured,
tags
} = req.body;
// Parse arrays
let featuresArray = [];
let tagsArray = [];
let pricingObj = {};
if (features) {
try {
featuresArray = JSON.parse(features);
} catch (e) {
featuresArray = features.split(',').map(f => f.trim());
}
}
if (tags) {
try {
tagsArray = JSON.parse(tags);
} catch (e) {
tagsArray = tags.split(',').map(t => t.trim());
}
}
if (pricing) {
try {
pricingObj = JSON.parse(pricing);
} catch (e) {
pricingObj = { basePrice: pricing };
}
}
const service = await Service.create({
name,
description,
shortDescription,
icon,
category,
features: featuresArray,
pricing: pricingObj,
estimatedTime,
isActive: isActive === 'on',
featured: featured === 'on',
tags: tagsArray
});
res.json({ success: true, service });
} catch (error) {
console.error('Service creation error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.put('/services/:id', requireAuth, async (req, res) => {
try {
const service = await Service.findByPk(req.params.id);
if (!service) {
return res.status(404).json({ success: false, message: 'Service not found' });
}
const {
name,
description,
shortDescription,
icon,
category,
features,
pricing,
estimatedTime,
isActive,
featured,
tags,
order,
seo
} = req.body;
// Parse arrays and objects
let featuresArray = [];
let tagsArray = [];
let pricingObj = {};
let seoObj = {};
if (features) {
if (Array.isArray(features)) {
featuresArray = features;
} else {
try {
featuresArray = JSON.parse(features);
} catch (e) {
featuresArray = features.split(',').map(f => f.trim());
}
}
}
if (tags) {
if (Array.isArray(tags)) {
tagsArray = tags;
} else {
try {
tagsArray = JSON.parse(tags);
} catch (e) {
tagsArray = tags.split(',').map(t => t.trim());
}
}
}
if (pricing) {
if (typeof pricing === 'object') {
pricingObj = pricing;
} else {
try {
pricingObj = JSON.parse(pricing);
} catch (e) {
pricingObj = { basePrice: pricing };
}
}
}
if (seo) {
if (typeof seo === 'object') {
seoObj = seo;
} else {
try {
seoObj = JSON.parse(seo);
} catch (e) {
seoObj = {};
}
}
}
const updateData = {
name,
description,
shortDescription,
icon,
category,
features: featuresArray,
pricing: pricingObj,
estimatedTime,
isActive: Boolean(isActive),
featured: Boolean(featured),
tags: tagsArray,
order: order ? parseInt(order) : 0,
seo: seoObj
};
// Remove undefined values
Object.keys(updateData).forEach(key => {
if (updateData[key] === undefined) {
delete updateData[key];
}
});
await service.update(updateData);
res.json({ success: true, service });
} catch (error) {
console.error('Service update error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.delete('/services/:id', requireAuth, async (req, res) => {
try {
const service = await Service.findByPk(req.params.id);
if (!service) {
return res.status(404).json({ success: false, message: 'Service not found' });
}
await service.destroy();
res.json({ success: true });
} catch (error) {
console.error('Service deletion error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
// Contacts API Routes
router.patch('/contacts/:id', requireAuth, async (req, res) => {
try {
const contact = await Contact.findByPk(req.params.id);
if (!contact) {
return res.status(404).json({ success: false, message: 'Contact not found' });
}
await contact.update(req.body);
res.json({ success: true, contact });
} catch (error) {
console.error('Contact update error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.delete('/contacts/:id', requireAuth, async (req, res) => {
try {
const contact = await Contact.findByPk(req.params.id);
if (!contact) {
return res.status(404).json({ success: false, message: 'Contact not found' });
}
await contact.destroy();
res.json({ success: true });
} catch (error) {
console.error('Contact deletion error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
// Telegram notification for contact
router.post('/contacts/:id/telegram', requireAuth, async (req, res) => {
try {
const contact = await Contact.findByPk(req.params.id);
if (!contact) {
return res.status(404).json({ success: false, message: 'Contact not found' });
}
// Send Telegram notification
const telegramService = require('../../services/telegram');
const result = await telegramService.sendContactNotification(contact);
if (result.success) {
res.json({ success: true });
} else {
res.status(500).json({ success: false, message: result.message || result.error });
}
} catch (error) {
console.error('Telegram notification error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
// Test Telegram connection
router.post('/telegram/test', requireAuth, async (req, res) => {
try {
const { botToken, chatId } = req.body;
// Temporarily set up telegram service with provided credentials
const axios = require('axios');
// Test bot info
const botResponse = await axios.get(`https://api.telegram.org/bot${botToken}/getMe`);
// Test sending a message
const testMessage = '✅ Telegram bot подключен успешно!\n\nЭто тестовое сообщение от SmartSolTech Admin Panel.';
await axios.post(`https://api.telegram.org/bot${botToken}/sendMessage`, {
chat_id: chatId,
text: testMessage,
parse_mode: 'Markdown'
});
res.json({
success: true,
bot: botResponse.data.result,
message: 'Test message sent successfully'
});
} catch (error) {
console.error('Telegram test error:', error);
let message = 'Connection failed';
if (error.response?.data?.description) {
message = error.response.data.description;
} else if (error.message) {
message = error.message;
}
res.status(400).json({ success: false, message });
}
});
// Settings API
const { SiteSettings } = require('../../models');
router.get('/settings', requireAuth, async (req, res) => {
try {
const settings = await SiteSettings.findOne() || {};
res.json({ success: true, settings });
} catch (error) {
console.error('Settings fetch error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
router.post('/settings', requireAuth, upload.fields([
{ name: 'logo', maxCount: 1 },
{ name: 'favicon', maxCount: 1 }
]), async (req, res) => {
try {
let settings = await SiteSettings.findOne();
if (!settings) {
settings = await SiteSettings.create({});
}
const updates = {};
// Handle nested objects
Object.keys(req.body).forEach(key => {
if (key.includes('.')) {
const [parent, child] = key.split('.');
if (!updates[parent]) updates[parent] = {};
updates[parent][child] = req.body[key];
} else {
updates[key] = req.body[key];
}
});
// Handle file uploads
if (req.files.logo) {
updates.logo = `/uploads/${req.files.logo[0].filename}`;
}
if (req.files.favicon) {
updates.favicon = `/uploads/${req.files.favicon[0].filename}`;
}
// Update existing settings with new values
Object.keys(updates).forEach(key => {
if (typeof updates[key] === 'object' && updates[key] !== null) {
settings[key] = { ...settings[key], ...updates[key] };
} else {
settings[key] = updates[key];
}
});
await settings.save();
res.json({ success: true, settings });
} catch (error) {
console.error('Settings update error:', error);
res.status(500).json({ success: false, message: error.message });
}
});
module.exports = router;

View File

@@ -0,0 +1,77 @@
const express = require('express');
const router = express.Router();
// Демо-роут для AdminLTE админки
router.get('/demo-adminlte', async (req, res) => {
try {
// Мок-данные для демонстрации
const stats = {
portfolioCount: 12,
servicesCount: 6,
contactsCount: 24,
usersCount: 3
};
const recentPortfolio = [
{
title: '삼성 모바일 앱 개발',
category: 'mobile-app',
status: 'completed',
createdAt: new Date('2024-10-20')
},
{
title: 'LG 웹사이트 리뉴얼',
category: 'web-development',
status: 'in-progress',
createdAt: new Date('2024-10-18')
},
{
title: '현대차 UI/UX 디자인',
category: 'ui-ux-design',
status: 'planning',
createdAt: new Date('2024-10-15')
}
];
const recentContacts = [
{
name: '김철수',
email: 'kim@example.com',
status: 'pending',
createdAt: new Date('2024-10-25')
},
{
name: '이영희',
email: 'lee@company.kr',
status: 'replied',
createdAt: new Date('2024-10-24')
},
{
name: '박민수',
email: 'park@startup.co.kr',
status: 'new',
createdAt: new Date('2024-10-23')
}
];
const user = {
name: '관리자'
};
res.render('admin/dashboard-adminlte', {
layout: 'admin/layout-adminlte',
title: '대시보드',
currentPage: 'dashboard',
currentLanguage: 'ko',
stats,
recentPortfolio,
recentContacts,
user
});
} catch (error) {
console.error('AdminLTE Demo Error:', error);
res.status(500).send('Server Error');
}
});
module.exports = router;

View File

@@ -0,0 +1,77 @@
const express = require('express');
const router = express.Router();
// Демо-роут для AdminLTE админки
router.get('/demo-adminlte', async (req, res) => {
try {
// Мок-данные для демонстрации
const stats = {
portfolioCount: 12,
servicesCount: 6,
contactsCount: 24,
usersCount: 3
};
const recentPortfolio = [
{
title: '삼성 모바일 앱 개발',
category: 'mobile-app',
status: 'completed',
createdAt: new Date('2024-10-20')
},
{
title: 'LG 웹사이트 리뉴얼',
category: 'web-development',
status: 'in-progress',
createdAt: new Date('2024-10-18')
},
{
title: '현대차 UI/UX 디자인',
category: 'ui-ux-design',
status: 'planning',
createdAt: new Date('2024-10-15')
}
];
const recentContacts = [
{
name: '김철수',
email: 'kim@example.com',
status: 'pending',
createdAt: new Date('2024-10-25')
},
{
name: '이영희',
email: 'lee@company.kr',
status: 'replied',
createdAt: new Date('2024-10-24')
},
{
name: '박민수',
email: 'park@startup.co.kr',
status: 'new',
createdAt: new Date('2024-10-23')
}
];
const user = {
name: '관리자'
};
res.render('admin/dashboard-adminlte', {
layout: 'admin/layout-adminlte',
title: '대시보드',
currentPage: 'dashboard',
currentLanguage: 'ko',
stats,
recentPortfolio,
recentContacts,
user
});
} catch (error) {
console.error('AdminLTE Demo Error:', error);
res.status(500).send('Server Error');
}
});
module.exports = router;

View File

@@ -0,0 +1,150 @@
const express = require('express');
const router = express.Router();
// Демо-роут для AdminLTE админки
router.get('/demo-adminlte', async (req, res) => {
try {
// Мок-данные для демонстрации
const stats = {
portfolioCount: 12,
servicesCount: 6,
contactsCount: 24,
usersCount: 3
};
const recentPortfolio = [
{
title: '삼성 모바일 앱 개발',
category: 'mobile-app',
status: 'completed',
createdAt: new Date('2024-10-20')
},
{
title: 'LG 웹사이트 리뉴얼',
category: 'web-development',
status: 'in-progress',
createdAt: new Date('2024-10-18')
},
{
title: '현대차 UI/UX 디자인',
category: 'ui-ux-design',
status: 'planning',
createdAt: new Date('2024-10-15')
}
];
const recentContacts = [
{
name: '김철수',
email: 'kim@example.com',
status: 'pending',
createdAt: new Date('2024-10-25')
},
{
name: '이영희',
email: 'lee@company.kr',
status: 'replied',
createdAt: new Date('2024-10-24')
},
{
name: '박민수',
email: 'park@startup.co.kr',
status: 'new',
createdAt: new Date('2024-10-23')
}
];
const user = {
name: '관리자'
};
res.render('admin/dashboard-adminlte', {
layout: 'admin/layout-adminlte',
title: '대시보드',
currentPage: 'dashboard',
currentLanguage: 'ko',
stats,
recentPortfolio,
recentContacts,
user
});
} catch (error) {
console.error('AdminLTE Demo Error:', error);
res.status(500).send('Server Error');
}
});
// Демо-роут для Tabler админки
router.get('/demo-tabler', async (req, res) => {
try {
// Мок-данные для демонстрации
const stats = {
portfolioCount: 12,
servicesCount: 6,
contactsCount: 24,
usersCount: 3
};
const recentPortfolio = [
{
title: '삼성 모바일 앱 개발',
category: 'mobile-app',
status: 'completed',
createdAt: new Date('2024-10-20')
},
{
title: 'LG 웹사이트 리뉴얼',
category: 'web-development',
status: 'in-progress',
createdAt: new Date('2024-10-18')
},
{
title: '현대차 UI/UX 디자인',
category: 'ui-ux-design',
status: 'planning',
createdAt: new Date('2024-10-15')
}
];
const recentContacts = [
{
name: '김철수',
email: 'kim@example.com',
status: 'pending',
createdAt: new Date('2024-10-25')
},
{
name: '이영희',
email: 'lee@company.kr',
status: 'replied',
createdAt: new Date('2024-10-24')
},
{
name: '박민수',
email: 'park@startup.co.kr',
status: 'new',
createdAt: new Date('2024-10-23')
}
];
const user = {
name: '관리자'
};
res.render('admin/dashboard-tabler', {
layout: 'admin/layout-tabler',
title: '대시보드',
currentPage: 'dashboard',
currentLanguage: 'ko',
stats,
recentPortfolio,
recentContacts,
user
});
} catch (error) {
console.error('Tabler Demo Error:', error);
res.status(500).send('Server Error');
}
});
module.exports = router;

View File

@@ -0,0 +1,150 @@
const express = require('express');
const router = express.Router();
// Демо-роут для AdminLTE админки
router.get('/demo-adminlte', async (req, res) => {
try {
// Мок-данные для демонстрации
const stats = {
portfolioCount: 12,
servicesCount: 6,
contactsCount: 24,
usersCount: 3
};
const recentPortfolio = [
{
title: '삼성 모바일 앱 개발',
category: 'mobile-app',
status: 'completed',
createdAt: new Date('2024-10-20')
},
{
title: 'LG 웹사이트 리뉴얼',
category: 'web-development',
status: 'in-progress',
createdAt: new Date('2024-10-18')
},
{
title: '현대차 UI/UX 디자인',
category: 'ui-ux-design',
status: 'planning',
createdAt: new Date('2024-10-15')
}
];
const recentContacts = [
{
name: '김철수',
email: 'kim@example.com',
status: 'pending',
createdAt: new Date('2024-10-25')
},
{
name: '이영희',
email: 'lee@company.kr',
status: 'replied',
createdAt: new Date('2024-10-24')
},
{
name: '박민수',
email: 'park@startup.co.kr',
status: 'new',
createdAt: new Date('2024-10-23')
}
];
const user = {
name: '관리자'
};
res.render('admin/dashboard-adminlte', {
layout: 'admin/layout-adminlte',
title: '대시보드',
currentPage: 'dashboard',
currentLanguage: 'ko',
stats,
recentPortfolio,
recentContacts,
user
});
} catch (error) {
console.error('AdminLTE Demo Error:', error);
res.status(500).send('Server Error');
}
});
// Демо-роут для Tabler админки
router.get('/demo-tabler', async (req, res) => {
try {
// Мок-данные для демонстрации
const stats = {
portfolioCount: 12,
servicesCount: 6,
contactsCount: 24,
usersCount: 3
};
const recentPortfolio = [
{
title: '삼성 모바일 앱 개발',
category: 'mobile-app',
status: 'completed',
createdAt: new Date('2024-10-20')
},
{
title: 'LG 웹사이트 리뉴얼',
category: 'web-development',
status: 'in-progress',
createdAt: new Date('2024-10-18')
},
{
title: '현대차 UI/UX 디자인',
category: 'ui-ux-design',
status: 'planning',
createdAt: new Date('2024-10-15')
}
];
const recentContacts = [
{
name: '김철수',
email: 'kim@example.com',
status: 'pending',
createdAt: new Date('2024-10-25')
},
{
name: '이영희',
email: 'lee@company.kr',
status: 'replied',
createdAt: new Date('2024-10-24')
},
{
name: '박민수',
email: 'park@startup.co.kr',
status: 'new',
createdAt: new Date('2024-10-23')
}
];
const user = {
name: '관리자'
};
res.render('admin/dashboard-tabler', {
layout: 'admin/layout-tabler',
title: '대시보드',
currentPage: 'dashboard',
currentLanguage: 'ko',
stats,
recentPortfolio,
recentContacts,
user
});
} catch (error) {
console.error('Tabler Demo Error:', error);
res.status(500).send('Server Error');
}
});
module.exports = router;

View File

@@ -0,0 +1,162 @@
const express = require('express');
const router = express.Router();
// Главная страница сравнения admin bundles
router.get('/admin-comparison', async (req, res) => {
try {
res.render('admin-bundle-comparison', {
layout: false // Не используем layout для этой страницы
});
} catch (error) {
console.error('Admin Comparison Error:', error);
res.status(500).send('Server Error');
}
});
// Демо-роут для AdminLTE админки
router.get('/demo-adminlte', async (req, res) => {
try {
// Мок-данные для демонстрации
const stats = {
portfolioCount: 12,
servicesCount: 6,
contactsCount: 24,
usersCount: 3
};
const recentPortfolio = [
{
title: '삼성 모바일 앱 개발',
category: 'mobile-app',
status: 'completed',
createdAt: new Date('2024-10-20')
},
{
title: 'LG 웹사이트 리뉴얼',
category: 'web-development',
status: 'in-progress',
createdAt: new Date('2024-10-18')
},
{
title: '현대차 UI/UX 디자인',
category: 'ui-ux-design',
status: 'planning',
createdAt: new Date('2024-10-15')
}
];
const recentContacts = [
{
name: '김철수',
email: 'kim@example.com',
status: 'pending',
createdAt: new Date('2024-10-25')
},
{
name: '이영희',
email: 'lee@company.kr',
status: 'replied',
createdAt: new Date('2024-10-24')
},
{
name: '박민수',
email: 'park@startup.co.kr',
status: 'new',
createdAt: new Date('2024-10-23')
}
];
const user = {
name: '관리자'
};
res.render('admin/dashboard-adminlte', {
layout: 'admin/layout-adminlte',
title: '대시보드',
currentPage: 'dashboard',
currentLanguage: 'ko',
stats,
recentPortfolio,
recentContacts,
user
});
} catch (error) {
console.error('AdminLTE Demo Error:', error);
res.status(500).send('Server Error');
}
});
// Демо-роут для Tabler админки
router.get('/demo-tabler', async (req, res) => {
try {
// Мок-данные для демонстрации
const stats = {
portfolioCount: 12,
servicesCount: 6,
contactsCount: 24,
usersCount: 3
};
const recentPortfolio = [
{
title: '삼성 모바일 앱 개발',
category: 'mobile-app',
status: 'completed',
createdAt: new Date('2024-10-20')
},
{
title: 'LG 웹사이트 리뉴얼',
category: 'web-development',
status: 'in-progress',
createdAt: new Date('2024-10-18')
},
{
title: '현대차 UI/UX 디자인',
category: 'ui-ux-design',
status: 'planning',
createdAt: new Date('2024-10-15')
}
];
const recentContacts = [
{
name: '김철수',
email: 'kim@example.com',
status: 'pending',
createdAt: new Date('2024-10-25')
},
{
name: '이영희',
email: 'lee@company.kr',
status: 'replied',
createdAt: new Date('2024-10-24')
},
{
name: '박민수',
email: 'park@startup.co.kr',
status: 'new',
createdAt: new Date('2024-10-23')
}
];
const user = {
name: '관리자'
};
res.render('admin/dashboard-tabler', {
layout: 'admin/layout-tabler',
title: '대시보드',
currentPage: 'dashboard',
currentLanguage: 'ko',
stats,
recentPortfolio,
recentContacts,
user
});
} catch (error) {
console.error('Tabler Demo Error:', error);
res.status(500).send('Server Error');
}
});
module.exports = router;

View File

@@ -0,0 +1,162 @@
const express = require('express');
const router = express.Router();
// Главная страница сравнения admin bundles
router.get('/admin-comparison', async (req, res) => {
try {
res.render('admin-bundle-comparison', {
layout: false // Не используем layout для этой страницы
});
} catch (error) {
console.error('Admin Comparison Error:', error);
res.status(500).send('Server Error');
}
});
// Демо-роут для AdminLTE админки
router.get('/demo-adminlte', async (req, res) => {
try {
// Мок-данные для демонстрации
const stats = {
portfolioCount: 12,
servicesCount: 6,
contactsCount: 24,
usersCount: 3
};
const recentPortfolio = [
{
title: '삼성 모바일 앱 개발',
category: 'mobile-app',
status: 'completed',
createdAt: new Date('2024-10-20')
},
{
title: 'LG 웹사이트 리뉴얼',
category: 'web-development',
status: 'in-progress',
createdAt: new Date('2024-10-18')
},
{
title: '현대차 UI/UX 디자인',
category: 'ui-ux-design',
status: 'planning',
createdAt: new Date('2024-10-15')
}
];
const recentContacts = [
{
name: '김철수',
email: 'kim@example.com',
status: 'pending',
createdAt: new Date('2024-10-25')
},
{
name: '이영희',
email: 'lee@company.kr',
status: 'replied',
createdAt: new Date('2024-10-24')
},
{
name: '박민수',
email: 'park@startup.co.kr',
status: 'new',
createdAt: new Date('2024-10-23')
}
];
const user = {
name: '관리자'
};
res.render('admin/dashboard-adminlte', {
layout: 'admin/layout-adminlte',
title: '대시보드',
currentPage: 'dashboard',
currentLanguage: 'ko',
stats,
recentPortfolio,
recentContacts,
user
});
} catch (error) {
console.error('AdminLTE Demo Error:', error);
res.status(500).send('Server Error');
}
});
// Демо-роут для Tabler админки
router.get('/demo-tabler', async (req, res) => {
try {
// Мок-данные для демонстрации
const stats = {
portfolioCount: 12,
servicesCount: 6,
contactsCount: 24,
usersCount: 3
};
const recentPortfolio = [
{
title: '삼성 모바일 앱 개발',
category: 'mobile-app',
status: 'completed',
createdAt: new Date('2024-10-20')
},
{
title: 'LG 웹사이트 리뉴얼',
category: 'web-development',
status: 'in-progress',
createdAt: new Date('2024-10-18')
},
{
title: '현대차 UI/UX 디자인',
category: 'ui-ux-design',
status: 'planning',
createdAt: new Date('2024-10-15')
}
];
const recentContacts = [
{
name: '김철수',
email: 'kim@example.com',
status: 'pending',
createdAt: new Date('2024-10-25')
},
{
name: '이영희',
email: 'lee@company.kr',
status: 'replied',
createdAt: new Date('2024-10-24')
},
{
name: '박민수',
email: 'park@startup.co.kr',
status: 'new',
createdAt: new Date('2024-10-23')
}
];
const user = {
name: '관리자'
};
res.render('admin/dashboard-tabler', {
layout: 'admin/layout-tabler',
title: '대시보드',
currentPage: 'dashboard',
currentLanguage: 'ko',
stats,
recentPortfolio,
recentContacts,
user
});
} catch (error) {
console.error('Tabler Demo Error:', error);
res.status(500).send('Server Error');
}
});
module.exports = router;