forked from UKSOURCE/cms.hailearning.edu.vn
347 lines
9.7 KiB
JavaScript
347 lines
9.7 KiB
JavaScript
const { addBaseUrlToImages } = require('../utils/imageHelper');
|
|
const Header = require('../models/header');
|
|
const Menu = require('../models/menuHeader');
|
|
|
|
// Helper function để thêm title và url cho programmes
|
|
const addProgrammeDetails = (programmes, menuUrl) => {
|
|
return programmes.map(prog => ({
|
|
...prog,
|
|
title: prog.name,
|
|
url: `${menuUrl}${prog.code}/`
|
|
}));
|
|
};
|
|
|
|
// Helper function để xử lý menu tree cho API (đơn giản hóa, map menuid thành id)
|
|
const processMenuTreeForAPI = (menuTree) => {
|
|
return menuTree.map(item => {
|
|
const processedItem = {
|
|
id: item.menuid, // Map menuid to id for frontend
|
|
title: item.title,
|
|
url: item.url,
|
|
order: item.order,
|
|
parent: item.parent || null,
|
|
type: item.type,
|
|
children: []
|
|
};
|
|
|
|
// Đệ quy cho children
|
|
if (item.children && item.children.length > 0) {
|
|
processedItem.children = processMenuTreeForAPI(item.children);
|
|
}
|
|
|
|
return processedItem;
|
|
});
|
|
};
|
|
|
|
// Helper function để xử lý menu tree và thêm programme details (cho admin)
|
|
const processMenuTree = (menuTree) => {
|
|
return menuTree.map(item => {
|
|
const processedItem = { ...item };
|
|
|
|
// Nếu có programmes, thêm title và url
|
|
if (item.programmes && item.programmes.length > 0) {
|
|
processedItem.programmes = addProgrammeDetails(item.programmes, item.url);
|
|
}
|
|
|
|
// Đệ quy cho children
|
|
if (item.children && item.children.length > 0) {
|
|
processedItem.children = processMenuTree(item.children);
|
|
}
|
|
|
|
return processedItem;
|
|
});
|
|
};
|
|
|
|
// Get header data from MongoDB
|
|
const getHeaderData = async () => {
|
|
const header = await Header.findOne({ name: 'default' });
|
|
|
|
if (!header) {
|
|
return {
|
|
topbar: {
|
|
contactInfo: {
|
|
phone: '',
|
|
email: ''
|
|
},
|
|
links: []
|
|
},
|
|
mainMenu: [],
|
|
logo: ''
|
|
};
|
|
}
|
|
|
|
// Convert to plain object to allow modifications
|
|
const headerData = header.toObject();
|
|
|
|
// Lấy menu tree từ collection menuHeader (đơn giản, không có programmes)
|
|
try {
|
|
const menuTree = await Menu.getMenuTree();
|
|
// Xử lý menu tree để map menuid thành id cho frontend
|
|
headerData.mainMenu = processMenuTreeForAPI(menuTree);
|
|
} catch (error) {
|
|
console.error('Error getting menu tree:', error);
|
|
headerData.mainMenu = [];
|
|
}
|
|
|
|
return headerData;
|
|
};
|
|
|
|
// API to get header data
|
|
exports.api = async (req, res) => {
|
|
try {
|
|
// Lấy header data
|
|
const header = await getHeaderData();
|
|
|
|
// Xử lý URL cho logo và các hình ảnh khác
|
|
const processedData = addBaseUrlToImages(header);
|
|
|
|
res.json(processedData);
|
|
} catch (err) {
|
|
console.error('API Error:', err);
|
|
res.status(500).json({ error: 'Error loading header data' });
|
|
}
|
|
};
|
|
|
|
// API để lấy menu tree cho frontend (public API)
|
|
exports.getMenuTreeAPI = async (req, res) => {
|
|
try {
|
|
const menuTree = await Menu.getMenuTree();
|
|
// Xử lý menu tree để map menuid thành id cho frontend
|
|
const processedMenuTree = processMenuTreeForAPI(menuTree);
|
|
res.json(processedMenuTree);
|
|
} catch (error) {
|
|
console.error('Error getting menu tree:', error);
|
|
res.status(500).json({ error: 'Error loading menu tree' });
|
|
}
|
|
};
|
|
|
|
// API để lấy menu tree (cho admin)
|
|
exports.getMenuTree = async (req, res) => {
|
|
try {
|
|
const menuTree = await Menu.getMenuTree();
|
|
res.json(menuTree);
|
|
} catch (error) {
|
|
console.error('Error getting menu tree:', error);
|
|
res.status(500).json({ error: 'Error loading menu tree' });
|
|
}
|
|
};
|
|
|
|
// API để lấy programmes theo menu ID
|
|
exports.getProgrammesByMenuId = async (req, res) => {
|
|
try {
|
|
const { menuId } = req.params;
|
|
const programmes = await Header.getProgrammesByMenuId(menuId);
|
|
|
|
// Lấy menu item để có URL
|
|
const menuItem = await Menu.findOne({ menuid: menuId });
|
|
if (menuItem) {
|
|
const programmesWithDetails = addProgrammeDetails(programmes, menuItem.url);
|
|
res.json(programmesWithDetails);
|
|
} else {
|
|
res.json(programmes);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error getting programmes by menu ID:', error);
|
|
res.status(500).json({ error: 'Error loading programmes' });
|
|
}
|
|
};
|
|
|
|
// API để lấy toàn bộ header data
|
|
exports.getHeaderData = async (req, res) => {
|
|
try {
|
|
const headerData = await getHeaderData();
|
|
res.json(headerData);
|
|
} catch (error) {
|
|
console.error('Error getting header data:', error);
|
|
res.status(500).json({ error: 'Error loading header data' });
|
|
}
|
|
};
|
|
|
|
// API để lấy menu item theo ID
|
|
exports.getMenuItem = async (req, res) => {
|
|
try {
|
|
const { menuId } = req.params;
|
|
const Menu = require('../models/menuHeader');
|
|
const menuItem = await Menu.findOne({ menuid: menuId });
|
|
|
|
if (!menuItem) {
|
|
return res.status(404).json({ error: 'Menu item not found' });
|
|
}
|
|
|
|
// Nếu là level type và có fetch = true, lấy programmes
|
|
if (menuItem.type === 'level' && menuItem.fetch) {
|
|
const programmes = await Menu.getProgrammesByMenuId(menuItem.menuid);
|
|
menuItem.programmes = addProgrammeDetails(programmes, menuItem.url);
|
|
}
|
|
|
|
res.json(menuItem);
|
|
} catch (error) {
|
|
console.error('Error getting menu item:', error);
|
|
res.status(500).json({ error: 'Error loading menu item' });
|
|
}
|
|
};
|
|
|
|
// Render admin view
|
|
exports.index = async (req, res) => {
|
|
try {
|
|
const data = await getHeaderData();
|
|
|
|
res.render('admin/header/index', {
|
|
title: 'Header Management',
|
|
data
|
|
});
|
|
} catch (error) {
|
|
console.error('Error in header index:', error);
|
|
req.flash('error_msg', 'An error occurred while loading the page');
|
|
res.redirect('/admin/dashboard');
|
|
}
|
|
};
|
|
|
|
// Update header (chỉ cập nhật topbar và logo)
|
|
exports.update = async (req, res) => {
|
|
try {
|
|
const headerData = req.body;
|
|
|
|
// Tìm và cập nhật header
|
|
const header = await Header.findOne({ name: 'default' });
|
|
if (!header) {
|
|
req.flash('error_msg', 'Header not found');
|
|
return res.redirect('/admin/header');
|
|
}
|
|
|
|
// Cập nhật từng phần
|
|
if (headerData.topbarJson) {
|
|
header.topbar = JSON.parse(headerData.topbarJson);
|
|
}
|
|
|
|
if (headerData.logo) {
|
|
header.logo = headerData.logo;
|
|
}
|
|
header.updatedAt = new Date();
|
|
await header.save();
|
|
|
|
// Process menu updates if any
|
|
let menuUpdateCount = 0;
|
|
let menuErrorCount = 0;
|
|
|
|
if (headerData.menuUpdates) {
|
|
try {
|
|
const updates = JSON.parse(headerData.menuUpdates);
|
|
|
|
if (Array.isArray(updates) && updates.length > 0) {
|
|
const Menu = require('../models/menuHeader');
|
|
|
|
for (const update of updates) {
|
|
try {
|
|
const { menuid, title, order, type, parent, fetch, isActive } = update;
|
|
|
|
const updateData = {
|
|
title: title,
|
|
order: order,
|
|
type: type,
|
|
parent: parent
|
|
};
|
|
|
|
// Add fetch field if provided
|
|
if (fetch !== undefined) {
|
|
updateData.fetch = fetch;
|
|
}
|
|
|
|
// Add isActive field if provided
|
|
if (isActive !== undefined) {
|
|
updateData.isActive = isActive;
|
|
}
|
|
|
|
const result = await Menu.findOneAndUpdate(
|
|
{ menuid: menuid },
|
|
updateData,
|
|
{ new: true }
|
|
);
|
|
|
|
if (result) {
|
|
menuUpdateCount++;
|
|
} else {
|
|
console.warn(`Menu item not found for update: ${menuid}`);
|
|
menuErrorCount++;
|
|
}
|
|
} catch (innerErr) {
|
|
console.error(`Error updating menu item ${update.menuid}:`, innerErr);
|
|
menuErrorCount++;
|
|
}
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error('Error processing menu updates:', err);
|
|
}
|
|
}
|
|
|
|
let flashMsg = 'Header updated successfully.';
|
|
if (menuUpdateCount > 0) {
|
|
flashMsg += ` Updated ${menuUpdateCount} menu items.`;
|
|
}
|
|
if (menuErrorCount > 0) {
|
|
req.flash('error_msg', `Updated ${menuUpdateCount} items, but failed to update ${menuErrorCount} items. Check logs.`);
|
|
} else {
|
|
req.flash('success_msg', flashMsg);
|
|
}
|
|
|
|
// Redirect back to the active tab
|
|
const activeTab = req.body.activeTab || 'topbar';
|
|
res.redirect(`/admin/header?activeTab=${activeTab}`);
|
|
} catch (error) {
|
|
console.error('Error updating header:', error);
|
|
req.flash('error_msg', 'Error updating header: ' + error.message);
|
|
res.redirect('/admin/header');
|
|
}
|
|
};
|
|
|
|
// Update menu structure (order and parent)
|
|
exports.updateMenu = async (req, res) => {
|
|
try {
|
|
const { updates } = req.body;
|
|
|
|
if (!updates || !Array.isArray(updates)) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Invalid updates data'
|
|
});
|
|
}
|
|
|
|
const Menu = require('../models/menuHeader');
|
|
|
|
// Update each menu item
|
|
for (const update of updates) {
|
|
const { menuid, title, order, type, parent, fetch, isActive } = update;
|
|
|
|
console.log(menuid, title, order, type, parent, fetch, isActive);
|
|
|
|
const updateData = {
|
|
title: title,
|
|
order: order,
|
|
type: type,
|
|
parent: parent
|
|
};
|
|
|
|
// Add fetch field if provided (for level type menus)
|
|
if (fetch !== undefined) {
|
|
updateData.fetch = fetch;
|
|
}
|
|
|
|
// Add isActive field if provided
|
|
if (isActive !== undefined) {
|
|
updateData.isActive = isActive;
|
|
}
|
|
|
|
await Menu.findOneAndUpdate(
|
|
{ menuid: menuid },
|
|
updateData,
|
|
{ new: true }
|
|
);
|
|
}
|
|
res.json({ success: true });
|
|
} catch (error) {
|
|
console.error('Error updating menu structure:', error);
|
|
req.flash('error_msg', 'Error updating menu structure: ' + error.message);
|
|
res.redirect('/admin/header');
|
|
}
|
|
};
|