require('dotenv').config(); const express = require('express'); const cors = require('cors'); const mysql = require('mysql2'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const path = require('path'); const multer = require('multer'); const fs = require('fs'); const app = express(); // Middleware app.use(cors()); app.use(express.json()); app.use(express.static(path.join(__dirname, 'public'))); // กำหนดการจัดเก็บไฟล์ const storage = multer.diskStorage({ destination: function (req, file, cb) { const uploadDir = 'public/uploads'; // สร้างโฟลเดอร์ถ้ายังไม่มี if (!fs.existsSync(uploadDir)){ fs.mkdirSync(uploadDir, { recursive: true }); } cb(null, uploadDir); }, filename: function (req, file, cb) { // สร้างชื่อไฟล์ใหม่เพื่อป้องกันการซ้ำ cb(null, Date.now() + path.extname(file.originalname)); } }); const upload = multer({ storage: storage, limits: { fileSize: 5 * 1024 * 1024 // จำกัดขนาดไฟล์ไม่เกิน 5MB }, fileFilter: function (req, file, cb) { // ตรวจสอบประเภทไฟล์ if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) { return cb(new Error('รองรับเฉพาะไฟล์รูปภาพ jpg, jpeg, png และ gif เท่านั้น!'), false); } cb(null, true); } }); // เชื่อมต่อฐานข้อมูล const db = mysql.createConnection({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, port: process.env.DB_PORT }); // ทดสอบการเชื่อมต่อฐานข้อมูล db.connect(error => { if (error) { console.error('Error connecting to the database:', error); return; } console.log("Successfully connected to the database."); }); // Register app.post('/register', async (req, res) => { try { const { username, password, email } = req.body; // ตรวจสอบว่า username หรือ email ซ้ำหรือไม่ const checkSql = 'SELECT * FROM users WHERE username = ? OR email = ?'; db.query(checkSql, [username, email], async (checkErr, checkResults) => { if (checkErr) { return res.status(500).json({ error: checkErr.message }); } if (checkResults.length > 0) { return res.status(400).json({ error: "Username หรือ Email นี้ถูกใช้งานแล้ว" }); } // ถ้าไม่ซ้ำ ทำการเข้ารหัสรหัสผ่านและบันทึกข้อมูล const hashedPassword = await bcrypt.hash(password, 10); const insertSql = 'INSERT INTO users (username, email, password, created_at) VALUES (?, ?, ?, NOW())'; db.query(insertSql, [username, email, hashedPassword], (insertErr, result) => { if (insertErr) { return res.status(500).json({ error: insertErr.message }); } res.status(201).json({ message: "ลงทะเบียนสำเร็จ" }); }); }); } catch (error) { res.status(500).json({ error: error.message }); } }); // Login app.post('/login', async (req, res) => { const { username, password } = req.body; const sql = 'SELECT * FROM users WHERE username = ?'; db.query(sql, [username], async (err, results) => { if (err) { return res.status(500).json({ error: err.message }); } if (results.length === 0) { return res.status(401).json({ error: "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง" }); } const validPassword = await bcrypt.compare(password, results[0].password); if (!validPassword) { return res.status(401).json({ error: "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง" }); } const token = jwt.sign( { id: results[0].id, username: results[0].username }, process.env.JWT_SECRET, { expiresIn: '1d' } ); res.json({ token, user: { id: results[0].id, username: results[0].username, email: results[0].email } }); }); }); // ดึงข้อมูลสินค้าทั้งหมด app.get('/api/products', (req, res) => { const { categoryId, supplierId } = req.query; let sql = ` SELECT p.*, c.name as category_name, s.name as supplier_name, s.contact_name, s.phone as supplier_phone FROM products p LEFT JOIN categories c ON p.category_id = c.id LEFT JOIN suppliers s ON p.supplier_id = s.id `; const params = []; const conditions = []; if (categoryId) { conditions.push('p.category_id = ?'); params.push(categoryId); } if (supplierId) { conditions.push('p.supplier_id = ?'); params.push(supplierId); } if (conditions.length > 0) { sql += ' WHERE ' + conditions.join(' AND '); } db.query(sql, params, (err, results) => { if (err) { return res.status(500).json({ error: err.message }); } res.json(results); }); }); // ค้นหาสินค้า app.get('/api/products/search', (req, res) => { const { name } = req.query; const sql = ` SELECT p.*, c.name as category_name, s.name as supplier_name, s.contact_name, s.phone as supplier_phone FROM products p LEFT JOIN categories c ON p.category_id = c.id LEFT JOIN suppliers s ON p.supplier_id = s.id WHERE p.name LIKE ? `; db.query(sql, [`%${name}%`], (err, results) => { if (err) { return res.status(500).json({ error: err.message }); } res.json(results); }); }); // ดึงข้อมูลหมวดหมู่ทั้งหมด app.get('/api/categories', (req, res) => { const sql = 'SELECT * FROM categories'; db.query(sql, (err, results) => { if (err) { return res.status(500).json({ error: err.message }); } res.json(results); }); }); // ดึงข้อมูลผู้จัดจำหน่ายทั้งหมด app.get('/api/suppliers', (req, res) => { const sql = 'SELECT * FROM suppliers'; db.query(sql, (err, results) => { if (err) { return res.status(500).json({ error: err.message }); } res.json(results); }); }); // แก้ไขสินค้า app.put('/api/products/:id', upload.single('image'), (req, res) => { const { id } = req.params; const { name, price, stock, category_id, supplier_id } = req.body; let sql = ` UPDATE products SET name = ?, price = ?, stock = ?, category_id = ?, supplier_id = ? `; let values = [name, price, stock, category_id, supplier_id]; // ถ้ามีการอัพโหลดรูปภาพใหม่ if (req.file) { sql += `, image_url = ?`; values.push(req.file.filename); // ลบรูปภาพเก่า (ถ้ามี) db.query('SELECT image_url FROM products WHERE id = ?', [id], (err, result) => { if (result[0]?.image_url) { const oldImagePath = path.join(__dirname, 'public/uploads', result[0].image_url); if (fs.existsSync(oldImagePath)) { fs.unlinkSync(oldImagePath); } } }); } sql += ` WHERE id = ?`; values.push(id); db.query(sql, values, (err, result) => { if (err) { return res.status(500).json({ error: err.message }); } if (result.affectedRows === 0) { return res.status(404).json({ error: "ไม่พบสินค้าที่ต้องการแก้ไข" }); } res.json({ message: "แก้ไขสินค้าสำเร็จ" }); }); }); // ลบสินค้า app.delete('/api/products/:id', (req, res) => { const { id } = req.params; // ลบรูปภาพก่อน db.query('SELECT image_url FROM products WHERE id = ?', [id], (err, result) => { if (result[0]?.image_url) { const imagePath = path.join(__dirname, 'public/uploads', result[0].image_url); if (fs.existsSync(imagePath)) { fs.unlinkSync(imagePath); } } // จากนั้นลบข้อมูลในฐานข้อมูล const sql = 'DELETE FROM products WHERE id = ?'; db.query(sql, [id], (err, result) => { if (err) { return res.status(500).json({ error: err.message }); } if (result.affectedRows === 0) { return res.status(404).json({ error: "ไม่พบสินค้าที่ต้องการลบ" }); } res.json({ message: "ลบสินค้าสำเร็จ" }); }); }); }); // เพิ่ม middleware สำหรับ serve ไฟล์รูปภาพ app.use('/uploads', express.static(path.join(__dirname, 'public/uploads'))); // เพิ่ม route สำหรับหน้าแรก app.get('/', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); // จัดการ error จาก multer app.use((error, req, res, next) => { if (error instanceof multer.MulterError) { if (error.code === 'LIMIT_FILE_SIZE') { return res.status(400).json({ error: 'ขนาดไฟล์ใหญ่เกินไป กรุณาอัพโหลดไฟล์ขนาดไม่เกิน 5MB' }); } } next(error); }); // เพิ่มสินค้าใหม่ app.post('/api/products', upload.single('image'), (req, res) => { const { name, price, stock, category_id, supplier_id } = req.body; let sql = ` INSERT INTO products (name, price, stock, category_id, supplier_id, image_url) VALUES (?, ?, ?, ?, ?, ?) `; const image_url = req.file ? req.file.filename : null; db.query(sql, [name, price, stock, category_id, supplier_id, image_url], (err, result) => { if (err) { return res.status(500).json({ error: err.message }); } res.json({ message: "เพิ่มสินค้าสำเร็จ", id: result.insertId }); }); }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); });