<template>
  <div class="repair-container">
    <!-- 上半部分：百度地图(左) + 图表(右) -->
    <div class="top-section">
      <el-card class="topo-card">
        <template #header>
          <div class="topo-header">
            <span class="card-title">燃气管网维修记录拓扑图</span>
            <div class="topo-legend">
              <span class="legend-item"><i class="legend-line high"></i> 高压</span>
              <span class="legend-item"><i class="legend-line medium"></i> 中压</span>
              <span class="legend-item"><i class="legend-line low"></i> 低压</span>
              <span class="legend-item"><i class="legend-dot repaired"></i> 有维修</span>
              <span class="legend-item"><i class="legend-dot point"></i> 管点</span>
            </div>
          </div>
        </template>
        <div class="map-wrapper">
          <div id="repairBaiduMap" class="baidu-map"></div>
          <div v-if="mapError" class="map-error">{{ mapError }}</div>
        </div>
      </el-card>

      <div class="charts-column">
        <el-card class="chart-card">
          <template #header><span class="card-title">维修统计</span></template>
          <div id="riskPieChart" style="height:260px"></div>
        </el-card>
        <el-card class="chart-card">
          <template #header><span class="card-title">维修趋势</span></template>
          <div id="repairTrendChart" style="height:260px"></div>
        </el-card>
      </div>
    </div>

    <!-- 下半部分：搜索 + 表格 -->
    <el-card class="table-card">
      <div class="table-toolbar">
        <div class="table-toolbar-left">
          <el-form :inline="true" :model="searchForm" class="search-form">
            <el-form-item label="管网ID">
              <el-select v-model="searchForm.networkId" placeholder="请选择" clearable style="width:190px" @change="onFilterChange">
                <el-option v-for="n in networkOptions" :key="n.networkId" :label="`${n.networkName}（${n.networkCode}）`" :value="n.networkId" />
              </el-select>
            </el-form-item>
            <el-form-item label="维修类型">
              <el-select v-model="searchForm.repairType" placeholder="请选择" clearable style="width:160px">
                <el-option v-for="d in repairTypeDict" :key="d.dictValue" :label="d.dictLabel" :value="d.dictValue" />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="handleSearch">查询</el-button>
              <el-button @click="handleReset">重置</el-button>
            </el-form-item>
          </el-form>
        </div>
        <div class="table-toolbar-right">
          <el-button type="success" @click="handleAdd">新增维修记录</el-button>
        </div>
      </div>

      <el-table :data="tableData" border stripe v-loading="loading" max-height="380" size="small">
        <el-table-column label="管网" width="130">
          <template #default="{ row }">{{ getNetworkName(row.networkId) }}</template>
        </el-table-column>
        <el-table-column prop="repairDate" label="维修日期" width="120" />
        <el-table-column prop="repairType" label="维修类型" width="120">
          <template #default="{ row }">{{ getDictLabel(repairTypeDict, row.repairType) }}</template>
        </el-table-column>
        <el-table-column prop="repairContent" label="维修内容" min-width="230" show-overflow-tooltip />
        <el-table-column prop="repairCompany" label="维修单位" min-width="160" show-overflow-tooltip />
        <el-table-column prop="repairCost" label="费用(元)" width="110" align="right" />
        <el-table-column prop="repairPerson" label="负责人" width="100" />
        <el-table-column label="图片" width="80">
          <template #default="{ row }">
            <template v-if="parseImageUrls(row.repairImages).length">
              <el-image
                :src="getImageUrl(parseImageUrls(row.repairImages)[0])"
                fit="cover"
                :preview-src-list="parseImageUrls(row.repairImages).map(getImageUrl)"
                preview-teleported
                class="table-image"
              />
            </template>
            <el-tag v-else type="info" size="small">无</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="创建时间" width="170" />
        <el-table-column label="操作" width="150" fixed="right">
          <template #default="{ row }">
            <el-button type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
            <el-button type="danger" size="small" @click="handleDelete(row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        v-model:current-page="pageNum" v-model:page-size="pageSize" :total="total"
        layout="total, prev, pager, next, sizes" :page-sizes="[10, 20, 50]"
        @size-change="() => { pageNum = 1; loadData() }" @current-change="() => loadData()"
        style="margin-top:16px;justify-content:flex-end"
      />
    </el-card>

    <!-- 详情对话框 -->
    <el-dialog :title="dialogTitle" v-model="dialogVisible" width="600px" destroy-on-close>
      <el-form :model="formData" ref="formRef" label-width="100px">
        <el-form-item label="管网ID" prop="networkId">
          <el-select v-model="formData.networkId" style="width:100%">
            <el-option v-for="n in networkOptions" :key="n.networkId" :label="`${n.networkName}（${n.networkCode}）`" :value="n.networkId" />
          </el-select>
        </el-form-item>
        <el-form-item label="维修日期" prop="repairDate">
          <el-date-picker v-model="formData.repairDate" type="date" value-format="YYYY-MM-DD" placeholder="选择日期" style="width:100%" />
        </el-form-item>
        <el-form-item label="维修类型" prop="repairType">
          <el-select v-model="formData.repairType" style="width:100%">
            <el-option v-for="d in repairTypeDict" :key="d.dictValue" :label="d.dictLabel" :value="d.dictValue" />
          </el-select>
        </el-form-item>
        <el-form-item label="维修内容"><el-input v-model="formData.repairContent" type="textarea" :rows="3" /></el-form-item>
        <el-form-item label="维修单位"><el-input v-model="formData.repairCompany" /></el-form-item>
        <el-form-item label="费用(元)"><el-input-number v-model="formData.repairCost" :precision="2" :step="100" style="width:100%" /></el-form-item>
        <el-form-item label="负责人"><el-input v-model="formData.repairPerson" /></el-form-item>
        <el-form-item label="备注"><el-input v-model="formData.remark" type="textarea" :rows="2" /></el-form-item>
        <el-form-item label="维修图片">
          <el-upload
            action="#"
            :auto-upload="false"
            :show-file-list="false"
            :http-request="() => {}"
            :on-change="handleImageChange"
            accept="image/jpeg,image/png,image/jpg"
            multiple
          >
            <el-button type="primary" plain>选择图片</el-button>
            <template #tip>
              <div class="el-upload__tip">支持 JPG/PNG 格式，单张不超过 5MB</div>
            </template>
          </el-upload>
          <div v-if="imageList.length" class="image-list">
            <div v-for="(img, index) in imageList" :key="index" class="image-item">
              <img :src="img" class="image-thumb" @click="previewImage(index)" />
              <el-icon class="image-remove" @click="removeImage(index)"><Close /></el-icon>
            </div>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit">确定</el-button>
      </template>
    </el-dialog>

    <!-- 图片预览 -->
    <el-image-viewer
      v-if="previewVisible"
      :url-list="previewList"
      :initial-index="previewIndex"
      hide-on-click-modal
      @close="previewVisible = false"
    />
  </div>
