|
@@ -74,25 +74,6 @@
|
|
|
</div>
|
|
</div>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
|
|
|
|
|
- <el-card shadow="never" class="panel-card detail-card">
|
|
|
|
|
- <template #header>
|
|
|
|
|
- <span>要素详情</span>
|
|
|
|
|
- </template>
|
|
|
|
|
- <div v-if="selectedFeature" class="detail-body">
|
|
|
|
|
- <div class="detail-name">{{ selectedFeature.name }}</div>
|
|
|
|
|
- <div class="detail-tag">{{ selectedFeature.category }}</div>
|
|
|
|
|
- <el-descriptions :column="1" border size="small">
|
|
|
|
|
- <el-descriptions-item
|
|
|
|
|
- v-for="item in selectedFeatureDetails"
|
|
|
|
|
- :key="item.label"
|
|
|
|
|
- :label="item.label"
|
|
|
|
|
- >
|
|
|
|
|
- {{ item.value }}
|
|
|
|
|
- </el-descriptions-item>
|
|
|
|
|
- </el-descriptions>
|
|
|
|
|
- </div>
|
|
|
|
|
- <el-empty v-else description="点击地图要素查看详情" :image-size="72" />
|
|
|
|
|
- </el-card>
|
|
|
|
|
</aside>
|
|
</aside>
|
|
|
|
|
|
|
|
<section class="dashboard-map-panel">
|
|
<section class="dashboard-map-panel">
|
|
@@ -114,9 +95,36 @@
|
|
|
<div class="toolbar-right">当前坐标: {{ currentCoordinate }}</div>
|
|
<div class="toolbar-right">当前坐标: {{ currentCoordinate }}</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div id="gisMap" ref="mapRef" class="gis-map"></div>
|
|
<div id="gisMap" ref="mapRef" class="gis-map"></div>
|
|
|
- <div v-if="mapError" class="map-error">{{ mapError }}</div>
|
|
|
|
|
|
|
+ <div v-if="mapError" class="map-error">
|
|
|
|
|
+ <el-result icon="warning" title="供水设施图层加载失败" :sub-title="mapError">
|
|
|
|
|
+ <template #extra><el-button type="primary" @click="loadGisData">重试</el-button></template>
|
|
|
|
|
+ </el-result>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-else-if="mapEmpty" class="map-error">
|
|
|
|
|
+ <el-empty description="当前筛选下没有可显示的供水设施" />
|
|
|
|
|
+ </div>
|
|
|
</section>
|
|
</section>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-drawer
|
|
|
|
|
+ v-model="detailOpen"
|
|
|
|
|
+ :title="detailTitle"
|
|
|
|
|
+ direction="rtl"
|
|
|
|
|
+ class="detail-drawer"
|
|
|
|
|
+ size="560px"
|
|
|
|
|
+ append-to-body
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-skeleton v-if="detailLoading" :rows="8" animated />
|
|
|
|
|
+ <el-result v-else-if="detailError" icon="warning" title="设施详情加载失败" :sub-title="detailError">
|
|
|
|
|
+ <template #extra><el-button type="primary" @click="loadFacilityDetail">重试</el-button></template>
|
|
|
|
|
+ </el-result>
|
|
|
|
|
+ <el-descriptions v-else-if="detailRecord" :column="1" border>
|
|
|
|
|
+ <el-descriptions-item v-for="item in detailEntries" :key="item.label" :label="item.label">
|
|
|
|
|
+ {{ item.value }}
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ </el-descriptions>
|
|
|
|
|
+ <el-empty v-else description="暂无设施详情" />
|
|
|
|
|
+ </el-drawer>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -127,6 +135,8 @@ import { ElMessage } from 'element-plus'
|
|
|
import { convertCoord } from '@/utils/coordTransform'
|
|
import { convertCoord } from '@/utils/coordTransform'
|
|
|
import { getWaterFacilityOverview, getWaterFacilityFeatures, getWaterFacilityDetail } from '@/api/pipeNetwork/waterSupply'
|
|
import { getWaterFacilityOverview, getWaterFacilityFeatures, getWaterFacilityDetail } from '@/api/pipeNetwork/waterSupply'
|
|
|
import { normalizeGeoJson, unwrapResponse } from '@/utils/waterSupplyModel'
|
|
import { normalizeGeoJson, unwrapResponse } from '@/utils/waterSupplyModel'
|
|
|
|
|
+import { getRequestErrorMessage } from '@/utils/waterFacilityQuery'
|
|
|
|
|
+import { buildFacilityMapModel, filterFacilityMapModel, findFacilityFeature } from '@/utils/waterFacilityGisModel'
|
|
|
|
|
|
|
|
const centerPoint = { lng: 110.386, lat: 28.445 }
|
|
const centerPoint = { lng: 110.386, lat: 28.445 }
|
|
|
|
|
|
|
@@ -174,15 +184,19 @@ const mapRef = ref(null)
|
|
|
const screenRef = ref(null)
|
|
const screenRef = ref(null)
|
|
|
const searchKeyword = ref('')
|
|
const searchKeyword = ref('')
|
|
|
const currentCoordinate = ref(`${centerPoint.lng}, ${centerPoint.lat}`)
|
|
const currentCoordinate = ref(`${centerPoint.lng}, ${centerPoint.lat}`)
|
|
|
-const selectedFeature = ref(null)
|
|
|
|
|
const mapError = ref('')
|
|
const mapError = ref('')
|
|
|
|
|
+const dataLoaded = ref(false)
|
|
|
const layerState = reactive(defaultLayerState())
|
|
const layerState = reactive(defaultLayerState())
|
|
|
const facilityOverview = ref([])
|
|
const facilityOverview = ref([])
|
|
|
const pipelineData = ref([])
|
|
const pipelineData = ref([])
|
|
|
const pointData = ref([])
|
|
const pointData = ref([])
|
|
|
|
|
+const detailOpen = ref(false)
|
|
|
|
|
+const detailLoading = ref(false)
|
|
|
|
|
+const detailError = ref('')
|
|
|
|
|
+const detailRecord = ref(null)
|
|
|
|
|
+const detailTarget = ref(null)
|
|
|
|
|
|
|
|
let mapInstance = null
|
|
let mapInstance = null
|
|
|
-let activeInfoWindow = null
|
|
|
|
|
let overlayClicked = false
|
|
let overlayClicked = false
|
|
|
|
|
|
|
|
const typeCount = type => {
|
|
const typeCount = type => {
|
|
@@ -198,34 +212,13 @@ const summaryStats = computed(() => ({
|
|
|
userCount: typeCount('user')
|
|
userCount: typeCount('user')
|
|
|
}))
|
|
}))
|
|
|
|
|
|
|
|
-const selectedFeatureDetails = computed(() => {
|
|
|
|
|
- if (!selectedFeature.value) return []
|
|
|
|
|
- return Object.entries(selectedFeature.value.details).map(([label, value]) => ({ label, value }))
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const searchableFeatures = computed(() => {
|
|
|
|
|
- const pipelines = pipelineData.value.map(item => ({
|
|
|
|
|
- kind: 'pipeline',
|
|
|
|
|
- type: item.type,
|
|
|
|
|
- name: item.name,
|
|
|
|
|
- code: item.code,
|
|
|
|
|
- road: item.road,
|
|
|
|
|
- lng: getMidPoint(item.points).lng,
|
|
|
|
|
- lat: getMidPoint(item.points).lat,
|
|
|
|
|
- raw: item
|
|
|
|
|
- }))
|
|
|
|
|
- const points = pointData.value.map(item => ({
|
|
|
|
|
- kind: 'point',
|
|
|
|
|
- type: item.type,
|
|
|
|
|
- name: item.name,
|
|
|
|
|
- code: item.code,
|
|
|
|
|
- road: item.road,
|
|
|
|
|
- lng: item.lng,
|
|
|
|
|
- lat: item.lat,
|
|
|
|
|
- raw: item
|
|
|
|
|
- }))
|
|
|
|
|
- return [...pipelines, ...points]
|
|
|
|
|
-})
|
|
|
|
|
|
|
+const fullMapModel = computed(() => ({ points: pointData.value, lines: pipelineData.value }))
|
|
|
|
|
+const visibleMapModel = computed(() => filterFacilityMapModel(fullMapModel.value, layerState))
|
|
|
|
|
+const mapEmpty = computed(() => dataLoaded.value && !mapError.value && visibleMapModel.value.isEmpty)
|
|
|
|
|
+const detailTitle = computed(() => `${labelMap[detailTarget.value?.type] || '供水设施'}详情`)
|
|
|
|
|
+const detailEntries = computed(() => Object.entries(detailRecord.value || {})
|
|
|
|
|
+ .filter(([, value]) => value !== null && value !== undefined && typeof value !== 'object')
|
|
|
|
|
+ .map(([label, value]) => ({ label, value: value === '' ? '-' : value })))
|
|
|
|
|
|
|
|
watch(layerState, () => {
|
|
watch(layerState, () => {
|
|
|
renderMapScene()
|
|
renderMapScene()
|
|
@@ -318,8 +311,7 @@ function initMap() {
|
|
|
overlayClicked = false
|
|
overlayClicked = false
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- closeInfoWindow()
|
|
|
|
|
- selectedFeature.value = null
|
|
|
|
|
|
|
+ detailOpen.value = false
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
mapInstance.addEventListener('mousemove', (event) => {
|
|
mapInstance.addEventListener('mousemove', (event) => {
|
|
@@ -341,7 +333,6 @@ function initMap() {
|
|
|
function renderMapScene() {
|
|
function renderMapScene() {
|
|
|
if (!mapInstance || typeof BMapGL === 'undefined') return
|
|
if (!mapInstance || typeof BMapGL === 'undefined') return
|
|
|
|
|
|
|
|
- closeInfoWindow()
|
|
|
|
|
try { mapInstance.clearOverlays() } catch (_) { /* ignore */ }
|
|
try { mapInstance.clearOverlays() } catch (_) { /* ignore */ }
|
|
|
try { drawPipelines() } catch (e) { console.warn('绘制供水管网失败:', e) }
|
|
try { drawPipelines() } catch (e) { console.warn('绘制供水管网失败:', e) }
|
|
|
try { drawPoints() } catch (e) { console.warn('绘制供水设施失败:', e) }
|
|
try { drawPoints() } catch (e) { console.warn('绘制供水设施失败:', e) }
|
|
@@ -357,13 +348,11 @@ function drawPipelines() {
|
|
|
strokeWeight: 6,
|
|
strokeWeight: 6,
|
|
|
strokeOpacity: 0.92
|
|
strokeOpacity: 0.92
|
|
|
})
|
|
})
|
|
|
- const firstPt = { lng: convertCoord(item.points[0].lng, item.points[0].lat)[0], lat: convertCoord(item.points[0].lng, item.points[0].lat)[1] }
|
|
|
|
|
try {
|
|
try {
|
|
|
polyline.addEventListener('click', (e) => {
|
|
polyline.addEventListener('click', (e) => {
|
|
|
overlayClicked = true
|
|
overlayClicked = true
|
|
|
e.domEvent && e.domEvent.stopPropagation && e.domEvent.stopPropagation()
|
|
e.domEvent && e.domEvent.stopPropagation && e.domEvent.stopPropagation()
|
|
|
- showPopup(firstPt.lng, firstPt.lat, buildPopupHTML(buildPipelineDetail(item)))
|
|
|
|
|
- selectedFeature.value = buildPipelineDetail(item)
|
|
|
|
|
|
|
+ openFacilityDetail(item)
|
|
|
})
|
|
})
|
|
|
} catch (_) { /* polyline click listener failed */ }
|
|
} catch (_) { /* polyline click listener failed */ }
|
|
|
mapInstance.addOverlay(polyline)
|
|
mapInstance.addOverlay(polyline)
|
|
@@ -383,8 +372,7 @@ function drawPoints() {
|
|
|
if (!layerState[item.type]) return
|
|
if (!layerState[item.type]) return
|
|
|
const [plng, plat] = convertCoord(item.lng, item.lat)
|
|
const [plng, plat] = convertCoord(item.lng, item.lat)
|
|
|
addPointMarker(plng, plat, colorMap[item.type], item.name, 'dot', () => {
|
|
addPointMarker(plng, plat, colorMap[item.type], item.name, 'dot', () => {
|
|
|
- showPopup(plng, plat, buildPopupHTML(buildPointDetail(item)))
|
|
|
|
|
- selectedFeature.value = buildPointDetail(item)
|
|
|
|
|
|
|
+ openFacilityDetail(item)
|
|
|
})
|
|
})
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
console.warn(`绘制供水设施 ${item.name} 失败:`, e)
|
|
console.warn(`绘制供水设施 ${item.name} 失败:`, e)
|
|
@@ -404,8 +392,7 @@ function addPipeLabel(lng, lat, text, color, rawItem) {
|
|
|
label.addEventListener('click', (e) => {
|
|
label.addEventListener('click', (e) => {
|
|
|
overlayClicked = true
|
|
overlayClicked = true
|
|
|
e.domEvent && e.domEvent.stopPropagation && e.domEvent.stopPropagation()
|
|
e.domEvent && e.domEvent.stopPropagation && e.domEvent.stopPropagation()
|
|
|
- showPopup(lng, lat, buildPopupHTML(buildPipelineDetail(rawItem)))
|
|
|
|
|
- selectedFeature.value = buildPipelineDetail(rawItem)
|
|
|
|
|
|
|
+ openFacilityDetail(rawItem)
|
|
|
})
|
|
})
|
|
|
} catch (_) { /* label click listener failed */ }
|
|
} catch (_) { /* label click listener failed */ }
|
|
|
mapInstance.addOverlay(label)
|
|
mapInstance.addOverlay(label)
|
|
@@ -434,80 +421,18 @@ function addPointMarker(lng, lat, color, name, shape, onClick) {
|
|
|
mapInstance.addOverlay(label)
|
|
mapInstance.addOverlay(label)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function showPopup(lng, lat, html) {
|
|
|
|
|
- try {
|
|
|
|
|
- closeInfoWindow()
|
|
|
|
|
- const point = new BMapGL.Point(lng, lat)
|
|
|
|
|
- const infoWindow = new BMapGL.InfoWindow(html, {
|
|
|
|
|
- width: 310,
|
|
|
|
|
- title: '',
|
|
|
|
|
- enableMessage: false
|
|
|
|
|
- })
|
|
|
|
|
- activeInfoWindow = infoWindow
|
|
|
|
|
- mapInstance.openInfoWindow(infoWindow, point)
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- console.warn('弹出信息窗口失败:', e)
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function closeInfoWindow() {
|
|
|
|
|
- if (activeInfoWindow && mapInstance) {
|
|
|
|
|
- mapInstance.closeInfoWindow()
|
|
|
|
|
- activeInfoWindow = null
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function buildPopupHTML(detail) {
|
|
|
|
|
- const rows = Object.entries(detail.details)
|
|
|
|
|
- .map(([k, v]) => `<div class="popup-row"><span class="popup-label">${k}</span><span class="popup-value">${v}</span></div>`)
|
|
|
|
|
- .join('')
|
|
|
|
|
- return `<div class="info-popup">
|
|
|
|
|
- <div class="popup-header">${detail.name}</div>
|
|
|
|
|
- <div class="popup-tag">${detail.category}</div>
|
|
|
|
|
- <div class="popup-divider"></div>
|
|
|
|
|
- ${rows}
|
|
|
|
|
- </div>`
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function buildPipelineDetail(item) {
|
|
|
|
|
|
|
+function getMidPoint(points) {
|
|
|
|
|
+ const first = points[0]
|
|
|
|
|
+ const last = points[points.length - 1]
|
|
|
return {
|
|
return {
|
|
|
- name: item.name,
|
|
|
|
|
- category: labelMap[item.type] || '供水管网',
|
|
|
|
|
- details: {
|
|
|
|
|
- '管网编号': item.code || '-',
|
|
|
|
|
- '管网名称': item.name,
|
|
|
|
|
- '管径': item.diameter || '-',
|
|
|
|
|
- '材质': item.material || '-',
|
|
|
|
|
- '起点位置': item.startPoint || '-',
|
|
|
|
|
- '终点位置': item.endPoint || '-',
|
|
|
|
|
- '铺设年份': item.layingYear || '-',
|
|
|
|
|
- '长度': item.length || '-',
|
|
|
|
|
- '运行状态': item.status || '-'
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ lng: (first.lng + last.lng) / 2,
|
|
|
|
|
+ lat: (first.lat + last.lat) / 2
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function buildPointDetail(item) {
|
|
|
|
|
- return {
|
|
|
|
|
- name: item.name,
|
|
|
|
|
- category: labelMap[item.type] || '供水设施',
|
|
|
|
|
- details: {
|
|
|
|
|
- '设施编号': item.code || '-',
|
|
|
|
|
- '设施名称': item.name,
|
|
|
|
|
- '所属类型': labelMap[item.type] || '-',
|
|
|
|
|
- '地址': item.address || item.location || '-',
|
|
|
|
|
- '状态': item.status || '-',
|
|
|
|
|
- '经度': item.lng.toFixed(5),
|
|
|
|
|
- '纬度': item.lat.toFixed(5)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-function getMidPoint(points) {
|
|
|
|
|
- return points[Math.floor(points.length / 2)]
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
async function loadGisData() {
|
|
async function loadGisData() {
|
|
|
|
|
+ mapError.value = ''
|
|
|
|
|
+ dataLoaded.value = false
|
|
|
try {
|
|
try {
|
|
|
const [overviewRes, featureRes] = await Promise.all([
|
|
const [overviewRes, featureRes] = await Promise.all([
|
|
|
getWaterFacilityOverview(),
|
|
getWaterFacilityOverview(),
|
|
@@ -516,49 +441,18 @@ async function loadGisData() {
|
|
|
const overviewData = unwrapResponse(overviewRes)
|
|
const overviewData = unwrapResponse(overviewRes)
|
|
|
facilityOverview.value = Array.isArray(overviewData) ? overviewData : (overviewData?.facilityOverview || [])
|
|
facilityOverview.value = Array.isArray(overviewData) ? overviewData : (overviewData?.facilityOverview || [])
|
|
|
const geoJson = normalizeGeoJson(featureRes)
|
|
const geoJson = normalizeGeoJson(featureRes)
|
|
|
- const lines = []
|
|
|
|
|
- const points = []
|
|
|
|
|
- ;(geoJson.features || []).forEach(feature => {
|
|
|
|
|
- const coordinates = feature.geometry?.coordinates || []
|
|
|
|
|
- const properties = feature.properties || {}
|
|
|
|
|
- const type = properties.facilityType || properties.type || ''
|
|
|
|
|
- if (feature.geometry?.type === 'LineString' && coordinates.length > 1) {
|
|
|
|
|
- lines.push({
|
|
|
|
|
- id: feature.id || properties.id,
|
|
|
|
|
- type: type || 'pipe',
|
|
|
|
|
- name: properties.pipeName || properties.name || properties.facilityTypeName || '供水管网',
|
|
|
|
|
- code: properties.pipeCode || properties.code || '-',
|
|
|
|
|
- material: properties.pipeMaterial,
|
|
|
|
|
- diameter: properties.pipeDiameter,
|
|
|
|
|
- startPoint: properties.startPoint,
|
|
|
|
|
- endPoint: properties.endPoint,
|
|
|
|
|
- layingYear: properties.layingYear,
|
|
|
|
|
- length: properties.pipeLength,
|
|
|
|
|
- status: properties.status,
|
|
|
|
|
- road: properties.road || properties.address || '',
|
|
|
|
|
- points: coordinates.map(([lng, lat]) => ({ lng, lat }))
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- if (feature.geometry?.type === 'Point' && coordinates.length >= 2) {
|
|
|
|
|
- points.push({
|
|
|
|
|
- id: feature.id || properties.id,
|
|
|
|
|
- type: type,
|
|
|
|
|
- name: properties.facilityName || properties.name || properties.pipeName || properties.facilityTypeName || '供水设施',
|
|
|
|
|
- code: properties.facilityCode || properties.code || '-',
|
|
|
|
|
- address: properties.address || properties.location || '',
|
|
|
|
|
- status: properties.status,
|
|
|
|
|
- road: properties.address || properties.location || '',
|
|
|
|
|
- lng: coordinates[0],
|
|
|
|
|
- lat: coordinates[1]
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- pipelineData.value = lines
|
|
|
|
|
- pointData.value = points
|
|
|
|
|
|
|
+ const model = buildFacilityMapModel(geoJson)
|
|
|
|
|
+ pipelineData.value = model.lines
|
|
|
|
|
+ pointData.value = model.points
|
|
|
|
|
+ dataLoaded.value = true
|
|
|
if (mapInstance && typeof BMapGL !== 'undefined') renderMapScene()
|
|
if (mapInstance && typeof BMapGL !== 'undefined') renderMapScene()
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
|
console.error('加载供水GIS数据失败', e)
|
|
console.error('加载供水GIS数据失败', e)
|
|
|
- ElMessage.warning('供水GIS数据加载失败')
|
|
|
|
|
|
|
+ facilityOverview.value = []
|
|
|
|
|
+ pipelineData.value = []
|
|
|
|
|
+ pointData.value = []
|
|
|
|
|
+ dataLoaded.value = true
|
|
|
|
|
+ mapError.value = getRequestErrorMessage(e, '供水GIS数据加载失败,请重试。')
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -569,9 +463,7 @@ function handleSearch() {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const matched = searchableFeatures.value.find(item =>
|
|
|
|
|
- [item.name, item.code, item.road].some(text => text?.includes(keyword))
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ const matched = findFacilityFeature(visibleMapModel.value, keyword)
|
|
|
|
|
|
|
|
if (!matched) {
|
|
if (!matched) {
|
|
|
ElMessage.info('未找到匹配要素')
|
|
ElMessage.info('未找到匹配要素')
|
|
@@ -579,19 +471,38 @@ function handleSearch() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const [mlng, mlat] = convertCoord(matched.lng, matched.lat)
|
|
const [mlng, mlat] = convertCoord(matched.lng, matched.lat)
|
|
|
- mapInstance.centerAndZoom(new BMapGL.Point(mlng, mlat), 18)
|
|
|
|
|
-
|
|
|
|
|
- if (matched.kind === 'pipeline') {
|
|
|
|
|
- selectedFeature.value = buildPipelineDetail(matched.raw)
|
|
|
|
|
- showPopup(mlng, mlat, buildPopupHTML(selectedFeature.value))
|
|
|
|
|
- } else {
|
|
|
|
|
- selectedFeature.value = buildPointDetail(matched.raw)
|
|
|
|
|
- showPopup(mlng, mlat, buildPopupHTML(selectedFeature.value))
|
|
|
|
|
|
|
+ if (mapInstance && typeof BMapGL !== 'undefined') {
|
|
|
|
|
+ mapInstance.centerAndZoom(new BMapGL.Point(mlng, mlat), 18)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ openFacilityDetail(matched)
|
|
|
|
|
+
|
|
|
ElMessage.success(`已定位到 ${matched.name}`)
|
|
ElMessage.success(`已定位到 ${matched.name}`)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+async function openFacilityDetail(feature) {
|
|
|
|
|
+ detailTarget.value = feature
|
|
|
|
|
+ detailOpen.value = true
|
|
|
|
|
+ detailRecord.value = null
|
|
|
|
|
+ detailError.value = ''
|
|
|
|
|
+ await loadFacilityDetail()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function loadFacilityDetail() {
|
|
|
|
|
+ const feature = detailTarget.value
|
|
|
|
|
+ if (!feature?.type || feature.id === null || feature.id === undefined) return
|
|
|
|
|
+ detailLoading.value = true
|
|
|
|
|
+ detailError.value = ''
|
|
|
|
|
+ try {
|
|
|
|
|
+ detailRecord.value = unwrapResponse(await getWaterFacilityDetail(feature.type, feature.id))
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ detailRecord.value = null
|
|
|
|
|
+ detailError.value = getRequestErrorMessage(error, '设施详情查询失败,请重试。')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ detailLoading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
async function refreshScene() {
|
|
async function refreshScene() {
|
|
|
layerState.source = true
|
|
layerState.source = true
|
|
|
layerState.plant = true
|
|
layerState.plant = true
|
|
@@ -599,8 +510,7 @@ async function refreshScene() {
|
|
|
layerState.pipe = true
|
|
layerState.pipe = true
|
|
|
layerState.user = true
|
|
layerState.user = true
|
|
|
searchKeyword.value = ''
|
|
searchKeyword.value = ''
|
|
|
- selectedFeature.value = null
|
|
|
|
|
- closeInfoWindow()
|
|
|
|
|
|
|
+ detailOpen.value = false
|
|
|
await loadGisData()
|
|
await loadGisData()
|
|
|
locateCenter()
|
|
locateCenter()
|
|
|
}
|
|
}
|
|
@@ -839,29 +749,6 @@ function handleFullscreenChange() {
|
|
|
min-height: 280px;
|
|
min-height: 280px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.detail-body {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
- gap: 10px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.detail-name {
|
|
|
|
|
- color: #1f2d3d;
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- font-weight: 700;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.detail-tag {
|
|
|
|
|
- display: inline-flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- width: fit-content;
|
|
|
|
|
- padding: 3px 10px;
|
|
|
|
|
- color: #2d6cdf;
|
|
|
|
|
- background: #edf4ff;
|
|
|
|
|
- border-radius: 999px;
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
.dashboard-map-panel {
|
|
.dashboard-map-panel {
|
|
|
position: relative;
|
|
position: relative;
|
|
|
flex: 1;
|
|
flex: 1;
|
|
@@ -944,62 +831,6 @@ function handleFullscreenChange() {
|
|
|
text-shadow: 0 0 3px #fff;
|
|
text-shadow: 0 0 3px #fff;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.info-popup {
|
|
|
|
|
- padding: 4px 2px;
|
|
|
|
|
- font-size: 13px;
|
|
|
|
|
- color: #333;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.popup-header {
|
|
|
|
|
- font-size: 15px;
|
|
|
|
|
- font-weight: 700;
|
|
|
|
|
- color: #1a1a2e;
|
|
|
|
|
- margin-bottom: 6px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.popup-tag {
|
|
|
|
|
- display: inline-block;
|
|
|
|
|
- padding: 2px 10px;
|
|
|
|
|
- font-size: 11px;
|
|
|
|
|
- color: #1d4ed8;
|
|
|
|
|
- background: #eff6ff;
|
|
|
|
|
- border-radius: 999px;
|
|
|
|
|
- margin-bottom: 10px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.popup-divider {
|
|
|
|
|
- height: 1px;
|
|
|
|
|
- background: #e5e7eb;
|
|
|
|
|
- margin-bottom: 10px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.popup-row {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- justify-content: space-between;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- padding: 5px 0;
|
|
|
|
|
- border-bottom: 1px dashed #f0f0f0;
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- line-height: 1.5;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.popup-row:last-child {
|
|
|
|
|
- border-bottom: none;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.popup-label {
|
|
|
|
|
- color: #6b7280;
|
|
|
|
|
- flex-shrink: 0;
|
|
|
|
|
- margin-right: 12px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.popup-value {
|
|
|
|
|
- color: #1f2937;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- text-align: right;
|
|
|
|
|
- word-break: break-all;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
.BMap_cpyCtrl,
|
|
.BMap_cpyCtrl,
|
|
|
.anchorBL {
|
|
.anchorBL {
|
|
|
display: none;
|
|
display: none;
|