<template>
  <div class="index-page" @wheel="handleWheel">
    <div class="index-page-container" ref="indexPageContainerRef">
      <div
        class="map-container"
        :style="{
          cursor: isDrag ? 'pointer' : 'default',
          transformOrigin: '0 0',
          transform: `scale(${isSizeRadio})`,
          height: imgBgObj.height + 'px',
          width: imgBgObj.width + 'px'
        }"
      >
        <div
          :class="isDrag ? 'indexpage-container-active' : 'indexpage-container'"
          v-if="imgBgObj.imgUrl"
          v-drag="isDrag"
          :style="{ scale: 1, transformOrigin: '0 0' }"
          ref="draggableElement"
        >
          <div class="indexpage-container-box">
            <img :src="imgBgObj.imgUrl" class="map-bg" />
            <div class="point-information">
              <div class="line-list" v-if="legendObj.driveLineShow">
                <svg id="svg" :width="imgBgObj.width" :height="imgBgObj.height">
                  <template v-for="(item, index) in state.mapRouteList" :key="index">
                    <template v-if="item.method == 0">
                      <!-- 直线 -->
                      <line
                        :x1="Number(item.startPointX) * radio"
                        :y1="Number(item.startPointY) * radio"
                        :x2="Number(item.endPointX) * radio"
                        :y2="Number(item.endPointY) * radio"
                        :stroke="item.isSelect ? '#f48924' : '#2d72d9'"
                        :stroke-width="4 * radio"
                      />
                    </template>
                    <!-- 曲线 -->
                    <template v-else>
                      <path
                        :d="getCurvePath(item)"
                        :stroke="item.isSelect ? '#f48924' : '#2d72d9'"
                        :stroke-width="4 * radio"
                        fill="none"
                      />
                    </template>
                  </template>
                </svg>
              </div>

              <!-- 小车 -->
              <div v-for="(item, index) in testCarList" :key="item.macAddress">
                <el-popover placement="bottom">
                  <template #reference>
                    <div
                      class="car-item"
                      v-if="legendObj.carShow"
                      :style="item.style"
                      @dblclick="carDbClick(item, index)"
                    >
                      <div style="font-size: 15px; color: #fff; z-index: 9999; background: #cb00c7">
                        {{ item.robotNo || '' }}
                      </div>
                      <img
                        src="@/assets/imgs/indexPage/car2.png"
                        style="position: absolute; top: 0; left: 0; width: 100%; height: 100%"
                      />
                    </div>
                  </template>
                  <div class="popover-robot-no">{{ item.robotNo }}</div>
                </el-popover>
              </div>
              <div
                class="map-point-list"
                v-for="(item, index) in state.allMapPointInfo"
                :key="index"
                :style="{
                  left:
                    (Number(item.locationX) - Number(item.locationWidePx) / 2) * Number(radio) +
                    'px',
                  top:
                    (Number(item.locationY) - Number(item.locationDeepPx) / 2) * Number(radio) +
                    'px',
                  width: Number(item.locationWidePx) * Number(radio) + 'px',
                  height: Number(item.locationDeepPx) * Number(radio) + 'px'
                }"
              >
                <!-- 1 路径点 -->
                <el-tooltip effect="light" placement="top">
                  <template #content>
                    <div v-if="item.type === 2">
                      <div
                        class="indexpage-popover-item"
                        v-if="item.dataList && item.dataList[0]?.laneName"
                      >
                        <div> 所属线库： </div>
                        <div>
                          {{ item.dataList[0]?.laneName || '' }}
                        </div>
                      </div>
                      <div
                        class="indexpage-popover-item"
                        v-if="item.dataList && item.dataList[0]?.areaName"
                      >
                        <div> 所属区域： </div>
                        <div>
                          {{ item.dataList[0]?.areaName || '' }}
                        </div>
                      </div>
                      <div class="indexpage-popover-item">
                        <div> 库位号： </div>
                        <div>
                          <div
                            v-for="(location, locationIndex) in item.dataList"
                            :key="locationIndex"
                          >
                            {{ location.locationNo || '' }}
                          </div>
                        </div>
                      </div>
                    </div>
                    <div v-else-if="item.type === 3">
                      <div class="indexpage-popover-item">
                        <div> 设备编号： </div>
                        <div>
                          {{ item.dataObj?.deviceNo || '' }}
                        </div>
                      </div>
                      <div class="indexpage-popover-item">
                        <div> 设备类型： </div>
                        <div>
                          {{ filterTypeFun(item.dataObj.deviceType) || '' }}
                        </div>
                      </div>
                    </div>
                    <div v-else>
                      <div class="indexpage-popover-item">
                        <div> 节点类型： </div>
                        <div>{{
                          item.type == 1
                            ? '路径点'
                            : item.type == 4
                              ? '停车点'
                              : item.type == 5
                                ? '区域变更点'
                                : item.type == 6
                                  ? '等待点'
                                  : ''
                        }}</div>
                        <div>
                          {{ item.sortNum || '' }}
                        </div>
                      </div>
                    </div>
                  </template>
                  <div>
                    <div
                      v-if="
                        item.type === 1 &&
                        legendObj.sortNumberShow &&
                        item.sortNum &&
                        sortNumberShow
                      "
                      class="sort-num"
                      :style="getSortNumStyle(item, index)"
                    >
                      {{ item.sortNum }}
                    </div>
                    <div
                      v-if="
                        item.type !== 1 &&
                        legendObj.sortNumberShow &&
                        item.sortNum &&
                        sortNumberShow
                      "
                      class="sort-num-location"
                      :style="getSortNumLocationStyle(item, index)"
                    >
                      {{ item.sortNum }}
                    </div>
                    <div
                      v-if="item.type === 1"
                      :style="{
                        width: Number(item.locationWidePx) * Number(radio) + 'px',
                        height: Number(item.locationDeepPx) * Number(radio) + 'px',
                        backgroundColor: '#000',
                        borderRadius: '50%'
                      }"
                    >
                    </div>
                    <!-- 库位点 -->
                    <img
                      v-else-if="item.type === 2"
                      src="@/assets/imgs/indexPage/bin-location.png"
                      :style="nodeStyle(item, index)"
                      @dblclick="storeClick(item)"
                    />
                    <!-- 设备点 -->
                    <img
                      v-else-if="item.type === 3"
                      :src="item.dataObj.mapImageUrl || '@/assets/imgs/indexPage/equipment.png'"
                      style="background: #fff"
                      :style="nodeStyle(item, index)"
                    />
                    <!-- 停车点 -->
                    <img
                      v-else-if="item.type === 4"
                      src="@/assets/imgs/indexPage/stop-car.png"
                      style="background: #fff"
                      :style="nodeStyle(item, index)"
                    />
                    <!-- 区域变更点 -->
                    <img
                      v-else-if="item.type === 5"
                      src="@/assets/imgs/indexPage/change-point.png"
                      style="background: #fff"
                      :style="nodeStyle(item, index)"
                    />
                    <!-- 等待点 -->
                    <img
                      v-else-if="item.type === 6"
                      src="@/assets/imgs/indexPage/wait-point.png"
                      style="background: #fff"
                      :style="nodeStyle(item, index)"
                    />
                  </div>
                </el-tooltip>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- 左下角图层 -->
  <div class="affix-container-left" v-if="!isAllBoard">
    <div class="affix-container-left-box">
      <div
        class="legend-list"
        :style="{
          height: legendObj.legendShow ? '126px' : '0',
          overflow: 'hidden',
          transition: 'all 0.3s ease-in-out'
        }"
      >
        <div class="legend-item" v-for="item in layerList" :key="item.type">
          <div class="legend-item-left"> {{ item.name }} </div>
          <el-icon
            class="legend-item-img"
            size="20"
            v-if="item.isShow"
            @click="changDriveLineShow(item)"
            color="#1677FF"
            ><View
          /></el-icon>
          <el-icon
            class="legend-item-img"
            size="20"
            v-if="!item.isShow"
            @click="changDriveLineShow(item)"
            color="#444444"
            ><Hide
          /></el-icon>
        </div>
      </div>
      <div class="legend-item-bottom" @click="legendObj.legendShow = !legendObj.legendShow">
        <div class="legend-item-bottom-left"> 图例 </div>
        <el-icon size="22" v-if="legendObj.legendShow" color="#98A4BF"><CaretTop /></el-icon>
        <el-icon size="22" v-else color="#98A4BF"><CaretBottom /></el-icon>
      </div>
    </div>
  </div>

  <!-- 右下角的功能 -->
  <div class="affix-container-right" v-if="!isAllBoard">
    <div class="item" @click="changeIsDrag">
      <img src="@/assets/imgs/indexPage/hand.png" />
    </div>
    <div class="item">
      <img src="@/assets/imgs/indexPage/zoom.png" @click="changeSize('add')" />
    </div>
    <div class="item">
      <img src="@/assets/imgs/indexPage/search.png" @click="changeSize('sub')" />
    </div>
    <div class="item">
      <img src="@/assets/imgs/indexPage/full-screen.png" @click="toggleFullScreen" />
    </div>
  </div>
  <storeDialog ref="storeDialogRef" @success="emitParent" />
  <carDialog ref="carDialogRef" />
