<!--实时监测一张图-->
<template>
  <div class="gis-monitor-container">
    <!-- 头部面板 -->
    <div class="header-panel">
      <div class="title-logo">
        <el-icon :size="28"><Monitor /></el-icon>
        <span class="title">窨井盖安全实时监测一张图</span>
        <span class="version">GIS动态态势平台</span>
      </div>
      <div class="stats-badge">
        <div class="stat-badge-item">
          <span class="dot online"></span> 在线 {{ onlineCount }}
        </div>
        <div class="stat-badge-item">
          <span class="dot alert"></span> 告警 {{ alertCount }}
        </div>
        <div class="stat-badge-item">
          <span class="dot offline"></span> 离线 {{ offlineCount }}
        </div>
        <div class="stat-badge-item">
          <el-date-picker v-model="dateRange" type="datetimerange" range-separator="至" size="small" :shortcuts="shortcuts" start-placeholder="开始时间" end-placeholder="结束时间" />
        </div>
      </div>
    </div>

    <!-- 主要内容区：左侧图层控制 + 右侧GIS地图 -->
    <div class="main-layout">
      <!-- 左侧图层分类控制卡 -->
      <div class="layer-panel">
        <div class="layer-header">
          <el-icon></el-icon> 动态监测图层
        </div>
        <el-tree
            :data="layerTree"
            show-checkbox
            node-key="id"
            :default-checked-keys="defaultCheckedLayers"
            @check="onLayerCheck"
            class="layer-tree"
        >
          <template #default="{ node, data }">
            <span class="custom-tree-node">
              <el-icon><component :is="data.icon" /></el-icon>
              <span>{{ node.label }}</span>
              <el-badge v-if="data.alertCount" :value="data.alertCount" class="badge-alert" type="danger" />
            </span>
          </template>
        </el-tree>

        <!-- 图例说明 -->
        <div class="legend-box">
          <div class="legend-title">图例</div>
          <div><span class="legend-icon normal-icon"></span> 正常井盖</div>
          <div><span class="legend-icon warning-icon"></span> 预警井盖</div>
          <div><span class="legend-icon critical-icon"></span> 严重告警</div>
          <div><span class="legend-icon water-icon"></span> 井下溢水</div>
          <div><span class="legend-icon gas-icon"></span> 有害气体</div>
        </div>
      </div>

      <!-- 右侧 GIS 地图核心区域 -->
      <div class="gis-stage">
        <div class="map-toolbar">
          <el-button-group>
            <el-button size="small" :icon="ZoomIn" @click="zoomIn">放大</el-button>
            <el-button size="small" :icon="ZoomOut" @click="zoomOut">缩小</el-button>
            <el-button size="small" :icon="Location" @click="fitBounds">全图</el-button>
          </el-button-group>
          <div class="current-time">实时监测动态更新: {{ currentTime }}</div>
        </div>

        <!-- 模拟地图画布 -->
        <div class="map-wrapper" ref="mapContainer">
          <canvas id="gisCanvas" ref="canvasRef" @click="handleCanvasClick" @mousemove="onCanvasMouseMove"></canvas>

          <!-- 悬浮信息卡片 -->
          <div v-if="hoveredManhole" class="hover-card" :style="{ top: hoverY + 'px', left: hoverX + 'px' }">
            <div class="hover-title">{{ hoveredManhole.name }}</div>
            <div>状态: {{ hoveredManhole.statusText }}</div>
            <div>位置: {{ hoveredManhole.address }}</div>
            <div>井下温度: {{ hoveredManhole.env?.temperature }}°C</div>
            <div>水位: {{ hoveredManhole.env?.waterLevel }}cm</div>
            <div>气体(H₂S): {{ hoveredManhole.env?.gas }}ppm</div>
          </div>
        </div>

        <!-- 右侧抽屉信息/被监测对象详情标识 -->
        <el-drawer v-model="drawerVisible" :title="selectedManhole?.name + ' - 监测数据详情'" direction="rtl" size="450px">
          <div v-if="selectedManhole">
            <el-descriptions :column="1" border>
              <el-descriptions-item label="设备ID">{{ selectedManhole.id }}</el-descriptions-item>
              <el-descriptions-item label="地理位置">{{ selectedManhole.address }}</el-descriptions-item>
              <el-descriptions-item label="经纬度">{{ selectedManhole.lng }}, {{ selectedManhole.lat }}</el-descriptions-item>
              <el-descriptions-item label="运行状态">
                <el-tag :type="getStatusTagType(selectedManhole.status)">{{ selectedManhole.statusText }}</el-tag>
              </el-descriptions-item>
              <el-descriptions-item label="井盖状态">
                <div>倾斜: {{ selectedManhole.statusDetails?.tilt ? '异常' : '正常'}} ({{ selectedManhole.statusDetails?.tiltAngle || 0 }}°)</div>
                <div>开启: {{ selectedManhole.statusDetails?.open ? '已开启' : '关闭' }}</div>
                <div>震动: {{ selectedManhole.statusDetails?.vibration ? '剧烈' : '平稳' }}</div>
              </el-descriptions-item>
            </el-descriptions>
            <el-divider>井下物理环境监测</el-divider>
            <el-row :gutter="12">
              <el-col :span="12"><el-statistic title="水位深度" :value="selectedManhole.env?.waterLevel || 0" suffix="cm" :value-style="selectedManhole.env?.waterLevel > 30 ? { color: '#f56c6c' } : {}" /></el-col>
              <el-col :span="12"><el-statistic title="硫化氢(H₂S)" :value="selectedManhole.env?.gas || 0" suffix="ppm" :value-style="selectedManhole.env?.gas > 10 ? { color: '#f56c6c' } : {}" /></el-col>
              <el-col :span="12"><el-statistic title="温度" :value="selectedManhole.env?.temperature || 0" suffix="°C" /></el-col>
              <el-col :span="12"><el-statistic title="湿度" :value="selectedManhole.env?.humidity || 0" suffix="%" /></el-col>
              <el-col :span="12"><el-statistic title="电池电量" :value="selectedManhole.battery || 0" suffix="%" /></el-col>
              <el-col :span="12"><el-statistic title="信号强度" :value="selectedManhole.signal || 0" suffix="%" /></el-col>
            </el-row>
            <el-divider>最新告警记录</el-divider>
            <el-timeline>
              <el-timeline-item v-for="alert in selectedManhole.alerts" :key="alert.time" :timestamp="alert.time" :type="alert.type">
                {{ alert.message }}
              </el-timeline-item>
              <el-timeline-item v-if="!selectedManhole.alerts?.length" timestamp="暂无" type="info">设备无告警记录</el-timeline-item>
            </el-timeline>
          </div>
        </el-drawer>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
