<!--监测报警一张图-->
<template>
  <div class="water-alert-gis">
    <!-- 页面头部 -->
    <div class="page-header">
      <div class="header-left">
        <el-icon><Warning /></el-icon>
        <span class="title">供水报警点位GIS一张图</span>
        <div class="stats-badge">
          <span class="stat-item critical"><i class="dot"></i>严重报警 {{ criticalCount }}</span>
          <span class="stat-item warning"><i class="dot"></i>预警 {{ warningCount }}</span>
          <span class="stat-item normal"><i class="dot"></i>正常 {{ normalCount }}</span>
        </div>
      </div>
      <div class="header-right">
        <el-input
            v-model="searchKeyword"
            placeholder="搜索报警点位/地址"
            clearable
            :prefix-icon="Search"
            style="width: 240px"
            @keyup.enter="searchAndLocate"
        />
        <el-button type="primary" :icon="Location" @click="searchAndLocate">定位</el-button>
        <el-button :icon="Refresh" @click="refreshMap">刷新</el-button>
        <el-button :icon="FullScreen" @click="fitBounds">全图</el-button>
      </div>
    </div>

    <!-- 统计卡片 -->
    <div class="stats-cards">
      <div class="stat-card critical" @click="filterByLevel('critical')">
        <div class="stat-value">{{ criticalCount }}</div>
        <div class="stat-label">严重报警</div>
      </div>
      <div class="stat-card warning" @click="filterByLevel('warning')">
        <div class="stat-value">{{ warningCount }}</div>
        <div class="stat-label">预警</div>
      </div>
      <div class="stat-card normal" @click="filterByLevel('normal')">
        <div class="stat-value">{{ normalCount }}</div>
        <div class="stat-label">正常点位</div>
      </div>
      <div class="stat-card">
        <div class="stat-value">{{ totalPoints }}</div>
        <div class="stat-label">监测点总数</div>
      </div>
    </div>

    <!-- 主内容区：左侧报警列表 + 右侧GIS地图 -->
    <div class="main-layout">
      <!-- 左侧报警列表 -->
      <div class="alert-list-panel">
        <div class="panel-header">
          <span><el-icon><List /></el-icon> 报警点列表</span>
          <el-select v-model="levelFilter" placeholder="报警级别" clearable size="small" style="width: 110px">
            <el-option label="严重报警" value="critical" />
            <el-option label="预警" value="warning" />
            <el-option label="正常" value="normal" />
          </el-select>
        </div>
        <div class="alert-list">
          <div
              v-for="point in paginatedPoints"
              :key="point.id"
              class="alert-item"
              :class="{
              selected: selectedPoint?.id === point.id,
              critical: point.level === 'critical',
              warning: point.level === 'warning'
            }"
              @click="selectPoint(point)"
          >
            <div class="alert-level-icon">
              <el-icon v-if="point.level === 'critical'"><WarningFilled /></el-icon>
              <el-icon v-else-if="point.level === 'warning'"><InfoFilled /></el-icon>
              <el-icon v-else><CircleCheck /></el-icon>
            </div>
            <div class="alert-info">
              <div class="alert-title">{{ point.name }}</div>
              <div class="alert-address">
                <el-icon><Location /></el-icon> {{ point.shortAddress }}
              </div>
              <div class="alert-value" v-if="point.alertValue">
                报警值: {{ point.alertValue }}
              </div>
              <div class="alert-time">{{ point.alertTime }}</div>
            </div>
          </div>
        </div>
        <div class="pagination-area">
          <el-pagination
              small
              layout="prev, pager, next"
              :total="filteredPoints.length"
              :page-size="pageSize"
              v-model:current-page="currentPage"
          />
        </div>
      </div>

      <!-- 右侧GIS地图 -->
      <div class="gis-container">
        <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="map-legend">
            <span><i class="legend-dot critical-dot"></i>严重报警</span>
            <span><i class="legend-dot warning-dot"></i>预警</span>
            <span><i class="legend-dot normal-dot"></i>正常</span>
          </div>
        </div>
        <div class="map-wrapper" ref="mapContainer">
          <canvas id="waterAlertMapCanvas" ref="canvasRef" @click="onMapClick" @mousemove="onCanvasMouseMove"></canvas>
          <div v-if="hoverPoint" class="hover-card" :style="{ top: hoverY + 'px', left: hoverX + 'px' }">
            <div class="hover-title">{{ hoverPoint.name }}</div>
            <div>级别: {{ hoverPoint.level === 'critical' ? '严重报警' : hoverPoint.level === 'warning' ? '预警' : '正常' }}</div>
            <div v-if="hoverPoint.alertValue">报警值: {{ hoverPoint.alertValue }}</div>
            <div>位置: {{ hoverPoint.address }}</div>
          </div>
        </div>

        <!-- 详情抽屉 -->
        <el-drawer v-model="detailDrawerVisible" :title="`点位详情 - ${currentPoint?.name}`" size="450px" direction="rtl">
          <div v-if="currentPoint" class="point-detail">
            <div class="level-tag" :class="currentPoint.level">
              {{ currentPoint.level === 'critical' ? '严重报警' : currentPoint.level === 'warning' ? '预警' : '正常' }}
            </div>
            <el-descriptions :column="1" border>
              <el-descriptions-item label="点位名称">{{ currentPoint.name }}</el-descriptions-item>
              <el-descriptions-item label="点位编号">{{ currentPoint.code }}</el-descriptions-item>
              <el-descriptions-item label="报警级别">
                <el-tag :type="currentPoint.level === 'critical' ? 'danger' : currentPoint.level === 'warning' ? 'warning' : 'success'">
                  {{ currentPoint.level === 'critical' ? '严重报警' : currentPoint.level === 'warning' ? '预警' : '正常' }}
                </el-tag>
              </el-descriptions-item>
              <el-descriptions-item label="报警类型">{{ currentPoint.alertType || '—' }}</el-descriptions-item>
              <el-descriptions-item label="报警值">{{ currentPoint.alertValue || '—' }}</el-descriptions-item>
              <el-descriptions-item label="报警阈值">{{ currentPoint.threshold || '—' }}</el-descriptions-item>
              <el-descriptions-item label="详细地址">{{ currentPoint.address }}</el-descriptions-item>
              <el-descriptions-item label="经纬度">{{ currentPoint.lng }}, {{ currentPoint.lat }}</el-descriptions-item>
              <el-descriptions-item label="报警时间">{{ currentPoint.alertTime }}</el-descriptions-item>
              <el-descriptions-item label="处理状态">
                <el-tag :type="currentPoint.status === 'pending' ? 'danger' : 'success'">
                  {{ currentPoint.status === 'pending' ? '待处理' : '已处理' }}
                </el-tag>
              </el-descriptions-item>
            </el-descriptions>
            <div class="action-buttons" v-if="currentPoint.status === 'pending'">
              <el-button type="primary" size="small" @click="handleAlert">开始处理</el-button>
              <el-button size="small" @click="viewHistory">查看历史</el-button>
            </div>
          </div>
        </el-drawer>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue'
import { Warning, Search, Refresh, FullScreen, Location, List, WarningFilled, InfoFilled, CircleCheck, ZoomIn, ZoomOut } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

// 供水报警点位数据
const alertPoints = ref([
  { id: 1, code: 'WA-001', name: '世纪大道供水管监测点', level: 'critical', alertType: '压力骤降', alertValue: '2.1 bar', threshold: '3.0 bar', shortAddress: '世纪大道福山路口', address: '世纪大道与福山路交叉口东侧', lng: 121.505, lat: 31.235, alertTime: '2025-04-02 15:23:45', status: 'pending' },
  { id: 2, code: 'WA-002', name: '人民广场供水点', level: 'critical', alertType: '流量异常', alertValue: '320 m³/h', threshold: '500 m³/h', shortAddress: '人民大道200号', address: '人民大道200号地下泵房', lng: 121.487, lat: 31.239, alertTime: '2025-04-02 14:58:12', status: 'pending' },
  { id: 3, code: 'WA-003', name: '张杨路水质监测点', level: 'warning', alertType: '浊度超标', alertValue: '5.2 NTU', threshold: '3.0 NTU', shortAddress: '张杨路松林路口', address: '张杨路与松林路交叉口', lng: 121.52, lat: 31.242, alertTime: '2025-04-02 14:32:05', status: 'pending' },
  { id: 4, code: 'WA-004', name: '龙阳路压力监测点', level: 'warning', alertType: '压力波动', alertValue: '3.8 bar', threshold: '4.2 bar', shortAddress: '龙阳路白杨路口', address: '龙阳路与白杨路交叉口', lng: 121.51, lat: 31.215, alertTime: '2025-04-02 14:15:30', status: 'pending' },
  { id: 5, code: 'WA-005', name: '东方路流量计', level: 'normal', alertType: '—', alertValue: null, threshold: null, shortAddress: '东方路蓝村路口', address: '东方路与蓝村路交叉口', lng: 121.53, lat: 31.248, alertTime: '2025-04-02 10:00:00', status: 'resolved' },
  { id: 6, code: 'WA-006', name: '浦东南路水质点', level: 'normal', alertType: '—', alertValue: null, threshold: null, shortAddress: '浦东南路400号', address: '浦东南路400号', lng: 121.49, lat: 31.23, alertTime: '2025-04-02 09:00:00', status: 'resolved' }
])