</template>

<script setup>
import {
  ref,
  defineComponent,
  reactive,
  nextTick,
  onMounted,
  onBeforeUnmount,
  onUnmounted
} from 'vue'
import * as MapApi from '@/api/map/map'
import WebSocketClient from '../webSocket.js'
import storeDialog from './storeDialog.vue'
import { color } from 'echarts'
import { resetDragPosition } from '@/utils/drag'
import carDialog from './carDialog.vue'
import { is } from 'bpmn-js/lib/util/ModelUtil'
import JSONBigInt from 'json-bigint'
import { propTypes } from '@/utils/propTypes'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import dayjs from 'dayjs'
import { throttle, debounce } from 'lodash-es'

const message = useMessage() // 消息弹窗

const carDialogRef = ref(null)
const socketClient = ref(null)
const router = useRouter() // 路由对象
const emit = defineEmits(['transmitMapId'])
const storeDialogRef = ref(null) // 仓库信息弹窗
const list = ref([])
const testCarList = ref([]) //小车数组
const carWidth = ref(226)
const carHeight = ref(124)

// 定义属性
const props = defineProps({
  isAllBoard: propTypes.bool.def(false), // 当前选中的链接
  isFullScreen: {
    type: Boolean,
    default: () => false
  },
  sortNumberShow: {
    type: Boolean,
    default: () => true
  }
})