</template>

<script setup>
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
import * as echarts from 'echarts'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Close } from '@element-plus/icons-vue'
import request from '@/utils/request'
import { convertCoord } from '@/utils/coordTransform'
import { getPipeNetworkOptions, getRepairRecordPage, getRepairStats, addRepairRecord, updateRepairRecord, deleteRepairRecord } from '@/api/pipeNetwork/basic'

const baseApi = import.meta.env.VITE_APP_BASE_API

// ==================== 数据 ====================
const loading = ref(false)
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref(0)
const searchForm = reactive({ networkId: '', repairType: '' })
const dialogVisible = ref(false)
const dialogTitle = ref('新增')
const formRef = ref(null)
const formData = reactive({ repairId: '', networkId: '', repairDate: '', repairType: '', repairContent: '', repairCompany: '', repairCost: null, repairPerson: '', remark: '', repairImages: '' })

const repairTypeDict = ref([
  { dictValue: '1', dictLabel: '抢修' },
  { dictValue: '2', dictLabel: '计划维修' },
  { dictValue: '3', dictLabel: '防腐层修复' },
  { dictValue: '4', dictLabel: '管件更换' },
  { dictValue: '5', dictLabel: '焊缝修补' },
  { dictValue: '6', dictLabel: '阀门维修' }
])
function getDictLabel(dict, value) {
  const item = dict.find(d => d.dictValue === String(value))
  return item ? item.dictLabel : value
}

// ==================== 百度地图配置 ====================
const centerPoint = { lng: 110.386, lat: 28.445 }
const MAP_BOUNDS = { southWest: { lng: 110.355, lat: 28.428 }, northEast: { lng: 110.410, lat: 28.460 } }
const MAP_MIN_ZOOM = 13
const MAP_MAX_ZOOM = 19
const MAP_DEFAULT_ZOOM = 15

const mapError = ref('')
const networkOptions = ref([])
let mapInstance = null
let activeInfoWindow = null
let overlayClicked = false
let mapOverlays = []

// ==================== 管网数据 (沅陵县真实坐标) ====================
const pipelineData = [
  { id: 'net001', name: '燃气1', pressure: 'high',
    points: [{lng:110.404947,lat:28.433419},{lng:110.404836,lat:28.433429},{lng:110.403275,lat:28.433571},{lng:110.401084,lat:28.433876},{lng:110.399601,lat:28.433876},{lng:110.398112,lat:28.433979},{lng:110.396717,lat:28.434314},{lng:110.394299,lat:28.434538},{lng:110.394352,lat:28.434887},{lng:110.391969,lat:28.434985},{lng:110.384374,lat:28.435695},{lng:110.381418,lat:28.43559},{lng:110.377993,lat:28.436193},{lng:110.376062,lat:28.436385},{lng:110.374231,lat:28.43655},{lng:110.372584,lat:28.437107},{lng:110.371292,lat:28.4377},{lng:110.370581,lat:28.438198},{lng:110.369831,lat:28.438821}] },
  { id: 'net002', name: '燃气2', pressure: 'medium',
    points: [{lng:110.361433,lat:28.454979},{lng:110.362363,lat:28.453169},{lng:110.362851,lat:28.452213},{lng:110.364377,lat:28.452443},{lng:110.365138,lat:28.45246},{lng:110.366462,lat:28.452157},{lng:110.369549,lat:28.451441},{lng:110.37219,lat:28.450897},{lng:110.372753,lat:28.450901},{lng:110.373875,lat:28.451194},{lng:110.373913,lat:28.451107},{lng:110.374597,lat:28.451476}] },
]

// 管点数据 (管网节点位置)
const pipePointData = [
  { name: 'A点', lng: 110.362363, lat: 28.453169, pipelineId: 'net001' },
  { name: 'B点', lng: 110.364377, lat: 28.452443, pipelineId: 'net001' },
  { name: 'C点', lng: 110.372753, lat: 28.450901, pipelineId: 'net001' },
  { name: 'D点', lng: 110.401084, lat: 28.433876, pipelineId: 'net001' },
  { name: 'E点', lng: 110.391969, lat: 28.434985, pipelineId: 'net001' },
  { name: 'F点', lng: 110.376062, lat: 28.436385, pipelineId: 'net001' },
  { name: 'G点', lng: 110.370581, lat: 28.438198, pipelineId: 'net001' },
]

// ==================== 维修记录数据 ====================
const tableData = ref([])

// 图片相关
const imageList = ref([])        // 展示用预览列表（URL）
const imageUrls = ref([])         // 已上传的图片URL列表
const imageUploading = ref(false) // 上传中状态
const previewVisible = ref(false)
const previewList = ref([])
const previewIndex = ref(0)

/** 获取图片展示 URL（直接使用上传接口返回的完整 URL） */
function getImageUrl(url) {
  if (!url) return ''
  return url.trim()
}

/** 将存储的 repairImages 字符串转为有效 URL 数组 */
function parseImageUrls(repairImages) {
  if (!repairImages) return []
  return repairImages.split(',').map(s => s.trim()).filter(Boolean)
}

