From b332137dc3a3ae1bb3bed15a6d076454a10768cd Mon Sep 17 00:00:00 2001
From: cwchen <1048842385@qq.com>
Date: Wed, 14 Jan 2026 10:21:20 +0800
Subject: [PATCH] =?UTF-8?q?=E7=99=BE=E5=BA=A6=E5=9C=B0=E5=9B=BE=E4=BF=AE?=
=?UTF-8?q?=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/static/map.html | 299 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 297 insertions(+), 2 deletions(-)
diff --git a/src/static/map.html b/src/static/map.html
index 9b38fb0..b9ce340 100644
--- a/src/static/map.html
+++ b/src/static/map.html
@@ -65,6 +65,79 @@
.tree-children { margin-top: 2px; display: none; }
.tree-children.expanded { display: block; }
+ /* 全选/全不选按钮 */
+ .tree-select-all {
+ display: flex;
+ gap: 10px;
+ padding: 10px 0;
+ margin-bottom: 10px;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+ }
+
+ .tree-select-btn {
+ flex: 1;
+ padding: 6px 12px;
+ font-size: 13px;
+ background: rgba(0, 45, 182, 0.8);
+ color: #fff;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: background-color 0.2s;
+ }
+ .tree-select-btn:hover {
+ background: rgba(0, 45, 182, 1);
+ }
+
+ /* 工程列表面板 */
+ .project-list-panel {
+ position: absolute; top: 0; left: 0; width: 100%; height: 100%;
+ z-index: 999; display: flex; pointer-events: none; align-items: flex-start;
+ }
+
+ .project-list-container {
+ width: 300px; height: auto; max-height: 80vh;
+ margin: 5% 0 0 2%;
+ background: rgba(30, 30, 30, 0.85);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ border-radius: 8px;
+ overflow-y: auto; overflow-x: hidden;
+ padding: 20px;
+ pointer-events: auto;
+ backdrop-filter: blur(5px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
+ color: #fff;
+ }
+
+ .project-list-container::-webkit-scrollbar { width: 6px; }
+ .project-list-container::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.05); border-radius: 3px; }
+ .project-list-container::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.3); border-radius: 3px; }
+ .project-list-container::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.5); }
+
+ .project-list-item {
+ display: flex; align-items: center; padding: 6px 8px;
+ cursor: pointer; border-radius: 4px; transition: background-color 0.2s;
+ min-height: 28px; margin-bottom: 2px;
+ }
+ .project-list-item:hover { background-color: rgba(255, 255, 255, 0.1); }
+
+ .project-list-radio {
+ width: 16px; height: 16px; margin-right: 8px; cursor: pointer;
+ accent-color: #002db6;
+ }
+
+ .project-list-label {
+ flex: 1; font-size: 14px; user-select: none;
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
+ }
+
+ .project-list-enter-btn {
+ padding: 4px 12px; font-size: 12px; background: rgba(0, 45, 182, 0.8);
+ color: #fff; border: none; border-radius: 4px; cursor: pointer;
+ transition: background-color 0.2s; margin-left: 8px;
+ }
+ .project-list-enter-btn:hover { background: rgba(0, 45, 182, 1); }
+
.model-preview-close {
position: absolute; top: 50px; right: 20px;
width: 40px; height: 40px;
@@ -79,6 +152,22 @@
}
.model-preview-close::after { transform: rotate(-45deg); }
+ /* AR 按钮 */
+ .model-preview-ar {
+ position: absolute; top: 100px; right: 20px;
+ width: 40px; height: 40px;
+ background: rgba(0, 45, 182, 0.95);
+ border-radius: 50%; display: flex; align-items: center; justify-content: center;
+ cursor: pointer; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
+ z-index: 1001; pointer-events: auto;
+ font-size: 20px;
+ color: #fff;
+ font-weight: bold;
+ }
+ .model-preview-ar:hover {
+ background: rgba(0, 45, 182, 1);
+ }
+
/* 地图 Label 样式 - 提取至 CSS */
.map-project-label {
color: #002db6 !important;
@@ -123,11 +212,23 @@
+
+
+
@@ -263,12 +364,14 @@
projectInfo: [],
currentClickedProject: null,
modelList: [],
- checkedNodeIds: []
+ checkedNodeIds: [],
+ selectedProjectId: null
},
elements: {
panel: null,
tree: null,
- closeBtn: null
+ closeBtn: null,
+ projectListContainer: null
},
init() {
@@ -287,6 +390,9 @@
// 初始化地图
this.initMap(this.state.projectInfo);
+ // 渲染工程列表
+ this.renderProjectList();
+
// 处理 URL Action
this.handleUrlActions(params);
},
@@ -295,6 +401,10 @@
this.elements.panel = document.getElementById('model-preview-panel');
this.elements.tree = document.getElementById('tree-container');
this.elements.closeBtn = document.getElementById('close-preview-btn');
+ this.elements.projectListContainer = document.getElementById('project-list-container');
+ this.elements.selectAllBtn = document.getElementById('select-all-btn');
+ this.elements.deselectAllBtn = document.getElementById('deselect-all-btn');
+ this.elements.arBtn = document.getElementById('ar-btn');
},
bindEvents() {
@@ -302,6 +412,21 @@
this.elements.closeBtn.addEventListener('click', () => this.closePreview());
}
+ // AR 按钮
+ if (this.elements.arBtn) {
+ this.elements.arBtn.addEventListener('click', () => this.navigateToAR());
+ }
+
+ // 全选按钮
+ if (this.elements.selectAllBtn) {
+ this.elements.selectAllBtn.addEventListener('click', () => this.selectAllNodes());
+ }
+
+ // 全不选按钮
+ if (this.elements.deselectAllBtn) {
+ this.elements.deselectAllBtn.addEventListener('click', () => this.deselectAllNodes());
+ }
+
// 监听 postMessage
window.addEventListener('message', (e) => {
const data = e.data;
@@ -360,6 +485,111 @@
});
},
+ renderProjectList() {
+ if (!this.elements.projectListContainer) return;
+
+ const projectInfo = this.state.projectInfo || [];
+ if (projectInfo.length === 0) {
+ this.elements.projectListContainer.innerHTML = '暂无工程数据
';
+ return;
+ }
+
+ const fragment = document.createDocumentFragment();
+ projectInfo.forEach((project, index) => {
+ const projectId = project.id || `project-${index}`;
+ const itemDiv = document.createElement('div');
+ itemDiv.className = 'project-list-item';
+ itemDiv.dataset.projectId = projectId;
+
+ // 单选框
+ const radio = document.createElement('input');
+ radio.type = 'radio';
+ radio.name = 'project-radio';
+ radio.className = 'project-list-radio';
+ radio.checked = this.state.selectedProjectId === projectId;
+
+ // 工程名称标签
+ const label = document.createElement('span');
+ label.className = 'project-list-label';
+ label.textContent = `${project.proName || '未命名工程'} (${project.declination || ''})`;
+
+ // 进入按钮
+ const enterBtn = document.createElement('button');
+ enterBtn.className = 'project-list-enter-btn';
+ enterBtn.textContent = '预览';
+ // 只有选中时才显示进入按钮
+ enterBtn.style.display = radio.checked ? 'block' : 'none';
+
+ itemDiv.appendChild(radio);
+ itemDiv.appendChild(label);
+ itemDiv.appendChild(enterBtn);
+
+ // 点击工程项:选中单选框并定位
+ itemDiv.addEventListener('click', (e) => {
+ // 如果点击的是按钮,不触发定位
+ if (e.target === enterBtn) return;
+
+ // 选中单选框
+ const projectId = project.id || `project-${index}`;
+ radio.checked = true;
+ this.state.selectedProjectId = projectId;
+
+ // 更新所有单选框状态和进入按钮显示状态
+ this.updateProjectRadioStates();
+ this.updateEnterButtonsVisibility();
+
+ // 定位到该工程坐标
+ if (project.lng && project.lat) {
+ const point = new BMapGL.Point(project.lng, project.lat);
+ this.map.centerAndZoom(point, 15);
+ }
+ });
+
+ // 单选框变化事件
+ radio.addEventListener('change', () => {
+ if (radio.checked) {
+ this.state.selectedProjectId = projectId;
+ this.updateProjectRadioStates();
+ this.updateEnterButtonsVisibility();
+ }
+ });
+
+ // 点击跳转按钮 - 直接进入模型预览
+ enterBtn.addEventListener('click', (e) => {
+ e.stopPropagation();
+ // 设置当前点击的工程
+ this.state.currentClickedProject = project;
+ // 直接触发模型预览
+ this.triggerPreview(project);
+ });
+
+ fragment.appendChild(itemDiv);
+ });
+
+ this.elements.projectListContainer.innerHTML = '';
+ this.elements.projectListContainer.appendChild(fragment);
+ },
+
+ updateProjectRadioStates() {
+ const radios = this.elements.projectListContainer.querySelectorAll('.project-list-radio');
+ radios.forEach(radio => {
+ const item = radio.closest('.project-list-item');
+ const projectId = item ? item.dataset.projectId : null;
+ radio.checked = this.state.selectedProjectId === projectId;
+ });
+ },
+
+ updateEnterButtonsVisibility() {
+ const items = this.elements.projectListContainer.querySelectorAll('.project-list-item');
+ items.forEach(item => {
+ const radio = item.querySelector('.project-list-radio');
+ const enterBtn = item.querySelector('.project-list-enter-btn');
+ if (radio && enterBtn) {
+ enterBtn.style.display = radio.checked ? 'block' : 'none';
+ }
+ });
+ },
+
openActionMenu(point, info) {
const content = `