//节点样式
const nodeStyle = (item, index) => {
  return {
    verticalAlign: 'top',
    objectFit: 'cover',
    width: Number(item.locationWidePx) * Number(radio.value) + 'px',
    height: Number(item.locationDeepPx) * Number(radio.value) + 'px',
    borderRadius: '3px'
  }
}
//sortNum路径点的样式
const getSortNumStyle = (item, index) => {
  let leftNum = 0
  if (item.sortNum.toString().length === 1) {
    leftNum = 3
  } else if (item.sortNum.toString().length === 2) {
    leftNum = 7
  } else if (item.sortNum.toString().length === 3) {
    leftNum = 10
  } else if (item.sortNum.toString().length === 4) {
    leftNum = 14
  } else if (item.sortNum.toString().length === 5) {
    leftNum = 18
  } else if (item.sortNum.toString().length === 6) {
    leftNum = 21
  } else if (item.sortNum.toString().length === 7) {
    leftNum = 25
  } else if (item.sortNum.toString().length === 8) {
    leftNum = 28
  } else if (item.sortNum.toString().length === 9) {
    leftNum = 31
  }
  return {
    left: Number(item.locationWidePx) / 2 - leftNum + 'px',
    top: 6 + 'px'
  }
}
//sortNum非路径点的样式
const getSortNumLocationStyle = (item, index) => {
  let leftNum = 0
  if (item.sortNum.toString().length === 1) {
    leftNum = 3
  } else if (item.sortNum.toString().length === 2) {
    leftNum = 7
  } else if (item.sortNum.toString().length === 3) {
    leftNum = 10
  } else if (item.sortNum.toString().length === 4) {
    leftNum = 14
  } else if (item.sortNum.toString().length === 5) {
    leftNum = 18
  } else if (item.sortNum.toString().length === 6) {
    leftNum = 21
  } else if (item.sortNum.toString().length === 7) {
    leftNum = 25
  } else if (item.sortNum.toString().length === 8) {
    leftNum = 28
  } else if (item.sortNum.toString().length === 9) {
    leftNum = 31
  }
  return {
    left: Number(item.locationWidePx) / 2 - leftNum + 'px',
    top: Number(item.locationDeepPx) / 2 - 2 + 'px'
  }
}

