<!--预警管理页面（RuoYi Element Plus 标准）-->
<!--数据源：early_warning 体系 /warning/*接口 -->
<!--确认异常后只建工单不派单，由工单系统处理后续流程-->

<template>
  <div class="warning-container">
    <!-- ========= 统计卡片区域 ========== -->
    <el-row :gutter="16" class="stat-row">
      <el-col :span="4">
        <div class="stat-item stat-primary">
          <div class="stat-icon"><el-icon><Warning /></el-icon></div>
          <div class="stat-content"><div class="stat-title">总预警</div><div class="stat-value">{{ stats.total }}</div></div>
          <div class="stat-caption">累计预警总量</div>
        </div>
      </el-col>
      <el-col :span="4">
        <div class="stat-item stat-warning">
          <div class="stat-icon"><el-icon><Bell /></el-icon></div>
          <div class="stat-content"><div class="stat-title">待确认</div><div class="stat-value">{{ stats.unconfirmed }}</div></div>
          <div class="stat-caption">待核实异常</div>
        </div>
      </el-col>
      <el-col :span="4">
        <div class="stat-item stat-processing">
          <div class="stat-icon"><el-icon><Tools /></el-icon></div>
          <div class="stat-content"><div class="stat-title">处理中</div><div class="stat-value">{{ stats.processing }}</div></div>
          <div class="stat-caption">正在处置</div>
        </div>
      </el-col>
      <el-col :span="4">
        <div class="stat-item stat-handled">
          <div class="stat-icon"><el-icon><CircleCheck /></el-icon></div>
          <div class="stat-content"><div class="stat-title">已处置</div><div class="stat-value">{{ stats.handled }}</div></div>
          <div class="stat-caption">等待复核清除</div>
        </div>
      </el-col>
      <el-col :span="4">
        <div class="stat-item stat-closed">
          <div class="stat-icon"><el-icon><CircleClose /></el-icon></div>
          <div class="stat-content"><div class="stat-title">已解除</div><div class="stat-value">{{ stats.closed }}</div></div>
          <div class="stat-caption">已完成闭环</div>
        </div>
      </el-col>
      <el-col :span="4">
        <div class="stat-item stat-today">
          <div class="stat-icon"><el-icon><TrendCharts /></el-icon></div>
          <div class="stat-content"><div class="stat-title">今日新增</div><div class="stat-value">{{ stats.today }}</div></div>
          <div class="stat-caption">今日新增预警</div>
        </div>
      </el-col>
    </el-row>

    <!-- ========== 图表区域 ========== -->
    <el-row :gutter="16" class="chart-row">
      <el-col :span="12"><el-card><template #header><span>近 7 天趋势</span></template><div id="trendChart" style="height:240px"/></el-card></el-col>
      <el-col :span="6"><el-card><template #header><span>级别分布</span></template><div id="levelChart" style="height:240px"/></el-card></el-col>
      <el-col :span="6"><el-card><template #header><span>级别占比</span></template><div id="typeChart" style="height:240px"/></el-card></el-col>
    </el-row>

    <!-- ========= 查询表单 ========== -->
    <el-card class="search-card">
      <el-form :inline="true" :model="queryParams">
        <el-form-item label="预警名称">
          <el-input v-model="queryParams.warningName" placeholder="请输入预警名称" clearable style="width:200px"/>
        </el-form-item>
        <el-form-item label="设备编码">
          <el-input v-model="queryParams.deviceCode" placeholder="请输入设备编码" clearable style="width:180px"/>
        </el-form-item>
        <el-form-item label="设备名称">
          <el-input v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable style="width:180px"/>
        </el-form-item>
        <el-form-item label="状态">
          <el-select v-model="queryParams.status" placeholder="全部状态" clearable style="width:150px">
            <el-option label="待确认" value="RELEASED"/>
            <el-option label="待办" value="PENDING"/>
            <el-option label="处理中" value="PROCESSING"/>
            <el-option label="已处置" value="HANDLED"/>
            <el-option label="已解除" value="CLOSED"/>
            <el-option label="草稿" value="DRAFT"/>
          </el-select>
        </el-form-item>
        <el-form-item label="级别">
          <el-select v-model="queryParams.warningLevel" placeholder="全部级别" clearable style="width:120px">
            <el-option label="1 级 (蓝)" value="1"/>
            <el-option label="2 级 (黄)" value="2"/>
            <el-option label="3 级 (橙)" value="3"/>
            <el-option label="4 级 (红)" value="4"/>
          </el-select>
        </el-form-item>
        <el-form-item label="类别">
          <el-select v-model="queryParams.category" placeholder="全部类别" clearable style="width:120px">
            <el-option label="普通预警" value="normal"/>
            <el-option label="特殊预警" value="special"/>
          </el-select>
        </el-form-item>
        <el-form-item label="日期范围">
          <el-date-picker v-model="queryParams.startDate" type="date" placeholder="开始日期" clearable value-format="YYYY-MM-DD" style="width:160px"/>
          <span style="margin:0 8px;color:#909399;">至</span>
          <el-date-picker v-model="queryParams.endDate" type="date" placeholder="结束日期" clearable value-format="YYYY-MM-DD" style="width:160px"/>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch"><el-icon><Search/></el-icon> 查询</el-button>
          <el-button @click="handleReset"><el-icon><Refresh/></el-icon> 重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <!-- ========== 预警列表 ========== -->
    <el-card class="table-card">
      <el-table :data="tableData" border stripe v-loading="loading" max-height="600">
        <el-table-column prop="warningNo" label="预警编号" width="140" />
        <el-table-column prop="warningName" label="预警名称" min-width="160" show-overflow-tooltip />
        <el-table-column label="关联设备" width="220">
          <template #default="{ row }">
            <div v-if="row.deviceCode || row.deviceName" class="device-cell">
              <span v-if="row.deviceName" class="device-name">{{ row.deviceName }}</span>
              <el-tag v-if="row.deviceCode" :type="row.warningLevel === '4' ? 'danger' : 'info'" size="small" effect="plain">{{ row.deviceCode }}</el-tag>
            </div>
            <span v-else class="no-device">未关联</span>
          </template>
        </el-table-column>
        <el-table-column prop="location" label="设备位置" min-width="140" show-overflow-tooltip />
        <el-table-column label="类别" width="100">
          <template #default="{ row }">
            <el-tag :type="row.category === 'normal' ? '' : 'warning'" size="small">
              {{ row.category === 'normal' ? '普通预警' : '特殊预警' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="级别" width="100">
          <template #default="{ row }">
            <el-tag :type="getLevelType(row.warningLevel)" size="small">{{ getLevelText(row.warningLevel) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="100">
          <template #default="{ row }">
            <el-tag :type="getStatusType(row.status)" size="small">{{ getStatusText(row.status) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="publishTime" label="发布时间" width="170" sortable class-name="publish-time-column" :formatter="formatPublishTime" />
        <el-table-column label="操作" width="180" fixed="right">
          <template #default="{ row }">
            <el-button v-if="isUnconfirmed(row.status)" type="primary" size="small" @click="openConfirm(row)">确认异常</el-button>
            <el-button v-if="isUnconfirmed(row.status)" type="info" size="small" @click="confirmMisreport(row)">误报</el-button>
            <el-button v-if="row.status === 'PROCESSING'" type="warning" size="small" @click="openProcess(row)">提交处理</el-button>
            <el-button v-if="row.status === 'HANDLED'" type="success" size="small" @click="clearHandled(row)">清除预警</el-button>
            <el-button type="info" size="small" @click="openDetail(row.warningId)">详情</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,30]"
                     @change="loadList" style="margin-top:16px;justify-content:flex-end" />
    </el-card>

    <!-- ========== 确认异常弹窗 ========== -->
    <el-dialog v-model="confirmVisible" title="⚠️ 确认预警异常" width="600px" append-to-body destroy-on-close>
      <el-descriptions :column="1" border>
        <el-descriptions-item label="预警编号">{{ current.warningNo }}</el-descriptions-item>
        <el-descriptions-item label="预警名称">{{ current.warningName }}</el-descriptions-item>
        <el-descriptions-item label="预警内容">{{ current.warningContent || '-' }}</el-descriptions-item>
        <el-descriptions-item label="关联设备">{{ formatWarningDevice(current) }}</el-descriptions-item>
        <el-descriptions-item label="设备位置">{{ current.location || '-' }}</el-descriptions-item>
      </el-descriptions>
      <el-form label-width="100px" style="margin-top:16px">
        <el-form-item label="备注信息">
          <el-input v-model="confirmingRemark" type="textarea" :rows="3" placeholder="填写异常情况描述（将写入工单描述）" maxlength="300" show-word-limit/>
        </el-form-item>
        <el-form-item label="处理人员">
          <el-input v-model="assignedUser" placeholder="可填写处理人账号，不填则使用预警原处理人或当前用户" clearable />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="confirmVisible=false">取消</el-button>
        <el-button type="primary" :loading="submitting" @click="submitConfirm">确认提交</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="processVisible" title="提交预警处理反馈" width="620px" append-to-body destroy-on-close>
      <el-descriptions :column="1" border>
        <el-descriptions-item label="预警编号">{{ processRow.warningNo }}</el-descriptions-item>
        <el-descriptions-item label="预警名称">{{ processRow.warningName }}</el-descriptions-item>
        <el-descriptions-item label="关联设备">{{ formatWarningDevice(processRow) }}</el-descriptions-item>
      </el-descriptions>
      <el-form label-width="100px" style="margin-top:16px">
        <el-form-item label="处理反馈" required>
          <el-input v-model="processContent" type="textarea" :rows="5" maxlength="1000" show-word-limit placeholder="请填写处理过程和处理结果" />
        </el-form-item>
        <el-form-item label="处理附件">
          <el-upload v-model:file-list="processFileList" action="#" list-type="text" :auto-upload="false" :limit="9" accept=".jpg,.jpeg,.png,.gif,.webp,.pdf,.xls,.xlsx,.doc,.docx" :on-change="handleProcessFileChange" :on-remove="handleProcessFileRemove" :on-exceed="handleProcessFileExceed">
            <el-icon><Plus /></el-icon>
          </el-upload>
          <div class="upload-tip">支持图片、PDF、Excel、Word，最多 9 个文件，单个不超过 20MB</div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="processVisible=false">取消</el-button>
        <el-button type="primary" :loading="submitting" @click="submitProcess">提交反馈</el-button>
      </template>
    </el-dialog>

    <!-- ========== 详情页抽屉 ========== -->
    <el-drawer v-model="detailVisible" title="📋 预警处理详情" size="560px">
      <template v-if="detail">
        <el-descriptions :column="1" border size="small">
          <el-descriptions-item label="预警编号">{{ detail.basicInfo.warning_no }}</el-descriptions-item>
          <el-descriptions-item label="预警名称">{{ detail.basicInfo.warning_name }}</el-descriptions-item>
          <el-descriptions-item label="预警类型">{{ detail.basicInfo.warning_type || '-' }}</el-descriptions-item>
          <el-descriptions-item label="预警级别">{{ getLevelText(detail.basicInfo.warning_level) }}</el-descriptions-item>
          <el-descriptions-item label="发布人">{{ detail.basicInfo.publisher || '-' }}</el-descriptions-item>
          <el-descriptions-item label="发布时间">{{ formatWarningTime(detail.basicInfo.publish_time) }}</el-descriptions-item>
          <el-descriptions-item label="状态">{{ getStatusText(detail.basicInfo.status) }}</el-descriptions-item>
          <el-descriptions-item label="预警内容">{{ detail.basicInfo.warning_content }}</el-descriptions-item>
        </el-descriptions>

        <div class="detail-section-title">🔗 关联设备</div>
        <el-descriptions :column="1" border size="small">
          <el-descriptions-item label="设备名称">{{ detail.basicInfo.device_name || detail.basicInfo.deviceName || '-' }}</el-descriptions-item>
          <el-descriptions-item label="设备编码">{{ detail.basicInfo.device_code || detail.basicInfo.deviceCode || extractDeviceCodeStr(detail.basicInfo) || '（手工录入，无设备关联）' }}</el-descriptions-item>
          <el-descriptions-item label="设备位置">{{ detail.basicInfo.location || '-' }}</el-descriptions-item>
          <el-descriptions-item label="权属单位">{{ detail.basicInfo.ownership_unit || '-' }}</el-descriptions-item>
        </el-descriptions>

        <div class="detail-section-title">🕐 处置历史</div>
        <el-timeline v-if="detail.disposalHistory?.length" style="padding:0 0 20px">
          <el-timeline-item v-for="(item,idx) in detail.disposalHistory" :key="idx" :timestamp="item.create_time" :type="disposalTimelineType(item.disposal_type)">
            <b>{{ disposalTypeText(item.disposal_type) }}</b>
            <div>{{ item.disposal_content || '-' }}</div>
            <div class="detail-sub">处置人：{{ item.disposal_user || '-' }}</div>
          </el-timeline-item>
        </el-timeline>
        <div v-else class="detail-empty">暂无处置记录</div>

        <div class="detail-section-title">📎 附件</div>
        <div v-if="detail.attachmentList?.length" class="attachment-list">
          <div v-for="stage in ['REPORT','PROCESS']" :key="stage" class="attachment-group">
            <div class="attachment-stage">{{ stage === 'PROCESS' ? '处理反馈附件' : '预警报告附件' }}</div>
            <div v-if="attachmentsByStage(stage).length" class="attachment-grid">
              <div v-for="(att,idx) in attachmentsByStage(stage)" :key="att.attachmentId || idx" class="attachment-item">
                <el-image v-if="isImageAttachment(att) && attachmentPreviewUrl(att)" class="attachment-image" :src="attachmentPreviewUrl(att)" :preview-src-list="[attachmentPreviewUrl(att)]" fit="cover" preview-teleported>
                  <template #error><div class="attachment-image-error">图片加载失败</div></template>
                </el-image>
                <div v-else-if="isImageAttachment(att)" class="attachment-image attachment-image-loading">加载中...</div>
                <div v-else class="attachment-file-icon"><el-icon><Document /></el-icon></div>
                <div class="attachment-name" :title="displayAttachmentName(att)">{{ displayAttachmentName(att) }}</div>
                <div class="attachment-actions">
                  <el-button v-if="canPreviewAttachment(att)" link type="primary" size="small" @click="previewAttachment(att)"><el-icon><View /></el-icon>预览</el-button>
                  <el-button link type="primary" size="small" @click="downloadAttachment(att)"><el-icon><Download /></el-icon>下载</el-button>
                </div>
              </div>
            </div>
            <div v-else class="detail-empty">暂无附件</div>
          </div>
        </div>
        <div v-else class="detail-empty">暂无附件</div>

        <div class="detail-section-title">预警督办</div>
        <div v-if="detail.supervisionList?.length" class="supervision-list">
          <div v-for="(item,idx) in detail.supervisionList" :key="idx" class="supervision-item">
            <b>{{ item.supervisionUser || '-' }}</b>
            <span>{{ formatWarningTime(item.createTime) }}</span>
            <p>{{ item.supervisionContent || '-' }}</p>
          </div>
        </div>
        <div v-else class="detail-empty">暂无督办记录</div>

        <div class="detail-section-title">📦 电子归档</div>
        <el-descriptions v-if="detail.electronicArchive" :column="2" border size="small">
          <el-descriptions-item label="归档编号">{{ detail.electronicArchive.archiveNo }}</el-descriptions-item>
          <el-descriptions-item label="归档时间">{{ detail.electronicArchive.createTime }}</el-descriptions-item>
        </el-descriptions>
        <div v-else class="detail-empty">暂无归档（解除预警后自动生成）</div>
      </template>
    </el-drawer>
  </div>
</template>

<script setup>
import { ref, computed, nextTick, onMounted, onBeforeUnmount } from 'vue'
import * as echarts from 'echarts'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Search, Refresh, Plus, Document, Download, View, Warning, Bell, Tools, CircleCheck, CircleClose, TrendCharts } from '@element-plus/icons-vue'
import { getWarningDashboardStatisticsData, getWarningSearchData, getWarningFullDetailData, confirmWarningData, misreportWarningData, submitWarningProcessData, clearWarningData, getWarningAttachmentPreviewData, getWarningAttachmentDownloadData } from '@/api/pipeNetwork/earlyWarning'
import { addManholeWorkOrder } from '@/api/pipeNetwork/basic'

// ========== 统计数据 ==========
const stats = ref({ total:0, unconfirmed:0, processing:0, handled:0, closed:0, today:0 })

// ========== 图表数据 ==========
const chartData = ref({ trend:[], levels:[], types:[] })

// ========== 查询参数 & 列表 ==========
const queryParams = ref({ warningName:'', deviceCode:'', deviceName:'', status:'', warningLevel:'', category:'', startDate:'', endDate:'' })
const tableData = ref([])
const loading = ref(false)
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref(0)

async function loadStats() {
  try {
    const res = await getWarningDashboardStatisticsData()
    if (!res.data) return
    const b = res.data.basicStats
    const t = res.data.trendStats || []
    chartData.value.trend = t.map(item => ({
      date: String(item.date || '').slice(5) || '-',
      count: Number(item.count || 0)
    }))
    chartData.value.levels = (res.data.levelStats || []).map(item => ({
      levelCode: String(item.levelCode || ''),
      count: Number(item.count || 0)
    }))
    chartData.value.types = (res.data.typeStats || []).map(item => ({
      typeCode: item.typeCode,
      typeName: item.typeName || item.typeCode,
      count: Number(item.count || 0)
    }))
    // releasedCount + pendingCount = 待确认
    stats.value = {
      total: Number(b.total || 0),
      unconfirmed: Number(b.releasedCount || 0) + Number(b.pendingCount || 0),
      processing: Number(b.processingCount || 0),
      handled: Number(b.handledCount || 0),
      closed: Number(b.closedCount || 0),
      today: t.length ? Number(t[t.length-1].count || 0) : 0
    }
  } catch(e) { console.warn('加载统计数据失败', e) }
}

async function loadList() {
  loading.value = true
  try {
    const params = { pageNum: pageNum.value, pageSize: pageSize.value }
    if (queryParams.value.warningName) params.warningName = queryParams.value.warningName
    if (queryParams.value.deviceCode) params.deviceCode = queryParams.value.deviceCode
    if (queryParams.value.deviceName) params.deviceName = queryParams.value.deviceName
    if (queryParams.value.status) params.status = queryParams.value.status
    if (queryParams.value.warningLevel) params.warningLevel = queryParams.value.warningLevel
    if (queryParams.value.category === 'normal') params.publisher = '系统自动'
    if (queryParams.value.category === 'special') params.excludePublisher = '系统自动'
    if (queryParams.value.startDate) params.startTime = queryParams.value.startDate + ' 00:00:00'
    if (queryParams.value.endDate) params.endTime = queryParams.value.endDate + ' 23:59:59'
    
    const res = await getWarningSearchData(params)
    if (!res.data) return
    tableData.value = (res.data.records || []).map(row => normalizeWarning(row))
    total.value = Number(res.data.total || 0)
  } catch(e) { ElMessage.error('加载预警列表失败'); console.error(e) }
  finally { loading.value = false }
}

// 后端统计接口异常或没有配置数据时，仍显示稳定的默认图表状态
const fillChartData = () => {
  if (chartData.value.trend?.length && chartData.value.levels?.length && chartData.value.types?.length) return
  const dates = [], counts = []
  for(let i=6;i>=0;i--) { const d=new Date(); d.setDate(d.getDate()-i); dates.push((d.getMonth()+1)+'-'+d.getDate()) }
  for(let i=6;i>=0;i--) { counts.push(0) }
  if (!chartData.value.trend?.length) chartData.value.trend = dates.map((date,idx)=>({date,count:counts[idx]}))
  if (!chartData.value.levels?.length) chartData.value.levels = [1,2,3,4].map(lv=>({levelCode:String(lv), count:0}))
  if (!chartData.value.types?.length) chartData.value.types = [{typeCode:'empty',typeName:'暂无数据',count:1}]
}

// 图表渲染时的空数据状态
const emptyChartData = { trend:[], levels:[], types:[] }

// ========== 图表管理 ==========
let trendChart, levelChart, typeChart

const initCharts = () => {
  // 如果数据为空，填充模拟数据
  if (chartData.value.trend?.length === 0) fillChartData()
  try { renderTrendChart() } catch(e){ console.warn('趋势图初始化失败:', e) }
  try { renderLevelChart() } catch(e){ console.warn('级别图初始化失败:', e) }
  try { renderTypeChart() } catch(e){ console.warn('类型图初始化失败:', e) }
}

// 下划线转驼峰 + 判断类别
function normalizeWarning(row) {
  const n = {}
  Object.keys(row).forEach(key => {
    const camel = key.replace(/_([a-z])/g, (_, c) => c.toUpperCase())
    n[camel] = row[key]
  })
  n.category = n.publisher === '系统自动' ? 'normal' : 'special'
  // 从 remark 字段提取设备编码 (AUTO|deviceCode|warningCode)
  n.deviceCode = n.deviceCode || extractDeviceCodeStr(row)
  n.deviceName = n.deviceName || row.device_name || row.deviceName || ''
  return n
}

function formatPublishTime(row, column, value) {
  return formatWarningTime(value)
}

function formatWarningTime(value) {
  if (!value) return '-'
  const text = String(value).trim()
  const match = text.match(/^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2}:\d{2})/)
  if (match) return `${match[1]} ${match[2]}`
  return text.replace('T', ' ').replace(/\.\d+(Z|[+-]\d{2}:?\d{2})$/, '')
}

function formatWarningDevice(warning) {
  const name = warning?.deviceName || ''
  const code = warning?.deviceCode || ''
  if (name && code) return `${name}（${code}）`
  return name || code || '未关联'
}

// 从预警行中提取设备编码
function extractDeviceCodeStr(row) {
  if (row.remark && typeof row.remark === 'string' && row.remark.startsWith('AUTO|')) {
    const parts = row.remark.split('|')
    if (parts.length >= 2) return parts[1]
  }
  const m = (row.warning_content || row.warningContent || '').match(/设备\s*\[([^\]]+)\]/)
  if (m) return m[1]
  return ''
}

// ========== ECharts ==========
const trendChartOpt = {
  tooltip:{ trigger:'axis' },
  legend:{ data:['新增预警'], top:0 },
  grid:{ left:40,right:20,top:44,bottom:32 },
  xAxis:{ type:'category', axisLabel:{ color:'#9098a6' }, axisLine:{ lineStyle:{ color:'#d0d5dd' } } },
  yAxis:{ type:'value', name:'数量', axisLabel:{ color:'#9098a6' }, splitLine:{ lineStyle:{ color:'#f0f2f6',type:'dashed' } } },
  series:[{ type:'line', smooth:true, data:[], lineStyle:{ color:'#e74c3c',width:2 }, itemStyle:{ color:'#e74c3c' } }]
}

const levelChartOpt = {
  tooltip:{ trigger:'axis' },
  grid:{ left:40,right:20,top:44,bottom:32 },
  xAxis:{ type:'category', data: ['1 级','2 级','3 级','4 级'], axisLabel:{ color:'#9098a6' }, axisLine:{ lineStyle:{ color:'#d0d5dd' } } },
  yAxis:{ type:'value', name:'数量', axisLabel:{ color:'#9098a6' }, splitLine:{ lineStyle:{ color:'#f0f2f6',type:'dashed' } } },
  series:[{
    type:'bar', barWidth:34,
    label:{ show:true, position:'top', color:'#606266', fontSize:12 },
    data:[],
    itemStyle:{
      color:function(params){
        const colors={1:'#5b8ff9',2:'#f6bd16',3:'#f6903d',4:'#e8684a'};
        return colors[params.dataIndex+1]||'#e3f2fd';
      },
      borderRadius:[4,4,0,0]
    }
  }]
}

const typeChartOpt = {
  tooltip:{ trigger:'item' },
  legend:{ top:'center', orient:'vertical', right:4, itemWidth:12, itemHeight:12, textStyle:{ color:'#606266' } },
  series:[{
    type:'pie', radius:['40%','70%'], avoidLabelOverlap:false,
    itemStyle:{ borderRadius:4, borderColor:'#fff', borderWidth:1 },
    label:{ show:false },
    data:[]
  }]
}

const resizeCharts = () => { trendChart?.resize(); levelChart?.resize(); typeChart?.resize() }

// ========== 图表渲染函数 ==========
function renderTrendChart() {
  const dom = document.getElementById('trendChart')
  if (!dom) return
  if (trendChart) trendChart.dispose()
  trendChart = echarts.init(dom)
  const data = chartData.value.trend.length ? chartData.value.trend : emptyChartData.trend
  trendChart.setOption({ ...trendChartOpt, xAxis:{ ...trendChartOpt.xAxis, data: data.map(i=>i.date) }, series:[{ ...trendChartOpt.series[0], data: data.map(i=>i.count || 0) }]
  })
}

function renderLevelChart() {
  const dom = document.getElementById('levelChart')
  if (!dom) return
  if (levelChart) levelChart.dispose()
  levelChart = echarts.init(dom)
  const data = chartData.value.levels.length ? chartData.value.levels : emptyChartData.levels
  levelChart.setOption({ ...levelChartOpt, series:[{ ...levelChartOpt.series[0], data: data.map(l=>l.count || 0) }]
  })
}

function renderTypeChart() {
  const dom = document.getElementById('typeChart')
  if (!dom) return
  if (typeChart) typeChart.dispose()
  typeChart = echarts.init(dom)
  const levels = chartData.value.levels || []
  const levelNames = { '1':'1 级（蓝）', '2':'2 级（黄）', '3':'3 级（橙）', '4':'4 级（红）' }
  const total = levels.reduce((sum, item) => sum + Number(item.count || 0), 0)
  const data = total > 0
    ? levels.map(item => ({ value:Number(item.count || 0), name:levelNames[String(item.levelCode)] || `${item.levelCode} 级` }))
    : [{ value:1, name:'暂无数据', itemStyle:{ color:'#c0c4cc' } }]
  typeChart.setOption({ ...typeChartOpt, series:[{ ...typeChartOpt.series[0], data }]
  })
}

// ========== 辅助函数 ==========
const isUnconfirmed = (status) => ['RELEASED','PENDING'].includes(status)
const getStatusText = (s) => ({ DRAFT:'草稿', PENDING:'待办', PROCESSING:'处理中', RELEASED:'待确认', HANDLED:'已处置', CLOSED:'已解除' }[s]||s)
const getStatusType = (s) => ({ DRAFT:'info', PENDING:'danger', PROCESSING:'warning', RELEASED:'warning', HANDLED:'primary', CLOSED:'success' }[s]||'')
const getLevelText = (lv) => ({ '1':'1 级 (蓝)','2':'2 级 (黄)','3':'3 级 (橙)','4':'4 级 (红)' }[lv]||'-' )
const getLevelType = (lv) => ({ '1':'','2':'warning','3':'warning','4':'danger' }[lv]||'')
const disposalTypeText = (t) => ({ RELEASE:'发布预警', CONFIRM:'确认异常', MISREPORT:'误报清除', HANDLE:'提交处理反馈', CLEAR:'清除预警', UPGRADE:'升级预警', RESOLVE:'解除预警', RETURN:'退回重办', SUPERVISION:'督办', INSTRUCTION:'批示' }[t]||t)
const disposalTimelineType = (t) => ({ RESOLVE:'success', UPGRADE:'warning', RETURN:'danger' }[t]||'primary')
const attachmentsByStage = (stage) => (detail.value?.attachmentList || []).filter(item => (item.attachmentStage || item.attachment_stage || 'REPORT') === stage)
const isImageAttachment = (attachment) => String(attachment.attachmentType || '').startsWith('image/') || /\.(png|jpe?g|gif|webp)$/i.test(attachment.attachmentName || '')
const attachmentPreviewUrls = ref({})
const attachmentPreviewUrl = (attachment) => attachmentPreviewUrls.value[attachment.attachmentId] || ''
const displayAttachmentName = (attachment) => String(attachment.attachmentName || '预警附件').replace(/^\[(预警报告|处理反馈)\]\s*/, '')
const canPreviewAttachment = (attachment) => isImageAttachment(attachment) || /\.pdf$/i.test(displayAttachmentName(attachment)) || String(attachment.attachmentType || '').toLowerCase() === 'application/pdf'

function revokeAttachmentPreviews() {
  Object.values(attachmentPreviewUrls.value).forEach(url => url && URL.revokeObjectURL(url))
  attachmentPreviewUrls.value = {}
}

async function loadAttachmentPreviews(attachments) {
  revokeAttachmentPreviews()
  const imageAttachments = (attachments || []).filter(isImageAttachment)
  await Promise.all(imageAttachments.map(async (attachment) => {
    try {
      const blob = await getWarningAttachmentPreviewData(attachment.attachmentId)
      attachmentPreviewUrls.value[attachment.attachmentId] = URL.createObjectURL(blob)
    } catch (e) {
      console.error('预警图片加载失败', attachment.attachmentId, e)
    }
  }))
}

async function previewAttachment(attachment) {
  try {
    const blob = isImageAttachment(attachment) && attachmentPreviewUrl(attachment)
      ? null
      : await getWarningAttachmentPreviewData(attachment.attachmentId)
    const url = attachmentPreviewUrl(attachment) || URL.createObjectURL(blob)
    window.open(url, '_blank', 'noopener,noreferrer')
    if (blob) setTimeout(() => URL.revokeObjectURL(url), 60000)
  } catch (e) {
    ElMessage.error('附件预览失败')
  }
}

async function downloadAttachment(attachment) {
  try {
    const blob = await getWarningAttachmentDownloadData(attachment.attachmentId)
    const url = URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = displayAttachmentName(attachment)
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    setTimeout(() => URL.revokeObjectURL(url), 1000)
  } catch (e) {
    ElMessage.error('附件下载失败')
  }
}

// ========== 操作处理 ==========
function handleSearch() { pageNum.value=1; loadList() }
function handleReset() { queryParams.value={warningName:'',deviceCode:'',deviceName:'',status:'',warningLevel:'',category:'',startDate:'',endDate:''}; pageNum.value=1; loadList() }

// ========== 确认异常 ==========
const confirmVisible = ref(false)
const current = ref({})
const confirmingRemark = ref('')
const assignedUser = ref('')
const submitting = ref(false)

function openConfirm(row) {
  current.value = row
  confirmingRemark.value = ''
  assignedUser.value = row.assignedUser || row.handler || ''
  confirmVisible.value = true
}

async function submitConfirm() {
  if (!confirmingRemark.value.trim()) { ElMessage.warning('请填写异常描述'); return }
  
  submitting.value = true
  try {
    await confirmWarningData({ warningId: current.value.warningId, assignedUser: assignedUser.value, confirmRemark: confirmingRemark.value })
    const orderDesc = `预警「${current.value.warningName}」异常确认；${confirmingRemark.value}`
    await addManholeWorkOrder({ alarmId: current.value.warningId, orderType: 1, orderLevel: getWorkOrderLevel(current.value.warningLevel), orderDesc: orderDesc.slice(0,500) })
    ElMessage.success(`✅ 预警已确认 | 工单已生成 (WO-...) | 请前往工单系统继续处理`)
    confirmVisible.value = false
    loadList()
  } catch(e) { ElMessage.error('确认失败：'+(e.msg||e.message||'重试')); console.error(e) }
  finally { submitting.value=false }
}

function getWorkOrderLevel(warningLevel) { const lv = Number(warningLevel); return lv>=3?1:(lv===2?2:3) }

// ========== 误报处理 ==========
function confirmMisreport(row) {
  ElMessageBox.prompt('请输入误报原因', '误报确认', {
    inputPlaceholder: '例如：传感器误判、测试数据等',
    inputValue: '',
    inputPattern: /.*/,
    message: '误报后将直接解除该预警',
    confirmButtonText:'确认误报',
    cancelButtonText:'取消'
  }).then(async ({value}) => {
    await misreportWarningData({ warningId: row.warningId, reason: value || '系统确认误报' })
    ElMessage.success('已标记为误报并解除')
    loadList()
  }).catch(()=>{})
}

const processVisible = ref(false)
const processRow = ref({})
const processContent = ref('')
const processFileList = ref([])
const processFiles = ref([])

function openProcess(row) {
  processRow.value = row
  processContent.value = ''
  processFiles.value = []
  processFileList.value = []
  processVisible.value = true
}

function handleProcessFileChange(uploadFile, uploadFiles) {
  const raw = uploadFile.raw
  const extension = String(raw?.name || '').split('.').pop().toLowerCase()
  const allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf', 'xls', 'xlsx', 'doc', 'docx']
  if (!raw || !allowedExtensions.includes(extension)) {
    processFileList.value = uploadFiles.filter(item => item.uid !== uploadFile.uid)
    ElMessage.warning('仅支持图片、PDF、Excel、Word文件')
    return
  }
  if (raw.size > 20 * 1024 * 1024) {
    processFileList.value = uploadFiles.filter(item => item.uid !== uploadFile.uid)
    ElMessage.warning('单个附件不能超过20MB')
    return
  }
  processFileList.value = uploadFiles
  processFiles.value = uploadFiles.map(item => item.raw).filter(Boolean)
}

