<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'
import axios from 'axios'
import { ElMessage, ElConfigProvider } from 'element-plus' // 添加这行引入Message组件
import zhCn from 'element-plus/es/locale/lang/zh-cn' // 导入中文语言包
import dayjs from 'dayjs'

// const url = 'http://112.33.111.160:8070'
const url = 'http://192.200.200.196:8070'
// const url = 'http://127.0.0.1:8070'

// Element Plus 中文语言配置
const locale = zhCn

// API 请求优化和缓存机制
const apiCache = new Map<string, { data: any; timestamp: number }>()
const CACHE_DURATION = 5000 // 缓存5秒
const REQUEST_TIMEOUT = 10000 // 请求超时10秒

// 优化的 API 请求函数
const apiRequest = async (url: string, options: any = {}, useCache: boolean = false) => {
  const cacheKey = `${url}?${JSON.stringify(options.params || {})}`

  // 检查缓存
  if (useCache && apiCache.has(cacheKey)) {
    const cached = apiCache.get(cacheKey)!
    if (Date.now() - cached.timestamp < CACHE_DURATION) {
      console.log('使用缓存数据:', cacheKey)
      performanceMetrics.value.cacheHits++
      return cached.data
    }
  }

  performanceMetrics.value.cacheMisses++

  try {
    const controller = new AbortController()
    const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT)

    const response = await axios({
      url,
      method: options.method || 'GET',
      params: options.params,
      data: options.data,
      signal: controller.signal,
      timeout: REQUEST_TIMEOUT
    })

    clearTimeout(timeoutId)

    // 缓存响应数据
    if (useCache && response.data) {
      apiCache.set(cacheKey, {
        data: response.data,
        timestamp: Date.now()
      })
    }

    performanceMetrics.value.lastUpdate = new Date()
    return response.data
  } catch (error: any) {
    if (error.name === 'AbortError') {
      console.error('请求超时:', url)
      throw new Error('请求超时，请检查网络连接')
    }
    console.error('API请求失败:', url, error)
    throw error
  }
}

// 清除过期缓存
const clearExpiredCache = () => {
  const now = Date.now()
  for (const [key, value] of apiCache.entries()) {
    if (now - value.timestamp > CACHE_DURATION) {
      apiCache.delete(key)
    }
  }
}

// 定期清理缓存 - 保存定时器引用以便清理
let cacheCleanupTimer: number | null = null
const startCacheCleanup = () => {
  if (cacheCleanupTimer) return
  cacheCleanupTimer = window.setInterval(clearExpiredCache, CACHE_DURATION)
}
const stopCacheCleanup = () => {
  if (cacheCleanupTimer) {
    clearInterval(cacheCleanupTimer)
    cacheCleanupTimer = null
  }
}
startCacheCleanup()

// 性能监控和调试功能
const performanceMetrics = ref({
  apiRequests: 0,
  apiErrors: 0,
  websocketMessages: 0,
  websocketErrors: 0,
  cacheHits: 0,
  cacheMisses: 0,
  lastUpdate: null as Date | null,
  averageResponseTime: 0,
  totalResponseTime: 0
})

const debugMode = ref(false)
const debugLogs = ref<string[]>([])


// 导出调试信息到控制台
const exportDebugInfo = () => {
  console.group('🔍 大屏系统调试信息')
  console.log('连接状态:', connectionStatus.value)
  console.log('性能指标:', performanceMetrics.value)
  console.log('缓存状态:', { size: apiCache.size, keys: Array.from(apiCache.keys()) })
  console.log('WebSocket状态:', wsConnectionStatus.value)
  console.log('轮询状态:', { isPolling, pollingErrors, interval: pollingInterval.value })
  console.log('错误信息:', errorMessages.value)
  console.log('调试日志:', debugLogs.value)
  console.groupEnd()
}

// 重置性能指标
const resetPerformanceMetrics = () => {
  performanceMetrics.value = {
    apiRequests: 0,
    apiErrors: 0,
    websocketMessages: 0,
    websocketErrors: 0,
    cacheHits: 0,
    cacheMisses: 0,
    lastUpdate: null,
    averageResponseTime: 0,
    totalResponseTime: 0
  }
}

// 切换调试模式
const toggleDebugMode = () => {
  debugMode.value = !debugMode.value
  if (debugMode.value) {
    console.log('🐛 调试模式已开启')
    exportDebugInfo()
    startDebugExport()
  } else {
    console.log('🐛 调试模式已关闭')
    stopDebugExport()
  }
}

// 定期导出调试信息（仅在调试模式下）
let debugExportTimer: number | null = null
const startDebugExport = () => {
  if (debugExportTimer) return
  debugExportTimer = window.setInterval(() => {
    if (debugMode.value) {
      exportDebugInfo()
    }
  }, 30000) // 每30秒导出一次
}
const stopDebugExport = () => {
  if (debugExportTimer) {
    clearInterval(debugExportTimer)
    debugExportTimer = null
  }
}

// ----websocket 优化版本
// 从HTTP URL转换为WSS URL
const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + ''

// WebSocket相关变量
let ws: WebSocket | null = null
let wsReconnectTimer: number | null = null
let wsHeartbeatTimer: number | null = null
let wsHeartbeatCheckTimer: number | null = null // 心跳响应检测定时器
const wsReconnectInterval = 5000 // 重连间隔时间（毫秒）
const wsHeartbeatInterval = 30000 // 心跳间隔时间（毫秒）
const wsHeartbeatTimeout = 10000 // 心跳响应超时时间（毫秒）
const maxReconnectAttempts = 10 // 最大重连次数
let reconnectAttempts = 0
let lastHeartbeatTime = 0 // 最后一次心跳响应时间
const isWsConnected = ref(false)
const wsConnectionStatus = ref('disconnected') // disconnected, connecting, connected, error

// ===== can_status=true 设备状态映射表 - 用于 WebSocket 实时更新 =====
const canStatusDeviceMap = new Map([
  // 基础状态
  ['ns4;i=18', 'yangtonzhongliang'], // 样桶重量
  ['ns4;i=19', 'chujigeiliaopidai'], // 初级给料皮带
  ['ns4;i=20', 'posuiji'], // 破碎机
  ['ns4;i=21', 'erjipidai'], // 二级皮带（缩分皮带）
  ['ns4;i=22', 'suofenqi'], // 缩分器
  ['ns4;i=23', 'luoxuanshusongji'], // 螺旋输送机
  ['ns4;i=24', 'doutiji'], // 斗提机
  ['ns4;i=25', 'caiyangtoudongzuodaojishi'], // 采样机间隔时间计时
  ['ns4;i=26', 'fengzhuangji'], // 封装系统当前模式
  ['ns4;i=27', 'caiyangtou'], // 采样头动作输出
  ['ns4;i=29', 'kaigaijifenggai'], // 开盖机封盖指令
  ['ns4;i=30', 'kaigaijifuwei'], // 开盖机复位指令
  ['ns4;i=31', 'fengzhuangjibuzongzhong'], // 封装机补桶中
  ['ns4;i=32', 'fengzhuangjibutongchenggong'], // 封装机补桶成功
  ['ns4;i=34', 'fengzhuangjichutongzhong'], // 封装机出桶中
  ['ns4;i=35', 'fengzhuangjichutong'], // 封装机出桶成功
  ['ns4;i=37', 'fengzhuangjijiuetonjiuxu'], // 封装机接桶就绪
  ['ns4;i=38', 'fengzhuangjibutongjiuxu'], // 封装机补桶就绪
  ['ns4;i=39', 'fengzhuangjichutongjiuxu'], // 封装机出桶就绪
  ['ns4;i=78', 'shodongcaiyangtougeshijian'], // 封装机出桶就绪
  ['ns4;i=69', 'suofendaojishixianshi'], // 缩分倒计时显示
  ['ns4;i=72', 'fengzhuangjishouzidong'], // 封装机手自动反馈
  ['ns4;i=73', 'huancunqidakaidaowei'], // 缓存器打开到位反馈
  ['ns4;i=74', 'huancunqiguanbidaowei'], // 缓存器关闭到位反馈
  ['ns4;i=75', 'fengzhuangxitongjiuxu'], // 封装系统就绪反馈
  ['ns4;i=41', 'fengzhuangjijigouguzhang'], // 封装机机构总故障
  ['ns4;i=59', 'caiyangxitongjiting'], // 采样系统急停
  ['ns4;i=60', 'fengzhuangxitongjiting'], // 封装系统急停报警
  ['ns4;i=64', 'zhiyangkouyunxingfankui'], // 制样口运行反馈
  ['ns4;i=70', 'liuguankouyunxingfankui'], // 溜管口运行反馈

  // 其他必要状态
  ['ns4;i=2', 'manualAutoMode'], // 当前运行模式（上位机手自动模式）
  ['ns4;i=3', 'sampleMode'], // 采样模式
  ['ns4;i=4', 'jiangejiangshijijiishi'], // 采样动作间隔时间
  ['ns4;i=5', 'suofenshijianjiange'], // 缩分间隔时间（上位机采样头缩分间隔）
  ['ns4;i=8', 'zhengfan'] // 正反转（手动模式一级皮带）
])

// 初始化WebSocket连接
const initWebSocket = () => {
  // 防止重复连接
  if (ws && (ws.readyState === WebSocket.CONNECTING || ws.readyState === WebSocket.OPEN)) {
    console.log('⚠️  WebSocket已连接或正在连接中，跳过初始化')
    return
  }

  console.log('🔌 正在初始化WebSocket连接:', wsUrl + '/ws/cyopcua')
  wsConnectionStatus.value = 'connecting'

  // 关闭已存在的连接
  if (ws) {
    try {
      ws.close()
    } catch (e) {
      console.warn('关闭旧连接失败:', e)
    }
    ws = null
  }

  try {
    // 创建WebSocket连接
    ws = new WebSocket(wsUrl + '/ws/cyopcua')

    // 连接成功事件
    ws.onopen = () => {
      console.log('✅ WebSocket连接成功')
      isWsConnected.value = true
      wsConnectionStatus.value = 'connected'
      connectionStatus.value.websocket = 'connected'
      reconnectAttempts = 0
      lastHeartbeatTime = Date.now()

      // 清除重连定时器
      if (wsReconnectTimer) {
        clearTimeout(wsReconnectTimer)
        wsReconnectTimer = null
      }

      // 启动心跳检测
      startHeartbeat()

      // 显示成功提示
      if (debugMode.value) {
        ElMessage.success('WebSocket连接成功')
      }
    }

    // 接收消息事件
    ws.onmessage = (event) => {
      try {
        performanceMetrics.value.websocketMessages++
        const data = JSON.parse(event.data)
        handleWebSocketMessage(data)
      } catch (error) {
        performanceMetrics.value.websocketErrors++
        console.error('解析WebSocket消息失败:', error, '原始数据:', event.data)
      }
    }

    // 连接关闭事件
    ws.onclose = (event) => {
      console.log('🔌 WebSocket连接关闭:', {
        code: event.code,
        reason: event.reason || '无原因',
        wasClean: event.wasClean
      })

      isWsConnected.value = false
      wsConnectionStatus.value = 'disconnected'
      connectionStatus.value.websocket = 'disconnected'

      // 停止心跳检测
      stopHeartbeat()

      // 判断是否需要重连
      // 1000 = 正常关闭，不需要重连
      // 1001 = 服务器主动关闭或客户端离开
      // 1006 = 异常关闭（网络问题等）
      const shouldReconnect = event.code !== 1000 && event.code !== 1001

      if (shouldReconnect && reconnectAttempts < maxReconnectAttempts) {
        reconnectAttempts++
        console.log(`⏳ 尝试重新连接WebSocket... (${reconnectAttempts}/${maxReconnectAttempts})`)

        if (!wsReconnectTimer) {
          wsReconnectTimer = window.setTimeout(() => {
            wsReconnectTimer = null
            initWebSocket()
          }, wsReconnectInterval)
        }
      } else if (reconnectAttempts >= maxReconnectAttempts) {
        console.error('❌ WebSocket重连次数已达上限，停止重连')
        wsConnectionStatus.value = 'error'
        connectionStatus.value.websocket = 'error'
        if (debugMode.value) {
          ElMessage.error('WebSocket连接失败，已停止重连')
        }
      } else {
        console.log('✅ WebSocket正常关闭，不重连')
      }
    }

    // 连接错误事件
    ws.onerror = (error) => {
      console.error('WebSocket连接错误:', error)
      isWsConnected.value = false
      wsConnectionStatus.value = 'error'
      connectionStatus.value.websocket = 'error'
    }
  } catch (error) {
    console.error('创建WebSocket连接失败:', error)
    wsConnectionStatus.value = 'error'
  }
}

// 心跳检测 - 优化版本
const startHeartbeat = () => {
  stopHeartbeat()

  // 发送心跳
  wsHeartbeatTimer = window.setInterval(() => {
    if (ws && ws.readyState === WebSocket.OPEN) {
      try {
        const now = Date.now()

        // 检查上次心跳响应时间，如果超时则认为连接异常
        if (lastHeartbeatTime > 0 && (now - lastHeartbeatTime) > wsHeartbeatTimeout + wsHeartbeatInterval) {
          console.warn('⚠️  心跳响应超时，主动关闭连接')
          ws.close()
          return
        }

        ws.send(JSON.stringify({ type: 'ping', timestamp: now }))

        if (debugMode.value) {
          console.log('💓 发送心跳 ping')
        }
      } catch (error) {
        console.error('❌ 发送心跳失败:', error)
        // 发送失败，可能连接已断开
        if (ws) {
          ws.close()
        }
      }
    }
  }, wsHeartbeatInterval)
}

const stopHeartbeat = () => {
  if (wsHeartbeatTimer) {
    clearInterval(wsHeartbeatTimer)
    wsHeartbeatTimer = null
  }
  if (wsHeartbeatCheckTimer) {
    clearTimeout(wsHeartbeatCheckTimer)
    wsHeartbeatCheckTimer = null
  }
}

// 手动重连WebSocket
const reconnectWebSocket = () => {
  reconnectAttempts = 0
  initWebSocket()
}
//当前批次
const currentBatch = ref('')
const currentTong = ref({})
// 处理WebSocket消息 - 优化版本
const handleWebSocketMessage = (data: any) => {
  try {
    // 处理心跳响应（服务器可能返回 pong 或原样返回 ping）
    if (data.type === 'pong' || data.type === 'ping') {
      lastHeartbeatTime = Date.now()
      if (debugMode.value) {
        console.log('💓 收到心跳响应:', data.type)
      }
      return
    }

    //     {
    //   "content": {
    //     "id": 55,
    //     "point": {
    //       "address": "%M3074.2",
    //       "canAlarm": true,
    //       "canLog": false,
    //       "canStatus": true,
    //       "canWrite": false,
    //       "dataType": "BIT",
    //       "device": "PLC",
    //       "direction": "→",
    //       "id": 60,
    //       "infoDesc": "破碎机堵转报警",
    //       "plcNodeId": "ns4;i=61",
    //       "signalName": "破碎机堵转报警",
    //       "valueDesc": "{\"false\": \"无\", \"true\": \"报警\"}",
    //       "valueDescType": "enum"
    //     },
    //     "pointId": 60,
    //     "updateTime": "2025-10-29 13:23:59",
    //     "value": "false"
    //   },
    //   "type": 1
    // }

    // 处理设备状态更新 (type=1)
    if (data.type === 1) {
      // WebSocket 返回的是单个对象，需要转换为数组格式
      const contentArray = Array.isArray(data.content) ? data.content : [data.content]

      if (debugMode.value) {
        console.log('📡 收到设备状态更新 (type=1):', {
          plcNodeId: data.content?.point?.plcNodeId,
          signalName: data.content?.point?.signalName,
          value: data.content?.value,
          canStatus: data.content?.point?.canStatus,
          updateTime: data.content?.updateTime
        })
      }
      console.log("收到：：：", data)

      updateDeviceStatusOptimized(contentArray)
      return
    }

    // 处理批次信息更新
    if (data.type === 2) {
      if ('bucketNo' in data.content) {
        console.log('收到批次信息更新:', data.content)
        currentBatch.value = data.content.batchNo
        const obj: any = {
          samplecard2: data.content.bucketNo, // 当前桶号
          batchNo: data.content.batchNo, // 批次号
          sampleCode: data.content.sampleCode, // 采样码
          sampleWeight: data.content.weight, // 重量
        }
        currentTong.value = obj
        console.log('更新当前桶信息:', currentTong.value)
        batchList()
      }
      return
    }

    // 处理其他类型的消息
    console.log('收到未知类型消息:', data)
  } catch (error) {
    console.error('处理WebSocket消息失败:', error, data)
  }
}

// ===== 优化设备状态更新 - 使用can_status映射表 =====
const updateDeviceStatusOptimized = (data: any[]) => {
  if (!Array.isArray(data) || data.length === 0) {
    console.warn('⚠️  WebSocket数据为空或格式错误')
    return
  }

  if (debugMode.value) {
    console.log(`📡 处理 ${data.length} 条设备状态更新`)
  }

  data.forEach((item: any) => {
    if (!item.point?.plcNodeId) {
      return
    }

    const plcNodeId = item.point.plcNodeId
    const deviceVarName = canStatusDeviceMap.get(plcNodeId)

    if (!deviceVarName) {
      // 忽略不在can_status列表中的设备
      return
    }

    try {
      const oldValue = eval(deviceVarName).value?.val
      const newValue = item.value

      // 根据设备变量名动态更新
      switch (deviceVarName) {
        case 'manualAutoMode':
          // 确保 manualAutoMode 是对象
          if (typeof manualAutoMode.value !== 'object' || manualAutoMode.value === null) {
            manualAutoMode.value = { id: 1, val: newValue }
          } else if (manualAutoMode.value) {
            manualAutoMode.value.val = newValue
          }
          if (debugMode.value) {
            console.log(`🔄 [${plcNodeId}] 运行模式更新: ${oldValue} → ${newValue}`)
          }
          break

        case 'sampleMode':
          // 确保 sampleMode 是对象
          if (typeof sampleMode.value !== 'object' || sampleMode.value === null) {
            sampleMode.value = { id: 2, val: newValue }
          } else if (sampleMode.value) {
            sampleMode.value.val = newValue
          }
          if (debugMode.value) {
            console.log(`🔄 [${plcNodeId}] 采样模式更新: ${oldValue} → ${newValue}`)
          }
          break

        // can_status=true 的所有设备
        case 'yangtonzhongliang':
          yangtonzhongliang.value.val = newValue
          if (debugMode.value) {
            console.log(`⚖️  [${plcNodeId}] 样桶重量: ${newValue}kg`)
          }
          break

        case 'chujigeiliaopidai':
          chujigeiliaopidai.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 初级给料皮带: ${oldValue} → ${newValue}`)
          }
          break

        case 'posuiji':
          posuiji.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 破碎机: ${oldValue} → ${newValue}`)
          }
          break

        case 'erjipidai':
          erjipidai.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 二级皮带: ${oldValue} → ${newValue}`)
          }
          break

        case 'suofenqi':
          suofenqi.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 缩分器: ${oldValue} → ${newValue}`)
          }
          break

        case 'luoxuanshusongji':
          luoxuanshusongji.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 螺旋输送机: ${oldValue} → ${newValue}`)
          }
          break

        case 'doutiji':
          doutiji.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 斗提机: ${oldValue} → ${newValue}`)
          }
          break

        case 'caiyangtoudongzuodaojishi':
          caiyangtoudongzuodaojishi.value.val = newValue
          if (debugMode.value) {
            console.log(`⏱️  [${plcNodeId}] 间隔时间计时: ${newValue}秒`)
          }
          break
        case 'shodongcaiyangtougeshijian':
          shodongcaiyangtougeshijian.value.val = newValue
          if (debugMode.value) {
            console.log(`⏱️手动  [${plcNodeId}] 间隔时间计时: ${newValue}秒`)
          }
          break

        case 'fengzhuangji':
          fengzhuangji.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 封装机模式: ${oldValue} → ${newValue}`)
          }
          break

        case 'caiyangtou':
          caiyangtou.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 采样头: ${oldValue} → ${newValue}`)
          }
          break

        case 'kaigaijifenggai':
          kaigaijifenggai.value.val = newValue
          break

        case 'kaigaijifuwei':
          kaigaijifuwei.value.val = newValue
          break

        case 'fengzhuangjibuzongzhong':
          fengzhuangjibuzongzhong.value.val = newValue
          break

        case 'fengzhuangjibutongchenggong':
          fengzhuangjibutongchenggong.value.val = newValue
          break

        case 'fengzhuangjichutongzhong':
          fengzhuangjichutongzhong.value.val = newValue
          break

        case 'fengzhuangjichutong':
          fengzhuangjichutong.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`📦 [${plcNodeId}] 封装机出桶成功: ${newValue}`)
          }
          break

        case 'fengzhuangjijiuetonjiuxu':
          fengzhuangjijiuetonjiuxu.value.val = newValue
          break

        case 'fengzhuangjibutongjiuxu':
          fengzhuangjibutongjiuxu.value.val = newValue
          break

        case 'fengzhuangjichutongjiuxu':
          fengzhuangjichutongjiuxu.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`✅ [${plcNodeId}] 封装机出桶就绪: ${newValue}`)
          }
          break

        case 'suofendaojishixianshi':
          suofendaojishixianshi.value.val = newValue
          break

        case 'fengzhuangjishouzidong':
          fengzhuangjishouzidong.value.val = newValue
          break

        case 'zhengfan':
          zhengfan.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 正反转: ${oldValue} → ${newValue}`)
          }
          break

        case 'suofenshijianjiange':
          suofenshijianjiange.value.val = newValue
          break

        case 'jiangejiangshijijiishi':
          jiangejiangshijijiishi.value.val = newValue
          if (debugMode.value) {
            console.log(`⏱️  [${plcNodeId}] 采样动作间隔时间: ${newValue}秒`)
          }
          break

        case 'huancunqidakaidaowei':
          huancunqidakaidaowei.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 缓存器打开到位: ${oldValue} → ${newValue}`)
          }
          break

        case 'huancunqiguanbidaowei':
          huancunqiguanbidaowei.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 缓存器关闭到位: ${oldValue} → ${newValue}`)
          }
          break

        case 'fengzhuangxitongjiuxu':
          fengzhuangxitongjiuxu.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🔄 [${plcNodeId}] 封装系统就绪: ${oldValue} → ${newValue}`)
          }
          break

        case 'fengzhuangjijigouguzhang':
          fengzhuangjijigouguzhang.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`⚠️  [${plcNodeId}] 封装机机构总故障: ${oldValue} → ${newValue}`)
          }
          break
        case 'caiyangxitongjiting':
        caiyangxitongjiting.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`⚠️  [${plcNodeId}] 采样系统急停: ${oldValue} → ${newValue}`)
          }
          break

        case 'fengzhuangxitongjiting':
          fengzhuangxitongjiting.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🚨 [${plcNodeId}] 封装系统急停报警: ${oldValue} → ${newValue}`)
          }
          break
        case 'zhiyangkouyunxingfankui':
        zhiyangkouyunxingfankui.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🚨 [${plcNodeId}] 制样口运行反馈: ${oldValue} → ${newValue}`)
          }
          break
        case 'liuguankouyunxingfankui':
        liuguankouyunxingfankui.value.val = newValue
          if (debugMode.value && oldValue !== newValue) {
            console.log(`🚨 [${plcNodeId}] 溜管口运行反馈: ${oldValue} → ${newValue}`)
          }
          break
      }

      // 添加到调试日志 - 限制日志数量防止内存泄漏
      if (debugMode.value && oldValue !== newValue) {
        debugLogs.value.unshift(`[${new Date().toLocaleTimeString()}] ${item.point.signalName}: ${oldValue} → ${newValue}`)
        // 限制日志最大数量为50条
        if (debugLogs.value.length > 50) {
          debugLogs.value = debugLogs.value.slice(0, 50)
        }
      }

    } catch (error) {
      console.error(`❌ 更新设备状态失败 [${deviceVarName}/${plcNodeId}]:`, error, item)
    }
  })
}

// ===== can_status=true 的所有状态属性 =====
// 这些状态会通过 WebSocket 实时更新

// 样桶重量 (ns4;i=18)
const yangtonzhongliang = ref({
  id: 17,
  plcNodeId: 'ns4;i=18',
  signalName: '样桶重量',
  val: 0,
  unit: '千克'
})

// 初级给料皮带 (ns4;i=19)
const chujigeiliaopidai = ref({
  id: 18,
  plcNodeId: 'ns4;i=19',
  signalName: '初级给料皮带',
  val: 0
})

// 破碎机状态反馈 (ns4;i=20)
const posuiji = ref({
  id: 19,
  plcNodeId: 'ns4;i=20',
  signalName: '破碎机',
  val: 0
})

// 缩分皮带状态反馈 (ns4;i=21) - 二级皮带
const erjipidai = ref({
  id: 20,
  plcNodeId: 'ns4;i=21',
  signalName: '二级皮带',
  val: 0
})

// 缩分机状态反馈 (ns4;i=22)
const suofenqi = ref({
  id: 21,
  plcNodeId: 'ns4;i=22',
  signalName: '缩分器',
  val: 0
})

// 螺旋输送机状态反馈 (ns4;i=23)
const luoxuanshusongji = ref({
  id: 22,
  plcNodeId: 'ns4;i=23',
  signalName: '螺旋输送机',
  val: 0
})

// 斗提机状态反馈 (ns4;i=24)
const doutiji = ref({
  id: 23,
  plcNodeId: 'ns4;i=24',
  signalName: '斗提机',
  val: 0
})

// 采样动作间隔时间 (ns4;i=4)  
const jiangejiangshijijiishi = ref({
  id: 24,
  plcNodeId: 'ns4;i=4',
  signalName: '采样动作间隔时间',
  val: 0,
  unit: '秒'
})
// 采样动作倒计时 (ns4;i=25) caiyangtoudongzuodaojishi
const caiyangtoudongzuodaojishi = ref({
  id: 24,
  plcNodeId: 'ns4;i=25',
  signalName: '采样头动作倒计时',
  val: 0,
  unit: '秒'
})
// 手动采样机间隔时间设置 (ns4;i=25)
const shodongcaiyangtougeshijian = ref({
  id: 66,
  plcNodeId: 'ns4;i=78',
  signalName: '手动采样头动作时间',
  val: 0,
  unit: '秒'
})



// 封装系统当前模式 (ns4;i=26)
const fengzhuangji = ref({
  id: 25,
  plcNodeId: 'ns4;i=26',
  signalName: '封装机当前运行模式',
  val: ''
})

// 采样头动作输出 (ns4;i=27)
const caiyangtou = ref({
  id: 26,
  plcNodeId: 'ns4;i=27',
  signalName: '采样头',
  val: ''
})

// 开盖机封盖指令 (ns4;i=29)
const kaigaijifenggai = ref({
  id: 28,
  plcNodeId: 'ns4;i=29',
  signalName: '开盖机封盖指令',
  val: ''
})

// 开盖机复位指令 (ns4;i=30)
const kaigaijifuwei = ref({
  id: 29,
  plcNodeId: 'ns4;i=30',
  signalName: '开盖机复位指令',
  val: ''
})

// 封装机补桶中 (ns4;i=31)
const fengzhuangjibuzongzhong = ref({
  id: 30,
  plcNodeId: 'ns4;i=31',
  signalName: '封装机补桶中',
  val: ''
})

// 封装机补桶成功 (ns4;i=32)
const fengzhuangjibutongchenggong = ref({
  id: 31,
  plcNodeId: 'ns4;i=32',
  signalName: '封装机补桶成功',
  val: ''
})

// 封装机出桶中 (ns4;i=34)
const fengzhuangjichutongzhong = ref({
  id: 33,
  plcNodeId: 'ns4;i=34',
  signalName: '封装机出桶中',
  val: ''
})

// 封装机出桶成功 (ns4;i=35)
const fengzhuangjichutong = ref({
  id: 34,
  plcNodeId: 'ns4;i=35',
  signalName: '封装机出桶成功',
  val: ''
})

// 封装机接桶就绪 (ns4;i=37)
const fengzhuangjijiuetonjiuxu = ref({
  id: 36,
  plcNodeId: 'ns4;i=37',
  signalName: '封装机接桶就绪',
  val: ''
})

// 封装机补桶就绪 (ns4;i=38)
const fengzhuangjibutongjiuxu = ref({
  id: 37,
  plcNodeId: 'ns4;i=38',
  signalName: '封装机补桶就绪',
  val: ''
})

// 封装机出桶就绪 (ns4;i=39)
const fengzhuangjichutongjiuxu = ref({
  id: 38,
  plcNodeId: 'ns4;i=39',
  signalName: '封装机出桶就绪',
  val: ''
})

// 缩分倒计时显示 (ns4;i=69)
const suofendaojishixianshi = ref({
  id: 69,
  plcNodeId: 'ns4;i=69',
  signalName: '缩分倒计时显示',
  val: 0,
  unit: '秒'
})

// 封装机手自动反馈 (ns4;i=72)
const fengzhuangjishouzidong = ref({
  id: 72,
  plcNodeId: 'ns4;i=72',
  signalName: '封装机手自动反馈',
  val: ''
})

// 缓存器打开到位反馈 (ns4;i=73)
const huancunqidakaidaowei = ref({
  id: 73,
  plcNodeId: 'ns4;i=73',
  signalName: '缓存器打开到位反馈',
  val: ''
})

// 缓存器关闭到位反馈 (ns4;i=74)
const huancunqiguanbidaowei = ref({
  id: 74,
  plcNodeId: 'ns4;i=74',
  signalName: '缓存器关闭到位反馈',
  val: ''
})

// 封装系统就绪反馈 (ns4;i=75)
const fengzhuangxitongjiuxu = ref({
  id: 75,
  plcNodeId: 'ns4;i=75',
  signalName: '封装系统就绪反馈',
  val: ''
})

// 封装机机构总故障 (ns4;i=41)
const fengzhuangjijigouguzhang = ref({
  id: 41,
  plcNodeId: 'ns4;i=41',
  signalName: '封装机机构总故障',
  val: ''
})
//采样系统急停 59
const caiyangxitongjiting = ref({
  id: 7,
  plcNodeId: 'ns4;i=59',
  val: '' 
})
// 封装系统急停报警 (ns4;i=60)
const fengzhuangxitongjiting = ref({
  id: 60,
  plcNodeId: 'ns4;i=60',
  signalName: '封装系统急停报警',
  val: ''
})

const zhiyangkouyunxingfankui = ref({
  id: 64,
  plcNodeId: 'ns4;i=64',
  signalName: '制样口运行反馈',
  val: ''
})
const liuguankouyunxingfankui = ref({
  id: 70,
  plcNodeId: 'ns4;i=70',
  signalName: '溜管口运行反馈',
  val: ''
})
// websocket 
/// ns4;i=2 1手动，2自动，3检修

let manualAutoMode: any = ref({
  id: 1,
  val: '1'
})

// 计算属性：用于开关显示（true=自动，false=手动）
const manualAutoModeSwitch = computed(() => {
  return manualAutoMode.value.val === '2' // '2'表示自动
})

/// 1采样 2溜管
let sampleMode: any = ref({
  id: 2,
  val: '1'
})


// 制样方式状态 (对应正反转)
const zhiyangFangshi = ref({
  id: 7,
  plcNodeId: 'ns4;i=8',
  val: '1' // 默认制样口，1=正转(制样口), 2=反转(溜管口), 3=停止
})

// 换桶重量 - 优化版本
const huanbuckezhongliang = ref('')
const setHuanBuckeZhongLiang = async (weight: any) => {
  try {
    isLoading.value = true
    const response = await retryOperation(async () => {
      return await apiRequest(`${url}/opc/pointValue/updateMaxWeight`, {
        method: 'PUT',
        params: { value: weight }
      })
    })

    if (response.code === 200) {
      handleSuccess('换桶重量设置成功', '换桶重量设置')
      // 清除相关缓存
      apiCache.delete(`${url}/opc/pointValue/getAll`)
    } else {
      handleError(new Error('服务器返回错误'), '换桶重量设置')
    }
  } catch (error) {
    handleError(error, '换桶重量设置')
  } finally {
    isLoading.value = false
  }
}

// 日志导出功能
const showLogExportDialog = ref(false) // 控制对话框显示
const logExportDateRange = ref<[string, string]>(['', ''])
const logExportType = ref('alarm') // alarm: 报警日志, operation: 操作日志, sample: 采样日志

const logTypeOptions = [
  { label: '报警日志', value: 'alarm' },
  { label: '操作日志', value: 'operation' },
  { label: '采样日志', value: 'sample' }
]

// 打开导出对话框
const openLogExportDialog = () => {
  showLogExportDialog.value = true
}

// 导出日志函数
const exportLogs = async () => {
  if (!logExportDateRange.value[0] || !logExportDateRange.value[1]) {
    ElMessage.warning('请选择日期范围')
    return
  }

  try {
    isLoading.value = true
    const startDate = logExportDateRange.value[0]
    const endDate = logExportDateRange.value[1]

    let endpoint = ''
    let filename = ''

    switch (logExportType.value) {
      case 'alarm':
        endpoint = `${url}/opc/alarm/export`
        filename = `报警日志_${startDate}_${endDate}.xlsx`
        break
      case 'operation':
        endpoint = `${url}/opc/log/export`
        filename = `操作日志_${startDate}_${endDate}.xlsx`
        break
      case 'sample':
        endpoint = `${url}/opc/batch/export`
        filename = `采样日志_${startDate}_${endDate}.xlsx`
        break
    }

    const response = await axios.get(endpoint, {
      params: { startDate, endDate },
      responseType: 'blob'
    })

    // 创建下载链接
    const blob = new Blob([response.data], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    })
    const link = document.createElement('a')
    link.href = window.URL.createObjectURL(blob)
    link.download = filename
    link.click()
    window.URL.revokeObjectURL(link.href)
    
    ElMessage.success('日志导出成功')
    showLogExportDialog.value = false // 导出成功后关闭对话框
  } catch (error) {
    console.error('日志导出失败:', error)
    ElMessage.error('日志导出失败')
  } finally {
    isLoading.value = false
  }
}
// 错误处理和用户反馈机制
const errorMessages = ref<string[]>([])
const isLoading = ref(false)
const connectionStatus = ref({
  websocket: 'disconnected',
  api: 'unknown',
  lastUpdate: null as Date | null
})

// 统一的错误处理函数
const handleError = (error: any, context: string, showMessage: boolean = true) => {
  const errorMsg = error.message || error.toString()
  const timestamp = new Date().toLocaleTimeString()
  const fullError = `[${timestamp}] ${context}: ${errorMsg}`

  console.error(fullError, error)

  // 添加到错误列表 - 限制数量防止内存泄漏
  errorMessages.value.unshift(fullError)
  // 限制错误消息最大数量为10条
  if (errorMessages.value.length > 10) {
    errorMessages.value = errorMessages.value.slice(0, 10)
  }

  // 显示用户提示
  if (showMessage) {
    ElMessage.error(`${context}失败: ${errorMsg}`)
  }

  // 更新连接状态
  connectionStatus.value.api = 'error'
}

// 成功处理函数
const handleSuccess = (message: string, context: string) => {
  console.log(`[${new Date().toLocaleTimeString()}] ${context}: ${message}`)
  ElMessage.success(message)
  connectionStatus.value.api = 'connected'
  connectionStatus.value.lastUpdate = new Date()
}

// 清除错误信息
const clearErrors = () => {
  errorMessages.value = []
}