//返回设备类型
const filterTypeFun = (deviceType) => {
  let list = getIntDictOptions(DICT_TYPE.DEVICE_TYPE)
  let deviceItem = list.find((item) => {
    return item.value == deviceType
  })
  return deviceItem.label
}

const convertActualToBrowser = (pointX, pointY) => {
  let resolution = Number(imgBgObj.resolution)
  let origin = imgBgObj.origin

  const y1 = Number(origin[1]) + Number(imgBgObj.height) * resolution
  let x = Math.max(Number(pointX) - Number(origin[0]), 0)
  let y = Math.max(y1 - Number(pointY), 0)

  return {
    x: x / resolution - carWidth.value / resolution / 100 / 2,
    y: y / resolution - carHeight.value / resolution / 100 / 2
  }
}

//是否可以拖拽
const isDrag = ref(false)
const changeIsDrag = () => {
  nextTick(() => {
    isDrag.value = !isDrag.value
    if (!isDrag.value) {
      //还原位置
      resetPosition()
    }
  })
}

// 获取曲线的路径
const getCurvePath = (curve) => {
  let startPointX = Number(curve.startPointX) * radio.value
  let startPointY = Number(curve.startPointY) * radio.value
  let endPointX = Number(curve.endPointX) * radio.value
  let endPointY = Number(curve.endPointY) * radio.value
  return `M ${startPointX} ${startPointY} C ${curve.beginControlX * radio.value} ${curve.beginControlY * radio.value}, ${curve.endControlX * radio.value} ${curve.endControlY * radio.value}, ${endPointX} ${endPointY}`
}

//放大缩小
const isSizeRadio = ref(1)
const changeSize = (type) => {
  if (type == 'add') {
    if (isSizeRadio.value < 4) {
      isSizeRadio.value += 0.1
    } else {
      isSizeRadio.value = 3.9
      message.warning('不能在放大了')
    }
  } else {
    if (isSizeRadio.value > 0.2) {
      isSizeRadio.value -= 0.1
    } else {
      isSizeRadio.value = 0.1
      message.warning('不能在缩小了')
    }
  }
}

// 图层显示切换相关
const layerList = ref([
  {
    type: 1,
    name: '行驶路线',
    isShow: true
  },
  {
    type: 2,
    name: '车辆',
    isShow: true
  },
  {
    type: 3,
    name: '节点ID',
    isShow: true
  }
])
const legendObj = reactive({
  driveLineShow: true,
  carShow: true,
  sortNumberShow: true,
  legendShow: true
})
const changDriveLineShow = (item) => {
  item.isShow = !item.isShow
  if (item.type == 1) {
    legendObj.driveLineShow = !legendObj.driveLineShow
  } else if (item.type == 2) {
    legendObj.carShow = !legendObj.carShow
  } else if (item.type == 3) {
    legendObj.sortNumberShow = !legendObj.sortNumberShow
  }
}

//全屏相关
const indexPageContainerRef = ref()
const isFullScreenDisplay = ref(false)
const toggleFullScreen = () => {
  if (!isFullScreenDisplay.value) {
    indexPageContainerRef.value.requestFullscreen().catch((err) => {
      console.error(`全屏错误: ${err.message}`)
    })
  } else {
    if (document.exitFullscreen) {
      document.exitFullscreen()
    }
  }
}
//全屏切换
const handleFullscreenChange = () => {
  isFullScreenDisplay.value = !!document.indexPageContainerRef
}

//库位双击
const storeClick = async (item) => {
  let storeData = await MapApi.houseLocationGetByMapItemId({
    mapId: item.positionMapId,
    mapItemId: item.id
  })
  storeDialogRef.value.open(JSON.parse(JSON.stringify(storeData)))
}

