百度地图修改
This commit is contained in:
parent
af33236f56
commit
b332137dc3
|
|
@ -65,6 +65,79 @@
|
||||||
.tree-children { margin-top: 2px; display: none; }
|
.tree-children { margin-top: 2px; display: none; }
|
||||||
.tree-children.expanded { display: block; }
|
.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 {
|
.model-preview-close {
|
||||||
position: absolute; top: 50px; right: 20px;
|
position: absolute; top: 50px; right: 20px;
|
||||||
width: 40px; height: 40px;
|
width: 40px; height: 40px;
|
||||||
|
|
@ -79,6 +152,22 @@
|
||||||
}
|
}
|
||||||
.model-preview-close::after { transform: rotate(-45deg); }
|
.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 */
|
/* 地图 Label 样式 - 提取至 CSS */
|
||||||
.map-project-label {
|
.map-project-label {
|
||||||
color: #002db6 !important;
|
color: #002db6 !important;
|
||||||
|
|
@ -123,11 +212,23 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="map-container"></div>
|
<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 id="model-preview-panel" class="model-preview-panel" style="display: none;">
|
||||||
<div class="model-preview-tree">
|
<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 id="tree-container"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="model-preview-close" id="close-preview-btn"></div>
|
<div class="model-preview-close" id="close-preview-btn"></div>
|
||||||
|
<div class="model-preview-ar" id="ar-btn">AR</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
@ -263,12 +364,14 @@
|
||||||
projectInfo: [],
|
projectInfo: [],
|
||||||
currentClickedProject: null,
|
currentClickedProject: null,
|
||||||
modelList: [],
|
modelList: [],
|
||||||
checkedNodeIds: []
|
checkedNodeIds: [],
|
||||||
|
selectedProjectId: null
|
||||||
},
|
},
|
||||||
elements: {
|
elements: {
|
||||||
panel: null,
|
panel: null,
|
||||||
tree: null,
|
tree: null,
|
||||||
closeBtn: null
|
closeBtn: null,
|
||||||
|
projectListContainer: null
|
||||||
},
|
},
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
|
@ -287,6 +390,9 @@
|
||||||
// 初始化地图
|
// 初始化地图
|
||||||
this.initMap(this.state.projectInfo);
|
this.initMap(this.state.projectInfo);
|
||||||
|
|
||||||
|
// 渲染工程列表
|
||||||
|
this.renderProjectList();
|
||||||
|
|
||||||
// 处理 URL Action
|
// 处理 URL Action
|
||||||
this.handleUrlActions(params);
|
this.handleUrlActions(params);
|
||||||
},
|
},
|
||||||
|
|
@ -295,6 +401,10 @@
|
||||||
this.elements.panel = document.getElementById('model-preview-panel');
|
this.elements.panel = document.getElementById('model-preview-panel');
|
||||||
this.elements.tree = document.getElementById('tree-container');
|
this.elements.tree = document.getElementById('tree-container');
|
||||||
this.elements.closeBtn = document.getElementById('close-preview-btn');
|
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() {
|
bindEvents() {
|
||||||
|
|
@ -302,6 +412,21 @@
|
||||||
this.elements.closeBtn.addEventListener('click', () => this.closePreview());
|
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
|
// 监听 postMessage
|
||||||
window.addEventListener('message', (e) => {
|
window.addEventListener('message', (e) => {
|
||||||
const data = e.data;
|
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) {
|
openActionMenu(point, info) {
|
||||||
const content = `
|
const content = `
|
||||||
<div class="action-menu">
|
<div class="action-menu">
|
||||||
|
|
@ -455,11 +685,24 @@
|
||||||
const fragment = document.createDocumentFragment();
|
const fragment = document.createDocumentFragment();
|
||||||
treeData.forEach(node => this.renderTreeNode(node, fragment, 0));
|
treeData.forEach(node => this.renderTreeNode(node, fragment, 0));
|
||||||
this.elements.tree.appendChild(fragment);
|
this.elements.tree.appendChild(fragment);
|
||||||
|
|
||||||
|
// 默认全选
|
||||||
|
this.selectAllNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.elements.panel.style.display = 'flex';
|
this.elements.panel.style.display = 'flex';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
navigateToAR() {
|
||||||
|
// 跳转到勘察逻辑
|
||||||
|
const projectInfo = this.state.currentClickedProject;
|
||||||
|
if (projectInfo) {
|
||||||
|
Bridge.sendMessage('navigateToProject', { projectInfo: projectInfo });
|
||||||
|
} else {
|
||||||
|
console.warn('没有选中的工程信息,无法跳转到勘察页面');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
closePreview() {
|
closePreview() {
|
||||||
this.elements.panel.style.display = 'none';
|
this.elements.panel.style.display = 'none';
|
||||||
this.clearModels();
|
this.clearModels();
|
||||||
|
|
@ -569,6 +812,7 @@
|
||||||
const checkbox = document.createElement('input');
|
const checkbox = document.createElement('input');
|
||||||
checkbox.type = 'checkbox';
|
checkbox.type = 'checkbox';
|
||||||
checkbox.className = 'tree-node-checkbox';
|
checkbox.className = 'tree-node-checkbox';
|
||||||
|
checkbox.dataset.id = node.id; // 添加data-id用于全选/全不选时更新UI
|
||||||
checkbox.checked = this.state.checkedNodeIds.includes(node.id);
|
checkbox.checked = this.state.checkedNodeIds.includes(node.id);
|
||||||
checkbox.addEventListener('change', (e) => this.handleCheck(node, e.target.checked));
|
checkbox.addEventListener('change', (e) => this.handleCheck(node, e.target.checked));
|
||||||
itemDiv.appendChild(checkbox);
|
itemDiv.appendChild(checkbox);
|
||||||
|
|
@ -621,6 +865,57 @@
|
||||||
this.loadBatchData();
|
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) {
|
syncCheckboxUI(rootNode, checked) {
|
||||||
// 简易实现:重新渲染虽然 heavy,但在没有 VDOM 的情况下保证一致性。
|
// 简易实现:重新渲染虽然 heavy,但在没有 VDOM 的情况下保证一致性。
|
||||||
// 更好的方式是在 render 时给 checkbox 加 data-id
|
// 更好的方式是在 render 时给 checkbox 加 data-id
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue