Skip to content
Snippets Groups Projects
Commit 40531f93 authored by 汤绍坚's avatar 汤绍坚
Browse files

tsj: 管廊-main-PipeMap 地图;解决地图图例图层的控制,二级图例可以单独控制展示\隐藏;修改右侧列表不能滚动的问题(去掉container的overflow: hidden)

parent fa8e96ff
Branches
Tags
No related merge requests found
src/assets/images/location.png

264 B | W: | H:

src/assets/images/location.png

1.14 KiB | W: | H:

src/assets/images/location.png
src/assets/images/location.png
src/assets/images/location.png
src/assets/images/location.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
width: 1346px; width: 1346px;
height: 723px; height: 723px;
border-radius: 20px; border-radius: 20px;
overflow: hidden;
// position: relative; // position: relative;
.mapTitle { .mapTitle {
...@@ -166,7 +165,7 @@ ...@@ -166,7 +165,7 @@
margin-bottom: 8px; margin-bottom: 8px;
background: rgba(67, 177, 255, 0.08); background: rgba(67, 177, 255, 0.08);
border-radius: 18px; border-radius: 18px;
overflow: hidden; // overflow: hidden;
.listItem { .listItem {
display: flex; display: flex;
...@@ -233,41 +232,33 @@ ...@@ -233,41 +232,33 @@
margin-bottom: 12px; margin-bottom: 12px;
} }
.layerGroup { :global {
display: flex; .ant-tree {
flex-direction: column; background: transparent;
gap: 12px; color: #CBEDFF;
}
.layerItem { .ant-tree-switcher {
.subLayers { display: none !important; // 添加此属性,隐藏展开/折叠按钮
margin-left: 12px;
margin-top: 8px;
display: flex;
flex-direction: column;
gap: 8px;
.subLayerImg{
width: 14px;
height: 16px;
} }
}
.subLayer { .ant-tree-node-content-wrapper {
display: flex; color: #CBEDFF;
align-items: center; }
gap: 8px;
color: rgb(203, 227, 240); .ant-tree-checkbox {
font-size: 16px; .ant-tree-checkbox-inner {
font-weight: 400; background-color: transparent;
line-height: 21px; border-color: #CBEDFF;
}
}
.dot { .ant-tree-checkbox-checked {
width: 8px; .ant-tree-checkbox-inner {
height: 8px; background-color: #1890ff;
border-radius: 50%; border-color: #1890ff;
}
} }
} }
} }
} }
} }
...@@ -383,4 +374,22 @@ ...@@ -383,4 +374,22 @@
} }
} }
.subLayer {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
.dot {
width: 18px;
height: 18px;
border-radius: 50%;
}
.subLayerImg {
width: 14px;
height: 16px;
}
}
import CooglMap from '@/components/CooglMap'; import CooglMap from '@/components/CooglMap';
import services from '@/services'; import services from '@/services';
import { Checkbox, } from 'antd'; import { Checkbox, Tree } from 'antd';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import locationIcon from '@/assets/images/location.png'; import locationIcon from '@/assets/images/location.png';
import pipeMapDetail from '@/assets/images/pipe-map-detail.png'; import pipeMapDetail from '@/assets/images/pipe-map-detail.png';
...@@ -11,6 +11,7 @@ import pipeMapCenter1 from '@/assets/images/pipe-map-center-1.png'; ...@@ -11,6 +11,7 @@ import pipeMapCenter1 from '@/assets/images/pipe-map-center-1.png';
import pipeMapCenter2 from '@/assets/images/pipe-map-center-2.png'; import pipeMapCenter2 from '@/assets/images/pipe-map-center-2.png';
import styles from './index.less'; import styles from './index.less';
import type { TabsProps } from 'antd'; import type { TabsProps } from 'antd';
import type { DataNode } from 'antd/es/tree';
// 添加类型定义 // 添加类型定义
interface PipelineType { interface PipelineType {
...@@ -35,6 +36,110 @@ const Map: React.FC = () => { ...@@ -35,6 +36,110 @@ const Map: React.FC = () => {
// 修改默认展开状态为空数组(都收起) // 修改默认展开状态为空数组(都收起)
const [expandedTypes, setExpandedTypes] = useState<string[]>([]); const [expandedTypes, setExpandedTypes] = useState<string[]>([]);
// 修改状态结构,记录每个类型的显示状态
// const [selectedSubLayers, setSelectedSubLayers] = useState<Record<string, boolean>>({
// '干线': true,
// '支线': true,
// '小型': true,
// '缆线': true
// });
// 修改为使用 Tree 的选中状态管理
const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([
'pipeline', 'monitor', 'pipeline-干线', 'pipeline-支线', 'pipeline-小型', 'pipeline-缆线'
]);
// 将管廊数据按类型分组
const groupedPipelines = pipelineData.reduce((acc: any, cur: any) => {
const type = cur.lx || '其他';
if (!acc[type]) {
acc[type] = [];
}
acc[type].push({
id: cur.id,
name: cur.mc,
...cur
});
return acc;
}, {});
// 修改 pipelineTypes 的定义,添加数量显示
const pipelineTypes: PipelineType[] = [
{
type: '干线',
name: '干线',
items: groupedPipelines['干线'] || [],
expanded: expandedTypes.includes('干线'),
count: groupedPipelines['干线']?.length || 0
},
{
type: '支线',
name: '支线',
items: groupedPipelines['支线'] || [],
expanded: expandedTypes.includes('支线'),
count: groupedPipelines['支线']?.length || 0
},
{
type: '小型',
name: '小型',
items: groupedPipelines['小型'] || [],
expanded: expandedTypes.includes('小型'),
count: groupedPipelines['小型']?.length || 0
},
{
type: '缆线',
name: '缆线',
items: groupedPipelines['缆线'] || [],
expanded: expandedTypes.includes('缆线'),
count: groupedPipelines['缆线']?.length || 0
}
];
// 构建 Tree 的数据结构
const treeData: DataNode[] = [
{
title: '管廊',
key: 'pipeline',
children: pipelineTypes.map(type => ({
title: (
<div className={styles.subLayer}>
<span className={styles.dot} style={{
background: type.type === '干线' ? '#AD6BFF' :
type.type === '支线' ? '#FDFFC6' :
type.type === '小型' ? '#6FDCFF' : '#4874FF'
}} />
<span>{type.name}</span>
</div>
),
key: `pipeline-${type.type}`,
})),
},
{
title: '监控中心',
key: 'monitor',
children: [
{
title: (
<div className={styles.subLayer}>
<img src={pipeMapCenter1} className={styles.subLayerImg} alt="" />
<span>总控中心</span>
</div>
),
key: 'monitor-总控',
},
{
title: (
<div className={styles.subLayer}>
<img src={pipeMapCenter2} className={styles.subLayerImg} alt="" />
<span>分控中心</span>
</div>
),
key: 'monitor-分控',
},
],
},
];
// 获取管廊基本信息 // 获取管廊基本信息
const getPipelineData = async (lx?: string) => { const getPipelineData = async (lx?: string) => {
try { try {
...@@ -109,7 +214,6 @@ const Map: React.FC = () => { ...@@ -109,7 +214,6 @@ const Map: React.FC = () => {
getPipelineData(); getPipelineData();
getPipelineCoords(); getPipelineCoords();
}, []); }, []);
// 绘制管廊路线 // 绘制管廊路线
const drawPipelines = () => { const drawPipelines = () => {
...@@ -122,16 +226,44 @@ const Map: React.FC = () => { ...@@ -122,16 +226,44 @@ const Map: React.FC = () => {
if (!item.processedCoordinates?.length) return; if (!item.processedCoordinates?.length) return;
// 使用CooglMap的Polyline组件绘制线 // 使用CooglMap的Polyline组件绘制线
return ( // return (
<CooglMap.Polyline // <CooglMap.Polyline
points={item.processedCoordinates} // points={item.processedCoordinates}
width={4} // width={4}
lineColor="#1890FF" // lineColor="#1890FF"
onClick={() => handlePipelineClick(item)} // onClick={() => handlePipelineClick(item)}
/> // />
); // );
return drawPipelinesFromCoord(item);
}); });
}; };
// 绘制管廊路线
const drawPipelinesFromCoord = (item: any) => {
// 找到对应的管廊基本信息
const pipelineInfo = pipelineData.find(p => p.mc === item.gridName);
const type = pipelineInfo?.lx;
// 只渲染有类型且类型被选中的线路
if (!type || !checkedKeys.includes(`pipeline-${type}`)) {
return null;
}
return (
<CooglMap.Polyline
key={item.id}
points={item.processedCoordinates}
lineColor={
type === '干线' ? '#AD6BFF' :
type === '支线' ? '#FDFFC6' :
type === '小型' ? '#6FDCFF' : '#4874FF'
}
width={2}
onClick={() => handlePipelineClick(item)}
/>
);
};
// 监听选中图层变化时重新绘制 // 监听选中图层变化时重新绘制
useEffect(() => { useEffect(() => {
...@@ -181,15 +313,53 @@ const Map: React.FC = () => { ...@@ -181,15 +313,53 @@ const Map: React.FC = () => {
} }
}; };
// 处理图层切换 // 处理子图层选择变化
const handleLayerChange = (values: string[]) => { // const handleSubLayerChange = (type: string, checked: boolean) => {
setSelectedLayers(values); // setSelectedSubLayers(prev => ({
}; // ...prev,
// [type]: checked
// }));
// // 根据类型筛选显示管廊
// if (mapRef.current) {
// pipelineCoords.forEach((item: any) => {
// const layerName = `pipeline-${item.id}`;
// const layer = mapRef.current.getLayer(layerName);
// if (layer && item.lx === type) {
// layer.setVisible(checked);
// }
// });
// }
// };
// 处理一级图层选择变化
// const handleLayerChange = (checkedValues: string[]) => {
// setSelectedLayers(checkedValues);
// // 如果取消选中管廊,则隐藏所有子图层
// if (!checkedValues.includes('pipeline')) {
// setSelectedSubLayers(prev =>
// Object.keys(prev).reduce((acc, key) => ({
// ...acc,
// [key]: false
// }), {})
// );
// }
// // 如果选中管廊,则显示所有子图层
// else if (checkedValues.includes('pipeline')) {
// setSelectedSubLayers(prev =>
// Object.keys(prev).reduce((acc, key) => ({
// ...acc,
// [key]: true
// }), {})
// );
// }
// };
// 处理图例点击 // 处理图例点击
const handleLegendClick = (type: string) => { // const handleLegendClick = (type: string) => {
getPipelineData(type); // getPipelineData(type);
}; // };
// 处理详情点击 // 处理详情点击
const handleDetailClick = (item: any) => { const handleDetailClick = (item: any) => {
...@@ -203,52 +373,6 @@ const Map: React.FC = () => { ...@@ -203,52 +373,6 @@ const Map: React.FC = () => {
// TODO: 打开详情弹窗 // TODO: 打开详情弹窗
}; };
// 将管廊数据按类型分组
const groupedPipelines = pipelineData.reduce((acc: any, cur: any) => {
const type = cur.lx || '其他';
if (!acc[type]) {
acc[type] = [];
}
acc[type].push({
id: cur.id,
name: cur.mc,
...cur
});
return acc;
}, {});
// 修改 pipelineTypes 的定义,添加数量显示
const pipelineTypes: PipelineType[] = [
{
type: '干线',
name: '干线',
items: groupedPipelines['干线'] || [],
expanded: expandedTypes.includes('干线'),
count: groupedPipelines['干线']?.length || 0
},
{
type: '支线',
name: '支线',
items: groupedPipelines['支线'] || [],
expanded: expandedTypes.includes('支线'),
count: groupedPipelines['支线']?.length || 0
},
{
type: '小型',
name: '小型',
items: groupedPipelines['小型'] || [],
expanded: expandedTypes.includes('小型'),
count: groupedPipelines['小型']?.length || 0
},
{
type: '缆线',
name: '缆线',
items: groupedPipelines['缆线'] || [],
expanded: expandedTypes.includes('缆线'),
count: groupedPipelines['缆线']?.length || 0
}
];
// 处理类型展开/收起 // 处理类型展开/收起
const toggleTypeExpand = (type: string) => { const toggleTypeExpand = (type: string) => {
setExpandedTypes(prev => setExpandedTypes(prev =>
...@@ -282,12 +406,59 @@ const Map: React.FC = () => { ...@@ -282,12 +406,59 @@ const Map: React.FC = () => {
handleLocationClick(item); handleLocationClick(item);
}; };
// 处理 Tree 选中变化
const onCheck = (checked: any) => {
// console.log('==>checked', checked);
// 如果取消选中管廊总图层,同时取消所有子图层
if (selectedLayers.includes('pipeline') && !checked.includes('pipeline')) {
const newChecked = checked.filter((key: string) => !key.startsWith('pipeline'));
setCheckedKeys(newChecked);
setSelectedLayers(newChecked);
return;
}
// 如果选中管廊总图层,同时选中所有子图层
if (!selectedLayers.includes('pipeline') && checked.includes('pipeline')) {
const allPipelineKeys = pipelineTypes.map(type => `pipeline-${type.type}`);
setCheckedKeys([...checked, ...allPipelineKeys]);
setSelectedLayers(checked.filter((key: string) => !key.includes('-')));
return;
}
// 正常更新选中状态
setCheckedKeys(checked);
setSelectedLayers(checked.filter((key: string) => !key.includes('-')));
};
// 过滤需要显示的管廊数据
const filteredPipelineCoords = pipelineCoords.filter(item => {
// 首先检查是否选中了管廊图层
if (!selectedLayers.includes('pipeline')) return false;
// 找到对应的管廊基本信息来获取类型
const pipelineInfo = pipelineData.find(p => p.mc === item.gridName);
const type = pipelineInfo?.lx;
// 检查该类型是否被选中
const typeKey = `pipeline-${type}`;
// console.log('==>item', {
// gridName: item.gridName,
// type,
// typeKey,
// isChecked: checkedKeys.includes(typeKey),
// checkedKeys
// });
// 只有当类型存在且该类型被选中时才显示
return type && checkedKeys.includes(typeKey);
});
return ( return (
<div className={styles.container}> <div className={styles.container}>
<CooglMap.MapView <CooglMap.MapView
ref={mapRef} ref={mapRef}
center={{ x: 103.96, y: 30.658842 }} center={{ x: 103.96, y: 30.658842 }}
// zoom={12}
zoom={8} zoom={8}
mode="3D" mode="3D"
> >
...@@ -295,30 +466,56 @@ const Map: React.FC = () => { ...@@ -295,30 +466,56 @@ const Map: React.FC = () => {
<div className={styles.mapTitle}>管廊分布</div> <div className={styles.mapTitle}>管廊分布</div>
{/* 管廊路线图层 */} {/* 管廊路线图层 */}
{selectedLayers.includes('pipeline') && pipelineCoords?.map((item: any, index: number) => { {filteredPipelineCoords.map((item: any) => {
if (!item?.processedCoordinates?.length) return null;
// 找到对应的管廊基本信息 // 找到对应的管廊基本信息
const pipelineInfo = pipelineData.find(p => p.mc === item.gridName); // const pipelineInfo = pipelineData.find(p => p.mc === item.gridName);
const type = pipelineInfo?.lx; // const type = pipelineInfo?.lx;
// const type = pipelineInfo?.lx || '其他';
// 根据类型设置不同颜色 // // 只渲染有类型且类型被选中的线路
const color = type === '干线' ? '#AD6BFF' : // if (!type || !checkedKeys.includes(`pipeline-${type}`)) {
type === '支线' ? '#FDFFC6' : // return null;
type === '小型' ? '#6FDCFF' : '#4874FF'; // }
return ( // return (
<CooglMap.Polyline // <CooglMap.Polyline
key={`${item.gridId || index}`} // key={item.id}
points={item.processedCoordinates} // points={item.processedCoordinates}
width={type === '干线' ? 5 : 4} // lineColor={
lineColor={color} // type === '干线' ? '#AD6BFF' :
onClick={() => handlePipelineClick(item)} // type === '支线' ? '#FDFFC6' :
/> // type === '小型' ? '#6FDCFF' : '#4874FF'
); // }
// width={2}
// onClick={() => handlePipelineClick(item)}
// />
// );
return drawPipelinesFromCoord(item);
})} })}
{/* 监控中心图层 */}
{selectedLayers.includes('monitor') && (
<>
{/* {checkedKeys.includes('monitor-总控') && (
<CooglMap.Marker
key="monitor-总控"
position={[104.06, 30.67]}
icon={pipeMapCenter1}
width={20}
height={20}
/>
)}
{checkedKeys.includes('monitor-分控') && (
<CooglMap.Marker
key="monitor-分控"
position={[104.08, 30.65]}
icon={pipeMapCenter2}
width={20}
height={20}
/>
)} */}
</>
)}
{/* 选中管廊的信息展示 */} {/* 选中管廊的信息展示 */}
{selectedPipeline && ( {selectedPipeline && (
<CooglMap.CustomOverlay <CooglMap.CustomOverlay
...@@ -373,43 +570,17 @@ const Map: React.FC = () => { ...@@ -373,43 +570,17 @@ const Map: React.FC = () => {
{/* 图层控制 */} {/* 图层控制 */}
<div className={styles.layerControl}> <div className={styles.layerControl}>
<div className={styles.title}>图层图例</div> <div className={styles.title}>图层图例</div>
<Checkbox.Group value={selectedLayers} onChange={handleLayerChange}> <Tree
<div className={styles.layerGroup}> checkable
<div className={styles.layerItem}> checkStrictly
<Checkbox value="pipeline">管廊</Checkbox> checkedKeys={checkedKeys}
<div className={styles.subLayers}> onCheck={(checked: any) => onCheck(checked.checked)}
{pipelineTypes.map(type => ( // onCheck={checked => onCheck(checked.checked)}
<div treeData={treeData}
key={type.type} defaultExpandAll
className={styles.subLayer} // showLine={false} // 添加此属性,隐藏展开/折叠按钮
onClick={() => handleLegendClick(type.type)} // switcherIcon={<div></div>} // 添加此属性,隐藏展开/折叠按钮 -- 自定义树节点的展开/折叠图标(带有默认 rotate 角度样式)
style={{ cursor: 'pointer' }} />
>
<span className={styles.dot} style={{
background: type.type === '干线' ? '#AD6BFF' :
type.type === '支线' ? '#FDFFC6' :
type.type === '小型' ? '#6FDCFF' : '#4874FF'
}} />
<span>{type.name}</span>
</div>
))}
</div>
</div>
<div className={styles.layerItem}>
<Checkbox value="monitor">监控中心</Checkbox>
<div className={styles.subLayers}>
<div >
<img src={pipeMapCenter1} className={styles.subLayerImg} alt="" />
<span>总控中心</span>
</div>
<div >
<img src={pipeMapCenter2} className={styles.subLayerImg} alt="" />
<span>分控中心</span>
</div>
</div>
</div>
</div>
</Checkbox.Group>
</div> </div>
{/* 右侧列表 */} {/* 右侧列表 */}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment