<template>
  <div class="app-container gis-page">
    <div class="top-bar">
      <div class="top-bar-left">
        <el-select v-model="currentUnit" placeholder="选择单位" size="small" style="width:180px" @change="onUnitChange">
          <el-option v-for="u in BUSINESS_UNITS" :key="u.key" :label="u.label" :value="u.key" />
        </el-select>
        <div class="layer-buttons">
          <template v-if="currentUnit === 'unit0'">
            <el-button
              v-for="dt in dataTypes"
              :key="dt.key"
              size="small"
              :type="dt.checked ? 'primary' : 'default'"
              :style="dt.checked ? { backgroundColor: dt.color, borderColor: dt.color } : {}"
              @click="onLayerButtonClick(dt)"
            >
              {{ dt.label }}
            </el-button>
          </template>
          <template v-else>
            <el-button
              v-for="btn in currentUnitButtons"
              :key="btn.code"
              size="small"
              disabled
            >
              {{ btn.label }}<el-tag size="small" type="info" style="margin-left:4px">{{ btn.count }}</el-tag>
            </el-button>
          </template>
        </div>
      </div>
      <div class="top-bar-right">
        <el-input
          v-model="keyword"
          placeholder="搜索站点名称"
          clearable
          size="small"
          prefix-icon="Search"
          style="width:200px"
          @input="onSearch"
        />
      </div>
    </div>

    <div class="gis-layout">
      <div class="left-panel">
        <el-card shadow="never" style="height:100%">
          <template #header>
            <div class="card-header">
              <span>图层控制</span>
              <el-button size="small" icon="Refresh" @click="refreshAll">刷新</el-button>
            </div>
          </template>
          <div class="layer-list">
            <div v-for="dt in dataTypes" :key="dt.key" class="layer-item">
              <el-checkbox v-model="dt.checked" @change="() => onLayerCheckChange(dt)">
                <span class="layer-dot" :style="{ background: dt.color }"></span>
                {{ dt.label }}
              </el-checkbox>
            </div>
          </div>
        </el-card>
      </div>

      <div class="map-area">
        <el-card shadow="never" style="height:100%;display:flex;flex-direction:column">
          <template #header>
            <div class="card-header">
              <span>水资源信息GIS</span>
            </div>
          </template>
          <div class="map-wrapper" v-loading="loading">
            <div id="viewDiv" class="map-container"></div>
          </div>
          <div class="coord-bar">
            经度: {{ coord.lng.toFixed(6) }} 纬度: {{ coord.lat.toFixed(6) }}
          </div>
        </el-card>
      </div>

      <div class="right-panel">
        <el-card shadow="never" style="height:100%;display:flex;flex-direction:column">
          <template #header>
            <div class="card-header">
              <span>站点数据</span>
              <el-tag size="small" type="info">{{ filteredData.length }}</el-tag>
            </div>
          </template>
          <el-table
            :data="filteredData"
            stripe
            size="small"
            :height="tableHeight"
            highlight-current-row
            @row-click="onTableRowClick"
            style="width:100%"
          >
            <el-table-column prop="stnm" label="站名" min-width="80" show-overflow-tooltip />
            <el-table-column prop="typeLabel" label="类型" width="65" show-overflow-tooltip />
            <el-table-column prop="z" label="水位(m)" width="65" />
            <el-table-column prop="q" label="流量(m³/s)" width="75" />
            <el-table-column prop="ph" label="pH" width="50" />
            <el-table-column prop="dox" label="DO(mg/L)" width="70" />
            <el-table-column prop="codmn" label="CODMn(mg/L)" width="85" />
            <el-table-column prop="nh3n" label="NH3N(mg/L)" width="75" />
            <el-table-column prop="tp" label="TP(mg/L)" width="65" />
            <el-table-column prop="tn" label="TN(mg/L)" width="65" />
            <el-table-column prop="codcr" label="CODcr(mg/L)" width="80" />
            <el-table-column prop="wt" label="水温(℃)" width="65" />
            <el-table-column prop="tm" label="监测时间" width="140" />
          </el-table>
        </el-card>
      </div>
    </div>
  </div>
</template>

<script setup name="GisWiu">
import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { getStationList, getRealtimeData, getWaterQualityData } from '@/api/slgc/hydrology/index'
import { getSyqNewest, getSjBasinNewest, getSzAutoNewest, getSzLzNewest } from '@/api/slgc/tbaGx/index'
import { getSyqStation } from '@/api/slgc/syq/index'
import { WIU_DATA_TYPES, BUSINESS_UNITS } from '@/utils/gis-config'
import { useArcGisMap } from '@/composables/useArcGisMap'

const {
  map, view, coord,
  initMap, addBasinBoundary,
  createGraphicsLayer, createPointMarker, createCircleSymbol,
  openPopup,
} = useArcGisMap()

const currentUnit = ref('unit0')
const keyword = ref('')

const currentUnitDef = computed(() => BUSINESS_UNITS.find(u => u.key === currentUnit.value))
const currentUnitButtons = computed(() => currentUnitDef.value?.buttons || [])

function onUnitChange() {
  dataTypes.forEach(dt => {
    dt.checked = false
    if (dt.layer && map.value) {
      map.value.removeLayer(dt.layer)
      dt.layer = null
    }
  })
  Object.keys(typeDataMap).forEach(k => delete typeDataMap[k])
  if (currentUnit.value !== 'unit0') {
    ElMessage.info(currentUnitDef.value?.label + ' 数据接口尚未接入')
  }
}
const loading = ref(false)
const stationMap = ref({})

const dataTypes = reactive(
  WIU_DATA_TYPES.map(dt => ({ ...dt, checked: false, layer: null }))
)

const typeDataMap = reactive({})

const POPUP_FIELDS = {
  TBA_SW_1H2H: [
    { key: 'rvnm', label: '河流名称', unit: '' },
    { key: 'z', label: '水位', unit: 'm' },
    { key: 'q', label: '流量', unit: 'm³/s' },
    { key: 'stcd', label: '测站编码', unit: '' },
  ],
  TBA_SZY_SJ_RIVER: [
    { key: 'rvnm', label: '河流名称', unit: '' },
    { key: 'wt', label: '水温', unit: '℃' },
    { key: 'ph', label: 'pH值', unit: '' },
    { key: 'dox', label: '溶解氧', unit: 'mg/L' },
    { key: 'codmn', label: '高锰酸盐指数', unit: 'mg/L' },
    { key: 'codcr', label: '化学需氧量', unit: 'mg/L' },
    { key: 'bod5', label: '五日生化需氧量', unit: 'mg/L' },
    { key: 'nh3n', label: '氨氮', unit: 'mg/L' },
    { key: 'tp', label: '总磷', unit: 'mg/L' },
    { key: 'cn', label: '氰化物', unit: 'mg/L' },
    { key: 'f', label: '氟化物', unit: 'mg/L' },
    { key: 's2', label: '硫化物', unit: 'mg/L' },
    { key: 'las', label: '阴离子表面活性剂', unit: 'mg/L' },
    { key: 'hg', label: '汞', unit: 'mg/L' },
    { key: 'cu', label: '铜', unit: 'mg/L' },
    { key: 'pb', label: '铅', unit: 'mg/L' },
    { key: 'cd', label: '镉', unit: 'mg/L' },
    { key: 'zn', label: '锌', unit: 'mg/L' },
    { key: 'ars', label: '砷', unit: 'mg/L' },
    { key: 'se', label: '硒', unit: 'mg/L' },
    { key: 'cr6', label: '六价铬', unit: 'mg/L' },
    { key: 'oil', label: '石油类', unit: 'mg/L' },
    { key: 'vlph', label: '挥发酚', unit: 'mg/L' },
  ],
  TBA_SZY_SJ_BASIN: [
    { key: 'rvnm', label: '河流名称', unit: '' },
    { key: 'wt', label: '水温', unit: '℃' },
    { key: 'ph', label: 'pH值', unit: '' },
    { key: 'dox', label: '溶解氧', unit: 'mg/L' },
    { key: 'codmn', label: '高锰酸盐指数', unit: 'mg/L' },
    { key: 'codcr', label: '化学需氧量', unit: 'mg/L' },
    { key: 'bod5', label: '五日生化需氧量', unit: 'mg/L' },
    { key: 'nh3n', label: '氨氮', unit: 'mg/L' },
    { key: 'tp', label: '总磷', unit: 'mg/L' },
    { key: 'tn', label: '总氮', unit: 'mg/L' },
    { key: 'cn', label: '氰化物', unit: 'mg/L' },
    { key: 'f', label: '氟化物', unit: 'mg/L' },
    { key: 's2', label: '硫化物', unit: 'mg/L' },
    { key: 'las', label: '阴离子表面活性剂', unit: 'mg/L' },
    { key: 'hg', label: '汞', unit: 'mg/L' },
    { key: 'cu', label: '铜', unit: 'mg/L' },
    { key: 'pb', label: '铅', unit: 'mg/L' },
    { key: 'cd', label: '镉', unit: 'mg/L' },
    { key: 'zn', label: '锌', unit: 'mg/L' },
    { key: 'ars', label: '砷', unit: 'mg/L' },
    { key: 'se', label: '硒', unit: 'mg/L' },
    { key: 'cr6', label: '六价铬', unit: 'mg/L' },
    { key: 'oil', label: '石油类', unit: 'mg/L' },
    { key: 'vlph', label: '挥发酚', unit: 'mg/L' },
  ],
  TBA_SZY_RH: [
    { key: 'rvnm', label: '河流名称', unit: '' },
    { key: 'wt', label: '水温', unit: '℃' },
    { key: 'ph', label: 'pH值', unit: '' },
    { key: 'dox', label: '溶解氧', unit: 'mg/L' },
    { key: 'codmn', label: '高锰酸盐指数', unit: 'mg/L' },
    { key: 'codcr', label: '化学需氧量', unit: 'mg/L' },
    { key: 'bod5', label: '五日生化需氧量', unit: 'mg/L' },
    { key: 'nh3n', label: '氨氮', unit: 'mg/L' },
    { key: 'tp', label: '总磷', unit: 'mg/L' },
    { key: 'cn', label: '氰化物', unit: 'mg/L' },
    { key: 'f', label: '氟化物', unit: 'mg/L' },
    { key: 's2', label: '硫化物', unit: 'mg/L' },
    { key: 'las', label: '阴离子表面活性剂', unit: 'mg/L' },
    { key: 'hg', label: '汞', unit: 'mg/L' },
    { key: 'cu', label: '铜', unit: 'mg/L' },
    { key: 'pb', label: '铅', unit: 'mg/L' },
    { key: 'cd', label: '镉', unit: 'mg/L' },
    { key: 'zn', label: '锌', unit: 'mg/L' },
    { key: 'ars', label: '砷', unit: 'mg/L' },
    { key: 'se', label: '硒', unit: 'mg/L' },
    { key: 'cr6', label: '六价铬', unit: 'mg/L' },
    { key: 'oil', label: '石油类', unit: 'mg/L' },
    { key: 'vlph', label: '挥发酚', unit: 'mg/L' },
  ],
  TBA_SYD_LZDC: [
    { key: 'rvnm', label: '河流名称', unit: '' },
    { key: 'wt', label: '水温', unit: '℃' },
    { key: 'ph', label: 'pH值', unit: '' },
    { key: 'cond', label: '电导率', unit: 'uS/cm' },
    { key: 'dox', label: '溶解氧', unit: 'mg/L' },
    { key: 'codmn', label: '高锰酸盐指数', unit: 'mg/L' },
    { key: 'nh3n', label: '氨氮', unit: 'mg/L' },
    { key: 'tn', label: '总氮', unit: 'mg/L' },
    { key: 'tp', label: '总磷', unit: 'mg/L' },
    { key: 'turb', label: '浊度', unit: 'NTU' },
    { key: 'chla', label: '叶绿素a', unit: 'mg/L' },
  ],
  TBA_SZ_1H2H: [
    { key: 'rvnm', label: '河流名称', unit: '' },
    { key: 'wt', label: '水温', unit: '℃' },
    { key: 'ph', label: 'pH值', unit: '' },
    { key: 'cond', label: '电导率', unit: 'uS/cm' },
    { key: 'dox', label: '溶解氧', unit: 'mg/L' },
    { key: 'codmn', label: '高锰酸盐指数', unit: 'mg/L' },
    { key: 'nh3n', label: '氨氮', unit: 'mg/L' },
    { key: 'tn', label: '总氮', unit: 'mg/L' },
    { key: 'tp', label: '总磷', unit: 'mg/L' },
    { key: 'turb', label: '浊度', unit: 'NTU' },
    { key: 'chla', label: '叶绿素a', unit: 'mg/L' },
  ],
  TBA_SZY_LZJC: [
    { key: 'lake', label: '湖区', unit: '' },
    { key: 'num', label: '蓝藻数量', unit: '' },
    { key: 'biomass', label: '生物量', unit: '' },
    { key: 'note', label: '主要优势种', unit: '' },
    { key: 'nblue', label: '蓝藻', unit: '' },
    { key: 'ngreen', label: '绿藻', unit: '' },
    { key: 'nsi', label: '硅藻', unit: '' },
    { key: 'nhide', label: '隐藻', unit: '' },
    { key: 'nyellow', label: '黄藻', unit: '' },
    { key: 'nnake', label: '裸藻', unit: '' },
    { key: 'nfirst', label: '甲藻', unit: '' },
    { key: 'ngold', label: '金藻', unit: '' },
  ],
}

const filteredData = computed(() => {
  const kw = keyword.value.trim().toLowerCase()
  const result = []
  dataTypes.forEach(dt => {
    if (!dt.checked) return
    const items = typeDataMap[dt.key] || []
    items.forEach(item => {
      if (kw && !item.stnm.toLowerCase().includes(kw)) return
      result.push({ ...item, typeLabel: dt.label })
    })
  })
  return result
})

const tableHeight = computed(() => 'calc(100vh - 340px)')

function onLayerButtonClick(dt) {
  dt.checked = !dt.checked
  onLayerCheckChange(dt)
}

function onLayerCheckChange(dt) {
  if (dt.checked) {
    loadLayerData(dt)
  } else {
    removeLayer(dt)
  }
}

async function loadStationList() {
  try {
    const [hydrologyRes, syqRes] = await Promise.allSettled([
      getStationList(),
      getSyqStation(),
    ])
    const map = {}
    for (const result of [hydrologyRes, syqRes]) {
      if (result.status !== 'fulfilled') continue
      const rows = result.value.rows || result.value.data || []
      rows.forEach(r => {
        const stnm = r.STNM || r.stnm || r.name || ''
        const lng = Number(r.LGTD || r.lng || r.long || 0)
        const lat = Number(r.LTTD || r.lat || r.latitude || 0)
        if (stnm && lng && lat) {
          map[stnm] = { lng, lat }
        }
      })
    }
    stationMap.value = map
  } catch {
    stationMap.value = {}
  }
}

function buildDataItem(row, dt, coords) {
  return {
    stnm: row.STNM || row.stnm || '',
    typeKey: dt.key,
    lng: coords.lng,
    lat: coords.lat,
    stcd: row.STCD || row.stcd || '-',
    rvnm: row.RVNM || row.rvnm || '-',
    z: parseFloatValue(row.Z ?? row.z),
    q: parseFloatValue(row.Q ?? row.q),
    wt: parseFloatValue(row.wt ?? row.WT),
    ph: parseFloatValue(row.pH ?? row.PH ?? row.ph),
    cond: parseFloatValue(row.cond ?? row.Cond ?? row.COND),
    dox: parseFloatValue(row.DO ?? row.do ?? row.dox ?? row.DOX),
    codmn: parseFloatValue(row.CODmn ?? row.codmn ?? row.CODMn),
    codcr: parseFloatValue(row.CODcr ?? row.codcr),
    bod5: parseFloatValue(row.BOD5 ?? row.bod5),
    nh3n: parseFloatValue(row.NH3N ?? row.nh3n),
    tn: parseFloatValue(row.TN ?? row.tn ?? row.Tn),
    tp: parseFloatValue(row.TP ?? row.tp),
    cn: parseFloatValue(row.cn ?? row.Cn ?? row.CN),
    f: parseFloatValue(row.f ?? row.F),
    s2: parseFloatValue(row.s2 ?? row.S2),
    las: parseFloatValue(row.las ?? row.Las ?? row.LAS),
    hg: parseFloatValue(row.hg ?? row.Hg ?? row.HG),
    cu: parseFloatValue(row.cu ?? row.Cu ?? row.CU),
    pb: parseFloatValue(row.pb ?? row.Pb ?? row.PB),
    cd: parseFloatValue(row.cd ?? row.Cd ?? row.CD),
    zn: parseFloatValue(row.zn ?? row.Zn ?? row.ZN),
    ars: parseFloatValue(row.ars ?? row.Ars ?? row.ARS),
    se: parseFloatValue(row.se ?? row.Se ?? row.SE),
    cr6: parseFloatValue(row.cr6 ?? row.Cr6 ?? row.CR6),
    oil: parseFloatValue(row.oil ?? row.Oil ?? row.OIL),
    vlph: parseFloatValue(row.vlph ?? row.Vlph ?? row.VLPH),
    turb: parseFloatValue(row.Turb ?? row.turb ?? row.TURB),
    chla: parseFloatValue(row.Chla ?? row.chla ?? row.CHLA),
    lake: row.lake || row.Lake || '-',
    num: parseFloatValue(row.num ?? row.Num ?? row.NUM),
    biomass: parseFloatValue(row.biomass ?? row.Biomass),
    note: row.note || row.Note || '-',
    nblue: parseFloatValue(row.nblue ?? row.Nblue ?? row.NBLUE),
    ngreen: parseFloatValue(row.ngreen ?? row.Ngreen ?? row.NGREEN),
    nsi: parseFloatValue(row.nsi ?? row.Nsi ?? row.NSI),
    nhide: parseFloatValue(row.nhide ?? row.Nhide ?? row.NHIDE),
    nyellow: parseFloatValue(row.nyellow ?? row.Nyellow ?? row.NYELLOW),
    nnake: parseFloatValue(row.nnake ?? row.Nnake ?? row.NNAKE),
    nfirst: parseFloatValue(row.nfirst ?? row.Nfirst ?? row.NFIRST),
    ngold: parseFloatValue(row.ngold ?? row.Ngold ?? row.NGOLD),
    tm: row.TM || row.tm || row.spt || row.dt || '-',
  }
}

function renderLayerItems(items, dt) {
  if (dt.layer && map.value.findLayerById(dt.layer.id)) {
    map.value.remove(dt.layer)
  }
  const layer = createGraphicsLayer(`wiu-${dt.key}`)
  dt.layer = layer
  map.value.add(layer)

  items.forEach(item => {
    const symbol = createCircleSymbol(dt.color, 14)
    const graphic = createPointMarker(item.lat, item.lng, symbol, item)
    layer.add(graphic)
  })

  typeDataMap[dt.key] = items
}

async function loadLayerData(dt) {
  if (!map.value || !Object.keys(stationMap.value).length) return
  loading.value = true
  try {
    const tbaGxApi = {
      TBA_SW_1H2H: () => getSyqNewest({ code: 'n' }),
      TBA_SZY_SJ_RIVER: () => getSjBasinNewest({ bizCode: 'TBA_SZY_SJ_RIVER' }),
      TBA_SZY_SJ_BASIN: () => getSjBasinNewest({ bizCode: 'TBA_SZY_SJ_BASIN' }),
      TBA_SZY_RH: () => getSjBasinNewest({ bizCode: 'TBA_SZY_RH' }),
      TBA_SYD_LZDC: () => getSzAutoNewest({ bizCode: 'TBA_SYD_LZDC' }),
      TBA_SZ_1H2H: () => getSzAutoNewest({ bizCode: 'TBA_SZ_1H2H' }),
      TBA_SZY_LZJC: () => getSzLzNewest({ bizCode: 'TBA_SZY_LZJC' }),
    }
    const fetcher = tbaGxApi[dt.key]
    if (fetcher) {
      try {
        const res = await fetcher()
        const rows = res.rows || res.data || []
        if (rows.length) {
          const items = []
          rows.forEach(row => {
            const stnm = row.STNM || row.stnm || ''
            const coords = stationMap.value[stnm]
            if (!coords) return
            items.push(buildDataItem(row, dt, coords))
          })
          if (items.length) {
            renderLayerItems(items, dt)
            return
          }
        }
      } catch {}
    }

    const api = dt.api === 'realtime' ? getRealtimeData : getWaterQualityData
    const res = await api()
    const rows = res.rows || res.data || []
    if (!rows.length) {
      dt.checked = false
      ElMessage.warning(`${dt.label} 无数据`)
      return
    }

    const items = []
    rows.forEach(row => {
      const stnm = row.STNM || row.stnm || ''
      const coords = stationMap.value[stnm]
      if (!coords) return
      items.push(buildDataItem(row, dt, coords))
    })

    if (items.length) {
      renderLayerItems(items, dt)
    }
  } catch {
    dt.checked = false
    ElMessage.error(`${dt.label} 数据加载失败`)
  } finally {
    loading.value = false
  }
}