/** 图片选择后立即上传到 MinIO */
async function handleImageChange(file) {
  if (!file.raw) return
  const isImage = file.raw.type === 'image/jpeg' || file.raw.type === 'image/png' || file.raw.type === 'image/jpg'
  if (!isImage) { ElMessage.error('只能上传图片文件 (JPG/PNG)!'); return }
  if (file.raw.size / 1024 / 1024 >= 5) { ElMessage.error('图片大小不能超过 5MB!'); return }

  imageUploading.value = true
  try {
    const uploadFormData = new FormData()
    uploadFormData.append('file', file.raw)
    uploadFormData.append('dir', 'upload') // 指定存储目录（可选）
    const uploadResponse = await request({
      url: '/minio/upload',
      method: 'post',
      data: uploadFormData
    })
    const url = uploadResponse.url || uploadResponse.fileName
    imageUrls.value.push(url)
    imageList.value.push(getImageUrl(url))
  } catch (e) {
    ElMessage.error('图片上传失败')
  } finally {
    imageUploading.value = false
  }
}

/** 删除图片 */
function removeImage(index) {
  imageUrls.value.splice(index, 1)
  imageList.value.splice(index, 1)
}

/** 预览大图 */
function previewImage(index) {
  previewList.value = [...imageList.value]
  previewIndex.value = index
  previewVisible.value = true
}

const pressureColors = { high: '#e63946', medium: '#f77f00', low: '#2a9d8f' }
const repairedNetworkIds = computed(() => { const s = new Set(); tableData.value.forEach(r => s.add(r.networkId)); return s })

async function loadNetworkOptions() {
  if (networkOptions.value.length > 0) return
  try { const res = await getPipeNetworkOptions(); networkOptions.value = res.data || [] } catch (e) { console.error(e) }
}
function getNetworkName(id) {
  const found = networkOptions.value.find(n => n.networkId === id)
  return found ? found.networkName : id
}
function getPipelineName(id) {
  const name = getNetworkName(id)
  return name !== id ? name : (pipelineData.find(p => p.id === id) || {}).name || id
}

// ==================== 数据加载 ====================
async function loadData() {
  loading.value = true
  try {
    const res = await getRepairRecordPage(pageNum.value, pageSize.value, searchForm)
    tableData.value = (res.data && res.data.records) ? res.data.records : []
    total.value = (res.data && res.data.total) ? res.data.total : 0
  } catch (e) { console.error(e) } finally { loading.value = false }
}

// ==================== 百度地图 ====================
function waitForBMapGL() {
  if (typeof BMapGL !== 'undefined') { initMap(); return }
  let attempts = 0
  const timer = setInterval(() => {
    attempts++
    if (typeof BMapGL !== 'undefined') { clearInterval(timer); initMap(); return }
    if (attempts >= 50) { clearInterval(timer); mapError.value = '百度地图脚本加载超时，请刷新页面重试。' }
  }, 200)
}

function closeInfoWindow() {
  if (activeInfoWindow) { try { activeInfoWindow.close(); mapInstance.removeOverlay(activeInfoWindow) } catch (_) {}; activeInfoWindow = null }
}

function getMidPoint(points) {
  let lng = 0, lat = 0
  points.forEach(p => { lng += p.lng; lat += p.lat })
  return { lng: lng / points.length, lat: lat / points.length }
}