// 重试机制
const retryOperation = async (operation: () => Promise<any>, maxRetries: number = 3) => {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await operation()
    } catch (error) {
      if (i === maxRetries - 1) {
        throw error
      }
      console.log(`重试第 ${i + 1} 次...`)
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)))
    }
  }
}

// 辅助函数：将原始值转换为显示值
const parseDisplayValue = (value: any, valueDescJson: string | null): any => {
  if (!valueDescJson) {
    return value
  }

  try {
    const valueDesc: any = JSON.parse(valueDescJson)

    // 尝试匹配各种可能的值类型
    if (value === 'false' || value === false) {
      return valueDesc[false as any] || valueDesc['false'] || value
    } else if (value === 'true' || value === true) {
      return valueDesc[true as any] || valueDesc['true'] || value
    } else if (value === '0' || value === 0) {
      return valueDesc[0] || valueDesc['0'] || value
    } else if (value === '1' || value === 1) {
      return valueDesc[1] || valueDesc['1'] || value
    } else if (value === '2' || value === 2) {
      return valueDesc[2] || valueDesc['2'] || value
    } else if (value === '3' || value === 3) {
      return valueDesc[3] || valueDesc['3'] || value
    } else {
      // 其他值直接显示原值
      return value
    }
  } catch (e) {
    console.error('解析valueDesc失败:', e)
    return value
  }
}

// 运行日志 - 优化版本
const runData = async () => {
  try {
    const response = await retryOperation(async () => {
      return await apiRequest(`${url}/opc/pointValue/getAll`, { method: 'GET' }, true)
    })

    if (response.code === 200 && response.data?.length > 0) {
      // 使用优化后的设备状态更新函数
      updateDeviceStatusOptimized(response.data)

      // 处理每条记录的显示值（val字段）
      response.data.forEach((item: any) => {
        // 处理最大重量字段
        if (item.point?.signalName === '最大重量') {
          huanbuckezhongliang.value = item.value
        }

        // 使用辅助函数转换显示值
        item.val = parseDisplayValue(item.value, item.point?.valueDesc || null)
      })

      tableData.value = response.data
      connectionStatus.value.api = 'connected'
      connectionStatus.value.lastUpdate = new Date()
    } else {
      handleError(new Error('数据为空或格式错误'), '获取运行日志', false)
    }
  } catch (error) {
    handleError(error, '获取运行日志', false)
  }
}
// 控制历史记录dialog显示的变量
const historyDialogVisible: any = ref(false)



// 打开历史记录dialog
const historyData = ref<any[]>([])
const openHistoryDialog = async () => {
  // 打开dialog
  const response = await axios.get(url + '/opc/log/sampleHeaderOut?pageNum=1&pageSize=1000&poindId=ns4;i=27') //?point.plcNodeId=ns4;i=27
  if (response.data.code === 200) {
    let arr: any = []
    response.data.rows.forEach((item: any) => {
      if (item.point.plcNodeId === 'ns4;i=27') {

        let valueDesc: any
        if (item.point['plcNodeId']) {
          valueDesc = JSON.parse(item.point['valueDesc'])
        } else {
          item['val'] = item.newValue
        }
        if (item.newValue === 'false') {
          item['val'] = valueDesc[false as any]
        }
        if (item.newValue === 'true') {
          item['val'] = valueDesc[true as any]
        }
        if (item.newValue === '1') {
          item['val'] = valueDesc[1 as any]
        }
        if (item.newValue === '2') {
          item['val'] = valueDesc[2 as any]
        }
        if (item.newValue === '0') {
          item['val'] = valueDesc[0 as any]
        }
        arr.push(item)
      }

    })
    historyData.value = arr
  } else {
    ElMessage.error('获取失败')
  }
  // historyData.value = res.data.rows
  historyDialogVisible.value = true
}
const closeHistoryDialog = () => {
  historyDialogVisible.value = false
}
const currentBatchIndex = ref(0) // 当前显示的桶样索引
const batchRecord = ref<any[]>([]) // 桶列表数据

// 切换到上一个桶样
const prevBatch = () => {
  if (batchRecord.value.length > 0) {
    currentBatchIndex.value = (currentBatchIndex.value - 1 + batchRecord.value.length) % batchRecord.value.length
  }
}

// 切换到下一个桶样
const nextBatch = () => {
  if (batchRecord.value.length > 0) {
    currentBatchIndex.value = (currentBatchIndex.value + 1) % batchRecord.value.length
  }
}
// id	signal_name	info_desc	data_type	value_desc	value_desc_type	address	device	direction	plc_node_id	can_write	can_alarm	can_status	can_log
// 1	上位机手自动模式	上位机手自动模式	INT16	{"1": "手动", "2": "自动"}	enum	%MW3000	PLC	←	ns4;i=2	t	f	f	t
// 2	上位机采样模式	上位机采样模式	INT16	{"1": "采样", "2": "溜管", "3": "清洁"}	enum	%MW3002	PLC	←	ns4;i=3	t	f	f	t
// 3	上位机采样头采样间隔	上位机采样头采样间隔	INT16	{"单位": "秒"}	unit	%MW3004	PLC	←	ns4;i=4	t	f	f	t
// 4	上位机采样头缩分间隔	上位机采样头缩分间隔	INT16	{"单位": "秒"}	unit	%MW3006	PLC	←	ns4;i=5	t	f	f	t
// 5	采样系统启停命令	采样系统启停命令	INT16	{"1": "启动", "2": "停止"}	enum	%MW3008	PLC	←	ns4;i=6	t	f	f	t
// 6	开盖机执行反馈	开盖机执行反馈	INT16	{"1": "开盖成功", "2": "开盖失败", "3": "封盖成功", "4": "封盖失败", "5": "复位成功", "6": "复位失败"}	enum	%MW3010	PLC	←	ns4;i=7	t	f	f	t
// 7	手动模式一级皮带启停命令	手动模式一级皮带启停命令	INT16	{"1": "正转", "2": "反转", "3": "停止"}	enum	%MW3012	PLC	←	ns4;i=8	t	f	f	t
// 8	手动模式破碎机启停命令	手动模式破碎机启停命令	INT16	{"1": "启动", "2": "停止"}	enum	%MW3014	PLC	←	ns4;i=9	t	f	f	t
// 9	手动模式缩分皮带启停命令	手动模式缩分皮带启停命令	INT16	{"1": "启动", "2": "停止"}	enum	%MW3016	PLC	←	ns4;i=10	t	f	f	t
// 10	手动模式缩分电机启停命令	手动模式缩分电机启停命令	INT16	{"1": "启动", "2": "停止"}	enum	%MW3018	PLC	←	ns4;i=11	t	f	f	t
// 11	手动模式螺旋输送机启停命令	手动模式螺旋输送机启停命令	INT16	{"1": "启动", "2": "停止"}	enum	%MW3020	PLC	←	ns4;i=12	t	f	f	t
// 12	手动模式斗提机启停命令	手动模式斗提机启停命令	INT16	{"1": "启动", "2": "停止"}	enum	%MW3022	PLC	←	ns4;i=13	t	f	f	t
// 13	采样以及封装系统急停命令	采样以及封装系统急停命令	BIT	{"false": "正常", "true": "执行"}	enum	%M3030.0	PLC	←	ns4;i=14	t	t	f	t
// 14	采样以及封装系统故障复位	采样以及封装系统故障复位	BIT	{"false": "正常", "true": "执行"}	enum	%M3030.1	PLC	←	ns4;i=15	t	t	f	t
// 15	封装系统补桶命令	封装系统补桶命令	BIT	{"false": "正常", "true": "执行"}	enum	%M3030.2	PLC	←	ns4;i=16	t	t	f	t
// 16	封装系统出桶命令	封装系统出桶命令	BIT	{"false": "正常", "true": "执行"}	enum	%M3030.3	PLC	←	ns4;i=17	t	t	f	t
// 17	样桶重量	样桶重量	REAL	{"单位": "千克"}	unit	%MD3048	PLC	→	ns4;i=18	f	f	t	f
// 18	初级给料皮带	初级给料皮带	INT16	{"0": "停止", "1": "采样口", "2": "溜管口","3":"故障"}	enum	%MW3052	PLC	→	ns4;i=19	f	f	t	f
// 19	破碎机状态反馈	破碎机状态反馈	INT16	{"0": "停止", "1": "运行", "2": "故障"}	enum	%MW3054	PLC	→	ns4;i=20	f	f	t	f
// 20	缩分皮带状态反馈	缩分皮带状态反馈	INT16	{"0": "停止", "1": "运行", "2": "故障"}	enum	%MW3056	PLC	→	ns4;i=21	f	f	t	f
// 21	缩分机状态反馈	缩分机状态反馈	INT16	{"0": "停止", "1": "运行", "2": "故障"}	enum	%MW3058	PLC	→	ns4;i=22	f	f	t	f
// 22	螺旋输送机状态反馈	螺旋输送机状态反馈	INT16	{"0": "停止", "1": "运行", "2": "故障"}	enum	%MW3060	PLC	→	ns4;i=23	f	f	t	f
// 23	斗提机状态反馈	斗提机状态反馈	INT16	{"0": "停止", "1": "运行", "2": "故障"}	enum	%MW3062	PLC	→	ns4;i=24	f	f	t	f
// 24	采样机间隔时间计时	采样机间隔时间计时	INT16	{"单位": "秒"}	unit	%MW3064	PLC	→	ns4;i=25	f	f	t	f
// 25	封装系统当前模式	封装系统当前模式	INT16	{"1": "手动", "2": "自动"}	enum	%MW3066	PLC	→	ns4;i=26	f	f	t	f
// 26	采样头动作输出	采样头动作输出	BIT	{"false": "停止", "true": "采样头动作"}	enum	%M3070.0	PLC	→	ns4;i=27	f	f	t	t
// 27	开盖机开盖指令	开盖机开盖指令	BIT	{"false": "未执行", "true": "执行开盖"}	enum	%M3070.1	PLC	→	ns4;i=28	f	t	t	f
// 28	开盖机封盖指令	开盖机封盖指令	BIT	{"false": "未执行", "true": "执行封盖"}	enum	%M3070.2	PLC	→	ns4;i=29	f	f	t	f
// 29	开盖机复位指令	开盖机复位指令	BIT	{"false": "未执行", "true": "执行复位"}	enum	%M3070.3	PLC	→	ns4;i=30	f	f	t	f
// 30	封装机补桶中	封装机补桶中	BIT	{"false": "无", "true": "补桶中"}	enum	%M3070.4	PLC	→	ns4;i=31	f	f	t	f
// 31	封装机补桶成功	封装机补桶成功	BIT	{"false": "无", "true": "补桶成功"}	enum	%M3070.5	PLC	→	ns4;i=32	f	f	t	f
// 32	封装机补桶失败	封装机补桶失败	BIT	{"false": "无", "true": "补桶失败"}	enum	%M3070.6	PLC	→	ns4;i=33	f	t	t	f
// 33	封装机出桶中	封装机出桶中	BIT	{"false": "无", "true": "出桶中"}	enum	%M3070.7	PLC	→	ns4;i=34	f	f	t	f
// 34	封装机出桶成功	封装机出桶成功	BIT	{"false": "无", "true": "出桶成功"}	enum	%M3071.0	PLC	→	ns4;i=35	f	f	t	f
// 35	封装机出桶失败	封装机出桶失败	BIT	{"false": "无", "true": "出桶失败"}	enum	%M3071.1	PLC	→	ns4;i=36	f	t	t	f
// 36	封装机接桶就绪	封装机接桶就绪	BIT	{"false": "无", "true": "接桶就绪"}	enum	%M3071.2	PLC	→	ns4;i=37	f	f	t	f
// 37	封装机补桶就绪	封装机补桶就绪	BIT	{"false": "无", "true": "补桶就绪"}	enum	%M3071.3	PLC	→	ns4;i=38	f	f	t	f
// 38	封装机出桶就绪	封装机出桶就绪	BIT	{"false": "无", "true": "出桶就绪"}	enum	%M3071.4	PLC	→	ns4;i=39	f	f	t	f
// 39	封装机接桶长时间未就绪报警	封装机接桶长时间未就绪报警	BIT	{"false": "无", "true": "报警"}	enum	%M3071.5	PLC	→	ns4;i=40	f	t	t	f
// 40	封装机机构总故障	封装机机构总故障	BIT	{"false": "无", "true": "报警"}	enum	%M3071.6	PLC	→	ns4;i=41	f	t	t	f
// 41	封装机帆布电机故障	封装机帆布电机故障	BIT	{"false": "无", "true": "报警"}	enum	%M3071.7	PLC	→	ns4;i=42	f	t	t	f
// 42	封装机落料滚筒电机故障	封装机落料滚筒电机故障	BIT	{"false": "无", "true": "报警"}	enum	%M3072.0	PLC	→	ns4;i=43	f	t	t	f
// 43	封装机夹桶电机故障	封装机夹桶电机故障	BIT	{"false": "无", "true": "报警"}	enum	%M3072.1	PLC	→	ns4;i=44	f	t	t	f
// 44	封装机顶升移载电机故障	封装机顶升移载电机故障	BIT	{"false": "无", "true": "报警"}	enum	%M3072.2	PLC	→	ns4;i=45	f	t	t	f
// 45	封装机靠封装提升机滚筒故障	封装机靠封装提升机滚筒故障	BIT	{"false": "无", "true": "报警"}	enum	%M3072.3	PLC	→	ns4;i=46	f	t	t	f
// 46	输送带靠门口提升机滚筒故障	输送带靠门口提升机滚筒故障	BIT	{"false": "无", "true": "报警"}	enum	%M3072.4	PLC	→	ns4;i=47	f	t	t	f
// 47	输送带没有空桶报警	输送带没有空桶报警	BIT	{"false": "无", "true": "报警"}	enum	%M3072.5	PLC	→	ns4;i=48	f	t	t	f
// 48	采样头空开	采样头空开	BIT	{"false": "无", "true": "报警"}	enum	%M3072.6	PLC	→	ns4;i=49	f	t	t	f
// 49	采样头制动器空开	采样头制动器空开	BIT	{"false": "无", "true": "报警"}	enum	%M3072.7	PLC	→	ns4;i=50	f	t	t	f
// 50	给料皮带空开	给料皮带空开	BIT	{"false": "无", "true": "报警"}	enum	%M3073.0	PLC	→	ns4;i=51	f	t	t	f
// 51	破碎电机空开	破碎电机空开	BIT	{"false": "无", "true": "报警"}	enum	%M3073.1	PLC	→	ns4;i=52	f	t	t	f
// 52	缩分皮带空开	缩分皮带空开	BIT	{"false": "无", "true": "报警"}	enum	%M3073.2	PLC	→	ns4;i=53	f	t	t	f
// 53	缩分电机空开	缩分电机空开	BIT	{"false": "无", "true": "报警"}	enum	%M3073.3	PLC	→	ns4;i=54	f	t	t	f
// 54	斗式提升机空开	斗式提升机空开	BIT	{"false": "无", "true": "报警"}	enum	%M3073.4	PLC	→	ns4;i=55	f	t	t	f
// 55	螺旋弃料机空开	螺旋弃料机空开	BIT	{"false": "无", "true": "报警"}	enum	%M3073.5	PLC	→	ns4;i=56	f	t	t	f
// 56	采样系统动力直流电源跳闸	采样系统动力直流电源跳闸	BIT	{"false": "无", "true": "报警"}	enum	%M3073.6	PLC	→	ns4;i=57	f	t	t	f
// 57	采样系统相序报警	采样系统相序报警	BIT	{"false": "无", "true": "报警"}	enum	%M3073.7	PLC	→	ns4;i=58	f	t	t	f
// 58	采样系统急停报警	采样系统急停报警	BIT	{"false": "无", "true": "报警"}	enum	%M3074.0	PLC	→	ns4;i=59	f	t	t	f
// 59	封装系统急停报警	封装系统急停报警	BIT	{"false": "无", "true": "报警"}	enum	%M3074.1	PLC	→	ns4;i=60	f	t	t	f
// 60	破碎机堵转报警	破碎机堵转报警	BIT	{"false": "无", "true": "报警"}	enum	%M3074.2	PLC	→	ns4;i=61	f	t	t	f
// 61	采样头重故障报警	采样头重故障报警	BIT	{"false": "无", "true": "报警"}	enum	%M3074.3	PLC	→	ns4;i=62	f	t	t	f
// 62	采样头不在原点位报警	采样头不在原点位报警	BIT	{"false": "无", "true": "报警"}	enum	%M3074.4	PLC	→	ns4;i=63	f	t	t	f
// 63	最大重量	换桶最大重量	INT16	{"单位": "KG"}	unit					f	f	f	f
// 64	采样口运行反馈	采样口运行反馈	INT16	{"true": "运行", "false": "停止"}	enum	%MW3076	PLC	←	ns4;i=64	f	f	t	f
// 65	采样间隔时间来源选择	采样间隔时间来源选择	INT16	{"1": "系统批次下发时间", "2": "本地操作员设置时间"}	enum	%MW3076	PLC	←	ns4;i=65	t	f	t	f
// 66	手动设置的采样间隔时间	手动设置的采样间隔时间	INT16	{"单位": "秒"}	unit	%MW3078	PLC	←	ns4;i=66	t	f	t	f
// 67	全自动启停命令	全自动启停命令	INT16	{"1": "启动", "2": "停止"}	enum	%MW3080	PLC	←	ns4;i=67	t	f	t	f
// 68	采样头启停	检修模式上位机手动启停采样头	INT16	{"1": "启动", "2": "停止"}	enum	%MW3082	PLC	←	ns4;i=68	t	f	t	f
// 69	缩分倒计时显示	缩分倒计时显示	INT16	{"单位": "秒"}	string	%MW3084	PLC	→	ns4;i=69	f	f	t	f
// 70	溜管口运行反馈	溜管口运行反馈	BIT	{"true": "运行", "false": "停止"}	enum	%M3086.0	PLC	→	ns4;i=70	f	t	t	f
// 71	输煤皮带运行反馈	输煤皮带运行反馈	BIT	{"true": "运行", "false": "停止"}	enum	%M3086.1	PLC	→	ns4;i=71	f	t	t	f
// 72	封装机手自动反馈	封装机手自动反馈	BIT	{"true": "自动", "false": "手动"}	enum	%M3086.2	PLC	→	ns4;i=72	f	f	t	f
// 73	缓存器打开到位反馈	缓存器打开到位反馈	BIT	{"true": "开到位", "false": "未到位"}	enum	%M3086.3	PLC	→	ns4;i=73	f	t	t	f
// 74	缓存器关闭到位反馈	缓存器关闭到位反馈	BIT	{"true": "关到位", "false": "未到位"}	enum	%M3086.4	PLC	→	ns4;i=74	f	t	t	f
// 75	封装系统就绪反馈	封装系统就绪反馈	BIT	{"true": "系统就绪", "false": "未就绪"}	enum	%M3086.5	PLC	→	ns4;i=75	f	t	t	f
// 76	煤流信号反馈	煤流信号反馈	BIT	{"true": "有煤流", "false": "无煤流"}	enum	%M3086.6	PLC	→	ns4;i=76	f	t	t	f