import { Monitor, ZoomIn, ZoomOut, Location, Warning, Document, Connection } from '@element-plus/icons-vue'

// --- 图层树结构 (支持分类图层展示)---
const layerTree = ref([
  {
    id: 'layer-status',
    label: '井盖状态监测图层',
    icon: 'Warning',
    alertCount: 2,
    children: [
      { id: 'tilt', label: '位移/倾斜监测点', icon: 'Location', alertCount: 1 },
      { id: 'open', label: '井盖开启监测点', icon: 'Lock', alertCount: 1 },
      { id: 'vibration', label: '震动异常监测', icon: 'Opportunity', alertCount: 0 }
    ]
  },
  {
    id: 'layer-environment',
    label: '井下物理环境监测图层',
    icon: '',
    alertCount: 3,
    children: [
      { id: 'water', label: '溢水/水位监测', icon: '', alertCount: 2 },
      { id: 'gas', label: '有害气体监测', icon: 'Warning', alertCount: 1 },
      { id: 'temp', label: '温湿度监测', icon: 'Temperature', alertCount: 0 }
    ]
  },
  {
    id: 'layer-device',
    label: '设备健康度图层',
    icon: 'Monitor',
    alertCount: 1,
    children: [
      { id: 'battery', label: '电池电压状态', icon: 'Battery', alertCount: 1 },
      { id: 'signal', label: '通讯信号强度', icon: 'Connection', alertCount: 0 }
    ]
  }
])
const defaultCheckedLayers = ['layer-status', 'layer-environment', 'tilt', 'open', 'water', 'gas', 'battery']
const visibleLayers = ref(new Set(defaultCheckedLayers))

const onLayerCheck = (checkedNode, { checkedKeys }) => {
  visibleLayers.value = new Set(checkedKeys)
  renderMap()
}

// --- 模拟窨井盖监测数据 (包含地理位置、监测数据)---
const manholes = ref([
  { id: 'M1001', name: '人民路1号井', lng: 121.487, lat: 31.249, address: '人民路与解放路口', status: 'warning', statusText: '倾斜预警', battery: 67, signal: 82,
    statusDetails: { tilt: true, tiltAngle: 8.5, open: false, vibration: false },
    env: { waterLevel: 12, gas: 5, temperature: 18, humidity: 65 },
    alerts: [{ time: '2025-04-02 09:23', message: '井盖倾斜角度超过阈值', type: 'warning' }] },
  { id: 'M1002', name: '滨江路2号井', lng: 121.502, lat: 31.235, address: '滨江路化工园区', status: 'critical', statusText: '严重告警-溢水+气体超标', battery: 34, signal: 48,
    statusDetails: { tilt: false, open: false, vibration: true },
    env: { waterLevel: 58, gas: 28, temperature: 22, humidity: 88 },
    alerts: [{ time: '2025-04-02 10:15', message: '井下水位超限，有害气体浓度过高', type: 'danger' }] },
  { id: 'M1003', name: '古城街古井', lng: 121.478, lat: 31.258, address: '古城街北段', status: 'normal', statusText: '正常', battery: 94, signal: 91,
    statusDetails: { tilt: false, open: false, vibration: false },
    env: { waterLevel: 5, gas: 1, temperature: 16, humidity: 60 },
    alerts: [] },
  { id: 'M1004', name: '高新区智慧井', lng: 121.512, lat: 31.242, address: '高新大道云计算中心', status: 'normal', statusText: '正常', battery: 87, signal: 95,
    statusDetails: { tilt: false, open: false, vibration: false },
    env: { waterLevel: 3, gas: 0.5, temperature: 19, humidity: 54 },
    alerts: [] },
  { id: 'M1005', name: '南港路车站井', lng: 121.495, lat: 31.228, address: '南港路旧车站', status: 'warning', statusText: '井盖开启告警', battery: 45, signal: 62,
    statusDetails: { tilt: false, open: true, vibration: false },
    env: { waterLevel: 9, gas: 3, temperature: 20, humidity: 70 },
    alerts: [{ time: '2025-04-02 08:45', message: '井盖异常开启', type: 'warning' }] },
  { id: 'M1006', name: '石化区防爆井', lng: 121.524, lat: 31.239, address: '石化大道', status: 'critical', statusText: '溢水告警', battery: 22, signal: 38,
    statusDetails: { tilt: false, open: false, vibration: true },
    env: { waterLevel: 72, gas: 9, temperature: 21, humidity: 91 },
    alerts: [{ time: '2025-04-02 07:20', message: '水位暴涨，有溢水风险', type: 'danger' }] }
])

const onlineCount = computed(() => manholes.value.filter(m => m.signal > 30).length)
const alertCount = computed(() => manholes.value.filter(m => m.status !== 'normal').length)
const offlineCount = computed(() => manholes.value.filter(m => m.signal <= 30).length)

// GIS画布相关变量
const canvasRef = ref(null)
const mapContainer = ref(null)
let ctx = null
let mapWidth = 0, mapHeight = 0
let mapZoom = 1
let offsetX = 0, offsetY = 0
let dragStart = null
let animationFrame = null

const bounds = { minLng: 121.45, maxLng: 121.55, minLat: 31.22, maxLat: 31.28 }

const dateRange = ref([])
const shortcuts = [{ text: '最近24小时', value: () => [new Date(Date.now() - 86400000), new Date()] }]
const currentTime = ref(new Date().toLocaleString())

// 交互状态
const selectedManhole = ref(null)
const hoveredManhole = ref(null)
const hoverX = ref(0), hoverY = ref(0)
const drawerVisible = ref(false)

setInterval(() => { currentTime.value = new Date().toLocaleString() }, 1000)

function worldToCanvas(lng, lat) {
  const px = (lng - bounds.minLng) / (bounds.maxLng - bounds.minLng) * mapWidth
  const py = (1 - (lat - bounds.minLat) / (bounds.maxLat - bounds.minLat)) * mapHeight
  const centerX = mapWidth / 2, centerY = mapHeight / 2
  let x = (px - centerX) * mapZoom + centerX + offsetX
  let y = (py - centerY) * mapZoom + centerY + offsetY
  return { x, y }
}

function drawBaseMap() {
  if (!ctx) return
  ctx.fillStyle = '#eaf5e9'
  ctx.fillRect(0, 0, mapWidth, mapHeight)
  ctx.strokeStyle = '#bfd8bf'
  ctx.lineWidth = 1
  for (let i = 0; i < 12; i++) {
    let x = (i / 12) * mapWidth
    ctx.beginPath()
    ctx.moveTo(x, 0)
    ctx.lineTo(x, mapHeight)
    ctx.stroke()
    let y = (i / 12) * mapHeight
    ctx.beginPath()
    ctx.moveTo(0, y)
    ctx.lineTo(mapWidth, y)
    ctx.stroke()
  }
  ctx.fillStyle = '#a8d0a6'
  ctx.font = '12px "Microsoft YaHei"'
  ctx.fillText('人民路', 200, 120)
  ctx.fillText('滨江路', 450, 300)
  ctx.fillText('高新区', 600, 180)
}

function drawManholes() {
  if (!ctx) return
  manholes.value.forEach(mh => {
    if (mh.signal <= 0) return
    let { x, y } = worldToCanvas(mh.lng, mh.lat)
    if (x < -30 || x > mapWidth + 30 || y < -30 || y > mapHeight + 30) return
    let color = '#67C23A'
    if (mh.status === 'critical') color = '#F56C6C'
    else if (mh.status === 'warning') color = '#E6A23C'
    else color = '#67C23A'
    ctx.beginPath()
    ctx.arc(x, y, 14, 0, 2 * Math.PI)
    ctx.fillStyle = color
    ctx.fill()
    ctx.shadowBlur = 0
    ctx.fillStyle = '#fff'
    ctx.font = 'bold 14px sans-serif'
    ctx.fillText(mh.name.slice(0, 3), x-10, y+5)
    ctx.strokeStyle = '#fff'
    ctx.lineWidth = 2
    ctx.stroke()

    // 图层过滤: 动态展示不同监测数据小图标（根据图层可见性绘制周围标注）
    if (visibleLayers.value.has('water') && mh.env.waterLevel > 30) {
      ctx.fillStyle = '#3b82f6'
      ctx.beginPath()
      ctx.rect(x+12, y-12, 8, 8)
      ctx.fill()
    }
    if (visibleLayers.value.has('gas') && mh.env.gas > 10) {
      ctx.fillStyle = '#f97316'
      ctx.beginPath()
      ctx.rect(x+12, y-4, 8, 8)
      ctx.fill()
    }
    if (visibleLayers.value.has('tilt') && mh.statusDetails.tilt) {
      ctx.fillStyle = '#ef4444'
      ctx.beginPath()
      ctx.moveTo(x+8, y-16)
      ctx.lineTo(x+16, y-10)
      ctx.lineTo(x+8, y-4)
      ctx.fill()
    }
  })
}

function renderMap() {
  if (!canvasRef.value) return
  const canvas = canvasRef.value
  const container = mapContainer.value
  if (!container) return
  mapWidth = container.clientWidth
  mapHeight = container.clientHeight
  canvas.width = mapWidth
  canvas.height = mapHeight
  ctx = canvas.getContext('2d')
  drawBaseMap()
  drawManholes()
}

function zoomIn() { mapZoom = Math.min(mapZoom + 0.1, 2.5); renderMap(); }
function zoomOut() { mapZoom = Math.max(mapZoom - 0.1, 0.6); renderMap(); }
function fitBounds() { mapZoom = 1; offsetX = 0; offsetY = 0; renderMap(); }

function handleCanvasClick(e) {
  const rect = canvasRef.value.getBoundingClientRect()
  const mouseX = (e.clientX - rect.left) * (mapWidth / rect.width)
  const mouseY = (e.clientY - rect.top) * (mapHeight / rect.height)
  let minDist = 20, hit = null
  manholes.value.forEach(mh => {
    const { x, y } = worldToCanvas(mh.lng, mh.lat)
    const dist = Math.hypot(mouseX - x, mouseY - y)
    if (dist < minDist) { minDist = dist; hit = mh }
  })
  if (hit) { selectedManhole.value = hit; drawerVisible.value = true }
}