function handleProcessFileRemove(uploadFile, uploadFiles) {
  handleProcessFileChange(uploadFile, uploadFiles)
}

function handleProcessFileExceed() {
  ElMessage.warning('最多上传9个附件')
}

async function submitProcess() {
  if (!processContent.value.trim()) {
    ElMessage.warning('请填写处理反馈')
    return
  }
  submitting.value = true
  try {
    await submitWarningProcessData({ warningId: processRow.value.warningId, processContent: processContent.value, files: processFiles.value })
    ElMessage.success('处理反馈已提交')
    processVisible.value = false
    await loadList()
  } catch (e) {
    ElMessage.error('提交处理反馈失败')
  } finally {
    submitting.value = false
  }
}

function clearHandled(row) {
  ElMessageBox.prompt('请输入清除说明', '清除预警', {
    inputPlaceholder: '例如：维修完成，现场复核正常',
    confirmButtonText: '确认清除',
    cancelButtonText: '取消'
  }).then(async ({ value }) => {
    if (!value || !value.trim()) {
      ElMessage.warning('请填写清除说明')
      return
    }
    await clearWarningData({ warningId: row.warningId, clearRemark: value })
    ElMessage.success('预警已清除')
    loadList()
  }).catch(() => {})
}

// ========== 详情抽屉 ==========
const detailVisible = ref(false)
const detail = ref(null)