//将节点实际宽高cm转换成px
const cmConversionPx = (cWidth, cHeight) => {
  let pWidth = Number(cWidth) / Number(imgBgObj.resolution) / 100
  let pHeight = Number(cHeight) / Number(imgBgObj.resolution) / 100
  return {
    pWidth,
    pHeight
  }
}

const draggableElement = ref(null)
const resetPosition = () => {
  if (draggableElement.value) {
    resetDragPosition(draggableElement.value)
  }
}

//websocket相关
const replaceHttpWithWs = (str) => {
  return str.replace(/^http/, 'ws')
}

// 优化轮询机制
const robotListTimerRef = ref(null)
const robotByFloorAndAreaList = ref([])

const getRobotByFloorAndAreaList = async () => {
  try {
    const res = await MapApi.getRobotByFloorAndArea({
      floor: imgBgObj.floor,
      area: imgBgObj.area
    })
    robotByFloorAndAreaList.value = res
    if (testCarList.value.length) {
      // 使用 Set 优化查找性能
      const onlineRobots = new Set(robotByFloorAndAreaList.value)
      testCarList.value = testCarList.value.filter((item) =>
        onlineRobots.has(item.data.pose2d.robotNo)
      )
    }
  } catch (error) {
    console.error('获取机器人列表失败:', error)
  }
}

// 使用 ref 管理 WebSocket 连接
const wsConnection = ref(null)

// WebSocket 连接管理
const initWebsocket = () => {
  if (wsConnection.value) {
    wsConnection.value.disconnect()
  }

  const websocketUrl = `${replaceHttpWithWs(import.meta.env.VITE_BASE_URL)}/infra/ws?type=map&floor=${imgBgObj.floor}&area=${imgBgObj.area}`
  wsConnection.value = new WebSocketClient(websocketUrl)

  if (wsConnection.value) {
    socketClient.value = wsConnection.value
    // 监听消息
    socketClient.value.onMessage((message) => {
      if (message == 'ping' || message == 'pong') return
      let jsonMsg = JSON.parse(message)
      if (jsonMsg.type == 'map_push') {
        requestAnimationFrame(() => {
          let data = JSON.parse(jsonMsg.content)
          // console.log(data)

          let dataList = Object.entries(data).map(([key, value]) => ({
            macAddress: key,
            data: JSON.parse(value)
          }))
          testCarList.value = throttledUpdateCarList(testCarList.value, dataList, imgBgObj)
        })
      }
      //告警信息
      if (jsonMsg.type == 'agv_warn') {
        ElMessage({
          message: () =>
            h(
              'div',
              {
                style: 'background-color: #C60606;'
              },
              [
                h(
                  'span',
                  { style: 'color: rgba(255,255,255,0.88);font-size: 14px;' },
                  `${JSON.parse(jsonMsg.content)}`
                ),
                h(
                  'span',
                  {
                    onClick: () => lookError(),
                    style:
                      'color: rgba(255,255,255,0.88);font-size: 14px;cursor: pointer;text-decoration-line: underline;margin-left: 32px;'
                  },
                  '详情'
                )
              ]
            ),
          showClose: false,
          duration: 3000, // 让消息持续显示，直到用户关闭
          type: 'info',
          customClass: 'indexpage-custom-message-style'
        })
      }
      // 规划路线信息
      if (jsonMsg.type == 'planning_move_pose') {
        let data = JSON.parse(jsonMsg.content)
        let dataList = JSON.parse(data).data
        if (state.mapRouteList.length > 0) {
          state.mapRouteList = setIsSelect(state.mapRouteList, dataList)
        }
      }
    })
  }
}

const throttledUpdateCarList = throttle((currentList, newDataList, mapInfo) => {
  return updateCarList(currentList, newDataList, mapInfo)
}, 100) // 100ms 节流

// 优化车辆数据合并逻辑
const mergeArraysWithoutDelete = (arr1, arr2) => {
  const macAddressMap = new Map(arr1.map((item) => [item.macAddress, item]))

  arr2.forEach((item2) => {
    const existingItem = macAddressMap.get(item2.macAddress)
    if (existingItem) {
      existingItem.data.pose2d = item2.data.pose2d
    } else {
      macAddressMap.set(item2.macAddress, item2)
    }
  })

  return Array.from(macAddressMap.values())
}