// 正反转 - 上位机采样模式 (ns4;i=8)
const zhengfan: any = ref({
  id: 2,
  plcNodeId: 'ns4;i=8',
  signalName: '上位机采样模式_opc',
  val: ''
})

// 缩分间隔时间 - 上位机采样头缩分间隔 (ns4;i=5)
const suofenshijianjiange: any = ref({
  id: 3,
  plcNodeId: 'ns4;i=5',
  signalName: '缩分间隔时间',
  val: ''
})

const tableData = ref<any[]>([])
const operationTableData = ref<any[]>([])
const alarmTableData = ref<any[]>([])
const tongjiData = ref<any[]>([]) // 统计数据

// 优化轮询机制
const pollingInterval = ref(30000) // 30秒轮询一次
let pollingTimer: number | null = null
let isPolling = false
let pollingErrors = 0
const maxPollingErrors = 3

// 智能轮询 - 根据连接状态调整轮询频率
const startPolling = () => {
  if (isPolling) return

  isPolling = true
  pollingErrors = 0

  // 先立即执行一次
  executePollingTasks()

  // 设置定时器进行轮询
  pollingTimer = window.setInterval(() => {
    executePollingTasks()
  }, pollingInterval.value)
}

// 执行轮询任务
const executePollingTasks = async () => {
  try {
    // 并行执行多个API调用
    await Promise.allSettled([
      runData(),
      operationData(),
      alarmData()
    ])

    // 重置错误计数
    pollingErrors = 0

    // 如果WebSocket连接正常，可以减少轮询频率
    if (isWsConnected.value) {
      pollingInterval.value = 60000 // 1分钟
    } else {
      pollingInterval.value = 30000 // 30秒
    }

  } catch (error) {
    pollingErrors++
    console.error(`轮询任务执行失败 (${pollingErrors}/${maxPollingErrors}):`, error)

    // 如果连续失败次数过多，停止轮询
    if (pollingErrors >= maxPollingErrors) {
      console.error('轮询失败次数过多，停止轮询')
      stopPolling()
    }
  }
}

// 停止轮询
const stopPolling = () => {
  if (pollingTimer !== null) {
    clearInterval(pollingTimer)
    pollingTimer = null
    isPolling = false
    pollingErrors = 0
  }
}

// 手动刷新数据
const refreshData = async () => {
  try {
    isLoading.value = true
    await executePollingTasks()
    handleSuccess('数据刷新成功', '数据刷新')
  } catch (error) {
    handleError(error, '数据刷新')
  } finally {
    isLoading.value = false
  }
}
// 操作记录 - 优化版本
const operationData = async () => {
  try {
    const response = await retryOperation(async () => {
      return await apiRequest(`${url}/opc/log/operation/list`, {
        method: 'GET',
        params: { pageNum: 1, pageSize: 1000 }
      }, true)
    })

    if (response.code === 200) {
      // 优化数据处理逻辑
      response.rows.forEach((item: any) => {
        // 使用辅助函数转换显示值
        item.val = parseDisplayValue(item.newValue, item.point?.valueDesc || null)
      })
      operationTableData.value = response.rows
      connectionStatus.value.api = 'connected'
      connectionStatus.value.lastUpdate = new Date()
    } else {
      handleError(new Error('服务器返回错误'), '获取操作记录')
    }
  } catch (error) {
    handleError(error, '获取操作记录', false)
  }
}

// 报警数据 - 优化版本
const alarmData = async () => {
  try {
    const response = await retryOperation(async () => {
      return await apiRequest(`${url}/opc/alarm/list`, {
        method: 'GET',
        params: { cleared: false }
      }, true)
    })

    if (response.code === 200) {
      alarmTableData.value = response.rows || []
      connectionStatus.value.api = 'connected'
      connectionStatus.value.lastUpdate = new Date()
    } else {
      handleError(new Error('服务器返回错误'), '获取报警数据')
    }
  } catch (error) {
    handleError(error, '获取报警数据', false)
  }
}

// 获取当前批次
const getCurrentBatch = async () => {
  try {
    const response = await retryOperation(async () => {
      return await apiRequest(`${url}/opc/batch/currentBatch`, {
        method: 'GET'
      })
    })

    if (response.code === 200 && response.data) {
      currentBatch.value = response.data.batchNo || ''
      if (response.data.bucketNo) {
        const obj: any = {
          samplecard2: response.data.bucketNo, // 当前桶号
          batchNo: response.data.batchNo, // 批次号
          sampleCode: response.data.sampleCode || '', // 采样码
          sampleWeight: response.data.weight || '-', // 重量
        }
        currentTong.value = obj
        batchRecord.value = [obj]
      }
      // 如果有批次号，获取批次列表
      if (currentBatch.value) {
        batchList()
      }
      connectionStatus.value.api = 'connected'
    } else {
      console.log('暂无当前批次数据')
    }
  } catch (error) {
    handleError(error, '获取当前批次', false)
  }
}

