HazardMap.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. <template>
  2. <div class="hazard-map-container">
  3. <el-card class="legend-card">
  4. <template #header><span>图例说明</span></template>
  5. <div class="legend-items">
  6. <div class="legend-item" v-for="item in levelLegend" :key="item.value">
  7. <span class="dot" :style="{ background: item.color }"></span> {{ item.label }}隐患
  8. </div>
  9. </div>
  10. </el-card>
  11. <div id="hazardMap" class="map-container"></div>
  12. <el-drawer v-model="detailVisible" title="隐患详情" size="400px">
  13. <template v-if="currentHazard">
  14. <el-descriptions :column="1" border size="small">
  15. <el-descriptions-item label="隐患编号">{{ currentHazard.hazardNo }}</el-descriptions-item>
  16. <el-descriptions-item label="隐患类型">{{ getDictLabel(hazardTypeDict, currentHazard.hazardType) }}</el-descriptions-item>
  17. <el-descriptions-item label="隐患等级">
  18. <el-tag :type="levelTag(currentHazard.hazardLevel)">{{ getDictLabel(hazardLevelDict, currentHazard.hazardLevel) }}</el-tag>
  19. </el-descriptions-item>
  20. <el-descriptions-item label="状态">{{ getDictLabel(hazardStatusDict, currentHazard.hazardStatus) }}</el-descriptions-item>
  21. <el-descriptions-item label="隐患描述">{{ currentHazard.hazardDesc }}</el-descriptions-item>
  22. <el-descriptions-item label="整改反馈">{{ currentHazard.rectifyFeedback || '暂无' }}</el-descriptions-item>
  23. <el-descriptions-item label="上报时间">{{ currentHazard.reportTime }}</el-descriptions-item>
  24. </el-descriptions>
  25. </template>
  26. </el-drawer>
  27. </div>
  28. </template>
  29. <script setup>
  30. import { ref, computed, onMounted, nextTick } from 'vue'
  31. import { getHazardMapPoints } from '@/api/pipeNetwork/hazard'
  32. import { getDicts } from '@/api/system/dict/data'
  33. const detailVisible = ref(false)
  34. const currentHazard = ref(null)
  35. let mapInstance = null
  36. const hazardTypeDict = ref([])
  37. const hazardLevelDict = ref([])
  38. const hazardStatusDict = ref([])
  39. function getDictLabel(dict, value) {
  40. const item = dict.find(d => d.dictValue === value)
  41. return item ? item.dictLabel : value
  42. }
  43. const levelColors = { '0': '#f5222d', '1': '#fa8c16', '2': '#1890ff', '3': '#52c41a' }
  44. function levelTag(level) {
  45. const map = { '0': 'danger', '1': 'warning', '2': '', '3': 'success' }
  46. return map[level] || ''
  47. }
  48. const levelLegend = computed(() =>
  49. hazardLevelDict.value.map(d => ({ value: d.dictValue, label: d.dictLabel, color: levelColors[d.dictValue] || '#999' }))
  50. )
  51. async function loadDicts() {
  52. const [typeRes, levelRes, statusRes] = await Promise.all([
  53. getDicts('hazard_type'),
  54. getDicts('hazard_level'),
  55. getDicts('hazard_status')
  56. ])
  57. hazardTypeDict.value = typeRes.data
  58. hazardLevelDict.value = levelRes.data
  59. hazardStatusDict.value = statusRes.data
  60. }
  61. async function initMap() {
  62. await nextTick()
  63. const el = document.getElementById('hazardMap')
  64. if (!el) return
  65. try {
  66. const L = await import('leaflet')
  67. mapInstance = L.map('hazardMap').setView([34.77, 113.65], 12)
  68. L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  69. attribution: '&copy; OpenStreetMap contributors'
  70. }).addTo(mapInstance)
  71. const res = await getHazardMapPoints()
  72. const points = res.data || []
  73. for (const p of points) {
  74. if (!p.longitude || !p.latitude) continue
  75. const color = levelColors[p.hazardLevel] || '#999'
  76. const marker = L.circleMarker([p.latitude, p.longitude], {
  77. radius: 10, fillColor: color, color: '#fff', weight: 2, fillOpacity: 0.8
  78. }).addTo(mapInstance)
  79. const typeLabel = getDictLabel(hazardTypeDict, p.hazardType)
  80. const levelLabel = getDictLabel(hazardLevelDict, p.hazardLevel)
  81. const statusLabel = getDictLabel(hazardStatusDict, p.hazardStatus)
  82. marker.bindPopup(`<b>${p.hazardNo}</b><br/>${typeLabel} | ${levelLabel}<br/>${statusLabel}`)
  83. marker.on('click', () => { currentHazard.value = p; detailVisible.value = true })
  84. }
  85. } catch (e) {
  86. el.innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:#999;">请安装Leaflet: npm install leaflet</div>'
  87. }
  88. }
  89. onMounted(async () => { await loadDicts(); initMap() })
  90. </script>
  91. <style scoped>
  92. .hazard-map-container { position: relative; height: calc(100vh - 100px); padding: 16px; }
  93. .legend-card { position: absolute; top: 32px; right: 32px; z-index: 1000; width: 160px; }
  94. .legend-items { display: flex; flex-direction: column; gap: 6px; }
  95. .legend-item { display: flex; align-items: center; gap: 6px; font-size: 13px; }
  96. .dot { width: 12px; height: 12px; border-radius: 50%; display: inline-block; }
  97. .map-container { width: 100%; height: 100%; border-radius: 4px; }
  98. </style>