// 优化车辆位置计算
const processCarData = (car, mapInfo) => {
  const browserPos = convertActualToBrowser(car.data.pose2d.x, car.data.pose2d.y)
  return {
    ...car,
    originWidth: mapInfo.width,
    originHeight: mapInfo.height,
    origin: mapInfo.origin,
    realX: browserPos.x,
    realY: browserPos.y,
    robotNo: car.data.pose2d.robotNo,
    style: {
      left: browserPos.x * radio.value + 'px',
      top: browserPos.y * radio.value + 'px',
      width: (carWidth.value / imgBgObj.resolution / 100) * radio.value + 'px',
      height: (carHeight.value / imgBgObj.resolution / 100) * radio.value + 'px',
      zIndex: 9999,
      transform: `rotate(${-car.data.pose2d.yaw * (180 / Math.PI)}deg)`
    }
  }
}

// 更新车辆列表
const updateCarList = (currentList, newDataList, mapInfo) => {
  const updatedList = mergeArraysWithoutDelete(currentList, newDataList)
  return updatedList.map((car) => processCarData(car, mapInfo))
}

const setIsSelect = (arr1, arr2) => {
  for (let i = 0; i < arr1.length; i++) {
    const element = arr1[i]
    const isExist = arr2.includes(element.id)
    element.isSelect = isExist
  }
  return arr1
}

// 查看更多异常列表
const lookError = () => {
  router.push({
    path: '/carError'
  })
}

const emitParent = () => {
  getMapData(imgBgObj)
}

const computedRatio = () => {
  nextTick(() => {
    if (props.isFullScreen) {
      let width = getElementWidthByClass('index-page-container')

      testCarList.value.forEach((item) => {
        item.originWidth = imgBgObj.width
        item.originHeight = imgBgObj.height
        item.origin = imgBgObj.origin
        item.realX = convertActualToBrowser(item.data.pose2d.x, item.data.pose2d.y).x
        item.realY = convertActualToBrowser(item.data.pose2d.x, item.data.pose2d.y).y
      })

      radio.value = width / imgBgObj.width
      imgBgObj.width = imgBgObj.width * radio.value
      imgBgObj.height = imgBgObj.height * radio.value
    }
  })
}

//偏航率斜率算旋转
const radianToDegree = (radian) => {
  const degree = radian * (180 / Math.PI)
  return `${-degree}`
}

const radio = ref(1) //放大缩小的倍数
const state = reactive({
  mapRouteList: [],
  allMapPointInfo: []
})

//获取扫描图  地图背景相关的信息
const imgBgObj = reactive({
  imgUrl: '',
  positionMapId: '',
  width: '',
  height: '',
  floor: '',
  area: '',
  resolution: 0,
  origin: null
})
const getMapData = async (item) => {
  let yamlJson = JSON.parse(item.yamlJson)
  imgBgObj.positionMapId = item.id
  imgBgObj.floor = item.floor
  imgBgObj.area = item.area
  imgBgObj.width = yamlJson.width
  imgBgObj.height = yamlJson.height
  imgBgObj.origin = yamlJson.origin
  imgBgObj.resolution = yamlJson.resolution
  //获取地图
  getMapDownloadPng(imgBgObj)
  //初始化Websocket
  initWebsocket()
}
const getMapDownloadPng = async (mapInfo) => {
  let data = await MapApi.getPositionMapdDwnloadPngBase64({
    floor: mapInfo.floor,
    area: mapInfo.area
  })
  imgBgObj.imgUrl = data

  //获取节点 路径等信息
  await getAllNodeList()
  await getAllMapRoute()
  await computedRatio()
  await getRobotByFloorAndAreaList()
}
// 获取地图连线
const getAllMapRoute = async () => {
  state.mapRouteList = await MapApi.getPositionMapLineByPositionMapId(imgBgObj.positionMapId)
}
//获取节点
const getAllNodeList = async (positionMapId) => {
  state.allMapPointInfo = await MapApi.getPositionMapItemList({
    positionMapId: imgBgObj.positionMapId
  })
  state.allMapPointInfo?.forEach((item) => {
    if (item.type === 1) {
      item.locationDeep = 40
      item.locationWide = 40
    } else if (item.type === 5 || item.type === 6) {
      item.locationDeep = 150
      item.locationWide = 150
    } else if (item.type === 2) {
      //库位点
      item.dataList = JSONBigInt({ storeAsString: true }).parse(item.dataJson)
      item.dataList = item.dataList.reverse()
      item.locationDeep = item.dataList[0].locationDeep
      item.locationWide = item.dataList[0].locationWide
    } else if (item.type === 3) {
      item.dataObj = JSONBigInt({ storeAsString: true }).parse(item.dataJson)
      item.locationDeep = item.dataObj.locationDeep
      item.locationWide = item.dataObj.locationWide
    } else if (item.type === 4) {
      item.dataObj = JSONBigInt({ storeAsString: true }).parse(item.dataJson)
      item.locationDeep = item.dataObj.locationDeep
      item.locationWide = item.dataObj.locationWide
    }
    //要将实际的cm改成px
    if (item.locationWide && item.locationDeep) {
      let pxObj = cmConversionPx(item.locationWide, item.locationDeep)
      item.locationWidePx = pxObj.pWidth
      item.locationDeepPx = pxObj.pHeight
    }
  })
}