// 获取桶列表数据 - 优化版本
const batchList = async () => {
  if (!currentBatch.value) return

  try {
    const response = await retryOperation(async () => {
      return await apiRequest(`${url}/opc/batch/pagelist`, {
        method: 'GET',
        params: { batchNo: currentBatch.value }
      })
    })

    if (response.code === 200) {
      batchRecord.value = [currentTong.value, ...response.rows]
      connectionStatus.value.api = 'connected'
      connectionStatus.value.lastUpdate = new Date()
    } else {
      handleError(new Error('服务器返回错误'), '获取桶列表数据')
    }
  } catch (error) {
    handleError(error, '获取桶列表数据', false)
  }
}

// 控制查看更多弹窗显示
const showGroupListDialog = ref(false)
const groupListData = ref<any[]>([])
const groupListDateRange = ref<[string, string]>(['', ''])

// 打开查看更多弹窗
const openGroupListDialog = async () => {
  // 默认查询最近30天
  const startTime = dayjs().subtract(30, 'day').format('YYYY-MM-DD')
  const endTime = dayjs().format('YYYY-MM-DD')
  groupListDateRange.value = [startTime, endTime]
  showGroupListDialog.value = true
  await queryGroupList()
}

// 查询分组列表
const queryGroupList = async () => {
  if (!groupListDateRange.value[0] || !groupListDateRange.value[1]) {
    ElMessage.warning('请选择日期范围')
    return
  }

  try {
    isLoading.value = true
    const response = await retryOperation(async () => {
      return await apiRequest(`${url}/opc/batch/grouplist`, {
        method: 'GET',
        params: {
          startTime: groupListDateRange.value[0],
          endTime: groupListDateRange.value[1]
        }
      })
    })

    if (response.code === 200 && response.data) {
      groupListData.value = response.data
      connectionStatus.value.api = 'connected'
    } else {
      handleError(new Error('服务器返回错误'), '获取分组列表数据')
    }
  } catch (error) {
    handleError(error, '获取分组列表数据', false)
  } finally {
    isLoading.value = false
  }
}

// 关闭分组列表弹窗
const closeGroupListDialog = () => {
  showGroupListDialog.value = false
}

// 统计数据 - 优化版本
const getTongjiData = async () => {
  const startTime = dayjs().subtract(30, 'day').format('YYYY-MM-DD')
  const endTime = dayjs().format('YYYY-MM-DD')

  try {
    const response = await retryOperation(async () => {
      return await apiRequest(`${url}/opc/batch/grouplist`, {
        method: 'GET',
        params: { startTime, endTime }
      }, true)
    })

    if (response.code === 200) {
      const result: any[] = []
      response.data.forEach((item: { list: any[]; batchNo: any; sampleCode: any }) => {
        if (item.list && item.list.length > 0) {
          item.list.forEach(bucket => {
            result.push({
              batchNo: item.batchNo,
              sampleCode: item.sampleCode,
              bucketNo: bucket.bucketNo,
              sampleWeight: bucket.sampleWeight || '-'
            })
          })
        }
      })
      tongjiData.value = result
      connectionStatus.value.api = 'connected'
      connectionStatus.value.lastUpdate = new Date()
    } else {
      handleError(new Error('服务器返回错误'), '获取统计数据')
    }
  } catch (error) {
    handleError(error, '获取统计数据', false)
  }
}


// 在组件挂载时开始轮询 - 优化版本
onMounted(() => {
  // 初始化WebSocket连接
  initWebSocket()

  // 初始化时获取所有数据
  const initializeData = async () => {
    try {
      isLoading.value = true

      // 并行执行初始数据加载
      await Promise.allSettled([
        runData(),
        operationData(),
        alarmData(),
        getTongjiData(),
        getCurrentBatch()
      ])

      // 然后开始智能轮询
      startPolling()

    } catch (error) {
      handleError(error, '初始化数据')
    } finally {
      isLoading.value = false
    }
  }

  initializeData()
})

