| | |
| | | @stage-change="handleStageChange" /> |
| | | <div v-if="props.showLayerControl" class="layer-control-root" :class="{ collapsed: props.rightCollapsed }"> |
| | | <div class="layer-control-wrap" ref="layerWrapRef"> |
| | | <div class="layer-control" @click="toggleLayerPanel"> |
| | | <div class="layer-control" @click.stop="toggleLayerPanel"> |
| | | <img :src="layerControlIcon" alt="图层控制" /> |
| | | </div> |
| | | <transition name="layer-panel-slide"> |
| | | <div v-if="showLayerPanel" class="layer-panel"> |
| | | <div class="panel-title">底图切换</div> |
| | | <div class="base-map-options"> |
| | | <div class="base-map-card" :class="{ active: baseLayerKey === 'base-standard' }" |
| | | @click="handleBaseLayerSelect('base-standard')"> |
| | | <img class="base-map-thumb standard" :src="dzIcon" alt=""> |
| | | <div class="base-map-label">标准地图</div> |
| | | </div> |
| | | <div class="base-map-card" :class="{ active: baseLayerKey === 'base-satellite' }" |
| | | @click="handleBaseLayerSelect('base-satellite')"> |
| | | <img class="base-map-thumb satellite" :src="yxIcon" alt=""> |
| | | <div class="base-map-label">卫星地图</div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="panel-title">图层管理</div> |
| | | <div class="panel-content"> |
| | | <el-tree ref="layerTreeRef" class="command-tree map-layer-tree" :data="layerTree" show-checkbox |
| | | default-expand-all node-key="key" :props="layerTreeProps" |
| | | <el-tree ref="layerTreeRef" class="command-tree map-layer-tree" :data="layerTree" |
| | | show-checkbox default-expand-all node-key="key" :props="layerTreeProps" |
| | | :default-checked-keys="treeCheckedKeys" @check="handleLayerCheck" /> |
| | | </div> |
| | | </div> |
| | | </transition> |
| | | </div> |
| | | </div> |
| | | <div v-if="props.showLayerControl" class="base-layer-switch-root" :class="{ collapsed: props.rightCollapsed }"> |
| | | <div class="base-layer-switch-wrap" @mouseenter="showBaseLayerPanel = true" |
| | | @mouseleave="showBaseLayerPanel = false"> |
| | | <div class="base-layer-trigger"> |
| | | <img class="base-layer-trigger-thumb" :src="currentBaseLayer.icon" :alt="currentBaseLayer.label"> |
| | | <div class="base-layer-trigger-label">{{ currentBaseLayer.shortLabel }}</div> |
| | | </div> |
| | | <transition name="layer-panel-slide"> |
| | | <div v-if="showBaseLayerPanel" class="base-layer-panel"> |
| | | <div class="base-map-options"> |
| | | <div class="base-map-card" :class="{ active: baseLayerKey === 'base-satellite' }" |
| | | @click="handleBaseLayerSelect('base-satellite')"> |
| | | <img class="base-map-thumb" :src="yxIcon" alt=""> |
| | | <div class="base-map-label">卫星地图</div> |
| | | </div> |
| | | <div class="base-map-card" :class="{ active: baseLayerKey === 'base-standard' }" |
| | | @click="handleBaseLayerSelect('base-standard')"> |
| | | <img class="base-map-thumb" :src="dzIcon" alt=""> |
| | | <div class="base-map-label">标准地图</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </transition> |
| | |
| | | const clusterVisible = ref(false) |
| | | const countyCenterMap = new Map() |
| | | const showLayerPanel = ref(false) |
| | | const showBaseLayerPanel = ref(false) |
| | | const layerWrapRef = ref(null) |
| | | const layerTreeRef = ref(null) |
| | | const selectedDevice = ref(null) |
| | |
| | | const baseLayerKeys = ['base-standard', 'base-satellite'] |
| | | const defaultCheckedKeys = ['ja-terrain', 'admin', 'city-base'] |
| | | const baseLayerKey = ref('base-satellite') |
| | | const baseLayerMeta = { |
| | | 'base-standard': { icon: dzIcon, label: '标准地图', shortLabel: '标准' }, |
| | | 'base-satellite': { icon: yxIcon, label: '卫星地图', shortLabel: '影像' }, |
| | | } |
| | | const currentBaseLayer = computed(() => baseLayerMeta[baseLayerKey.value] || baseLayerMeta['base-satellite']) |
| | | const treeCheckedKeys = ref([...defaultCheckedKeys]) |
| | | const layerTree = ref([ |
| | | { |
| | |
| | | watch( |
| | | () => props.rightCollapsed, |
| | | isCollapsed => { |
| | | if (isCollapsed) showLayerPanel.value = false |
| | | if (!isCollapsed) return |
| | | showLayerPanel.value = false |
| | | showBaseLayerPanel.value = false |
| | | } |
| | | ) |
| | | |
| | |
| | | setDroneVisibility(!showCluster) |
| | | } |
| | | |
| | | const handleMapReady = async ({ viewer: mapViewer, publicCesium: mapPublic }) => { |
| | | const handleMapReady = async ({ viewer: mapViewer, publicCesium: mapPublic }) => { |
| | | if (mapReadyHandled) return |
| | | mapReadyHandled = true |
| | | viewer = mapViewer |
| | |
| | | updateStageDisplay(stage) |
| | | } |
| | | |
| | | const handleClickOutside = event => { |
| | | const handleLayerClickOutside = event => { |
| | | if (!showLayerPanel.value) return |
| | | const target = event.target |
| | | if (layerWrapRef.value?.contains(target)) return |
| | |
| | | } |
| | | |
| | | onMounted(() => { |
| | | document.addEventListener('click', handleClickOutside) |
| | | document.addEventListener('click', handleLayerClickOutside) |
| | | const map = mapRef.value?.getMap() |
| | | if (map?.viewer) handleMapReady(map) |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | document.removeEventListener('click', handleClickOutside) |
| | | document.removeEventListener('click', handleLayerClickOutside) |
| | | clearDeviceEntities() |
| | | clearPartitionEntities() |
| | | clearAggregationEntities() |
| | |
| | | overflow: auto; |
| | | } |
| | | |
| | | .base-map-title { |
| | | margin-bottom: 8px; |
| | | font-size: 12px; |
| | | color: #ffffff; |
| | | font-weight: 600; |
| | | } |
| | | } |
| | | |
| | | .base-map-options { |
| | | padding: 16px; |
| | | display: grid; |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | gap: 8px; |
| | | } |
| | | .base-layer-switch-root { |
| | | position: absolute; |
| | | right: 337px; |
| | | bottom: 78px; |
| | | z-index: 11; |
| | | transition: transform 0.3s ease-in-out; |
| | | pointer-events: none; |
| | | |
| | | .base-map-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 6px; |
| | | &.collapsed { |
| | | transform: translateX(317px); |
| | | } |
| | | } |
| | | |
| | | .base-layer-switch-wrap { |
| | | position: relative; |
| | | pointer-events: auto; |
| | | } |
| | | |
| | | .base-layer-trigger { |
| | | width: 55px; |
| | | padding: 8px 0; |
| | | border-radius: 8px; |
| | | background: #191932; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | gap: 6px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .base-layer-trigger-thumb { |
| | | width: 36px; |
| | | height: 36px; |
| | | border-radius: 6px; |
| | | display: block; |
| | | // border: 2px solid #fff; |
| | | background-size: cover; |
| | | background-position: center; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .base-layer-trigger-label { |
| | | margin-top: 8px; |
| | | font-size: 12px; |
| | | line-height: 1; |
| | | color: #ffffff; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .base-layer-panel { |
| | | position: absolute; |
| | | right: calc(100% + 10px); |
| | | bottom: 0; |
| | | margin-bottom: 0; |
| | | width: 160px; |
| | | background: #191932; |
| | | border-radius: 8px; |
| | | z-index: 99; |
| | | |
| | | &::after { |
| | | content: ''; |
| | | position: absolute; |
| | | right: -10px; |
| | | top: 0; |
| | | width: 10px; |
| | | height: 100%; |
| | | background: transparent; |
| | | } |
| | | } |
| | | |
| | | .base-map-options { |
| | | padding: 8px; |
| | | display: grid; |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | gap: 8px; |
| | | } |
| | | |
| | | .base-map-card { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 6px; |
| | | border-radius: 6px; |
| | | color: #d8e6ff; |
| | | font-size: 12px; |
| | | cursor: pointer; |
| | | transition: all 0.2s ease; |
| | | |
| | | .base-map-thumb { |
| | | width: 36px; |
| | | height: 36px; |
| | | border-radius: 6px; |
| | | color: #d8e6ff; |
| | | font-size: 12px; |
| | | cursor: pointer; |
| | | transition: all 0.2s ease; |
| | | |
| | | .base-map-thumb { |
| | | width: 46px; |
| | | height: 46px; |
| | | border-radius: 4px; |
| | | background-size: cover; |
| | | background-position: center; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | &.active { |
| | | .base-map-thumb { |
| | | border: 2px solid #2ea8ff; |
| | | } |
| | | |
| | | .base-map-label { |
| | | color: #2ea8ff; |
| | | } |
| | | } |
| | | // border: 2px solid #fff; |
| | | background-size: cover; |
| | | background-position: center; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .base-map-label { |
| | | margin-top: 8px; |
| | | font-size: 12px; |
| | | line-height: 1; |
| | | color: #ffffff; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | |
| | | // &.active { |
| | | // .base-map-thumb { |
| | | // border: 2px solid #2ea8ff; |
| | | // } |
| | | |
| | | // .base-map-label { |
| | | // color: #2ea8ff; |
| | | // } |
| | | // } |
| | | } |
| | | |
| | | .layer-panel-slide-enter-active, |