function parseFloatValue(val) {
  if (val === undefined || val === null || val === '') return '-'
  const n = Number(val)
  return isNaN(n) ? '-' : n
}

function removeLayer(dt) {
  if (dt.layer && map.value) {
    const existing = map.value.findLayerById(dt.layer.id)
    if (existing) map.value.remove(existing)
    dt.layer = null
  }
  delete typeDataMap[dt.key]
}

function refreshAll() {
  dataTypes.forEach(dt => {
    if (dt.checked) {
      removeLayer(dt)
      loadLayerData(dt)
    }
  })
}

function onSearch() {
  keyword.value = keyword.value.trim()
}

function onTableRowClick(row) {
  if (!view.value || !row.lng || !row.lat) return
  view.value.goTo({ center: [row.lng, row.lat], zoom: 12 })
  const fields = POPUP_FIELDS[row.typeKey] || []
  const content = buildPopupContent(row, fields)
  openPopup(view.value, row.stnm, content, [row.lng, row.lat])
}

function buildPopupContent(item, fields) {
  const paramsHtml = fields.map(f => {
    const val = item[f.key] ?? '-'
    return `<div style="display:flex;justify-content:space-between;padding:2px 0;border-bottom:1px solid #f5f5f5">
      <span style="color:#888;font-size:12px">${f.label}</span>
      <span style="font-weight:600;font-size:12px">${val} ${f.unit}</span>
    </div>`
  }).join('')

  const chartUrl = `/slgc/hydrology?stnm=${encodeURIComponent(item.stnm)}`

  return `<div style="min-width:220px">
    <div style="font-size:15px;font-weight:700;margin-bottom:8px;padding-bottom:6px;border-bottom:2px solid #409EFF">${item.stnm}</div>
    <div style="margin-bottom:4px">
      <span style="font-size:12px;color:#909399">监测时间: ${item.tm || '-'}</span>
    </div>
    <div>${paramsHtml}</div>
    <div style="margin-top:8px;padding-top:6px;border-top:1px solid #eee">
      <a href="javascript:void(0)" style="color:#409EFF;font-size:12px;text-decoration:none" onclick="window.open('${chartUrl}', '_blank')">查看历史图表 &gt;</a>
    </div>
  </div>`
}

function setupClickHandler() {
  if (!view.value) return
  view.value.on('click', (event) => {
    view.value.hitTest(event).then(response => {
      const result = response.results.find(r => r.graphic && r.graphic.attributes && r.graphic.attributes.stnm)
      if (!result) return
      const graphic = result.graphic
      const attrs = graphic.attributes
      const fields = POPUP_FIELDS[attrs.typeKey] || []
      const content = buildPopupContent(attrs, fields)
      openPopup(view.value, attrs.stnm, content, graphic.geometry)
    })
  })
}

onMounted(async () => {
  await initMap('viewDiv', [31.2, 120.5], 8)
  addBasinBoundary()
  await loadStationList()
  setupClickHandler()
})
</script>

<style scoped>
.gis-page {
  height: calc(100vh - 120px);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.top-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background: #fff;
  border-radius: 6px;
  border: 1px solid #e4e7ed;
  flex-shrink: 0;
}

.top-bar-left {
  display: flex;
  align-items: center;
  gap: 12px;
}

.top-bar-right {
  display: flex;
  align-items: center;
}

.layer-buttons {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.gis-layout {
  flex: 1;
  display: flex;
  gap: 6px;
  min-height: 0;
}

.left-panel {
  width: 200px;
  flex-shrink: 0;
}

.map-area {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.right-panel {
  width: 340px;
  flex-shrink: 0;
}

.card-header {
  font-weight: 600;
  font-size: 15px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.map-wrapper {
  flex: 1;
  position: relative;
  min-height: 300px;
}

.map-container {
  position: absolute;
  inset: 0;
}

.coord-bar {
  flex-shrink: 0;
  padding: 6px 12px;
  font-size: 12px;
  color: #909399;
  font-family: 'Courier New', monospace;
  border-top: 1px solid #f0f0f0;
}

.layer-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.layer-item {
  padding: 4px 0;
  border-bottom: 1px solid #f5f5f5;
}

.layer-item:last-child {
  border-bottom: none;
}

.layer-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: middle;
  border: 1px solid rgba(0,0,0,0.08);
}
</style>