// 统计数据
const criticalCount = computed(() => alertPoints.value.filter(p => p.level === 'critical').length)
const warningCount = computed(() => alertPoints.value.filter(p => p.level === 'warning').length)
const normalCount = computed(() => alertPoints.value.filter(p => p.level === 'normal').length)
const totalPoints = computed(() => alertPoints.value.length)

// 筛选
const searchKeyword = ref('')
const levelFilter = ref('')
const currentPage = ref(1)
const pageSize = 5
const selectedPoint = ref(alertPoints.value[0])
const currentPoint = ref(null)
const detailDrawerVisible = ref(false)

const filteredPoints = computed(() => {
  let list = alertPoints.value
  if (levelFilter.value) {
    list = list.filter(p => p.level === levelFilter.value)
  }
  if (searchKeyword.value) {
    const kw = searchKeyword.value.toLowerCase()
    list = list.filter(p => p.name.toLowerCase().includes(kw) || p.address.toLowerCase().includes(kw))
  }
  return list
})

const paginatedPoints = computed(() => {
  const start = (currentPage.value - 1) * pageSize
  return filteredPoints.value.slice(start, start + pageSize)
})

// 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 isDragging = false
const bounds = { minLng: 121.45, maxLng: 121.56, minLat: 31.20, maxLat: 31.27 }

// 交互状态
const hoverPoint = ref(null)
const hoverX = ref(0), hoverY = ref(0)

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 = '#eaf5e9'
  ctx.fillRect(0, 0, mapWidth, mapHeight)
  ctx.strokeStyle = '#c8ddc4'
  ctx.lineWidth = 1
  for (let i = 0; i <= 10; i++) {
    const x = (i / 10) * mapWidth
    ctx.beginPath()
    ctx.moveTo(x, 0); ctx.lineTo(x, mapHeight); ctx.stroke()
    const y = (i / 10) * mapHeight
    ctx.beginPath()
    ctx.moveTo(0, y); ctx.lineTo(mapWidth, y); ctx.stroke()
  }
  ctx.fillStyle = '#a8d0a6'
  ctx.font = '12px "Microsoft YaHei"'
  ctx.fillText('世纪大道', 350, 120)
  ctx.fillText('张杨路', 450, 280)
  ctx.fillText('东方路', 580, 200)
  ctx.fillText('龙阳路', 200, 370)
  ctx.fillText('人民广场', 180, 300)
}

