Sửa lỗi xóa ảnh trong quản lí ảnh và media
This commit is contained in:
@@ -638,7 +638,7 @@ router.delete('/assets/:id', protect, async (req, res) => {
|
|||||||
if (!asset) return res.status(404).json({ message: 'Ảnh không tồn tại' });
|
if (!asset) return res.status(404).json({ message: 'Ảnh không tồn tại' });
|
||||||
|
|
||||||
// Kiểm tra quyền: Người upload hoặc Admin (Chủ sở hữu)
|
// Kiểm tra quyền: Người upload hoặc Admin (Chủ sở hữu)
|
||||||
const isOwner = asset.uploadedBy.toString() === req.user._id.toString();
|
const isOwner = asset.uploadedBy && asset.uploadedBy.toString() === req.user._id.toString();
|
||||||
const isAdmin = req.user.role === 'Chủ sở hữu' || req.user.role === 'admin';
|
const isAdmin = req.user.role === 'Chủ sở hữu' || req.user.role === 'admin';
|
||||||
|
|
||||||
if (!isOwner && !isAdmin) {
|
if (!isOwner && !isAdmin) {
|
||||||
@@ -659,7 +659,7 @@ router.delete('/assets/:id', protect, async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. Xóa file vật lý trên disk
|
// 2. Xóa file vật lý trên disk
|
||||||
if (fs.existsSync(asset.filePath)) {
|
if (asset.filePath && fs.existsSync(asset.filePath)) {
|
||||||
fs.unlinkSync(asset.filePath);
|
fs.unlinkSync(asset.filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -594,7 +594,9 @@ html, body {
|
|||||||
box-shadow: 0 10px 40px rgba(0,0,0,0.6) !important;
|
box-shadow: 0 10px 40px rgba(0,0,0,0.6) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#logout-confirm-modal {
|
#logout-confirm-modal,
|
||||||
|
#delete-asset-confirm-modal,
|
||||||
|
#success-modal {
|
||||||
z-index: 5500; /* Cao hơn Dashboard (4500) và Close Button (5000) */
|
z-index: 5500; /* Cao hơn Dashboard (4500) và Close Button (5000) */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+22
-1
@@ -132,7 +132,7 @@
|
|||||||
<div id="create-scene-modal" class="modal">
|
<div id="create-scene-modal" class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<span class="close-btn" onclick="closeModal()">×</span>
|
<span class="close-btn" onclick="closeModal()">×</span>
|
||||||
<h2>Create New 3D Scene</h2>
|
<h2 id="create-scene-modal-title">Create New 3D Scene</h2>
|
||||||
<form id="create-scene-form" onsubmit="submitScene(event)">
|
<form id="create-scene-form" onsubmit="submitScene(event)">
|
||||||
<!-- Hidden field for editing existing scene -->
|
<!-- Hidden field for editing existing scene -->
|
||||||
<input type="hidden" id="modal-scene-id" name="sceneId">
|
<input type="hidden" id="modal-scene-id" name="sceneId">
|
||||||
@@ -179,6 +179,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Delete Asset Confirmation Modal -->
|
||||||
|
<div id="delete-asset-confirm-modal" class="modal-overlay">
|
||||||
|
<div class="modal-content action-modal-content logout-modal-dark">
|
||||||
|
<h2 style="color: #fff; margin-bottom: 10px;" id="delete-asset-modal-title">Xác nhận xóa ảnh</h2>
|
||||||
|
<p style="color: #ccc; margin-bottom: 25px;" id="delete-asset-modal-desc">Bạn có chắc chắn muốn xóa ảnh này? Nếu ảnh đang được gắn vào một cảnh, cảnh đó cũng sẽ bị xóa vĩnh viễn.</p>
|
||||||
|
<div class="action-buttons">
|
||||||
|
<button onclick="confirmDeleteAsset()" class="delete-btn-large">Xóa vĩnh viễn</button>
|
||||||
|
<button onclick="closeDeleteAssetModal()" class="edit-btn-large" style="background: #6c757d;">Hủy bỏ</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Success Message Modal -->
|
||||||
|
<div id="success-modal" class="modal-overlay" onclick="closeSuccessModal(event)">
|
||||||
|
<div class="modal-content action-modal-content logout-modal-dark" style="border-top: 4px solid #28a745; max-width: 350px;">
|
||||||
|
<div style="font-size: 40px; color: #28a745; margin-bottom: 10px;">✓</div>
|
||||||
|
<h2 style="color: #fff; margin-bottom: 5px;">Thành công</h2>
|
||||||
|
<p style="color: #ccc;" id="success-modal-message">Dữ liệu đã được cập nhật.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Modal for Action Choice (Edit/Delete) -->
|
<!-- Modal for Action Choice (Edit/Delete) -->
|
||||||
<div id="action-choice-modal" class="modal">
|
<div id="action-choice-modal" class="modal">
|
||||||
<div class="modal-content action-modal-content">
|
<div class="modal-content action-modal-content">
|
||||||
|
|||||||
+61
-8
@@ -8,6 +8,8 @@ let previousSceneId = null;
|
|||||||
let miniMap = null;
|
let miniMap = null;
|
||||||
let miniMapMarker = null;
|
let miniMapMarker = null;
|
||||||
let systemSettings = { timezone: 'Asia/Ho_Chi_Minh', language: 'vi' };
|
let systemSettings = { timezone: 'Asia/Ho_Chi_Minh', language: 'vi' };
|
||||||
|
let returnToDashboardAfterEdit = false;
|
||||||
|
let assetIdToDelete = null;
|
||||||
|
|
||||||
// Initialize when DOM is ready
|
// Initialize when DOM is ready
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
@@ -420,6 +422,10 @@ function openCreateSceneModal(lat, lng) {
|
|||||||
document.getElementById('modal-scene-id').value = '';
|
document.getElementById('modal-scene-id').value = '';
|
||||||
document.getElementById('modal-lat').value = lat.toFixed(6);
|
document.getElementById('modal-lat').value = lat.toFixed(6);
|
||||||
document.getElementById('modal-lng').value = lng.toFixed(6);
|
document.getElementById('modal-lng').value = lng.toFixed(6);
|
||||||
|
|
||||||
|
const lang = systemSettings.language || 'vi';
|
||||||
|
const modalTitle = document.getElementById('create-scene-modal-title');
|
||||||
|
if (modalTitle) modalTitle.innerText = lang === 'vi' ? "Tạo 3D scene mới" : "Create New 3D Scene";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -689,6 +695,10 @@ function openEditSceneModal(scene) {
|
|||||||
document.getElementById('modal-privacy').value = scene.privacy;
|
document.getElementById('modal-privacy').value = scene.privacy;
|
||||||
document.getElementById('modal-panorama').required = false; // Photo update is optional
|
document.getElementById('modal-panorama').required = false; // Photo update is optional
|
||||||
|
|
||||||
|
const lang = systemSettings.language || 'vi';
|
||||||
|
const modalTitle = document.getElementById('create-scene-modal-title');
|
||||||
|
if (modalTitle) modalTitle.innerText = lang === 'vi' ? "Sửa 3D scene" : "Edit 3D scene";
|
||||||
|
|
||||||
toggleSharedUsers();
|
toggleSharedUsers();
|
||||||
document.getElementById('create-scene-modal').style.display = 'flex';
|
document.getElementById('create-scene-modal').style.display = 'flex';
|
||||||
}
|
}
|
||||||
@@ -1277,22 +1287,38 @@ async function loadMyAssets() {
|
|||||||
/**
|
/**
|
||||||
* Xóa ảnh khỏi kho media
|
* Xóa ảnh khỏi kho media
|
||||||
*/
|
*/
|
||||||
window.deleteAsset = async function(assetId) {
|
window.deleteAsset = function(assetId) {
|
||||||
if (!confirm('Bạn có chắc chắn muốn xóa ảnh này? Nếu ảnh đang được gắn vào một cảnh, cảnh đó cũng sẽ bị xóa vĩnh viễn.')) {
|
assetIdToDelete = assetId;
|
||||||
return;
|
document.getElementById('delete-asset-confirm-modal').style.display = 'flex';
|
||||||
}
|
};
|
||||||
|
|
||||||
|
window.closeDeleteAssetModal = function() {
|
||||||
|
document.getElementById('delete-asset-confirm-modal').style.display = 'none';
|
||||||
|
assetIdToDelete = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.confirmDeleteAsset = async function() {
|
||||||
|
if (!assetIdToDelete) return;
|
||||||
|
|
||||||
const token = localStorage.getItem('jwt');
|
const token = localStorage.getItem('jwt');
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API_BASE_URL}/assets/${assetId}`, {
|
const res = await fetch(`${API_BASE_URL}/assets/${assetIdToDelete}`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: { 'Authorization': `Bearer ${token}` }
|
headers: { 'Authorization': `Bearer ${token}` }
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
|
||||||
|
|
||||||
if (!res.ok) throw new Error(data.message);
|
let data;
|
||||||
|
const contentType = res.headers.get("content-type");
|
||||||
|
if (contentType && contentType.includes("application/json")) {
|
||||||
|
data = await res.json();
|
||||||
|
}
|
||||||
|
|
||||||
alert(data.message);
|
if (!res.ok) {
|
||||||
|
throw new Error(data?.message || `Lỗi máy chủ (${res.status})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDeleteAssetModal();
|
||||||
|
showSuccessModal(data.message || "Đã xóa thành công");
|
||||||
loadMyAssets(); // Nạp lại kho ảnh
|
loadMyAssets(); // Nạp lại kho ảnh
|
||||||
loadScenes(); // Nạp lại bản đồ nếu có scene bị xóa kèm theo
|
loadScenes(); // Nạp lại bản đồ nếu có scene bị xóa kèm theo
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -1300,11 +1326,38 @@ window.deleteAsset = async function(assetId) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hiển thị Modal thông báo thành công
|
||||||
|
*/
|
||||||
|
window.showSuccessModal = function(message) {
|
||||||
|
const modal = document.getElementById('success-modal');
|
||||||
|
const msgElem = document.getElementById('success-modal-message');
|
||||||
|
if (modal && msgElem) {
|
||||||
|
msgElem.innerText = message;
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
// Tự động ẩn sau 3 giây
|
||||||
|
setTimeout(() => closeSuccessModal(), 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Đóng Modal thành công (hỗ trợ click ra ngoài)
|
||||||
|
*/
|
||||||
|
window.closeSuccessModal = function(e) {
|
||||||
|
const modal = document.getElementById('success-modal');
|
||||||
|
if (!modal) return;
|
||||||
|
// Nếu nhấn từ code (không có e) hoặc click trúng overlay thì đóng
|
||||||
|
if (e && e.target !== modal) return;
|
||||||
|
modal.style.display = 'none';
|
||||||
|
};
|
||||||
|
|
||||||
window.openEditFromMedia = function(scene) {
|
window.openEditFromMedia = function(scene) {
|
||||||
if (!scene || !scene._id) {
|
if (!scene || !scene._id) {
|
||||||
alert("Không thể chỉnh sửa: Ảnh này không được gắn với một Scene hợp lệ.");
|
alert("Không thể chỉnh sửa: Ảnh này không được gắn với một Scene hợp lệ.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
returnToDashboardAfterEdit = true;
|
||||||
|
closeDashboard();
|
||||||
openEditSceneModal(scene);
|
openEditSceneModal(scene);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user