<!--监测报警一张图-->
<template>
  <div class="gis-alert-dashboard">
    <!-- 顶部状态栏 -->
    <div class="top-bar">

      <div class="alert-stats">
        <div class="stat" @click="focusLayer('critical')">
          <span class="stat-value critical">{{ criticalCount }}</span>
          <span class="stat-label">严重报警</span>
        </div>
        <div class="stat" @click="focusLayer('warning')">
          <span class="stat-value warning">{{ warningCount }}</span>
          <span class="stat-label">一般报警</span>
        </div>
        <div class="stat" @click="focusLayer('normal')">
          <span class="stat-value">{{ normalCount }}</span>
          <span class="stat-label">正常井盖</span>
        </div>
        <div class="stat" @click="focusLayer('offline')">
          <span class="stat-value offline">{{ offlineCount }}</span>
          <span class="stat-label">离线设备</span>
        </div>
      </div>
    </div>

    <div class="main-layout">
      <!-- 左侧图层控制面板 -->
      <div class="layer-control">
        <div class="layer-header">
          <el-icon>x</el-icon> 态势图层
        </div>
        <el-tree
            :data="layerTree"
            show-checkbox
            node-key="id"
            :default-checked-keys="defaultCheckedLayers"
            @check="onLayerChange"
            class="layer-tree"
        >
          <template #default="{ node, data }">
            <span class="layer-node">
              <el-icon><component :is="data.icon" /></el-icon>
              <span>{{ node.label }}</span>
              <el-badge v-if="data.alertCount" :value="data.alertCount" type="danger" class="layer-badge" />
            </span>
          </template>
        </el-tree>
        <div class="legend-panel">
          <div class="legend-title">图例说明</div>
          <div><span class="legend-marker critical-dot"></span> 严重报警</div>
          <div><span class="legend-marker warning-dot"></span> 一般报警</div>
          <div><span class="legend-marker normal-dot"></span> 正常在线</div>
          <div><span class="legend-marker offline-dot"></span> 离线/停用</div>
          <div><span class="legend-marker alarm-pulse"></span> 实时报警闪烁</div>
        </div>
        <div class="time-selector">
          <el-date-picker v-model="timeRange" type="datetimerange" range-separator="至" size="small" :shortcuts="shortcuts" start-placeholder="开始" end-placeholder="结束" />
        </div>
      </div>

      <!-- 右侧GIS地图核心区 -->
      <div class="gis-map-area">
        <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="FullScreen" @click="resetView">重置视图</el-button>
          </el-button-group>
          <div class="current-stat">
            <span><el-icon><Position /></el-icon> 监测点总数: {{ totalDevices }}</span>
            <span class="alert-summary">报警中: {{ totalActiveAlerts }}</span>
          </div>
        </div>
        <div class="map-container" ref="mapContainer">
          <canvas id="alertMapCanvas" ref="canvasRef" @click="onMapClick" @mousemove="onCanvasMouseMove"></canvas>
          <!-- 悬浮信息卡 -->
          <div v-if="hoverDevice" class="hover-card" :style="{ top: hoverY + 'px', left: hoverX + 'px' }">
            <div class="hover-title">{{ hoverDevice.name }}</div>
            <div>状态: {{ hoverDevice.statusText }}</div>
            <div>报警: {{ hoverDevice.hasAlert ? hoverDevice.alertType : '无' }}</div>
            <div>位置: {{ hoverDevice.locationShort }}</div>
          </div>
        </div>
        <!-- 右下角报警聚合弹窗/详情 -->
        <el-drawer v-model="drawerVisible" :title="selectedDevice?.name + ' - 监测报警详情'" direction="rtl" size="420px">
          <div v-if="selectedDevice">
            <el-descriptions :column="1" border>
              <el-descriptions-item label="设备编号">{{ selectedDevice.id }}</el-descriptions-item>
              <el-descriptions-item label="地理位置">{{ selectedDevice.address }}</el-descriptions-item>
              <el-descriptions-item label="当前状态">
                <el-tag :type="getStatusTag(selectedDevice.status)">{{ selectedDevice.statusText }}</el-tag>
              </el-descriptions-item>
              <el-descriptions-item label="报警级别" v-if="selectedDevice.hasAlert">
                <el-tag :type="selectedDevice.level === 'critical' ? 'danger' : 'warning'">{{ selectedDevice.level === 'critical' ? '严重报警' : '一般报警' }}</el-tag>
              </el-descriptions-item>
              <el-descriptions-item label="报警类型">{{ selectedDevice.alertType || '无' }}</el-descriptions-item>
              <el-descriptions-item label="实时监测值">{{ selectedDevice.realTimeValue || '—' }}</el-descriptions-item>
              <el-descriptions-item label="报警阈值">{{ selectedDevice.threshold || '—' }}</el-descriptions-item>
              <el-descriptions-item label="最近通讯">{{ selectedDevice.lastComm }}</el-descriptions-item>
            </el-descriptions>
            <el-divider>处置建议</el-divider>
            <div class="advice-box">
              <p>{{ getAlertAdvice(selectedDevice) }}</p>
              <el-button type="primary" size="small" style="margin-top: 12px;" @click="dispatchWorkOrder">派发处置工单</el-button>
            </div>
            <el-divider v-if="selectedDevice.alertLogs?.length">报警记录</el-divider>
            <el-timeline>
              <el-timeline-item v-for="log in selectedDevice.alertLogs" :key="log.time" :timestamp="log.time" type="danger">
                {{ log.content }}
              </el-timeline-item>
            </el-timeline>
          </div>
        </el-drawer>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
import { MapLocation, ZoomIn, ZoomOut, FullScreen, Position, WarningFilled, Location, Monitor, Opportunity } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

// 图层树结构（分图层汇聚展示）
const layerTree = ref([
  {
    id: 'layer-status',
    label: '井盖本体状态图层',
    icon: 'Monitor',
    alertCount: 3,
    children: [
      { id: 'tilt', label: '位移/倾斜监测', icon: 'Position', alertCount: 2 },
      { id: 'open', label: '开盖状态监测', icon: 'Lock', alertCount: 1 },
      { id: 'vibration', label: '震动异常监测', icon: 'Opportunity', alertCount: 0 }
    ]
  },
  {
    id: 'layer-alert',
    label: '实时报警图层',
    icon: 'WarningFilled',
    alertCount: 3,
    children: [
      { id: 'critical-alert', label: '严重报警点', icon: 'WarningFilled', alertCount: 2 },
      { id: 'warning-alert', label: '一般报警点', icon: 'InfoFilled', alertCount: 1 }
    ]
  },
  {
    id: 'layer-device',
    label: '设备运维图层',
    icon: 'Setting',
    alertCount: 1,
    children: [
      { id: 'battery-low', label: '低电量设备', icon: 'Battery', alertCount: 1 },
      { id: 'offline', label: '离线设备', icon: 'Connection', alertCount: 1 }
    ]
  }
])
const defaultCheckedLayers = ['layer-status', 'layer-alert', 'tilt', 'open', 'critical-alert', 'warning-alert']
const visibleLayers = ref(new Set(defaultCheckedLayers))

// 模拟窨井盖设备数据 (含报警态势)
const mockManholes = ref([
  { id: 'MN-001', name: '人民路1号', lng: 121.487, lat: 31.249, address: '人民路与解放路口', status: 'critical', statusText: '严重报警', hasAlert: true, level: 'critical', alertType: '倾斜超标', realTimeValue: '14.2°', threshold: '8°', lastComm: '2025-04-02 14:20', locationShort: '人民路口', battery: 67,
    alertLogs: [{ time: '2025-04-02 14:18', content: '倾斜角14.2°超过阈值8°' }] },
  { id: 'MN-002', name: '滨江路防爆井', lng: 121.502, lat: 31.235, address: '滨江路化工园区', status: 'critical', statusText: '严重报警', hasAlert: true, level: 'critical', alertType: '水位超标', realTimeValue: '62cm', threshold: '40cm', lastComm: '2025-04-02 14:05', locationShort: '滨江园区', battery: 34,
    alertLogs: [{ time: '2025-04-02 13:58', content: '水位62cm超阈值' }] },
  { id: 'MN-003', name: '古城街井盖', lng: 121.478, lat: 31.258, address: '古城街北段', status: 'warning', statusText: '一般报警', hasAlert: true, level: 'warning', alertType: '异常震动', realTimeValue: '112mg', threshold: '80mg', lastComm: '2025-04-02 13:30', locationShort: '古城街', battery: 55,
    alertLogs: [{ time: '2025-04-02 13:25', content: '震动112mg异常' }] },
  { id: 'MN-004', name: '高新区智能井', lng: 121.512, lat: 31.242, address: '高新大道云计算中心', status: 'normal', statusText: '正常', hasAlert: false, lastComm: '2025-04-02 14:15', locationShort: '高新区', battery: 92 },
  { id: 'MN-005', name: '南港路井盖', lng: 121.495, lat: 31.228, address: '南港路旧车站', status: 'warning', statusText: '一般报警', hasAlert: true, level: 'warning', alertType: '井盖开启异常', realTimeValue: '开启', threshold: '关闭', lastComm: '2025-04-02 12:50', locationShort: '南港路', battery: 41,
    alertLogs: [{ time: '2025-04-02 12:48', content: '井盖非正常开启' }] },
  { id: 'MN-006', name: '石化区防爆井', lng: 121.524, lat: 31.239, address: '石化大道', status: 'offline', statusText: '离线', hasAlert: false, lastComm: '2025-04-01 20:00', locationShort: '石化区', battery: 12 }
])

// 统计
const criticalCount = computed(() => mockManholes.value.filter(m => m.status === 'critical').length)
const warningCount = computed(() => mockManholes.value.filter(m => m.status === 'warning').length)
const normalCount = computed(() => mockManholes.value.filter(m => m.status === 'normal').length)
const offlineCount = computed(() => mockManholes.value.filter(m => m.status === 'offline').length)
const totalDevices = computed(() => mockManholes.value.length)
const totalActiveAlerts = computed(() => criticalCount.value + warningCount.value)

// GIS Canvas 绘图部分
const canvasRef = ref(null)
const mapContainer = ref(null)
let ctx = null
let mapWidth = 0, mapHeight = 0
let mapZoom = 1
let offsetX = 0, offsetY = 0
const bounds = { minLng: 121.45, maxLng: 121.55, minLat: 31.22, maxLat: 31.28 }

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 cx = mapWidth / 2, cy = mapHeight / 2
  return { x: (px - cx) * mapZoom + cx + offsetX, y: (py - cy) * mapZoom + cy + offsetY }
}

function drawBaseMap() {
  if (!ctx) return
  ctx.fillStyle = '#eaf2e6'
  ctx.fillRect(0, 0, mapWidth, mapHeight)
  ctx.strokeStyle = '#c8ddc4'
  ctx.lineWidth = 1
  for (let i = 0; i < 12; i++) {
    ctx.beginPath()
    ctx.moveTo((i / 12) * mapWidth, 0)
    ctx.lineTo((i / 12) * mapWidth, mapHeight)
    ctx.stroke()
    ctx.beginPath()
    ctx.moveTo(0, (i / 12) * mapHeight)
    ctx.lineTo(mapWidth, (i / 12) * mapHeight)
    ctx.stroke()
  }
  ctx.fillStyle = '#a8d0a6'
  ctx.font = '12px "Microsoft YaHei"'
  ctx.fillText('人民路', 180, 110)
  ctx.fillText('滨江路', 380, 280)
  ctx.fillText('高新区', 580, 170)
}

function drawManholes() {
  if (!ctx) return
  mockManholes.value.forEach(device => {
    const { x, y } = worldToCanvas(device.lng, device.lat)
    if (x < -40 || x > mapWidth + 40 || y < -40 || y > mapHeight + 40) return
    // 根据状态确定图标样式
    let color = '#67C23A'
    let size = 14
    let isAlertBlink = false
    if (device.status === 'critical') { color = '#F56C6C'; size = 18; isAlertBlink = true }
    else if (device.status === 'warning') { color = '#E6A23C'; size = 16 }
    else if (device.status === 'offline') { color = '#909399'; size = 12 }
    // 闪烁效果: 简单模拟根据时间正弦变化，但在重绘中直接绘制不闪烁，但可增加外圈
    ctx.beginPath()
    ctx.arc(x, y, size, 0, 2 * Math.PI)
    ctx.fillStyle = color
    ctx.fill()
    ctx.strokeStyle = '#fff'
    ctx.lineWidth = 2
    ctx.stroke()
    if (isAlertBlink) {
      ctx.beginPath()
      ctx.arc(x, y, size + 4, 0, 2 * Math.PI)
      ctx.fillStyle = 'rgba(245,108,108,0.3)'
      ctx.fill()
    }
    ctx.fillStyle = '#fff'
    ctx.font = 'bold 12px sans-serif'
    ctx.fillText(device.name.slice(0, 4), x-10, y-8)
    // 图层过滤额外绘制报警标识
    if (visibleLayers.value.has('critical-alert') && device.status === 'critical') {
      ctx.fillStyle = '#ff4d4f'
      ctx.beginPath()
      ctx.moveTo(x+12, y-12)
      ctx.lineTo(x+18, y-5)
      ctx.fill()
    }
    if (visibleLayers.value.has('tilt') && device.alertType?.includes('倾斜')) {
      ctx.fillStyle = '#f56c6c'
      ctx.fillRect(x+8, y-14, 6, 6)
    }
  })
}

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

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

const onLayerChange = () => { renderMap() }
const focusLayer = (type) => { /* 可缩放至对应类型设备，简化处理 */ ElMessage.info(`聚焦${type}类设备`) }

// 交互变量
const selectedDevice = ref(null)
const drawerVisible = ref(false)
const hoverDevice = ref(null)
const hoverX = ref(0), hoverY = ref(0)
const timeRange = ref([])
const shortcuts = [{ text: '最近24小时', value: () => [new Date(Date.now() - 86400000), new Date()] }]

function onMapClick(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
  mockManholes.value.forEach(device => {
    const { x, y } = worldToCanvas(device.lng, device.lat)
    const dist = Math.hypot(mouseX - x, mouseY - y)
    if (dist < minDist) { minDist = dist; hit = device }
  })
  if (hit) { selectedDevice.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
  mockManholes.value.forEach(device => {
    const { x, y } = worldToCanvas(device.lng, device.lat)
    const dist = Math.hypot(mouseX - x, mouseY - y)
    if (dist < minDist) { minDist = dist; hit = device }
  })
  if (hit) { hoverDevice.value = hit; hoverX.value = e.clientX + 12; hoverY.value = e.clientY - 40 }
  else hoverDevice.value = null
}

const getStatusTag = (status) => {
  if (status === 'critical') return 'danger'
  if (status === 'warning') return 'warning'
  if (status === 'offline') return 'info'
  return 'success'
}
const getAlertAdvice = (device) => {
  if (device.alertType?.includes('倾斜')) return '建议立即安排检修人员现场确认井盖固定情况，如损坏需更换。'
  if (device.alertType?.includes('水位')) return '井内水位过高，需紧急排水，检查管道是否堵塞。'
  if (device.alertType?.includes('震动')) return '持续震动可能为外力破坏，建议巡检周边施工情况。'
  return '请根据现场情况迅速核实并处置。'
}
const dispatchWorkOrder = () => { ElMessage.success('已派发工单至维护班组') }

onMounted(() => {
  nextTick(() => {
    renderMap()
    window.addEventListener('resize', renderMap)
  })
})
onUnmounted(() => window.removeEventListener('resize', renderMap))
</script>

<style scoped>
.gis-alert-dashboard {
  background: #eef2f0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.top-bar {
  background: white;
  padding: 10px 24px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.logo-area { display: flex; align-items: center; gap: 14px; }
.title { font-size: 1.5rem; font-weight: 700; background: linear-gradient(135deg, #1e5128, #409eff); -webkit-background-clip: text; background-clip: text; color: transparent; }
.alert-stats { display: flex; gap: 24px; }
.stat { text-align: center; cursor: pointer; padding: 4px 16px; border-radius: 40px; transition: 0.2s; }
.stat:hover { background: #f0f2f5; }
.stat-value { font-size: 26px; font-weight: bold; display: block; line-height: 1.2; }
.stat-value.critical { color: #f56c6c; }
.stat-value.warning { color: #e6a23c; }
.stat-value.offline { color: #909399; }
.stat-label { font-size: 12px; color: #606266; }
.main-layout { display: flex; flex: 1; gap: 16px; padding: 16px; overflow: hidden; }
.layer-control {
  width: 280px;
  background: white;
  border-radius: 20px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow-y: auto;
}
.layer-header { font-weight: bold; display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.layer-tree { flex: 1; }
.layer-badge { margin-left: auto; }
.legend-panel { border-top: 1px solid #e9ecef; padding-top: 12px; margin-top: 8px; }
.legend-title { margin-bottom: 8px; font-weight: 500; font-size: 13px; }
.legend-marker { display: inline-block; width: 14px; height: 14px; border-radius: 14px; margin-right: 8px; vertical-align: middle; }
.critical-dot { background: #f56c6c; box-shadow: 0 0 0 2px rgba(245,108,108,0.4); }
.warning-dot { background: #e6a23c; }
.normal-dot { background: #67c23a; }
.offline-dot { background: #909399; }
.alarm-pulse { width: 14px; height: 14px; background: red; border-radius: 50%; animation: pulse 1s infinite; display: inline-block; margin-right: 8px; }
@keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.4; transform: scale(1.2); } 100% { opacity: 1; } }
.gis-map-area {
  flex: 1;
  background: white;
  border-radius: 20px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.map-toolbar {
  padding: 12px 16px;
  border-bottom: 1px solid #edf2f0;
  display: flex;
  justify-content: space-between;
}
.current-stat { display: flex; gap: 20px; font-size: 13px; }
.map-container {
  flex: 1;
  position: relative;
  cursor: crosshair;
}
canvas { width: 100%; height: 100%; display: block; }
.hover-card {
  position: fixed;
  background: rgba(0,0,0,0.8);
  color: white;
  padding: 8px 12px;
  border-radius: 12px;
  font-size: 12px;
  pointer-events: none;
  z-index: 200;
  backdrop-filter: blur(6px);
}
.advice-box { background: #f8f9fa; padding: 12px; border-radius: 12px; }
</style>