function drawPoints() {
  filteredPoints.value.forEach(point => {
    const { x, y } = worldToCanvas(point.lng, point.lat)
    if (x < -20 || x > mapWidth + 20 || y < -20 || y > mapHeight + 20) return

    let color = '#67c23a'
    let size = 12
    if (point.level === 'critical') { color = '#f56c6c'; size = 16 }
    else if (point.level === 'warning') { color = '#e6a23c'; size = 14 }

    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 (point.level === 'critical') {
      ctx.beginPath()
      ctx.arc(x, y, size + 5, 0, 2 * Math.PI)
      ctx.fillStyle = 'rgba(245,108,108,0.3)'
      ctx.fill()
    }

    ctx.fillStyle = '#333'
    ctx.font = '10px sans-serif'
    ctx.fillText(point.name.slice(0, 6), x - 15, y - 10)
  })
}

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()
  drawPoints()
}

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

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
  filteredPoints.value.forEach(point => {
    const { x, y } = worldToCanvas(point.lng, point.lat)
    const dist = Math.hypot(mouseX - x, mouseY - y)
    if (dist < minDist) { minDist = dist; hit = point }
  })
  if (hit) { currentPoint.value = hit; detailDrawerVisible.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 = 20, hit = null
  filteredPoints.value.forEach(point => {
    const { x, y } = worldToCanvas(point.lng, point.lat)
    const dist = Math.hypot(mouseX - x, mouseY - y)
    if (dist < minDist) { minDist = dist; hit = point }
  })
  if (hit) {
    hoverPoint.value = hit
    hoverX.value = e.clientX + 12
    hoverY.value = e.clientY - 40
  } else {
    hoverPoint.value = null
  }
}

function initDragEvents() {
  const canvas = canvasRef.value
  if (!canvas) return
  canvas.addEventListener('mousedown', (e) => {
    dragStart = { x: e.clientX, y: e.clientY, offsetX: offsetX, offsetY: offsetY }
    isDragging = true
    canvas.style.cursor = 'grabbing'
  })
  window.addEventListener('mousemove', (e) => {
    if (!isDragging) return
    const dx = e.clientX - dragStart.x, dy = e.clientY - dragStart.y
    offsetX = dragStart.offsetX + dx; offsetY = dragStart.offsetY + dy
    renderMap()
  })
  window.addEventListener('mouseup', () => {
    isDragging = false
    if (canvasRef.value) canvasRef.value.style.cursor = 'crosshair'
  })
}

function searchAndLocate() {
  if (!searchKeyword.value) return
  const found = alertPoints.value.find(p => p.name.includes(searchKeyword.value) || p.address.includes(searchKeyword.value))
  if (found) {
    const center = worldToCanvas(found.lng, found.lat)
    mapZoom = 2
    offsetX = mapWidth/2 - center.x
    offsetY = mapHeight/2 - center.y
    renderMap()
    currentPoint.value = found
    detailDrawerVisible.value = true
    ElMessage.success(`已定位到: ${found.name}`)
  } else {
    ElMessage.warning('未找到匹配的点位')
  }
}

const selectPoint = (point) => {
  currentPoint.value = point
  detailDrawerVisible.value = true
  // 地图居中
  const center = worldToCanvas(point.lng, point.lat)
  offsetX = mapWidth/2 - center.x
  offsetY = mapHeight/2 - center.y
  renderMap()
}

const filterByLevel = (level) => {
  levelFilter.value = level
  currentPage.value = 1
}

const handleAlert = () => { ElMessage.success('开始处理报警') }
const viewHistory = () => { ElMessage.info('查看历史记录（演示）') }

watch(() => filteredPoints.value, () => { currentPage.value = 1; renderMap() })
watch(() => levelFilter.value, () => renderMap())

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