async function openDetail(warningId) {
  detailVisible.value = true
  detail.value = null
  revokeAttachmentPreviews()
  try {
    const res = await getWarningFullDetailData(warningId)
    if (res.data) {
      detail.value = res.data
      await loadAttachmentPreviews(res.data.attachmentList)
    }
  } catch(e) { ElMessage.error('详情加载中'); console.error(e) }
}

onBeforeUnmount(() => {
  revokeAttachmentPreviews()
  window.removeEventListener('resize', resizeCharts)
  trendChart?.dispose()
  levelChart?.dispose()
  typeChart?.dispose()
})

onMounted(async () => {
  await nextTick()
  await Promise.all([loadStats(), loadList()])
  await fillChartData()
  initCharts()
  window.addEventListener('resize', resizeCharts)
})
</script>

<style scoped>
.warning-container { padding: 20px; min-height: calc(100vh - 84px); }
.stat-row { margin-bottom: 16px; }
.stat-item {
  position:relative;min-height:104px;padding:16px 16px 12px 62px;background:#fff;
  border:1px solid #e9edf3;border-radius:10px;box-shadow:0 3px 12px rgba(31,45,61,.07);
  overflow:hidden;transition:transform .2s,box-shadow .2s;
}
.stat-item::before { content:'';position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--stat-color); }
.stat-item:hover { transform:translateY(-2px);box-shadow:0 8px 20px rgba(31,45,61,.12); }
.stat-icon { position:absolute;left:16px;top:22px;width:34px;height:34px;border-radius:9px;display:flex;align-items:center;justify-content:center;color:var(--stat-color);background:var(--stat-bg);font-size:19px; }
.stat-content { display:flex;align-items:baseline;justify-content:space-between;gap:8px; }
.stat-title { font-size:13px;color:#667085;white-space:nowrap; }
.stat-value { font-size:30px;line-height:34px;font-weight:700;color:var(--stat-color);transition:all .3s; }
.stat-caption { margin-top:8px;color:#98a2b3;font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis; }
.stat-primary { --stat-color:#409eff;--stat-bg:#ecf5ff; }
.stat-warning { --stat-color:#e6a23c;--stat-bg:#fdf6ec; }
.stat-processing { --stat-color:#8a96a3;--stat-bg:#f2f4f7; }
.stat-handled { --stat-color:#67c23a;--stat-bg:#f0f9eb; }
.stat-closed { --stat-color:#18a567;--stat-bg:#eafaf3; }
.stat-today { --stat-color:#8e5cc7;--stat-bg:#f5effb; }
.stat-value.highlight { animation: pulse 1.5s ease-in-out; }
@keyframes pulse { 0%{transform:scale(1)}50%{transform:scale(1.12)}100%{transform:scale(1)} }

.chart-row { margin-bottom: 16px; }
.chart-card { min-height: 300px; }
.chart-empty {
  display: flex; align-items: center; justify-content: center;
  height: 240px; color: #c0c4cc; font-size: 14px;
  flex-direction: column; gap: 8px;
}
.chart-empty::before { content:'\1F4CA'; font-size: 32px; opacity: 0.5; }

.search-card { margin-bottom: 16px; }
.table-card { min-height: 600px; }
.device-cell { display:flex; align-items:center; gap:4px; }
.device-name { max-width:96px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:#606266; font-size:12px; }
.no-device { color:#c0c4cc; font-size:12px; }
:deep(.publish-time-column .cell) { white-space: nowrap; }

.detail-section-title { font-weight:600;font-size:14px;color:#2c3e50;margin:16px 0 10px;padding-bottom:8px;border-bottom:1px solid #eef2f6 }
.detail-sub { font-size:12px;color:#9098a6;margin-top:4px }
.detail-empty { font-size:13px;color:#9098a6;padding:12px 0 }
.attachment-list { display:flex;flex-direction:column;gap:6px }
.attachment-group { margin-bottom:12px }
.attachment-stage { color:#606266;font-size:13px;font-weight:600;margin-bottom:6px }
.attachment-grid { display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px }
.attachment-item { min-width:0;padding:8px;border:1px solid #ebeef5;border-radius:6px;background:#fff }
.attachment-image,.attachment-image-loading,.attachment-file-icon { width:100%;height:86px;border-radius:4px;overflow:hidden }
.attachment-image-loading,.attachment-image-error,.attachment-file-icon { display:flex;align-items:center;justify-content:center;color:#a8abb2;background:#f5f7fa;font-size:12px }
.attachment-file-icon { color:#409eff;font-size:32px }
.attachment-name { margin-top:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#606266;font-size:12px }
.attachment-actions { display:flex;justify-content:center;gap:4px;margin-top:3px }
.attachment-actions .el-button { margin-left:0;padding:2px 3px }
.supervision-list { display:flex;flex-direction:column;gap:8px }
.supervision-item { padding:8px 10px;background:#f7f8fa;border-radius:4px;font-size:12px }
.supervision-item span { color:#909399;margin-left:8px }
.supervision-item p { margin:6px 0 0;color:#606266 }
.upload-tip { color:#909399;font-size:12px;line-height:20px }

@media (max-width: 1300px) {
  .stat-row { display:flex; gap:10px; flex-wrap:wrap; }
  .stat-row > * { flex-shrink:0; width: calc(33.33% - 14px) !important; }
}
@media (max-width: 900px) {
  .stat-row > * { width: calc(50% - 10px) !important; }
}
</style>
