117 lines
5.5 KiB
JavaScript
117 lines
5.5 KiB
JavaScript
const { createCrudRoutes } = require('../database/crud');
|
||
const multer = require('multer');
|
||
const path = require('path');
|
||
const fs = require('fs');
|
||
const sharp = require('sharp');
|
||
|
||
let db;
|
||
|
||
function init(database) { db = database; }
|
||
|
||
function setupRoutes(app, auth) {
|
||
const uploadDir = path.join(__dirname, '..', '..', 'data', 'equipment_images');
|
||
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true });
|
||
|
||
const storage = multer.diskStorage({
|
||
destination: uploadDir,
|
||
filename: (req, file, cb) => {
|
||
const ext = path.extname(file.originalname);
|
||
cb(null, 'equip_' + Date.now() + '_' + Math.round(Math.random() * 1000) + ext);
|
||
}
|
||
});
|
||
const upload = multer({
|
||
storage,
|
||
limits: { fileSize: 5 * 1024 * 1024 },
|
||
fileFilter: (req, file, cb) => {
|
||
const allowed = ['.jpg', '.jpeg', '.png', '.webp', '.gif'];
|
||
const ext = path.extname(file.originalname).toLowerCase();
|
||
cb(null, allowed.includes(ext));
|
||
}
|
||
});
|
||
|
||
async function convertToWebp(filePath, fname) {
|
||
const ext = path.extname(fname).toLowerCase();
|
||
if (ext === '.webp') return fname;
|
||
try {
|
||
const webpName = path.basename(fname, ext) + '.webp';
|
||
await sharp(filePath).webp({ quality: 85 }).toFile(path.join(uploadDir, webpName));
|
||
fs.unlinkSync(filePath);
|
||
return webpName;
|
||
} catch (e) { return fname; }
|
||
}
|
||
|
||
app.post('/api/admin/equipment/upload', auth.authenticateToken, auth.requireAdmin, upload.single('image'), async (req, res) => {
|
||
if (!req.file) return res.status(400).json({ error: 'Файл не загружен' });
|
||
const fname = await convertToWebp(req.file.path, req.file.filename);
|
||
res.json({ path: fname, url: `/data/equipment_images/${fname}` });
|
||
});
|
||
|
||
app.post('/api/admin/equipment/gallery/upload', auth.authenticateToken, auth.requireAdmin, upload.array('images', 10), async (req, res) => {
|
||
if (!req.files || req.files.length === 0) return res.status(400).json({ error: 'Файлы не загружены' });
|
||
const results = [];
|
||
for (const file of req.files) {
|
||
const fname = await convertToWebp(file.path, file.filename);
|
||
results.push({ path: fname, url: `/data/equipment_images/${fname}` });
|
||
}
|
||
res.json(results);
|
||
});
|
||
|
||
app.get('/api/admin/equipment/:id/gallery', auth.authenticateToken, auth.requireAdmin, (req, res) => {
|
||
const id = parseInt(req.params.id);
|
||
if (isNaN(id)) return res.status(400).json({ error: 'Неверный ID' });
|
||
db.all(`SELECT * FROM equipment_gallery WHERE equipment_id = ? ORDER BY sort_order`, [id], (err, rows) => {
|
||
if (err) return res.status(500).json({ error: 'Ошибка БД' });
|
||
res.json(rows);
|
||
});
|
||
});
|
||
|
||
app.post('/api/admin/equipment/:id/gallery', auth.authenticateToken, auth.requireAdmin, (req, res) => {
|
||
const id = parseInt(req.params.id);
|
||
if (isNaN(id)) return res.status(400).json({ error: 'Неверный ID' });
|
||
const { image_path, sort_order } = req.body;
|
||
if (!image_path) return res.status(400).json({ error: 'Не указан путь к изображению' });
|
||
const stmt = db.prepare(`INSERT INTO equipment_gallery (equipment_id, image_path, sort_order) VALUES (?, ?, ?)`);
|
||
stmt.run(id, image_path, sort_order || 0, function(err) {
|
||
if (err) return res.status(500).json({ error: 'Ошибка создания' });
|
||
db.get(`SELECT * FROM equipment_gallery WHERE id = ?`, [this.lastID], (e2, row) => {
|
||
if (e2) return res.status(500).json({});
|
||
res.status(201).json(row);
|
||
});
|
||
});
|
||
stmt.finalize();
|
||
});
|
||
|
||
app.put('/api/admin/equipment/gallery/:imageId', auth.authenticateToken, auth.requireAdmin, (req, res) => {
|
||
const imageId = parseInt(req.params.imageId);
|
||
if (isNaN(imageId)) return res.status(400).json({ error: 'Неверный ID' });
|
||
const { image_path, sort_order } = req.body;
|
||
const stmt = db.prepare(`UPDATE equipment_gallery SET image_path = COALESCE(?, image_path), sort_order = COALESCE(?, sort_order) WHERE id = ?`);
|
||
stmt.run(image_path || null, sort_order != null ? sort_order : null, imageId, function(err) {
|
||
if (err) return res.status(500).json({ error: 'Ошибка обновления' });
|
||
if (this.changes === 0) return res.status(404).json({ error: 'Не найдено' });
|
||
db.get(`SELECT * FROM equipment_gallery WHERE id = ?`, [imageId], (e2, row) => {
|
||
res.json(row);
|
||
});
|
||
});
|
||
stmt.finalize();
|
||
});
|
||
|
||
app.delete('/api/admin/equipment/gallery/:imageId', auth.authenticateToken, auth.requireAdmin, (req, res) => {
|
||
const imageId = parseInt(req.params.imageId);
|
||
if (isNaN(imageId)) return res.status(400).json({ error: 'Неверный ID' });
|
||
const stmt = db.prepare(`DELETE FROM equipment_gallery WHERE id = ?`);
|
||
stmt.run(imageId, function(err) {
|
||
if (err) return res.status(500).json({ error: 'Ошибка удаления' });
|
||
if (this.changes === 0) return res.status(404).json({ error: 'Не найдено' });
|
||
res.json({ message: 'Удалено' });
|
||
});
|
||
stmt.finalize();
|
||
});
|
||
|
||
createCrudRoutes(app, auth, 'equipment', {
|
||
fields: ['name', 'brand', 'image_path', 'qty', 'specs', 'sort_order', 'is_active']
|
||
});
|
||
}
|
||
|
||
module.exports = { init, setupRoutes };
|