//鼠标滚轮
const handleWheel = (event) => {
  // 判断 Ctrl 键是否被按下
  if (event.ctrlKey && !props.isFullScreen) {
    // 阻止默认的滚动行为
    event.preventDefault()

    // 根据滚轮滚动方向调整缩放比例
    if (event.deltaY < 0) {
      // 向上滚动，放大
      //放大
      if (isSizeRadio.value < 4) {
        isSizeRadio.value += 0.1
      } else {
        isSizeRadio.value = 3.9
        message.warning('不能在放大了')
      }
    } else {
      //缩小
      if (isSizeRadio.value > 0.2) {
        isSizeRadio.value -= 0.1
      } else {
        isSizeRadio.value = 0.1
        message.warning('不能在缩小了')
      }
    }
  }
}

const getElementWidthByClass = (className) => {
  const element = document.querySelector(`.${className}`)
  if (element) {
    const widthWithUnit = window.getComputedStyle(element).width
    return widthWithUnit.slice(0, -2)
  }
  return null
}
//小车双击
const carDbClick = (item, index) => {
  carDialogRef.value.open(JSON.parse(JSON.stringify(item)))
}

onMounted(() => {
  document.addEventListener('fullscreenchange', handleFullscreenChange)
  document.addEventListener('webkitfullscreenchange', handleFullscreenChange)
  document.addEventListener('mozfullscreenchange', handleFullscreenChange)
  document.addEventListener('MSFullscreenChange', handleFullscreenChange)

  // 设置轮询间隔
  robotListTimerRef.value = setInterval(() => {
    if (document.hidden) return // 页面不可见时暂停轮询
    getRobotByFloorAndAreaList()
  }, 10000)

  // 监听页面可见性变化
  document.addEventListener('visibilitychange', () => {
    if (!document.hidden && robotListTimerRef.value === null) {
      robotListTimerRef.value = setInterval(getRobotByFloorAndAreaList, 10000)
    }
  })
})

onUnmounted(() => {
  document.removeEventListener('fullscreenchange', handleFullscreenChange)
  document.removeEventListener('webkitfullscreenchange', handleFullscreenChange)
  document.removeEventListener('mozfullscreenchange', handleFullscreenChange)
  document.removeEventListener('MSFullscreenChange', handleFullscreenChange)

  clearTheTimer()
})
onBeforeUnmount(() => {
  clearTheTimer()
})

const clearTheTimer = () => {
  // 清除轮询定时器
  if (robotListTimerRef.value) {
    clearInterval(robotListTimerRef.value)
    robotListTimerRef.value = null
  }

  // 清理WebSocket连接
  if (wsConnection.value) {
    wsConnection.value.disconnect()
    wsConnection.value = null
  }

  // 清理socketClient引用
  if (socketClient.value) {
    socketClient.value = null
  }

  // 清理其他相关数据
  testCarList.value = []
  robotByFloorAndAreaList.value = []
}

defineExpose({ getMapData, computedRatio, clearTheTimer }) // 提供 open 方法，用于打开弹窗
</script>

