Tạo scripts backup dữ liệu
This commit is contained in:
@@ -142,6 +142,23 @@
|
||||
</div>
|
||||
<button type="submit" class="submit-btn">Lưu cấu hình</button>
|
||||
</form>
|
||||
<div class="form-group" style="border-top: 1px solid rgba(255,255,255,0.1); margin-top: 30px; padding-top: 20px;">
|
||||
<label>Dữ liệu & Bảo trì</label>
|
||||
<div class="backup-restore-actions" style="display: flex; flex-direction: column; gap: 10px; margin-top: 15px;">
|
||||
<button type="button" class="edit-btn-large" onclick="handleBackup()" style="background: #17a2b8; width: 100%;">
|
||||
<span class="icon">📥</span> Tạo bản sao lưu (Backup)
|
||||
</button>
|
||||
<div class="restore-container">
|
||||
<input type="file" id="restore-file-input" accept=".zip" style="display:none" onchange="handleRestore(this)">
|
||||
<button type="button" class="edit-btn-large" onclick="document.getElementById('restore-file-input').click()" style="background: #fd7e14; width: 100%;">
|
||||
<span class="icon">📤</span> Khôi phục dữ liệu (Restore)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p style="font-size: 11px; color: #888; margin-top: 10px;">
|
||||
* Backup bao gồm toàn bộ database và các tệp tin ảnh 360 trong thư mục uploads.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2026,6 +2026,58 @@ async function submitEditScene(e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Xử lý tải xuống bản sao lưu
|
||||
*/
|
||||
async function handleBackup() {
|
||||
const token = localStorage.getItem('jwt');
|
||||
try {
|
||||
showNotification("Đang chuẩn bị bản sao lưu...", "success");
|
||||
const response = await fetch(`${API_BASE_URL}/admin/backup`, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
if (!response.ok) throw new Error("Lỗi khi tạo backup");
|
||||
const blob = await response.blob();
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `backup_3dtour_${new Date().toISOString().slice(0,10)}.zip`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
showNotification("Đã tải xuống bản sao lưu!", "success");
|
||||
} catch (e) { showNotification(e.message, "error"); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Xử lý khôi phục dữ liệu từ file zip
|
||||
*/
|
||||
async function handleRestore(input) {
|
||||
if (!input.files || !input.files[0]) return;
|
||||
if (!confirm("CẢNH BÁO: Khôi phục dữ liệu sẽ xóa sạch dữ liệu hiện tại và thay thế bằng dữ liệu từ bản sao lưu. Bạn có chắc chắn?")) {
|
||||
input.value = ''; return;
|
||||
}
|
||||
const token = localStorage.getItem('jwt');
|
||||
const formData = new FormData();
|
||||
formData.append('backupFile', input.files[0]);
|
||||
try {
|
||||
showNotification("Đang khôi phục... Vui lòng không đóng trình duyệt.", "success");
|
||||
const response = await fetch(`${API_BASE_URL}/admin/restore`, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': `Bearer ${token}` },
|
||||
body: formData
|
||||
});
|
||||
const data = await response.json();
|
||||
if (!response.ok) throw new Error(data.message);
|
||||
showNotification("Khôi phục thành công! Hệ thống sẽ tải lại.", "success");
|
||||
setTimeout(() => location.reload(), 2000);
|
||||
} catch (e) {
|
||||
showNotification(e.message, "error");
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a specific tab within the dashboard.
|
||||
* @param {string} tabName - The ID of the tab pane to open (e.g., 'profile', 'my-scenes').
|
||||
|
||||
Reference in New Issue
Block a user