// 在组件卸载时清理资源 - 优化版本
onUnmounted(() => {
  console.log('组件卸载，清理资源...')

  // 停止轮询
  stopPolling()

  // 关闭WebSocket连接
  if (ws) {
    try {
      ws.close()
    } catch (e) {
      console.warn('关闭WebSocket失败:', e)
    }
    ws = null
  }

  // 清除所有定时器
  if (wsReconnectTimer) {
    clearTimeout(wsReconnectTimer)
    wsReconnectTimer = null
  }

  if (wsHeartbeatTimer) {
    clearInterval(wsHeartbeatTimer)
    wsHeartbeatTimer = null
  }

  if (wsHeartbeatCheckTimer) {
    clearTimeout(wsHeartbeatCheckTimer)
    wsHeartbeatCheckTimer = null
  }

  // 停止缓存清理定时器
  stopCacheCleanup()

  // 停止调试导出定时器
  stopDebugExport()

  // 清除API缓存
  apiCache.clear()

  // 清空调试日志
  debugLogs.value = []

  console.log('资源清理完成')
})
// 斗提机启停设置
const setDouTiji = async (val: any) => {
  try {
    const response = await axios.post(url + '/opc/control/manualBucketElevatorStartStop?value=' + val, {
      // nodeId: 'ns4;i=13',
      value: val
    })
    console.log(response.data, '斗提机启停设置')
    if (response.data.code === 200) {
      ElMessage.success('指令发送成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}
//二级皮带启停设置
const setErjiPidai = async (val: any) => {
  try {
    const response = await axios.post(url + '/opc/control/manualDivisionBeltStartStop?value=' + val, {
      // nodeId: 'ns4;i=10',
      value: val
    })
    console.log(response.data, '二级皮带启停设置')
    if (response.data.code === 200) {
      ElMessage.success('指令发送成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}
//螺旋输送机启停设置
const setLuoxuanshusongji = async (val: any) => {
  try {
    const response = await axios.post(url + '/opc/control/manualScrewConveyorStartStop?value=' + val, {
      // nodeId: 'ns4;i=12',
      value: val
    })
    console.log(response.data, '螺旋输送机启停设置')
    if (response.data.code === 200) {
      ElMessage.success('指令发送成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}


//破碎机启动停止设置
const setPosuiji = async (val: any) => {
  try {
    const response = await axios.post(url + '/opc/control/manualCrusherStartStop?value=' + val, {
      nodeId: 'ns4;i=3',
      value: 1
    })
    console.log(response.data, '破碎机启动停止设置')
    if (response.data.code === 200) {
      ElMessage.success('指令发送成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}
//缩分器启动停止设置
const setSuofenqi = async (val: any) => {
  try {
    const response = await axios.post(url + '/opc/control/manualDivisionMotorStartStop?&value=' + val, {
      nodeId: '',
      value: val
    })
    console.log(response.data, '缩分器启动停止设置')
    if (response.data.code === 200) {
      ElMessage.success('指令发送成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}
//采样头缩分间隔时间设置
const setSampleHeadDivisionInterval = async (val: any) => {
  console.log(val, '采样头缩分间隔时间设置')
  try {
    // 判断是修改哪个时间
    const value = val.target ? val.target.value : val
    const response = await axios.post(url + '/opc/control/sampleHeadDivisionInterval?value=' + value)
    console.log(response.data, '采样头缩分间隔时间设置')
    if (response.data.code === 200) {
      ElMessage.success('采样头缩分间隔时间设置成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}
//手动采样头缩分间隔时间设置
const setManualSampleInterval = async (val: any) => {
  console.log(val, '手动采样头间隔时间设置')
  try {
    // 判断是修改哪个时间
    const value = val.target ? val.target.value : val
    const response = await axios.post(url + '/opc/control/manualSampleInterval?value=' + value)
    console.log(response.data, '手动采样头间隔时间设置')
    if (response.data.code === 200) {
      ElMessage.success('手动采样头间隔时间设置成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}
//自动采样间隔时间设置
// const setSampleHeadSampleInterval = async (val: any) => {
//   console.log(val, '采样间隔时间设置')
//   try {
//     // 判断是修改哪个时间
//     const value = val.target ? val.target.value : val
//     const response = await axios.post(url + '/opc/control/sampleHeadSampleInterval?value=' + value)
//     console.log(response.data, '采样间隔时间设置')
//     if (response.data.code === 200) {
//       ElMessage.success('采样间隔时间设置成功')
//       runData()
//     } else {
//       ElMessage.error('指令发送失败')
//     }
//   } catch (error) {
//     console.error('请求失败:', error)
//   }
// }

// 采样系统启动停止
const setcaiyangSystem = async (val: any) => {
  console.log(val, '当前采样系统运行模式设置')
  try {
    const response = await axios.post(url + '/opc/control/sampleSystemStartStop?value=' + val)
    console.log(response.data, '当前采样系统运行模式设置')
    if (response.data.code === 200) {
      ElMessage.success('指令发送成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}

//当前采样系统运行模式设置 , {nodeId: 'ns4;i=2',value: val?'1':'0'}
const setManualAutoMode = async (val: any) => {
  console.log(val, '当前采样系统运行模式设置')
  try {
    const response = await axios.post(url + '/opc/control/manualAutoMode?value=' + val)
    console.log(response.data, '当前采样系统运行模式设置')
    if (response.data.code === 200) {
      // 确保 manualAutoMode.value 是对象而不是布尔值
      if (typeof manualAutoMode.value !== 'object' || manualAutoMode.value === null) {
        manualAutoMode.value = { id: 1, val: val }
      } else {
        manualAutoMode.value.val = val
      }
      ElMessage.success('指令发送成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}
const setCaiYangJiModel = async (val: any) => {
  console.log(val, '当前采样模式设置')
  try {
    const response = await axios.post(url + '/opc/control/sampleMode?value=' + val)
    console.log(response.data, '当前采样模式设置')
    if (response.data.code === 200) {
      sampleMode.value.val = val // 更新本地状态
      ElMessage.success('采样模式切换成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}

// 检修模式下的采样头启停控制
const setCaiYangTouControl = async (val: any) => {
  console.log(val, '检修模式采样头启停控制')
  try {
    const response = await axios.post(url + '/opc/control/repairModeSampleHeadControl?value=' + val)
    console.log(response.data, '检修模式采样头启停控制')
    if (response.data.code === 200) {
      ElMessage.success(val === 1 ? '采样头启动成功' : '采样头停止成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
    ElMessage.error('请求失败')
  }
}

// 制样方式设置（对应手动模式一级皮带启停命令）
const setZhiYangFangShi = async (val: any) => {
  console.log(val, '制样方式设置')
  try {
    // val: 1=正转(制样口), 2=反转(溜管口), 3=停止
    const response = await axios.post(url + '/opc/control/manualBelt1StartStop?value=' + val)
    console.log(response.data, '制样方式设置')
    if (response.data.code === 200) {
      zhiyangFangshi.value.val = val // 更新本地状态
      ElMessage.success('制样方式切换成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}
const jinjitingzhi = async (val: any) => {
  try {
    const response = await axios.post(url + '/opc/control/emergencyStop?value=' + val, {
      nodeId: 'ns4;i=14',
      value: '1'
    })
    console.log(response.data, '初级给料皮带启停设置')
    if (response.data.code === 200) {
      ElMessage.success('指令发送成功')
      runData()
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}
const guzhangfuwei = async (val: any) => {
  try {
    const response = await axios.post(url + '/opc/control/faultReset?value=' + val)
    console.log(response.data, '故障反馈设置')
    if (response.data.code === 200) {
      ElMessage.success('指令发送成功')
      runData();
      alarmData();
    } else {
      ElMessage.error('指令发送失败')
    }
  } catch (error) {
    console.error('请求失败:', error)

  }
}

const jiechu = async (item: any) => {
  try {
    const response = await axios.put(url + '/opc/alarm/clear/' + item.id)
    if (response.data.code === 200) {
      ElMessage.success('解除报警成功')
      alarmData();
    } else {
      ElMessage.error('解除报警失败')
    }
  } catch (error) {
    console.error('请求失败:', error)
  }
}
</script>

<template>
  <el-config-provider :locale="locale">
    <div class="app-container">
    <div class="top">
      <img id="bg-image" src="./assets/header.png" alt="">
      <span>福泉公司1号火车采样机</span>
    </div>
    <div class="belt-sampling">
      <div class="left">
        <div class="item yunxingrizhi">
          <div class="title">运行日志</div>
          <el-table :data="tableData" :max-height="240">
            <el-table-column prop="updateTime" label="时间"  />
            <el-table-column prop="point.signalName" label="设备" />
            <el-table-column prop="val" label="状态" width="100">
              <template #default="scope">
                <div>{{ scope.row.val }}</div>
              </template>
            </el-table-column>
          </el-table>
        </div>
        <div class="item caozuojilu">
          <div class="title">操作记录</div>
          <el-table :data="operationTableData" :max-height="240">
            <el-table-column prop="operateTime" label="时间" />
            <el-table-column prop="point.signalName" label="设备" />
            <el-table-column prop="newValue" label="状态"  width="70">
              <template #default="scope">
                <div>{{ scope.row.val }}</div>
              </template>
            </el-table-column>
            <el-table-column prop="operator" label="操作员"  width="80"/>
          </el-table>
        </div>
        <div class="item baojingxinxi">
          <div class="title">报警信息</div>
          <el-table :data="alarmTableData" :max-height="240">
            <el-table-column prop="alarmTime" label="时间" />
            <el-table-column prop="alarmDesc" label="报警信息" />
            <el-table-column label="操作"  width="90">
              <template #default="scope">
                <el-button type="primary" class="small" @click="jiechu(scope.row)">解除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
      <div class="center">
        <div class="devices">
          <div class="center-top">
            <div />
            <div class="oprate">
              <img width="24" src="./assets/screen/common/video.png" alt="">
              <div>
                <span class="model">当前运行模式:</span>
                <el-switch v-model="manualAutoModeSwitch" inline-prompt active-text="自动" inactive-text="手动"
                  style="--el-switch-on-color: #1890ff; --el-switch-off-color: rgba(255, 255, 255, 0.5)" disabled />
              </div>
            </div>
            <!-- 右上角状态信息 -->
            <div class="status-info-panel">
              <div class="status-info-item">
                <span class="info-label">当前批次</span>
                <span class="info-value">{{ currentBatch || '-' }}</span>
              </div>
              <div class="status-info-item">
                <span class="info-label">当前采样方案</span>
                <span class="info-value">{{ jiangejiangshijijiishi.val || '-' }}<span class="info-unit">s</span></span>
              </div>
              <div class="status-info-item">
                <span class="info-label">采样头动作倒计时</span>
                <span class="info-value">{{ caiyangtoudongzuodaojishi.val || '-' }}<span
                    class="info-unit">s</span></span>
              </div>
              <div class="status-info-item">
                <span class="info-label">缩分停止倒计时</span>
                <span class="info-value">{{ suofendaojishixianshi.val || '-' }}<span class="info-unit">s</span></span>
              </div>
            </div>
          </div>
          <div class="device-content">
            <img class="caiyang" width="95%" src="./assets/screen/belt-sampling/cai.png" alt="">
            <div class="caiyangtong">
              <div class="caiyangtong-left caiyangtong-item" @click="prevBatch">&lt;</div>
              <div class="caiyangtong-center">
                <div class="center-item">
                  <img src="./assets/screen/belt-sampling/down.png" alt="">
                  <img width="35" src="./assets/screen/belt-sampling/bottle.png" alt="">
                  <!-- 查看更多 -->
                  <div class="more-btn-wrapper">
                    <div class="btn blue more-btn" @click="openGroupListDialog">查看更多</div>
                  </div>
                </div>
                <div class="bottle-content">
                  <table>
                    <tbody>
                      <tr>
                        <td>序号</td>
                        <td>{{ currentBatchIndex + 1 }}</td>
                      </tr>
                      <tr>
                        <td>当前桶号</td>
                        <td>{{ batchRecord[currentBatchIndex]?.samplecard2 || '-' }}</td>
                      </tr>
                      <tr>
                        <td>批次号</td>
                        <td>{{ batchRecord[currentBatchIndex]?.batchNo || '-' }}</td>
                      </tr>
                      <tr>
                        <td>重量</td>
                        <td>{{ ((batchRecord[currentBatchIndex]?.sampleWeight || 0) / 1000).toFixed(2) }}kg</td>
                      </tr>
                    </tbody>
                  </table>
                </div>
              </div>
              <div class="caiyangtong-right caiyangtong-item" @click="nextBatch">&gt;</div>
            </div>
            <div class="infos">
              <div class="caiyangtou info-item">
                <div class="caiyangtou-item">
                  <div class="name">采样头</div>
                  <div>
                    <i
                      :class="{ 'green': String(caiyangtou.val) === 'true' || String(caiyangtou.val) === '1', 'red': String(caiyangtou.val) !== 'true' && String(caiyangtou.val) !== '1' }"></i>
                    <span>{{ (String(caiyangtou.val) === 'true' || String(caiyangtou.val) === '1') ? '运行' : '停止'
                      }}</span>
                  </div>
                </div>
                <!-- 检修模式下显示启动停止按钮 -->
                <div v-if="manualAutoMode.val === '3'" class="caiyangtou-controls">
                  <div class="btns">
                    <div>
                      <div class="btn blue" @click="setCaiYangTouControl(1)">启动</div>
                    </div>
                    <div>
                      <div class="btn red" @click="setCaiYangTouControl(2)">停止</div>
                    </div>
                  </div>
                </div>
                <div style="border-top: 1px solid #1890ff;padding-top:4px;">
                  <div class="btn blue history" @click="openHistoryDialog">查询历史</div>
                </div>
              </div>
              
              <div class="chujigeiliaopidai">
                <div class="caiyangtou-item" style="border-bottom:1px solid #1890ff;">
                    <div class="name" style="width:100px;">初级给料皮带</div>
                    
                    <div>
                        <i :class="{ 'red': chujigeiliaopidai.val == 3, 'green': chujigeiliaopidai.val != 3 }"></i>
                        <span>{{ chujigeiliaopidai.val == 3? '故障' :"正常"}}</span>
                      </div>
                </div>
                <div class="chujigeiliaopidai-item">
                  <div style="border-right: 1px solid #1890ff;">
                    <div style="border-bottom:1px solid #1890ff;">制样口</div>
                    <div>溜管口</div>
                  </div>
                  <div>
                    <div style="border-bottom:1px solid #1890ff;">
                      <i :class="{ 'green':( zhengfan.val == 2||chujigeiliaopidai.val==2), 'red': (zhengfan.val != 1&&chujigeiliaopidai.val!=1) }"></i>
                      <span>{{ (zhengfan.val == 1||chujigeiliaopidai.val==1) ? '运行' : '停止' }}</span>
                    </div>
                    <div>
                      <i :class="{ 'green': (zhengfan.val == 1||chujigeiliaopidai.val==1), 'red': zhengfan.val != 2&&chujigeiliaopidai.val!=2 }"></i>
                      <span>{{( zhengfan.val == 2 ||chujigeiliaopidai.val==2)? '运行' : '停止' }}</span>
                    </div>

                  </div>
                  <div class="btns">
                    <div>
                      <div class="btn blue" @click="setZhiYangFangShi(1)">启动</div>
                    </div>
                    <div>
                      <div class="btn blue" @click="setZhiYangFangShi(2)">启动</div>
                    </div>
                  </div>
                  <div class="btns">
                    <div>
                      <div class="btn red"  @click="setZhiYangFangShi(3)">停止</div>
                    </div>
                  </div>
                  <div>

                  </div>
                </div>
              </div>
              <div class="posuiji info">
                <div class="name">破碎机</div>
                <div>
                  <i :class="{ 'green': posuiji.val == 1, 'red': posuiji.val != 1 }"></i>
                  <span>{{ posuiji.val == 1 ? '运行' : '停止' }}</span>
                </div>
                <div class="btns">
                  <div>
                    <div class="btn blue" @click="setPosuiji(1)">启动</div>
                  </div>
                  <div>
                    <div class="btn red" @click="setPosuiji(2)">停止</div>
                  </div>
                </div>
              </div>
              <div class="suofenqi info">
                <div class="name" style="width:60px;">缩分器</div>
                <div>
                  <i :class="{ 'green': suofenqi.val == 1, 'red': suofenqi.val != 1 }"></i>
                  <span>{{ suofenqi.val == 1 ? '运行' : '停止' }}</span>
                </div>
                <div class="btns">
                  <div>
                    <div class="btn blue" @click="setSuofenqi(1)">启动</div>
                  </div>
                  <div>
                    <div class="btn red" @click="setSuofenqi(2)">停止</div>
                  </div>
                </div>
              </div>
              <div class="cijigeiliaopidai info">
                <div class="flex">
                  <div class="name">二级皮带</div>
                  <div>
                    <i :class="{ 'green': erjipidai.val == 1, 'red': erjipidai.val != 1 }"></i>
                    <span>{{ erjipidai.val == 1 ? '运行' : '停止' }}</span>
                  </div>
                </div>

                <div class="btns">
                  <div>
                    <div class="btn blue" @click="setErjiPidai(1)">启动</div>
                  </div>
                  <div>
                    <div class="btn red" @click="setErjiPidai(2)">停止</div>
                  </div>
                </div>
              </div>

              <div class="luoxuanshusongji info">
                <div class="flex">
                  <div class="name">螺旋<br />输送机</div>
                  <div style="line-height: 36px;">
                    <i :class="{ 'green': luoxuanshusongji.val == 1, 'red': luoxuanshusongji.val != 1 }"></i>
                    <span>{{ luoxuanshusongji.val == 1 ? '运行' : '停止' }}</span>
                  </div>
                </div>
                <div class="btns">
                  <div>
                    <div class="btn blue" @click="setLuoxuanshusongji(1)">启动</div>
                  </div>
                  <div>
                    <div class="btn red" @click="setLuoxuanshusongji(2)">停止</div>
                  </div>
                </div>
              </div>
              <div class="tishengji info">
                <div class="flex">
                  <div class="name">斗提机</div>
                  <div>
                    <i :class="{ 'green': doutiji.val == 1, 'red': doutiji.val != 1 }"></i>
                    <span>{{ doutiji.val == 1 ? '运行' : '停止' }}</span>
                  </div>
                </div>
                <div class="btns">
                  <div>
                    <div class="btn blue" @click="setDouTiji(1)">启动</div>
                  </div>
                  <div>
                    <div class="btn red" @click="setDouTiji(2)">停止</div>
                  </div>
                </div>
              </div>

              
              

            </div>
          </div>
        </div>

      </div>
      <div class="right">
        <div class="item task">
          <div class="title">采样系统</div>
          <div class="caiyang-system-panel">
            <!-- 第一行：采样模式（滑块样式） -->
            <div class="panel-row">
              <div class="row-label">采样模式</div>
              <div class="slider-buttons-group">
                <div class="slider-background" :style="{
                  left: manualAutoMode.val === '2' ? '0%' : manualAutoMode.val === '1' ? '33.33%' : '66.66%',
                  width: '33.33%'
                }"></div>
                
                <div class="slider-btn" :class="{ 'active': manualAutoMode.val === '2' }"
                  @click="setManualAutoMode('2')">自动
                </div>
                <div class="slider-btn" :class="{ 'active': manualAutoMode.val === '1' }"
                  @click="setManualAutoMode('1')">手动
                </div>
                <div class="slider-btn" :class="{ 'active': manualAutoMode.val === '3' }"
                  @click="setManualAutoMode('3')">检修
                </div>
              </div>
            </div>
            <!-- 第二行：制样方式（滑块样式） -->
            <div class="panel-row">
              <div class="row-label">制样方式</div>
              <div class="slider-buttons-group">
                <div class="slider-background" :style="{
                  left: sampleMode.val === '1' ? '0%' : '50%',
                  width: '50%'
                }"></div>
                <div class="slider-btn" :class="{ 'active': sampleMode.val === '1' }" @click="setCaiYangJiModel('1')">
                  制样口
                </div>
                <div class="slider-btn" :class="{ 'active': sampleMode.val === '2' }" @click="setCaiYangJiModel('2')">
                  溜管口
                </div>
              </div>
            </div>
            <!-- 第三行：手动模式 -->
            <div class="panel-row">
              <div class="row-label">手动模式</div>
              <div class="row-buttons">
                <div class="system-btn" @click="setcaiyangSystem(1)">启动</div>
                <div class="system-btn stop-btn" @click="setcaiyangSystem(2)">停止</div>
              </div>
            </div>
            <!-- 第四行：紧急作业 -->
            <div class="panel-row">
              <div class="row-label">紧急作业</div>
              <div class="row-buttons">
                <div class="system-btn stop-btn" @click="jinjitingzhi(1)">紧急停止</div>
                <div class="system-btn" @click="guzhangfuwei(1)">故障复位</div>
              </div>
            </div>
          </div>
        </div>
        <div class="item task status-panel">
          <div class="title">采样系统</div>
          <div class="status-content">
            <!-- 输入框区域 -->
            <div class="input-section">
              <!-- <div class="input-row">
                <label>自动采样间隔时间</label>
                <div class="input-wrapper">
                  <input type="number" v-model="jiangejiangshijijiishi.val"  @change="setSampleHeadSampleInterval" />
                  <span class="unit">s</span>
                </div>
              </div> -->
              <div class="input-row">
                <label>手动采样间隔时间</label>
                <div class="input-wrapper">
                  <input type="number" v-model="shodongcaiyangtougeshijian.val" @change="setManualSampleInterval" />
                  <span class="unit">s</span>
                </div>
              </div>

              <div class="input-row">
                <label>缩分间隔时间</label>
                <div class="input-wrapper">
                  <input type="number" v-model="suofenshijianjiange.val" @change="setSampleHeadDivisionInterval" />
                  <span class="unit">s</span>
                </div>
              </div>
            </div>

            <!-- 状态指示区域 - 2x2网格布局 -->
            <div class="status-indicators">
              <div class="status-item">
                <span class="status-label">制样口运行中</span>
                <span class="status-dot " :class="{ 'active': zhiyangkouyunxingfankui.val === '1' }"></span>
              </div>
              <div class="status-item">
                <span class="status-label">输煤皮带运行中</span>
                <span class="status-dot" :class="{ 'active': chujigeiliaopidai.val == 1 }"></span>
              </div>
              <div class="status-item">
                <span class="status-label">溜管口运行中</span>
                <span class="status-dot" :class="{ 'active': liuguankouyunxingfankui.val === '2' }"></span>
              </div>
              <div class="status-item">
                <span class="status-label">采样系统急停</span>
                <span class="status-dot " :class="{ 'error': caiyangxitongjiting.val === 'true' }"></span>
              </div>
            </div>

            <!-- 日志导出按钮 -->
            <div class="log-export-btn-wrapper">
              <div class="log-export-trigger-btn" @click="openLogExportDialog">
                <span>日志导出</span>
              </div>
            </div>
          </div>
        </div>
        <div class="item task fengzhuang-panel">
          <div class="title">封装系统</div>
          <div class="fengzhuang-content">
            <!-- 封装模式 -->
            <div class="fengzhuang-row">
              <span class="fz-label">封装模式</span>
              <div class="slider-buttons-group fz-slider">
                <div class="slider-background" :style="{
                  left: fengzhuangjishouzidong.val === 'false' ? '0%' : '50%',
                  width: '50%'
                }"></div>
                <div class="slider-btn" :class="{ 'active': fengzhuangjishouzidong.val === 'false' }">手动</div>
                <div class="slider-btn" :class="{ 'active': fengzhuangjishouzidong.val === 'true' }">自动</div>
              </div>
            </div>

            <!-- 当前重量 -->
            <div class="fengzhuang-row">
              <span class="fz-label">当前重量</span>
              <div class="fz-value-box">
                <span class="fz-value">{{ ((yangtonzhongliang.val || 0) / 1000).toFixed(2) }}</span>
                <span class="fz-unit">kg</span>
              </div>
            </div>

            <!-- 换桶重量 -->
            <div class="fengzhuang-row">
              <span class="fz-label">换桶重量</span>
              <div class="input-wrapper fz-input">
                <input type="number" v-model="huanbuckezhongliang"
                  @change="setHuanBuckeZhongLiang(huanbuckezhongliang)" />
                <span class="unit">kg</span>
              </div>
            </div>

            <!-- 状态指示器 - 2列布局 -->
            <div class="fengzhuang-status">
              <div class="fz-status-item">
                <span class="status-label">缓存器打开到位</span>
                <span class="status-dot" :class="{ 'active': huancunqidakaidaowei.val === 'true' }"></span>
              </div>

              <div class="fz-status-item">
                <span class="status-label">封装系统就绪</span>
                <span class="status-dot" :class="{ 'active': fengzhuangxitongjiuxu.val === 'true' }"></span>
              </div>
              <div class="fz-status-item">
                <span class="status-label">缓存器关闭到位</span>
                <span class="status-dot" :class="{ 'active': huancunqiguanbidaowei.val === 'true' }"></span>
              </div>
              <div class="fz-status-item">
                <span class="status-label">封装机补桶中</span>
                <span class="status-dot" :class="{ 'active': fengzhuangjibuzongzhong.val === 'true' }"></span>
              </div>
              <div class="fz-status-item">
                <span class="status-label">封装系统故障</span>
                <span class="status-dot " :class="{ 'error': fengzhuangjijigouguzhang.val === 'true' }"></span>
              </div>

              <div class="fz-status-item">
                <span class="status-label">封装机出桶就绪</span>
                <span class="status-dot" :class="{ 'active': fengzhuangjichutongjiuxu.val === 'true' }"></span>
              </div>
              <div class="fz-status-item">
                <span class="status-label">封装机出桶中</span>
                <span class="status-dot" :class="{ 'active': fengzhuangjichutongzhong.val === 'true' }"></span>
              </div>

              <div class="fz-status-item">
                <span class="status-label">封装系统急停</span>
                <span class="status-dot " :class="{ 'error': fengzhuangxitongjiting.val === 'true' }"></span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <el-dialog v-model="historyDialogVisible" title="采样头历史记录" width="26%" :before-close="closeHistoryDialog"
      class="dark-dialog">
      <el-table :data="historyData" style="width: 100%" max-height="200px">
        <el-table-column prop="batchNo" label="批次号" width="180" />
        <el-table-column prop="point.signalName" label="名称" width="120" />
        <el-table-column prop="newValue" label="状态" width="120">
          <template #default="scope">
            {{ scope.row.val }}
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>

    <!-- 分组列表弹窗 -->
    <el-dialog 
      v-model="showGroupListDialog" 
      title="批次分组列表" 
      width="70%" 
      :before-close="closeGroupListDialog"
      class="dark-dialog"
    >
      <div class="group-list-dialog-content">
        <!-- 日期范围选择 -->
        <div class="dialog-query-row">
          <label class="dialog-query-label">日期范围</label>
          <el-date-picker
            v-model="groupListDateRange"
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            format="YYYY-MM-DD"
            value-format="YYYY-MM-DD"
            size="default"
            style="width: 250px; flex-shrink: 0;"
          />
          <el-button type="primary" @click="queryGroupList" :loading="isLoading" style="margin-left: 10px;">查询</el-button>
        </div>

        <!-- 数据表格 -->
        <el-table 
          :data="groupListData" 
          style="width: 100%" 
          max-height="500px"
          border
        >
          <el-table-column prop="batchNo" label="批次号" width="180" />
          <el-table-column prop="sampleCode" label="采样码" width="150" />
          <el-table-column label="桶列表" min-width="300">
            <template #default="scope">
              <div v-if="scope.row.list && scope.row.list.length > 0">
                <div v-for="(item, index) in scope.row.list" :key="index" class="bucket-item">
                  <span>桶号: {{ item.bucketNo }}</span>
                  <span>重量: {{ item.sampleWeight || '-' }}</span>
                </div>
              </div>
              <span v-else>-</span>
            </template>
          </el-table-column>
        </el-table>
      </div>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="closeGroupListDialog">关闭</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 日志导出对话框 -->
    <el-dialog 
      v-model="showLogExportDialog" 
      title="日志导出" 
      width="500px" 
      class="dark-dialog log-export-dialog"
    >
      <div class="log-export-dialog-content">
        <!-- 日期范围选择 -->
        <div class="dialog-export-row">
          <label class="dialog-export-label">日期范围</label>
          <el-date-picker
            v-model="logExportDateRange"
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            format="YYYY-MM-DD"
            value-format="YYYY-MM-DD"
            size="default"
            style="width: 100%;"
          />
        </div>

        <!-- 日志类型选择 -->
        <div class="dialog-export-row">
          <label class="dialog-export-label">日志类型</label>
          <el-select 
            v-model="logExportType" 
            placeholder="请选择日志类型"
            size="default"
            style="width: 100%;"
          >
            <el-option
              v-for="item in logTypeOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </div>
      </div>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="showLogExportDialog = false">取消</el-button>
          <el-button type="primary" @click="exportLogs" :loading="isLoading">导出</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 调试面板 -->
    <div v-if="debugMode" class="debug-panel">
      <div class="debug-header">
        <h3>🔍 调试面板</h3>
        <div class="debug-controls">
          <button @click="exportDebugInfo" class="debug-btn">导出信息</button>
          <button @click="resetPerformanceMetrics" class="debug-btn">重置指标</button>
          <button @click="clearErrors" class="debug-btn">清除错误</button>
          <button @click="refreshData" class="debug-btn">刷新数据</button>
          <button @click="reconnectWebSocket" class="debug-btn">重连WS</button>
        </div>
      </div>

      <div class="debug-content">
        <div class="debug-section">
          <h4>连接状态</h4>
          <p>WebSocket: {{ connectionStatus.websocket }}</p>
          <p>API: {{ connectionStatus.api }}</p>
          <p>最后更新: {{ connectionStatus.lastUpdate?.toLocaleTimeString() || '无' }}</p>
        </div>

        <div class="debug-section">
          <h4>性能指标</h4>
          <p>API请求: {{ performanceMetrics.apiRequests }}</p>
          <p>API错误: {{ performanceMetrics.apiErrors }}</p>
          <p>WS消息: {{ performanceMetrics.websocketMessages }}</p>
          <p>WS错误: {{ performanceMetrics.websocketErrors }}</p>
          <p>缓存命中: {{ performanceMetrics.cacheHits }}</p>
          <p>缓存未命中: {{ performanceMetrics.cacheMisses }}</p>
          <p>平均响应时间: {{ performanceMetrics.averageResponseTime.toFixed(2) }}ms</p>
        </div>

        <div class="debug-section">
          <h4>系统状态</h4>
          <p>轮询状态: {{ isPolling ? '运行中' : '已停止' }}</p>
          <p>轮询错误: {{ pollingErrors }}</p>
          <p>缓存大小: {{ apiCache.size }}</p>
          <p>错误数量: {{ errorMessages.length }}</p>
          <p>加载状态: {{ isLoading ? '加载中' : '空闲' }}</p>
        </div>

        <div class="debug-section" v-if="errorMessages.length > 0">
          <h4>最近错误</h4>
          <div class="error-list">
            <div v-for="(error, index) in errorMessages.slice(0, 5)" :key="index" class="error-item">
              {{ error }}
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 调试按钮 -->
    <div class="debug-toggle">
      <button @click="toggleDebugMode" class="debug-toggle-btn">
        {{ debugMode ? '关闭调试' : '开启调试' }}
      </button>
    </div>
    </div>
  </el-config-provider>
</template>

<style>
/* 样式已拆分到 src/styles/ 目录下 */
/* 通过 main.ts 导入: import './styles/index.css' */
</style>
