百度地图修改

This commit is contained in:
cwchen 2026-01-14 10:21:20 +08:00
parent af33236f56
commit b332137dc3
1 changed files with 297 additions and 2 deletions

View File

@ -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 @@
<body>
<div id="map-container"></div>
<!-- 工程列表面板 -->
<div id="project-list-panel" class="project-list-panel">
<div class="project-list-container">
<div id="project-list-container"></div>
</div>
</div>
<div id="model-preview-panel" class="model-preview-panel" style="display: none;">
<div class="model-preview-tree">
<div class="tree-select-all">
<button class="tree-select-btn" id="select-all-btn">全选</button>
<button class="tree-select-btn" id="deselect-all-btn">全不选</button>
</div>
<div id="tree-container"></div>
</div>
<div class="model-preview-close" id="close-preview-btn"></div>
<div class="model-preview-ar" id="ar-btn">AR</div>
</div>
</body>
@ -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 = '<div style="color:#aaa;text-align:center;padding:20px;">暂无工程数据</div>';
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 = `
<div class="action-menu">
@ -455,11 +685,24 @@
const fragment = document.createDocumentFragment();
treeData.forEach(node => this.renderTreeNode(node, fragment, 0));
this.elements.tree.appendChild(fragment);
// 默认全选
this.selectAllNodes();
}
this.elements.panel.style.display = 'flex';
},
navigateToAR() {
// 跳转到勘察逻辑
const projectInfo = this.state.currentClickedProject;
if (projectInfo) {
Bridge.sendMessage('navigateToProject', { projectInfo: projectInfo });
} else {
console.warn('没有选中的工程信息,无法跳转到勘察页面');
}
},
closePreview() {
this.elements.panel.style.display = 'none';
this.clearModels();
@ -569,6 +812,7 @@
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'tree-node-checkbox';
checkbox.dataset.id = node.id; // 添加data-id用于全选/全不选时更新UI
checkbox.checked = this.state.checkedNodeIds.includes(node.id);
checkbox.addEventListener('change', (e) => this.handleCheck(node, e.target.checked));
itemDiv.appendChild(checkbox);
@ -621,6 +865,57 @@
this.loadBatchData();
},
// 获取所有节点ID递归
getAllNodeIds(nodes) {
let ids = [];
nodes.forEach(node => {
ids.push(node.id);
if (node.children && node.children.length > 0) {
ids = ids.concat(this.getAllNodeIds(node.children));
}
});
return ids;
},
// 全选
selectAllNodes() {
const treeData = this.buildTreeData(this.state.modelList);
const allIds = this.getAllNodeIds(treeData);
this.state.checkedNodeIds = [...new Set(allIds)]; // 去重
// 更新所有复选框UI
this.updateAllCheckboxes();
// 触发数据加载
this.loadBatchData();
},
// 全不选
deselectAllNodes() {
this.state.checkedNodeIds = [];
// 更新所有复选框UI
this.updateAllCheckboxes();
// 清除模型
this.clearModels();
},
// 更新所有复选框状态
updateAllCheckboxes() {
const checkboxes = this.elements.tree.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => {
// 从checkbox的data-id获取节点ID
const nodeId = checkbox.dataset.id;
if (nodeId !== undefined) {
// 确保ID类型一致都转为字符串或数字进行比较
const idStr = String(nodeId);
const checkedIdsStr = this.state.checkedNodeIds.map(id => String(id));
checkbox.checked = checkedIdsStr.includes(idStr);
}
});
},
syncCheckboxUI(rootNode, checked) {
// 简易实现:重新渲染虽然 heavy但在没有 VDOM 的情况下保证一致性。
// 更好的方式是在 render 时给 checkbox 加 data-id