diff --git a/modules/rooms/index.js b/modules/rooms/index.js index c865947..43fb3a9 100644 --- a/modules/rooms/index.js +++ b/modules/rooms/index.js @@ -120,7 +120,7 @@ function uploadRoomImage(req, res) { return res.status(400).json({ error: 'Файл не загружен' }); } - let imagePath = 'uploads/rooms/' + req.file.filename; + let imagePath = 'data/room_images/' + req.file.filename; if (req.file.mimetype !== 'image/webp') { const inputPath = req.file.path; @@ -131,7 +131,7 @@ function uploadRoomImage(req, res) { .toFile(outputPath) .then(() => { try { fs.unlinkSync(inputPath); } catch {} - imagePath = 'uploads/rooms/' + path.basename(outputPath); + imagePath = 'data/room_images/' + path.basename(outputPath); res.json({ path: imagePath }); }) .catch(err => { @@ -156,7 +156,7 @@ function uploadRoomImages(req, res) { if (index >= req.files.length) return; const file = req.files[index]; - let imagePath = 'uploads/rooms/' + file.filename; + let imagePath = 'data/room_images/' + file.filename; function saveByPath(finalPath) { db.get(`SELECT MAX(sort_order) as maxOrder FROM room_images WHERE room_id = ?`, [roomId], (err, row) => { @@ -178,7 +178,7 @@ function uploadRoomImages(req, res) { .toFile(outputPath) .then(() => { try { fs.unlinkSync(inputPath); } catch {} - saveByPath('uploads/rooms/' + path.basename(outputPath)); + saveByPath('data/room_images/' + path.basename(outputPath)); }) .catch(() => { saveByPath(imagePath); @@ -293,6 +293,21 @@ function getAvailability(req, res) { }); } +function clearLegacyImage(req, res) { + const { id } = req.params; + db.get(`SELECT image_path FROM rooms WHERE id = ?`, [id], (err, row) => { + if (err) return res.status(500).json({ error: 'Database error' }); + if (!row) return res.status(404).json({ error: 'Номер не найден' }); + if (!row.image_path) return res.json({ message: 'Изображение уже отсутствует' }); + const filePath = path.join(__dirname, '..', '..', row.image_path); + try { if (fs.existsSync(filePath)) fs.unlinkSync(filePath); } catch {} + db.run(`UPDATE rooms SET image_path = NULL WHERE id = ?`, [id], (err) => { + if (err) return res.status(500).json({ error: 'Database error' }); + res.json({ message: 'Изображение удалено' }); + }); + }); +} + function setupRoutes(app, authenticateToken, requireAdmin, upload) { app.get('/api/rooms', getAll); app.get('/api/rooms/availability', getAvailability); @@ -305,6 +320,7 @@ function setupRoutes(app, authenticateToken, requireAdmin, upload) { app.delete('/api/admin/rooms/images/:imageId', authenticateToken, requireAdmin, deleteRoomImage); app.put('/api/admin/rooms/images/:imageId/primary', authenticateToken, requireAdmin, setPrimaryImage); app.put('/api/admin/rooms/images/reorder', authenticateToken, requireAdmin, reorderImages); + app.delete('/api/admin/rooms/:id/image', authenticateToken, requireAdmin, clearLegacyImage); } module.exports = { init, setupRoutes }; diff --git a/public/admin.html b/public/admin.html index 12dafed..95b898f 100644 --- a/public/admin.html +++ b/public/admin.html @@ -1774,9 +1774,9 @@ function renderRooms(rooms) { const primaryImg = images.find(i => i.is_primary) || images[0]; let imageSrc = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 250"%3E%3Crect fill="%23274151" width="400" height="250"/%3E%3Ctext fill="%2364748b" font-family="sans-serif" font-size="16" x="50%25" y="50%25" text-anchor="middle" dy=".3em"%3EБез фото%3C/text%3E%3C/svg%3E'; if (primaryImg && primaryImg.image_path) { - imageSrc = primaryImg.image_path.startsWith('uploads') ? '/' + primaryImg.image_path : primaryImg.image_path; + imageSrc = (primaryImg.image_path.startsWith('uploads') || primaryImg.image_path.startsWith('data')) ? '/' + primaryImg.image_path : primaryImg.image_path; } else if (r.image_path) { - imageSrc = r.image_path.startsWith('uploads') ? '/' + r.image_path : r.image_path; + imageSrc = (r.image_path.startsWith('uploads') || r.image_path.startsWith('data')) ? '/' + r.image_path : r.image_path; } const statusClass = r.is_active ? 'badge-status-оплачена' : 'badge-status-отменена'; const statusText = r.is_active ? 'Активен' : 'Скрыт'; @@ -1981,14 +1981,17 @@ async function loadRoomImages(roomId) { function renderRoomImages(images) { const container = document.getElementById('roomImagesContainer'); if (!container) return; - container.innerHTML = images.map((img, idx) => ` + container.innerHTML = images.map((img, idx) => { + const src = img.image_path.startsWith('data') ? '/' + img.image_path : '/' + img.image_path; + const hasId = img.id !== null && img.id !== undefined; + return `
- - + + ${img.is_primary ? 'Главное' : ''} - ${!img.is_primary && img.id ? `` : ''} + ${!img.is_primary && hasId ? `` : ''}
- `).join(''); + `}).join(''); } async function deleteRoomImage(imageId) { @@ -1997,6 +2000,17 @@ async function deleteRoomImage(imageId) { await api('/api/admin/rooms/images/' + imageId, { method: 'DELETE' }); showToast('Изображение удалено'); if (editingRoomId) loadRoomImages(editingRoomId); + else loadRooms(); + } catch(err) { showToast(err.message, 'error'); } +} + +async function clearLegacyImage(roomId) { + if (!confirm('Удалить изображение номера?')) return; + try { + await api('/api/admin/rooms/' + roomId + '/image', { method: 'DELETE' }); + showToast('Изображение удалено'); + loadRoomImages(roomId); + loadRooms(); } catch(err) { showToast(err.message, 'error'); } } diff --git a/public/js/rooms-public.js b/public/js/rooms-public.js index e180312..a7266f2 100644 --- a/public/js/rooms-public.js +++ b/public/js/rooms-public.js @@ -46,14 +46,14 @@ function renderRoomsPublic(rooms) { if (primaryImg && primaryImg.image_path) { imageSrc = primaryImg.image_path; } - const fullImageSrc = imageSrc.startsWith('uploads') ? '/' + imageSrc : imageSrc; + const fullImageSrc = imageSrc.startsWith('uploads') || imageSrc.startsWith('data') ? '/' + imageSrc : imageSrc; const allImages = images.length > 0 ? images : (room.image_path ? [{ image_path: room.image_path, is_primary: 1 }] : []); let imagesHtml = ''; if (allImages.length > 1) { const dotsHtml = allImages.map((img, i) => { - const src = img.image_path.startsWith('uploads') ? '/' + img.image_path : img.image_path; + const src = img.image_path.startsWith('uploads') || img.image_path.startsWith('data') ? '/' + img.image_path : img.image_path; return ``; }).join(''); imagesHtml = `