function onCanvasMouseMove(e) {
  const rect = canvasRef.value.getBoundingClientRect()
  const mouseX = (e.clientX - rect.left) * (mapWidth / rect.width)
  const mouseY = (e.clientY - rect.top) * (mapHeight / rect.height)
  let minDist = 18, hit = null
  manholes.value.forEach(mh => {
    const { x, y } = worldToCanvas(mh.lng, mh.lat)
    const dist = Math.hypot(mouseX - x, mouseY - y)
    if (dist < minDist) { minDist = dist; hit = mh }
  })
  if (hit) {
    hoveredManhole.value = hit
    hoverX.value = e.clientX + 12
    hoverY.value = e.clientY - 40
  } else hoveredManhole.value = null
}

function getStatusTagType(status) {
  if (status === 'critical') return 'danger'
  if (status === 'warning') return 'warning'
  return 'success'
}

watch(() => visibleLayers.value, () => renderMap(), { deep: true })
onMounted(() => {
  nextTick(() => {
    renderMap()
    window.addEventListener('resize', () => renderMap())
  })
})
onUnmounted(() => window.removeEventListener('resize', () => renderMap()))
</script>

<style scoped>
.gis-monitor-container {
  background: #eef2f0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  font-family: 'Segoe UI', 'PingFang SC', Roboto, sans-serif;
}
.header-panel {
  background: white;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 24px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.05);
  z-index: 10;
}
.title-logo {
  display: flex;
  align-items: center;
  gap: 12px;
}
.title {
  font-size: 1.4rem;
  font-weight: 600;
  background: linear-gradient(135deg, #2e7d32, #1b5e20);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.version {
  background: #e9f5e9;
  padding: 2px 8px;
  border-radius: 20px;
  font-size: 12px;
}
.stats-badge {
  display: flex;
  gap: 24px;
  align-items: center;
}
.dot {
  width: 10px;
  height: 10px;
  border-radius: 10px;
  display: inline-block;
  margin-right: 6px;
}
.dot.online { background: #67c23a; }
.dot.alert { background: #f56c6c; }
.dot.offline { background: #909399; }
.main-layout {
  display: flex;
  flex: 1;
  overflow: hidden;
  gap: 12px;
  padding: 12px;
}
.layer-panel {
  width: 280px;
  background: white;
  border-radius: 20px;
  padding: 16px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.05);
  display: flex;
  flex-direction: column;
}
.layer-header {
  font-weight: bold;
  font-size: 16px;
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.layer-tree {
  flex: 1;
  overflow-y: auto;
}
.custom-tree-node {
  display: flex;
  align-items: center;
  gap: 6px;
}
.badge-alert {
  margin-left: auto;
}
.legend-box {
  margin-top: 24px;
  border-top: 1px solid #e9ecef;
  padding-top: 12px;
}
.legend-icon {
  width: 14px;
  height: 14px;
  display: inline-block;
  margin-right: 8px;
  border-radius: 2px;
}
.normal-icon { background: #67c23a; }
.warning-icon { background: #e6a23c; }
.critical-icon { background: #f56c6c; }
.water-icon { background: #3b82f6; }
.gas-icon { background: #f97316; }
.gis-stage {
  flex: 1;
  background: white;
  border-radius: 20px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: 0 6px 14px rgba(0,0,0,0.08);
}
.map-toolbar {
  padding: 12px 16px;
  display: flex;
  justify-content: space-between;
  border-bottom: 1px solid #f0f0f0;
}
.map-wrapper {
  flex: 1;
  position: relative;
  cursor: crosshair;
}
canvas {
  width: 100%;
  height: 100%;
  display: block;
}
.hover-card {
  position: fixed;
  background: rgba(0,0,0,0.8);
  backdrop-filter: blur(6px);
  color: white;
  border-radius: 12px;
  padding: 8px 12px;
  font-size: 12px;
  pointer-events: none;
  z-index: 200;
  white-space: nowrap;
}
</style>