function initMap() {
  const el = document.getElementById('repairBaiduMap')
  if (!el) { mapError.value = '地图容器未找到。'; return }

  try { mapInstance = new BMapGL.Map('repairBaiduMap', { enableMapClick: true }) } catch (e) {
    console.error('创建地图实例失败：', e); mapError.value = '百度地图初始化失败，请检查AK和网络连接。'; return
  }

  const [clng, clat] = convertCoord(centerPoint.lng, centerPoint.lat); try { mapInstance.centerAndZoom(new BMapGL.Point(clng, clat), MAP_DEFAULT_ZOOM); mapInstance.enableScrollWheelZoom(true) } catch (e) { console.error('设置中心失败：', e) }

  try { if (typeof mapInstance.setMinZoom === 'function') mapInstance.setMinZoom(MAP_MIN_ZOOM); if (typeof mapInstance.setMaxZoom === 'function') mapInstance.setMaxZoom(MAP_MAX_ZOOM) } catch (e) {}

  try {
    if (typeof mapInstance.setMaxBounds === 'function') {
      const sw = new BMapGL.Point(MAP_BOUNDS.southWest.lng, MAP_BOUNDS.southWest.lat)
      const ne = new BMapGL.Point(MAP_BOUNDS.northEast.lng, MAP_BOUNDS.northEast.lat)
      mapInstance.setMaxBounds(new BMapGL.Bounds(sw, ne))
    }
  } catch (e) {}

  mapInstance.addEventListener('click', () => {
    if (overlayClicked) { overlayClicked = false; return }
    closeInfoWindow()
  })

  try { renderMapScene() } catch (e) { console.error('渲染地图失败：', e); mapError.value = '地图要素渲染失败。' }
}

function renderMapScene() {
  if (!mapInstance || typeof BMapGL === 'undefined') return
  closeInfoWindow()
  try { mapInstance.clearOverlays() } catch (_) {}
  mapOverlays = []

  // 绘制管线
  pipelineData.forEach(pipe => {
    try {
      const hasRepair = repairedNetworkIds.value.has(pipe.id)
      const pts = pipe.points.map(p => { const [lng, lat] = convertCoord(p.lng, p.lat); return new BMapGL.Point(lng, lat) })
      const polyline = new BMapGL.Polyline(pts, {
        strokeColor: hasRepair ? '#f59e0b' : pressureColors[pipe.pressure],
        strokeWeight: hasRepair ? 5 : 3.5,
        strokeOpacity: 0.9
      })
      mapInstance.addOverlay(polyline)
      mapOverlays.push({ overlay: polyline, pipe })

      polyline.addEventListener('click', (e) => {
        overlayClicked = true
        if (e && e.domEvent) e.domEvent.stopPropagation()
        closeInfoWindow()
        const rawMid = getMidPoint(pipe.points)
        const mid = { lng: convertCoord(rawMid.lng, rawMid.lat)[0], lat: convertCoord(rawMid.lng, rawMid.lat)[1] }
        const count = tableData.value.filter(r => r.networkId === pipe.id).length
        const repairList = tableData.value.filter(r => r.networkId === pipe.id).slice(0, 3).map(r => `${r.repairDate} ${getDictLabel(repairTypeDict, r.repairType)}`).join('<br>')
        const html = `<div style="font-size:13px;max-width:300px;"><b>${pipe.name}</b>（${getNetworkName(pipe.id)}）<br>
          <span style="color:${pressureColors[pipe.pressure]};font-weight:bold;">${pipe.pressure === 'high' ? '高压' : pipe.pressure === 'medium' ? '中压' : '低压'}</span>
          &nbsp;累计维修 <b style="color:#e63946;">${count}</b> 次
          ${count > 0 ? '<br><span style="color:#909399;font-size:11px;">' + repairList + '</span>' : ''}</div>`
        activeInfoWindow = new BMapGL.InfoWindow(html, { width: 260 })
        mapInstance.openInfoWindow(activeInfoWindow, new BMapGL.Point(mid.lng, mid.lat))
        // 筛选表格
        searchForm.networkId = pipe.id
        pageNum.value = 1
      })
    } catch (_) {}
  })

  // 绘制管点
  pipePointData.forEach(point => {
    try {
      const hasRepair = repairedNetworkIds.value.has(point.pipelineId)
      const [plng, plat] = convertCoord(point.lng, point.lat); const pt = new BMapGL.Point(plng, plat)
      const color = hasRepair ? '#f59e0b' : '#3b82f6'
      const size = hasRepair ? 10 : 7
      const label = new BMapGL.Label(point.name, {
        position: pt,
        offset: new BMapGL.Size(-22, -22)
      })
      label.setStyle({
        color: '#fff', fontSize: '10px', padding: '2px 6px',
        backgroundColor: color, borderRadius: '3px', whiteSpace: 'nowrap',
        border: hasRepair ? '2px solid #fff' : 'none', boxShadow: hasRepair ? '0 0 6px rgba(245,158,11,0.6)' : 'none'
      })
      mapInstance.addOverlay(label)
      mapOverlays.push({ overlay: label, point })

      label.addEventListener('click', (e) => {
        overlayClicked = true
        if (e && e.domEvent) e.domEvent.stopPropagation()
        closeInfoWindow()
        const pipeName = getPipelineName(point.pipelineId)
        const count = tableData.value.filter(r => r.networkId === point.pipelineId).length
        const html = `<div style="font-size:13px;"><b>${point.name}</b><br>所属管线: ${point.pipelineId} ${pipeName}<br>维修记录: <b style="color:#e63946;">${count}</b> 次</div>`
        activeInfoWindow = new BMapGL.InfoWindow(html, { width: 240 })
        mapInstance.openInfoWindow(activeInfoWindow, pt)
        searchForm.networkId = point.pipelineId
        pageNum.value = 1
      })
    } catch (_) {}
  })

  // 维修标记点 (有维修记录的管线中点位置)
  pipelineData.forEach(pipe => {
    if (!repairedNetworkIds.value.has(pipe.id)) return
    try {
      const rawMid2 = getMidPoint(pipe.points)
      const mid2 = { lng: convertCoord(rawMid2.lng, rawMid2.lat)[0], lat: convertCoord(rawMid2.lng, rawMid2.lat)[1] }
      const pt = new BMapGL.Point(mid2.lng, mid2.lat)
      const count = tableData.value.filter(r => r.networkId === pipe.id).length
      const marker = new BMapGL.Label(String(count), {
        position: pt,
        offset: new BMapGL.Size(-12, -12)
      })
      marker.setStyle({
        color: '#fff', fontSize: '11px', fontWeight: 'bold',
        backgroundColor: '#e63946', borderRadius: '12px',
        padding: '2px 7px', border: '2px solid #fff',
        boxShadow: '0 0 8px rgba(230,57,70,0.5)'
      })
      mapInstance.addOverlay(marker)
      mapOverlays.push({ overlay: marker, pipe })
    } catch (_) {}
  })
}