<style scoped>
.water-alert-gis {
  background: #f0f2f6;
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.page-header {
  background: white;
  padding: 12px 24px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #e9ecef;
}
.header-left { display: flex; align-items: center; gap: 20px; }
.header-left .title { font-size: 1.3rem; font-weight: 600; }
.stats-badge { display: flex; gap: 20px; }
.stat-item { font-size: 13px; display: flex; align-items: center; gap: 6px; }
.stat-item.critical { color: #f56c6c; }
.stat-item.warning { color: #e6a23c; }
.stat-item.normal { color: #67c23a; }
.stat-item .dot { width: 8px; height: 8px; border-radius: 50%; }
.stat-item.critical .dot { background: #f56c6c; }
.stat-item.warning .dot { background: #e6a23c; }
.stat-item.normal .dot { background: #67c23a; }
.header-right { display: flex; gap: 12px; }

.stats-cards {
  display: flex;
  gap: 16px;
  padding: 16px;
  background: white;
  margin: 0 12px 12px 12px;
  border-radius: 16px;
}
.stat-card {
  flex: 1;
  text-align: center;
  padding: 12px;
  border-radius: 12px;
  cursor: pointer;
  transition: all 0.2s;
}
.stat-card.critical { background: #fff8f8; border-left: 3px solid #f56c6c; }
.stat-card.warning { background: #fffef5; border-left: 3px solid #e6a23c; }
.stat-card.normal { background: #f5fff5; border-left: 3px solid #67c23a; }
.stat-value { font-size: 28px; font-weight: bold; }
.stat-card.critical .stat-value { color: #f56c6c; }
.stat-card.warning .stat-value { color: #e6a23c; }
.stat-card.normal .stat-value { color: #67c23a; }
.stat-label { font-size: 13px; color: #909399; margin-top: 4px; }

.main-layout {
  display: flex;
  flex: 1;
  overflow: hidden;
  padding: 0 12px 12px 12px;
  gap: 12px;
}
.alert-list-panel {
  width: 360px;
  background: white;
  border-radius: 16px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.panel-header {
  padding: 16px;
  border-bottom: 1px solid #e9ecef;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: 600;
}
.alert-list {
  flex: 1;
  overflow-y: auto;
  padding: 12px;
}
.alert-item {
  display: flex;
  gap: 12px;
  padding: 12px;
  margin-bottom: 8px;
  border-radius: 12px;
  background: #fafbfc;
  border: 1px solid #e9ecef;
  cursor: pointer;
  transition: all 0.2s;
}
.alert-item.selected { background: #ecf5ff; border-color: #409eff; }
.alert-item.critical { border-left: 3px solid #f56c6c; }
.alert-item.warning { border-left: 3px solid #e6a23c; }
.alert-level-icon { font-size: 22px; }
.alert-item.critical .alert-level-icon { color: #f56c6c; }
.alert-item.warning .alert-level-icon { color: #e6a23c; }
.alert-info { flex: 1; }
.alert-title { font-weight: 600; margin-bottom: 4px; }
.alert-address { font-size: 12px; color: #6c757d; display: flex; align-items: center; gap: 4px; margin-bottom: 4px; }
.alert-value { font-size: 12px; color: #f56c6c; margin-bottom: 4px; }
.alert-time { font-size: 11px; color: #aaa; }

.gis-container {
  flex: 1;
  background: white;
  border-radius: 16px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.map-toolbar {
  padding: 10px 16px;
  border-bottom: 1px solid #e9ecef;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.map-legend { display: flex; gap: 16px; font-size: 12px; }
.legend-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 4px; }
.critical-dot { background: #f56c6c; }
.warning-dot { background: #e6a23c; }
.normal-dot { background: #67c23a; }
.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);
  color: white;
  padding: 8px 12px;
  border-radius: 10px;
  font-size: 12px;
  pointer-events: none;
  z-index: 200;
}
.hover-title { font-weight: 600; margin-bottom: 4px; }

.point-detail { padding: 8px; }
.level-tag { text-align: center; padding: 8px; border-radius: 8px; margin-bottom: 16px; font-weight: bold; }
.level-tag.critical { background: #f56c6c20; color: #f56c6c; }
.level-tag.warning { background: #e6a23c20; color: #e6a23c; }
.level-tag.normal { background: #67c23a20; color: #67c23a; }
.action-buttons { margin-top: 16px; display: flex; gap: 12px; justify-content: flex-end; }
.pagination-area { padding: 12px; text-align: center; border-top: 1px solid #eee; }
</style>