feat: Implement core admin panel functionalities including appointment, contact, and pricing management with associated models, controllers, views, and routes.

This commit is contained in:
LNHA
2026-02-03 14:58:00 +07:00
parent d1b931d547
commit df8e1f9665
25 changed files with 4574 additions and 659 deletions

View File

@@ -9,18 +9,18 @@ const storage = multer.diskStorage({
try {
// Lấy loại ảnh từ request fields
const imageType = req.query.imageType || 'general';
// Tạo đường dẫn đến thư mục lưu trữ
const uploadPath = path.join(__dirname, '../public/uploads', imageType);
console.log('Creating upload directory:', uploadPath);
// Kiểm tra và tạo thư mục nếu chưa tồn tại
if (!fs.existsSync(uploadPath)) {
fs.mkdirSync(uploadPath, { recursive: true });
console.log('Directory created successfully');
}
cb(null, uploadPath);
} catch (error) {
console.error('Error creating directory:', error);
@@ -31,11 +31,11 @@ const storage = multer.diskStorage({
try {
const imageType = req.query.imageType || 'general';
const uploadPath = path.join(__dirname, '../public/uploads', imageType);
// Lấy tên file gốc (sanitize để tránh ký tự đặc biệt)
const originalName = file.originalname.replace(/[^a-zA-Z0-9.-]/g, '_');
const fullPath = path.join(uploadPath, originalName);
// Kiểm tra nếu file đã tồn tại
if (fs.existsSync(fullPath)) {
console.log('File already exists, reusing:', originalName);
@@ -63,7 +63,7 @@ const fileFilter = (req, file, cb) => {
const allowedTypes = /jpeg|jpg|png|gif|webp|svg/;
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = allowedTypes.test(file.mimetype);
if (extname && mimetype) {
return cb(null, true);
} else {
@@ -83,12 +83,12 @@ const videoStorage = multer.diskStorage({
destination: function (req, file, cb) {
// Tạo đường dẫn đến thư mục lưu trữ video
const uploadPath = path.join(__dirname, '../public/uploads/videos');
// Kiểm tra và tạo thư mục nếu chưa tồn tại
if (!fs.existsSync(uploadPath)) {
fs.mkdirSync(uploadPath, { recursive: true });
}
cb(null, uploadPath);
},
filename: function (req, file, cb) {
@@ -103,7 +103,7 @@ const videoStorage = multer.diskStorage({
const videoFileFilter = (req, file, cb) => {
const allowedTypes = /mp4|webm/;
const mimetype = allowedTypes.test(file.mimetype);
if (mimetype) {
return cb(null, true);
} else {
@@ -124,7 +124,7 @@ async function convertToWebp(req, res, next) {
if (!req.file) return next();
console.log('🔄 Converting image to webp format...');
console.log('Original file:', req.file.path);
try {
const filePath = req.file.path;
const webpPath = filePath.replace(path.extname(filePath), '.webp');
@@ -139,7 +139,7 @@ async function convertToWebp(req, res, next) {
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
}
// Cập nhật thông tin file
req.file.filename = path.basename(webpPath);
req.file.path = webpPath;