// ==================== ECharts ====================
let riskPieChart = null
let repairTrendChart = null

function initRiskPie(data) {
  const dom = document.getElementById('riskPieChart')
  if (!dom) return
  if (riskPieChart) riskPieChart.dispose()
  riskPieChart = echarts.init(dom)
  riskPieChart.setOption({
    tooltip: { trigger: 'item', formatter: '{b}: {c} 次 ({d}%)' },
    legend: { orient: 'vertical', right: 6, top: 'center', itemWidth: 10, itemHeight: 10, textStyle: { color: '#606a78', fontSize: 11 }, itemGap: 14 },
    series: [{
      type: 'pie', radius: ['50%', '76%'], center: ['38%', '50%'],
      avoidLabelOverlap: false, itemStyle: { borderRadius: 6, borderColor: '#fff', borderWidth: 3 },
      label: { show: false }, emphasis: { scale: true, scaleSize: 6 },
      data: (data || []).map(d => ({ value: d.value, name: d.name, itemStyle: { color: d.color } }))
    }]
  })
}

function initRepairTrend(data) {
  const dom = document.getElementById('repairTrendChart')
  if (!dom) return
  if (repairTrendChart) repairTrendChart.dispose()
  repairTrendChart = echarts.init(dom)
  const t = data || {}
  const months = t.months || ['1月','2月','3月','4月','5月','6月']
  repairTrendChart.setOption({
    tooltip: { trigger: 'axis' },
    legend: { top: 0, textStyle: { color: '#606a78', fontSize: 11 } },
    grid: { left: 44, right: 20, top: 36, bottom: 32 },
    xAxis: { type: 'category', data: months, boundaryGap: false, axisLabel: { color: '#9098a6', fontSize: 11 }, axisLine: { lineStyle: { color: '#d0d5dd' } } },
    yAxis: { type: 'value', name: '次数', minInterval: 1, axisLabel: { color: '#9098a6', fontSize: 11 }, splitLine: { lineStyle: { color: '#f0f2f6', type: 'dashed' } } },
    series: [
      { name: '高压', type: 'line', data: t.high || [], smooth: true, symbol: 'circle', symbolSize: 7, lineStyle: { width: 3, color: '#e63946' }, itemStyle: { color: '#e63946', borderColor: '#fff', borderWidth: 2 }, areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(230,57,70,0.12)' }, { offset: 1, color: 'rgba(230,57,70,0)' }]) } },
      { name: '中压', type: 'line', data: t.medium || [], smooth: true, symbol: 'circle', symbolSize: 7, lineStyle: { width: 3, color: '#f77f00' }, itemStyle: { color: '#f77f00', borderColor: '#fff', borderWidth: 2 }, areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(247,127,0,0.12)' }, { offset: 1, color: 'rgba(247,127,0,0)' }]) } },
      { name: '低压', type: 'line', data: t.low || [], smooth: true, symbol: 'circle', symbolSize: 7, lineStyle: { width: 3, color: '#2a9d8f' }, itemStyle: { color: '#2a9d8f', borderColor: '#fff', borderWidth: 2 }, areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(42,157,143,0.12)' }, { offset: 1, color: 'rgba(42,157,143,0)' }]) } }
    ]
  })
}

async function loadStats() {
  try {
    const res = await getRepairStats()
    const d = res.data || {}
    initRiskPie(d.typeStats)
    initRepairTrend(d.trend)
  } catch (e) { console.error(e) }
}

function resizeCharts() { riskPieChart?.resize(); repairTrendChart?.resize() }

// ==================== 操作 ====================
function onFilterChange() { pageNum.value = 1; loadData() }
function handleSearch() { pageNum.value = 1; loadData() }
function handleReset() {
  searchForm.networkId = ''; searchForm.repairType = ''; pageNum.value = 1
  loadData()
}
function handleAdd() {
  dialogTitle.value = '新增'; dialogVisible.value = true
  Object.assign(formData, { repairId: '', networkId: '', repairDate: '', repairType: '', repairContent: '', repairCompany: '', repairCost: null, repairPerson: '', remark: '', repairImages: '' })
  imageList.value = []
  imageUrls.value = []
  loadNetworkOptions()
}
function handleEdit(row) {
  dialogTitle.value = '编辑'; dialogVisible.value = true
  Object.assign(formData, { ...row })
  // 回显已有图片
  const urls = parseImageUrls(row.repairImages)
  imageUrls.value = [...urls]
  imageList.value = urls.map(url => getImageUrl(url))
  loadNetworkOptions()
}
async function handleSubmit() {
  try {
    if (imageUploading.value) { ElMessage.warning('图片正在上传，请稍候'); return }
    // 将图片URL列表拼接为逗号分隔字符串
    formData.repairImages = imageUrls.value.join(',')
    if (formData.repairId) { await updateRepairRecord(formData); ElMessage.success('修改成功') }
    else { await addRepairRecord(formData); ElMessage.success('新增成功') }
    dialogVisible.value = false; loadData(); nextTick(() => renderMapScene())
  } catch (e) { const msg = e?.response?.data?.msg || e?.message || '操作失败'; ElMessage.error(msg) }
}
function handleDelete(row) {
  ElMessageBox.confirm('确认删除该维修记录？', '提示', { type: 'warning' }).then(async () => {
    try { await deleteRepairRecord(row.repairId); ElMessage.success('删除成功'); loadData(); nextTick(() => renderMapScene()) } catch (e) { ElMessage.error('删除失败') }
  }).catch(() => {})
}

// ==================== 生命周期 ====================
let resizeTimer = null
onMounted(async () => {
  await nextTick()
  await loadNetworkOptions()
  await loadData()
  waitForBMapGL()
  loadStats()
  window.addEventListener('resize', () => {
    clearTimeout(resizeTimer)
    resizeTimer = setTimeout(() => {
      resizeCharts()
      if (mapInstance) {
        try { mapInstance.resize() } catch (_) {}
        try { mapInstance.setViewport([new BMapGL.Point(centerPoint.lng, centerPoint.lat)], { zoom: mapInstance.getZoom() }) } catch (_) {}
      }
    }, 200)
  })
})
onBeforeUnmount(() => {
  window.removeEventListener('resize', resizeCharts)
  riskPieChart?.dispose(); repairTrendChart?.dispose()
  if (mapInstance) { try { mapInstance.clearOverlays() } catch (_) {}; mapInstance = null }
})
</script>

<style scoped>
.repair-container { padding: 16px; display: flex; flex-direction: column; gap: 16px; background: #f0f2f6; min-height: calc(100vh - 84px); }

/* 多图上传样式 */
.table-image {
  width: 40px;
  height: 40px;
  border-radius: 4px;
  cursor: pointer;
}
.image-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}
.image-item {
  position: relative;
  width: 80px;
  height: 80px;
  border-radius: 4px;
  overflow: visible;
}
.image-thumb {
  width: 80px;
  height: 80px;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid #dcdfe6;
  cursor: pointer;
}
.image-thumb:hover {
  border-color: #409eff;
}
.image-remove {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 18px;
  height: 18px;
  background: #f56c6c;
  color: #fff;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  z-index: 1;
}
.image-remove:hover {
  background: #e64a4a;
}

/* ========== 上半部分 ========== */
.top-section { display: flex; gap: 16px; align-items: stretch; }
.topo-card { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.charts-column { width: 340px; flex-shrink: 0; display: flex; flex-direction: column; gap: 16px; }
.chart-card { flex: 1; }
.card-title { font-size: 15px; font-weight: 700; color: #1f2d3d; }

.topo-header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; }
.topo-legend { display: flex; gap: 14px; flex-wrap: wrap; }
.legend-item { font-size: 11px; color: #606a78; display: flex; align-items: center; gap: 5px; }
.legend-line { display: inline-block; width: 24px; height: 3px; border-radius: 2px; }
.legend-line.high { background: #e63946; }
.legend-line.medium { background: #f77f00; }
.legend-line.low { background: #2a9d8f; }
.legend-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; }
.legend-dot.repaired { background: #f59e0b; border: 2px solid #fff; box-shadow: 0 0 4px rgba(245,158,11,0.5); }
.legend-dot.point { background: #3b82f6; border: 2px solid #fff; }

.map-wrapper { position: relative; width: 100%; height: 100%; min-height: 460px; border-radius: 6px; overflow: hidden; }
.baidu-map { width: 100%; height: 100%; min-height: 460px; }
.map-error { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: #fafbfc; color: #e63946; font-size: 14px; font-weight: 600; }
.topo-card { display: flex; flex-direction: column; }
:deep(.topo-card .el-card__body) { flex: 1; display: flex; padding: 0; overflow: hidden; }

/* ========== 表格 ========== */
.table-toolbar { display: flex; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.search-form { margin-bottom: 0; }
:deep(.search-form .el-form-item) { margin-bottom: 0; }

:deep(.el-card__header) { padding: 12px 18px; border-bottom: 1px solid #f0f2f6; flex-shrink: 0; }
:deep(.topo-card .el-card__body) { flex: 1; display: flex; padding: 0; overflow: hidden; }
:deep(.chart-card .el-card__body) { padding: 12px; }
:deep(.table-card .el-card__body) { padding: 12px; }

@media (max-width: 1400px) {
  .top-section { flex-direction: column; }
  .map-wrapper { height: 400px; }
  .charts-column { width: 100%; flex-direction: row; }
  .charts-column .chart-card { flex: 1; min-width: 300px; }
}
</style>
