Files
3dtours/frontend/index.html

600 lines
35 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Virtual 3D Tour Map</title>
<!-- Leaflet CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
<!-- Pannellum (3D Viewer) CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pannellum@2.5.6/build/pannellum.css"/>
<!-- Chart.js CSS (tùy chọn, có thể không cần nếu chỉ dùng JS) -->
<!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.min.css"> -->
<!-- Leaflet MarkerCluster CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css" />
<!-- Custom Style -->
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<!-- Map container -->
<div id="map"></div>
<!-- Top Bar -->
<div id="top-bar">
<div class="app-brand">
<h1>Virtual 3D Tour Map</h1>
</div>
<div id="user-controls">
<div id="user-avatar" onclick="toggleDropdown()">
<span id="avatar-initials">?</span>
</div>
<div id="user-dropdown" class="dropdown-content">
<div id="auth-guest">
<div class="auth-tabs">
<button id="tab-login-btn" class="auth-tab-btn active" onclick="switchAuthMode('login')">Đăng nhập</button>
<button id="tab-register-btn" class="auth-tab-btn" onclick="switchAuthMode('register')">Đăng ký</button>
</div>
<!-- Login Form -->
<div id="login-section">
<input type="text" id="username-input" placeholder="Tên đăng nhập" onkeydown="if(event.key === 'Enter') handleLogin()">
<input type="password" id="password-input" placeholder="Mật khẩu" onkeydown="if(event.key === 'Enter') handleLogin()">
<p id="login-error-msg" class="auth-error"></p>
<button onclick="handleLogin()" class="auth-submit-btn">Đăng nhập</button>
</div>
<!-- Register Form -->
<div id="register-section" style="display: none;">
<input type="text" id="reg-fullname" placeholder="Họ và tên đầy đủ">
<input type="email" id="reg-email" placeholder="Địa chỉ Email">
<input type="text" id="reg-username" placeholder="Tên đăng nhập">
<input type="password" id="reg-password" placeholder="Mật khẩu">
<input type="password" id="reg-confirm" placeholder="Nhắc lại mật khẩu">
<label class="rules-checkbox">
<input type="checkbox" id="reg-agree"> Đồng ý với <a href="#" style="color: #007bff;">quy định của trang</a>
</label>
<p id="reg-error-msg" class="auth-error"></p>
<button onclick="handleRegister()" class="auth-submit-btn">Đăng ký thành viên</button>
</div>
</div>
<div id="auth-logged-in" style="display: none;">
<!--<p>Welcome, <strong id="logged-username"></strong> (<span id="logged-role"></span>)</p>-->
<button onclick="openDashboard()">Manage Profile</button>
<button onclick="showLogoutConfirm()">Đăng xuất</button>
</div>
</div>
</div>
</div>
<!-- Dashboard Overlay -->
<div id="dashboard-overlay" class="modal-overlay">
<div class="modal-content dashboard-content">
<span class="close-btn" onclick="closeDashboard()">&times;</span>
<div class="dashboard-tabs">
<!-- Dòng 1: Avatar và Tên -->
<div class="sidebar-user-header">
<div id="sidebar-avatar" class="avatar-circle">?</div>
<div id="sidebar-username" class="user-name-text">Username</div>
</div>
<!-- Dòng 2: Status -->
<div id="sidebar-status" class="user-status-text">Status...</div>
<!-- Dòng 3: Dòng kẻ ngang -->
<hr class="sidebar-divider">
<!-- Dòng 4-8: Menu điều hướng -->
<button class="tab-btn active" onclick="openDashboardTab('profile')">Hồ sơ</button>
<button class="tab-btn" onclick="openDashboardTab('my-scenes')">Quản lí scene</button>
<button class="tab-btn" onclick="openDashboardTab('media-library')">Quản lí ảnh và media</button>
<button class="tab-btn admin-only" id="admin-tab-users" onclick="openDashboardTab('user-management')">Quản lí người dùng</button>
<button class="tab-btn admin-only" id="admin-tab-system" onclick="openDashboardTab('system-settings')">Cài đặt hệ thống</button>
<!-- Dòng 9: Đăng xuất -->
<button class="tab-btn logout-item" onclick="showLogoutConfirm()">Đăng xuất</button>
</div>
<div id="dashboard-tab-content">
<div id="tab-profile" class="dashboard-tab-pane active">
<form id="profile-form" onsubmit="updateProfile(event)">
<div class="profile-header-edit">
<div class="avatar-edit-container">
<img id="profile-avatar-preview" src="" alt="Avatar" style="display:none;">
<div id="profile-avatar-placeholder" class="avatar-circle">?</div>
<label for="profile-avatar-input" class="avatar-upload-label">
<i class="fas fa-camera"></i> Thay đổi
</label>
<input type="file" id="profile-avatar-input" name="avatar" accept="image/*" onchange="previewAvatar(this)" style="display:none;">
</div>
</div>
<div class="profile-grid"> <!-- Đảm bảo class này được sử dụng -->
<div class="form-group">
<label>Họ và tên</label>
<input type="text" id="profile-fullname" name="fullName" required>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" id="profile-email" name="email" required>
</div>
<div class="form-group">
<label>Tên đăng nhập (Username)</label>
<input type="text" id="profile-username" name="username" required>
</div>
<div class="form-group">
<label>Mật khẩu mới (để trống nếu không đổi)</label>
<input type="password" id="profile-password" name="password" placeholder="********">
</div>
</div>
<button type="submit" class="submit-btn profile-submit-btn">Cập nhật</button>
</form>
</div>
<div id="tab-my-scenes" class="dashboard-tab-pane">
<h3>Các scene đã tạo</h3>
<div id="my-scenes-list" class="dashboard-list">
<!-- Nạp dữ liệu qua JS -->
<p>Đang tải danh sách...</p>
</div>
</div>
<div id="tab-media-library" class="dashboard-tab-pane">
<h3>Quản lí ảnh và media</h3>
<div id="media-library-list" class="dashboard-grid">
<!-- Nạp dữ liệu qua JS -->
<p>Đang tải kho ảnh...</p>
</div>
</div>
<div id="tab-user-management" class="dashboard-tab-pane admin-only">
<div class="admin-management-header">
<button class="cleanup-btn" onclick="openManualCleanupConfirm()">
🧹 Dọn dẹp dữ liệu
</button>
</div>
<div class="admin-search-container">
<input type="text" id="admin-user-search-input" placeholder="Tìm kiếm theo tên, email, username..." onkeydown="if(event.key === 'Enter') loadAdminUsers(1)">
<button onclick="loadAdminUsers(1)" class="admin-search-btn">Tìm kiếm</button>
</div>
<div id="admin-users-list" class="dashboard-list"></div>
<div id="admin-users-pagination" class="pagination-container"></div>
</div>
<div id="tab-system-settings" class="dashboard-tab-pane admin-only">
<h3>Cài đặt hệ thống</h3>
<form id="system-settings-form" onsubmit="updateSystemSettings(event)">
<div class="form-group">
<label>Múi giờ (Timezone)</label>
<select id="sys-timezone" name="timezone">
<option value="Asia/Ho_Chi_Minh">Asia/Ho Chi Minh (GMT+7)</option>
<option value="UTC">UTC</option>
</select>
</div>
<div class="form-group">
<label>Ngôn ngữ mặc định</label>
<select id="sys-language" name="language">
<option value="vi">Tiếng Việt</option>
<option value="en">English</option>
</select>
</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>
</div>
<!-- View Stats Modal -->
<div id="view-stats-modal" class="modal-overlay">
<div class="modal-content logout-modal-dark" style="max-width: 700px;">
<h2 style="color: #fff; margin-bottom: 15px;" id="view-stats-modal-title">Thống kê lượt xem</h2>
<div style="width: 100%; height: 300px;">
<canvas id="view-stats-chart"></canvas>
</div>
<p style="color: #ccc; font-size: 12px; margin-top: 15px;">
Biểu đồ hiển thị số lượt xem theo ngày trong 30 ngày gần nhất.
</p>
<button onclick="closeViewStatsModal()" class="edit-btn-large" style="background: #444; width: 100%; margin-top: 20px; font-size: 14px;">Đóng</button>
</div>
</div>
<!-- Modal for Creating Scene -->
<div id="create-scene-modal" class="modal">
<div class="modal-content">
<span class="close-btn" onclick="closeModal()">&times;</span>
<h2 id="create-scene-modal-title">Create New 3D Scene</h2>
<form id="create-scene-form" onsubmit="submitScene(event)">
<!-- Hidden field for editing existing scene -->
<input type="hidden" id="modal-scene-id" name="sceneId">
<div class="form-group">
<label>Selected Coordinates:</label>
<div style="display: flex; gap: 10px;">
<input type="text" id="modal-lat" name="lat" readonly>
<input type="text" id="modal-lng" name="lng" readonly>
</div>
</div>
<div class="form-group">
<label for="modal-title">Scene Title:</label>
<input type="text" id="modal-title" name="title" required placeholder="My Awesome Room">
</div>
<div class="form-group">
<label for="modal-panorama">Upload 360° Panorama Image:</label>
<input type="file" id="modal-panorama" name="panorama" accept="image/*" required>
</div>
<div class="form-group">
<label for="modal-privacy">Privacy:</label>
<select id="modal-privacy" name="privacy" onchange="toggleSharedUsers()">
<option value="public">Public (Everyone)</option>
<option value="private">Private (Only Me)</option>
<option value="member">Members (Logged-in Only)</option>
<option value="shared">Shared via Link/Token</option>
</select>
</div>
<div class="form-group" id="shared-with-group" style="display: none;">
<label for="modal-shared-users">Shared with User IDs (JSON Array):</label>
<input type="text" id="modal-shared-users" name="sharedWithUsers" placeholder='["60c72b2f9b1d8a41c8888888"]'>
</div>
<!-- Progress Bar for Scene Upload -->
<div id="create-progress-container" style="display: none; margin-bottom: 15px;">
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 5px;">
<span id="create-progress-status">Uploading image...</span>
<span id="create-progress-percent">0%</span>
</div>
<div style="width: 100%; height: 8px; background: #eee; border-radius: 4px; overflow: hidden;">
<div id="create-progress-bar" style="width: 0%; height: 100%; background: #28a745; transition: width 0.3s;"></div>
</div>
</div>
<div class="modal-footer" style="padding: 0; border: none; background: transparent;">
<button type="button" class="cancel-btn" onclick="closeModal()">Hủy bỏ</button>
<button type="submit" class="save-btn" style="padding: 12px 24px; font-weight: bold;">Save Scene</button>
</div>
</form>
</div>
</div>
<!-- Modal for Editing Scene Metadata (No Upload) -->
<div id="edit-scene-metadata-modal" class="modal">
<div class="modal-content">
<span class="close-btn" onclick="closeEditMetadataModal()">&times;</span>
<h2 id="edit-metadata-modal-title">Sửa 3D Scene</h2>
<form id="edit-scene-metadata-form" onsubmit="submitEditScene(event)">
<input type="hidden" id="edit-modal-scene-id">
<div class="form-group">
<label for="edit-modal-title">Tên Scene:</label>
<input type="text" id="edit-modal-title" required placeholder="Tên cảnh quay">
</div>
<div class="form-group">
<label for="edit-modal-description">Mô tả:</label>
<textarea id="edit-modal-description" rows="3" placeholder="Mô tả chi tiết về cảnh này..."></textarea>
</div>
<div class="form-group">
<label>Vị trí tọa độ (Click bản đồ để đổi):</label>
<div style="display: flex; gap: 10px; margin-bottom: 10px;">
<input type="text" id="edit-modal-lat" readonly>
<input type="text" id="edit-modal-lng" readonly>
</div>
<div id="edit-mini-map" style="height: 200px; width: 100%; border-radius: 4px; border: 1px solid #ccc; background: #eee;"></div>
</div>
<div class="form-group" id="edit-privacy-container">
<label for="edit-modal-privacy">Quyền riêng tư:</label>
<div style="display: flex; gap: 8px; align-items: center;">
<select id="edit-modal-privacy" onchange="handleEditPrivacyChange()" style="flex: 1;">
<option value="public">Public (Everyone)</option>
<option value="private">Private (Only Me)</option>
<option value="member">Members (Specific People)</option>
<option value="shared">Shared via Link</option>
</select>
<button type="button" id="btn-edit-privacy-settings" class="privacy-settings-btn" title="Cài đặt chia sẻ" onclick="openPrivacySettingsModal()" style="display: none;">⚙️</button>
</div>
<div id="edit-child-privacy-info" style="display: none; color: #888; font-size: 12px; margin-top: 5px;">
️ Cảnh con kế thừa quyền riêng tư từ cảnh cha.
</div>
</div>
<div class="modal-footer" style="padding: 0; border: none; background: transparent;">
<button type="button" class="cancel-btn" onclick="closeEditMetadataModal()">Hủy bỏ</button>
<button type="submit" class="save-btn">Lưu thay đổi</button>
</div>
</form>
</div>
</div>
<!-- Modal Manage Shared Members -->
<div id="share-member-modal" class="modal-overlay">
<div class="modal-content logout-modal-dark" style="max-width: 500px;">
<h2 style="color: #fff; margin-bottom: 15px;">Chia sẻ với thành viên</h2>
<div class="form-group">
<label>Thêm thành viên (Username hoặc Email):</label>
<div style="position: relative;">
<input type="text" id="share-user-search" placeholder="Nhập tên hoặc email..." oninput="searchUsersToShare(this.value)">
<div id="search-results-dropdown" class="search-dropdown" style="display: none;"></div>
</div>
</div>
<div class="shared-list-container">
<label>Danh sách đã chia sẻ:</label>
<div id="current-shared-list" class="shared-users-list">
<!-- Sẽ được fill bằng JS -->
</div>
</div>
<div class="modal-footer" style="padding: 20px 0 0 0; background: transparent; border: none;">
<button onclick="closeShareMemberModal()" class="save-btn">Xong</button>
</div>
</div>
</div>
<!-- Modal Shared Link -->
<div id="share-link-modal" class="modal-overlay">
<div class="modal-content logout-modal-dark" style="max-width: 500px; text-align: center;">
<h2 style="color: #fff; margin-bottom: 15px;">Liên kết chia sẻ</h2>
<p style="color: #ccc; font-size: 14px; margin-bottom: 20px;">Bất kỳ ai có liên kết này đều có thể xem cảnh quay mà không cần đăng nhập.</p>
<div class="form-group" style="text-align: left; margin-bottom: 20px;">
<label style="color: #fff;">Thời hạn liên kết:</label>
<select id="share-link-expire" style="background: #222; color: #fff; border: 1px solid #444;">
<option value="7">7 ngày (Mặc định)</option>
<option value="1">1 ngày</option>
<option value="30">30 ngày</option>
<option value="never">Vĩnh viễn</option>
</select>
</div>
<div class="link-display-area">
<input type="text" id="shared-link-input" readonly style="background: rgba(0,0,0,0.3); color: #00d4ff; border: 1px solid #444; padding: 12px; width: 100%; border-radius: 4px; font-family: monospace; font-size: 13px;">
</div>
<div class="action-buttons" style="margin-top: 25px;">
<button onclick="copySharedLink()" class="edit-btn-large" style="background: #007bff; width: 100%;">
📋 Sao chép liên kết & Đóng
</button>
<button onclick="closeShareLinkModal()" class="edit-btn-large" style="background: #444; width: 100%; margin-top: 10px;">
Đóng
</button>
</div>
</div>
</div>
<!-- Delete Scene Confirmation Modal -->
<div id="delete-scene-confirm-modal" class="modal-overlay">
<div class="modal-content action-modal-content logout-modal-dark">
<h2 style="color: #fff; margin-bottom: 10px;">Xác nhận xóa Scene</h2>
<p style="color: #ccc; margin-bottom: 25px;">Bạn có chắc chắn muốn xóa Scene này? Toàn bộ các scene con liên kết và các hotspot sẽ bị xóa vĩnh viễn khỏi hệ thống.</p>
<div class="action-buttons">
<button onclick="confirmDeleteScene()" class="delete-btn-large">Xóa vĩnh viễn</button>
<button onclick="closeDeleteSceneModal()" class="edit-btn-large" style="background: #6c757d;">Hủy bỏ</button>
</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 id="success-modal-icon" 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>
<!-- Error/Warning Message Modal -->
<div id="error-modal" class="modal-overlay" onclick="closeErrorModal(event)">
<div class="modal-content action-modal-content logout-modal-dark" style="border-top: 4px solid #dc3545; max-width: 380px;">
<div id="error-modal-icon" style="font-size: 40px; color: #dc3545; margin-bottom: 10px;">⚠️</div>
<h2 style="color: #fff; margin-bottom: 5px;" id="error-modal-title">Thông báo</h2>
<p style="color: #ccc;" id="error-modal-message">Bạn không có quyền thực hiện thao tác này.</p>
<button onclick="closeErrorModal()" class="edit-btn-large" style="background: #444; width: 100%; margin-top: 20px; font-size: 14px;">Đóng</button>
</div>
</div>
<!-- Modal for Action Choice (Edit/Delete) -->
<div id="action-choice-modal" class="modal">
<div class="modal-content action-modal-content">
<span class="close-btn" onclick="closeActionModal()">&times;</span>
<h2 id="action-modal-title">Tùy chọn Scene</h2>
<p id="action-modal-desc">Bạn muốn thực hiện thao tác gì với scene này?</p>
<div class="action-buttons">
<button id="btn-share-action" class="edit-btn-large" style="background: #28a745;">
<span class="icon">🔗</span> Lấy link chia sẻ
</button>
<button id="btn-edit-privacy-action" class="edit-btn-large" style="background: #6f42c1;">
<span class="icon">🔒</span> Chỉnh sửa privacy
</button>
<button id="btn-edit-action" class="edit-btn-large">
<span class="icon">✏️</span> Chế độ sửa scene
</button>
<button id="btn-delete-action" class="delete-btn-large">
<span class="icon">🗑️</span> Xóa vĩnh viễn
</button>
</div>
</div>
</div>
<!-- Hotspot Action Choice Modal -->
<div id="hotspot-action-modal" class="modal">
<div class="modal-content action-modal-content">
<span class="close-btn" onclick="closeHotspotActionModal()">&times;</span>
<h2 id="hs-action-title">Tùy chọn Hotspot</h2>
<div class="action-buttons">
<button id="btn-hs-edit" class="edit-btn-large">
<span class="icon">✏️</span> Chỉnh sửa Hotspot
</button>
<button id="btn-hs-delete" class="delete-btn-large">
<span class="icon">🗑️</span> Xóa Hotspot
</button>
</div>
</div>
</div>
<!-- Maintenance Confirmation Modal -->
<div id="maintenance-confirm-modal" class="modal-overlay">
<div class="modal-content action-modal-content logout-modal-dark">
<div id="maintenance-confirm-icon" style="font-size: 40px; color: #ffc107; margin-bottom: 10px;">⚙️</div>
<h2 style="color: #fff; margin-bottom: 10px;" id="maintenance-confirm-title">Xác nhận bảo trì</h2>
<p style="color: #ccc; margin-bottom: 25px;" id="maintenance-confirm-desc">Nội dung xác nhận...</p>
<input type="hidden" id="maintenance-action-type">
<div class="action-buttons">
<button id="maintenance-confirm-btn" class="edit-btn-large" style="background: #28a745;">Xác nhận thực hiện</button>
<button onclick="closeMaintenanceConfirm()" class="edit-btn-large" style="background: #6c757d;">Hủy bỏ</button>
</div>
</div>
</div>
<!-- Logout Confirmation Modal -->
<div id="logout-confirm-modal" class="modal-overlay">
<div class="modal-content action-modal-content logout-modal-dark">
<h2 style="color: #fff; margin-bottom: 10px;">Xác nhận</h2>
<p style="color: #ccc; margin-bottom: 25px;">Bạn có chắc chắn muốn đăng xuất khỏi tài khoản này không?</p>
<div class="action-buttons">
<button onclick="handleLogout()" class="delete-btn-large">
Đăng xuất
</button>
<button onclick="closeLogoutConfirm()" class="edit-btn-large" style="background: #6c757d;">
Hủy bỏ
</button>
</div>
</div>
</div>
<!-- 3D Panorama Viewer Container -->
<div id="viewer-container" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 2000; background: #000;">
<div id="panorama-viewer"></div>
<button id="close-viewer-btn" onclick="closeViewer()">Close 3D View</button>
</div>
<!-- Hotspot Editor Modal -->
<div id="hotspot-modal" class="modal-overlay" style="display: none; z-index: 3000;">
<div class="modal-content">
<div class="modal-header">
<h3 id="hotspot-modal-title">Biên tập điểm điều hướng</h3>
<span class="close-btn" onclick="closeHotspotModal()">&times;</span>
</div>
<form id="hotspot-form">
<!-- Tọa độ ẩn để xử lý GPS và vị trí -->
<input type="hidden" id="hs-pitch">
<input type="hidden" id="hs-yaw">
<input type="hidden" id="hs-id">
<div class="form-group">
<label for="hs-title">Tiêu đề (Label)</label>
<input type="text" id="hs-title" name="title" placeholder="Ví dụ: Cổng vào, Phòng khách..." required>
</div>
<div class="form-group">
<label for="hs-desc">Mô tả chi tiết</label>
<textarea id="hs-desc" name="description" rows="3" placeholder="Thông tin thêm về vị trí này..."></textarea>
</div>
<div class="form-group divider">
<label>Kiểu liên kết:</label>
<div class="radio-group">
<label class="radio-item">
<input type="radio" name="hsLinkType" value="existing" checked onclick="toggleHSLinkType('existing')">
Chọn từ ảnh có sẵn
</label>
<label class="radio-item">
<input type="radio" name="hsLinkType" value="upload" onclick="toggleHSLinkType('upload')">
Upload ảnh mới
</label>
</div>
</div>
<!-- Lựa chọn B: Chọn ảnh có sẵn -->
<div id="hs-section-existing" class="tab-content">
<label for="hs-target-id">Danh sách Scene của bạn:</label>
<select id="hs-target-id" name="targetSceneId">
<option value="">-- Chọn một cảnh để liên kết --</option>
<!-- Sẽ được fill bằng JS -->
</select>
</div>
<!-- Lựa chọn A: Tải ảnh mới -->
<div id="hs-section-upload" class="tab-content" style="display: none;">
<label for="hs-panorama-file">Chọn ảnh Panorama 360°:</label>
<input type="file" id="hs-panorama-file" name="panorama-file" accept="image/*">
<div class="gps-inheritance">
<label>Xử lý GPS cho ảnh mới:</label>
<div class="radio-group" style="flex-direction: column; gap: 5px;">
<label class="radio-item">
<input type="radio" name="hsGPSMode" value="map" checked onclick="toggleHSGPSMode('map')">
Map Selection (Chọn trên bản đồ con)
</label>
<label class="radio-item">
<input type="radio" name="hsGPSMode" value="manual" onclick="toggleHSGPSMode('manual')">
Manual Input (Nhập thủ công)
</label>
<label class="radio-item">
<input type="radio" name="hsGPSMode" value="inherit" onclick="toggleHSGPSMode('inherit')">
Inherit Parent (Kế thừa từ cảnh hiện tại)
</label>
</div>
<div id="hs-map-selector" style="margin-top: 10px;">
<div id="hs-mini-map"></div>
</div>
<div id="hs-manual-gps" style="display: none; margin-top: 10px;">
<input type="number" step="any" id="hs-lat" name="hs-lat" placeholder="Latitude">
<input type="number" step="any" id="hs-lng" name="hs-lng" placeholder="Longitude">
</div>
</div>
</div>
<!-- Progress Bar for Hotspot Upload -->
<div id="hs-progress-container" style="display: none; margin-bottom: 15px;">
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 5px;">
<span id="hs-progress-status">Uploading image...</span>
<span id="hs-progress-percent">0%</span>
</div>
<div style="width: 100%; height: 8px; background: #eee; border-radius: 4px; overflow: hidden;">
<div id="hs-progress-bar" style="width: 0%; height: 100%; background: #007bff; transition: width 0.3s;"></div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="cancel-btn" onclick="closeHotspotModal()">Hủy</button>
<button type="submit" class="save-btn">Lưu điểm điều hướng</button>
</div>
</form>
</div>
</div>
<!-- Leaflet JS -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<!-- Pannellum JS -->
<script src="https://cdn.jsdelivr.net/npm/pannellum@2.5.6/build/pannellum.js"></script>
<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.min.js"></script>
<!-- Leaflet MarkerCluster JS -->
<script src="https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js"></script>
<!-- Custom Scripts -->
<script src="js/viewer360.js"></script>
<script src="js/main_map.js"></script>
</body>
</html>