<style lang="scss" scoped>
.index-page {
  width: 100%;
  height: 100%;
  box-sizing: border-box;

  .index-page-container {
    position: relative;
    width: 100%;

    .map-container {
      width: 100%;
      position: relative;
      transform-style: preserve-3d; /* 3D 变换优化 */
      backface-visibility: hidden;
      perspective: 1000;

      .indexpage-container {
        width: 100%;
        position: relative;
        transform: translateZ(0);
        will-change: transform;
      }

      .indexpage-container-active {
        width: 100%;
        position: relative;
        cursor: grab;
        transform: translateZ(0);
        will-change: transform;
      }

      .indexpage-container-active:active {
        cursor: grabbing;
      }

      .indexpage-container-box {
        width: 100%;
        position: relative;

        .map-bg {
          width: 100%;
          height: auto;
        }
      }

      .point-information {
        --radio: 1;
        width: 100%;
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        transform: translateZ(0);

        .line-list {
          position: absolute;
          transform: translateZ(0);
          will-change: transform;
        }
      }

      .car-item {
        position: absolute;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        will-change: transform; /* 提示浏览器该元素会频繁变化 */
        transform: translateZ(0); /* 强制GPU加速 */
      }

      .map-point-list {
        position: absolute;
        cursor: pointer;
        transform: translateZ(0);
        will-change: transform;

        .sort-num {
          position: absolute;
          font-size: 13px;
          user-select: none;
          color: #000;
        }
        .sort-num-location {
          position: absolute;
          font-size: 13px;
          user-select: none;
          color: #000;
        }
      }
    }
  }
}

.indexpage-popover-item {
  display: flex;
  font-family:
    PingFangSC,
    PingFang SC;
  font-weight: 400;
  font-size: 14px;
  color: #0d162a;
  padding: 3px;
}

.affix-container-left {
  position: fixed;
  right: 30px;
  bottom: 70px;
  z-index: 999;

  .affix-container-left-box {
    width: 144px;
  }

  .legend-list {
    width: 100%;
    border-bottom: 1px solid #eeeeee;
    background: #ffffff;
    transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1);

    .legend-item {
      width: 100%;
      padding: 0 18px;
      height: 42px;
      display: flex;
      align-items: center;
      justify-content: space-between;
    }
  }

  .legend-item-left {
    font-family:
      PingFangSC,
      PingFang SC;
    font-weight: 400;
    font-size: 14px;
    color: rgba(0, 0, 0, 0.88);
  }

  .legend-item-img {
    cursor: pointer;
  }

  .legend-item-bottom {
    width: 100%;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    background: #ffffff;
  }

  .legend-item-bottom-left {
    cursor: pointer;
    flex-shrink: 0;
    font-family:
      PingFangSC,
      PingFang SC;
    font-weight: 400;
    font-size: 16px;
    color: #98a4bf;
    margin-right: 2px;
  }
}

.affix-container-right {
  position: fixed;
  z-index: 999;
  right: 30px;
  bottom: 20px;
  display: flex;
  align-items: center;
  justify-content: flex-end;

  .item {
    width: 30px;
    height: 30px;
    cursor: pointer;
    flex-shrink: 0;
    margin-left: 8px;

    img {
      width: 100%;
      height: 100%;
    }
  }
}

.popover-robot-no {
  font-size: 15px;
  text-align: center;
  color: #000;
  font-weight: 600;
}

/* 全屏模式下的样式 */
.index-page-container:-webkit-full-screen {
  width: 100vw;
  height: 100vh;
  background-color: white;
  box-sizing: border-box;
  overflow: auto; /* 允许滚动 */
}

.index-page-container:-moz-full-screen {
  width: 100vw;
  height: 100vh;
  background-color: white;
  box-sizing: border-box;
  overflow: auto;
}

.index-page-container:-ms-fullscreen {
  width: 100vw;
  height: 100vh;
  background-color: white;
  box-sizing: border-box;
  overflow: auto;
}

.index-page-container:fullscreen {
  width: 100vw;
  height: 100vh;
  background-color: white;
  box-sizing: border-box;
  overflow: auto;
}
</style>
