<template>
  <div class="map-page">
    <div ref="mapContainer" class="map-container"></div>

    <div v-if="loading" class="loading-mask">
      <div class="loading-content">
        <div class="loading-spinner"></div>
        <div class="loading-text">地图加载中...</div>
      </div>
    </div>

    <div class="tool-dock dock-left">
      <button
        v-for="btn in leftButton"
        :key="btn.click"
        :class="['dock-toggle', { active: isActive(btn) }]"
        :data-tooltip="btn.text"
        @click="handleDockClick(btn)"
        v-show="btn.visible !== false"
      >
        <img
          class="dock-icon"
          :src="getDynamicIcon(btn.svg)"
          @error="handleSvgError"
          :alt="btn.text"/>
        <span class="dock-text">{{ btn.text }}</span>
        <!--        <span v-if="btn.tip" class="dock-tip">{{ btn.tip }}</span>-->
      </button>
    </div>

    <div class="tool-dock dock-right">
      <button
        v-for="btn in rightButton"
        :key="btn.click"
        :class="['dock-toggle', { active: isActive(btn) }]"
        :data-tooltip="btn.text"
        @click="handleDockClick(btn)"
        v-show="btn.visible !== false"
      >
        <img
          class="dock-icon"
          :src="getDynamicIcon(btn.svg)"
          @error="handleSvgError"
          :alt="btn.text"/>
        <span class="dock-text">{{ btn.text }}</span>
        <!--        <span v-if="btn.tip" class="dock-tip">{{ btn.tip }}</span>-->
      </button>
    </div>
    <!-- wms切换图层 -->
    <div
      class="fixed-device-panel"
      :class="{ collapsed: collapsed }"
      id="fixed-device-panel"
    >
      <!-- 面板头部 -->
      <div
        class="device-panel-header"
        id="device-panel-header"
        @click="togglePanel"
      >
        <h4>设备图层</h4>

        <!-- 右侧收缩按钮 -->
        <button
          class="device-panel-toggle"
          id="device-panel-toggle"
          @click.stop="togglePanel"
        >
          <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
            <path d="M7 14l5-5 5 5z"/>
          </svg>
        </button>
      </div>

      <!-- 面板内容 -->
      <div class="device-panel-content" v-if="geoserverWmsLayer.length > 0">
        <DeviceLayerPanel
          :layerData="geoserverWmsLayer"
          mode="horizontal"
          :getDynamicIcon="getDynamicIcon"
          :handleSvgError="handleSvgError"
          @select="LayerSelect"
        />
      </div>
    </div>

    <div class="map-center-info">
      <span>中心坐标</span>
      <span class="coord">{{ centerText }}</span>
    </div>

    <div
      v-if="currentEngine === 'AMAP'"
      class="amap-logo-mask"
    ></div>

    <!-- 提示信息 -->
    <div v-if="tipMessage" class="map-tip">
      {{ tipMessage }}
    </div>

    <!-- 业务卡片（内部处理非 custom 功能） -->
    <div v-if="businessCard.visible" :class="['business-card', `business-card-${businessCard.position}`]">
      <div class="business-card-header">
        <span class="business-card-title">{{ businessCard.title }}</span>
      </div>
      <div class="business-card-content">
        <button
          v-for="(item, index) in businessCard.buttons"
          v-if="!item.engine || item.engine === currentEngine"
          :key="index"
          :class="['business-card-button', { 'business-card-button-active': isButtonActive(item) }]"
          :data-tooltip="item.text"
          @click="handleButtonClick(item)"
        >
          <img
            :src="getDynamicIcon(item.svg)"
            @error="handleSvgError"
            :alt="item.text"/>
          <span v-if="item.tip" class="business-card-tip">{{ item.tip }}</span>
        </button>
      </div>
    </div>

    <!-- 定位列表卡片 -->
    <div
      v-if="locationVisible"
      :class="['location-card']"
    >
      <div class="location-card-header">图幅定位</div>
      <div class="location-card-body">
        <div
          v-for="(item, idx) in locationList"
          :key="idx"
          :class="['location-item', { active: locationActive === item.text }]"
          @click="handlelocationClick(item)"
        >
          {{ item.text }}
        </div>
      </div>
    </div>

    <!-- 信息窗口容器（AMap 和 OpenLayers 共用） -->
    <div
      id="map-info-window-container"
    >
      <component
        v-if="currentInfoWindowComponent"
        :is="currentInfoWindowComponent"
        v-bind="currentInfoWindowProps"
        v-on="currentInfoWindowListeners"
      />
    </div>
  </div>
</template>

<script>
/**
 * 地图工具组件（无业务 UI）
 * - 负责初始化地图并暴露方法给业务层调用（通过 ref）
 * - 业务侧可在外部组合自己的业务 UI（如 Demo 组件）
 */

import mapService from '@vue2-client/base-client/components/common/AfMap/map/mapService'
import { getConfigByName, getConfigByNameAsync } from '@vue2-client/services/api/common'
import DeviceLayerPanel from '@vue2-client/base-client/components/common/AfMap/components/DeviceLayerPanel/DeviceLayerPanel.vue'

export default {
  name: 'MapTool',
  components: {
    DeviceLayerPanel
  },
  emits: ['inited', 'loading-change', 'engine-change', 'dock-click', 'wms-click', 'map-click', 'update-geoserver-layer', 'close-all-draggable-modal'],
  props: {
    mapOptionsName: {
      type: String,
      required: true,
      default: 'MAP_OPTIONS'
    },
    serviceName: {
      type: String,
      required: false,
      default: process.env.VUE_APP_SYSTEM_NAME
    },
    queryLoading: {
      type: Boolean,
      required: false,
      default: false
    },
    loadingMessage: {
      type: String,
      required: false,
      default: 'loadingMessage'
    },
    showGroupIdArr: {
      type: Array,
      required: false,
      default: () => []
    },
    getDynamicIcon: {
      type: Function,
      required: true
    },
    handleSvgError: {
      type: Function,
      required: true
    }
  },
  data () {
    return {
      inited: false,
      loading: true,
      MAP_OPTIONS: null,
      mapConfig: null,
      currentEngine: 'OPENLAYERS',
      activeDock: null,
      button: {},
      centerText: '--',
      leftButton: [],
      rightButton: [],
      geoserverWmsLayer: [],
      /**
       * 面板是否收缩
       * true  → 收缩
       * false → 展开
       */
      collapsed: false,
      businessCard: {
        visible: false,
        title: '',
        buttons: [],
        position: 'right', // 'left' 或 'right'
        activeButton: null // 当前选中的按钮 click 值
      },
      mapViewMode: '3D',
      baseActive: 'vector', // 'vector' | 'satellite' | 'tdtVec' | 'tdtImg'
      tipMessage: '',
      locationVisible: false,
      locationList: [],
      locationActive: null,
      wmsClickEnabled: false, // WMS点击查询状态
      currentInfoWindowComponent: null, // 当前信息窗口组件
      currentInfoWindowProps: {}, // 当前信息窗口组件 props
      currentInfoWindowListeners: {}, // 当前信息窗口组件事件监听器
    }
  },
  async mounted () {
    getConfigByName('mapConfig', 'af-system', async (data) => {
      try {
        this.mapConfig = data
        if (!('aMapWebKey' in this.mapConfig) || !('tianDiTuWebKey' in this.mapConfig)) {
          console.error('mapConfig 缺少 aMapWebKey 或 tianDiTuWebKey')
          this.$message.error('mapConfig 缺少 aMapWebKey 或 tianDiTuWebKey', 0)
        }
        mapService.setLoadingCallback((loading) => {
          this.loading = loading
          this.$emit('loading-change', loading)
        })
        mapService.setViewChangeCallback((center) => {
          if (center && Array.isArray(center) && center.length === 2) {
            this.centerText = `${Number(center[0]).toFixed(6)}, ${Number(center[1]).toFixed(6)}`
          }
        })

        this.MAP_OPTIONS = await getConfigByNameAsync(this.mapOptionsName, this.serviceName)

        this.button = this.MAP_OPTIONS.toolButton
        this.leftButton = this.button.filter(t => t.position === 'left')
        this.rightButton = this.button.filter(t => t.position === 'right')
        if (this.MAP_OPTIONS?.MAP_OPTIONS?.center) {
          const [lng, lat] = this.MAP_OPTIONS.MAP_OPTIONS.center
          this.centerText = `${Number(lng).toFixed(6)}, ${Number(lat).toFixed(6)}`
        }

        mapService.setEngine(this.MAP_OPTIONS.MAP_ENGINE)
        this.currentEngine = mapService.getCurrentEngine()
        const INIT_MAP_OPTIONS = this.MAP_OPTIONS.MAP_OPTIONS
        INIT_MAP_OPTIONS.AMAPKEY = this.mapConfig.aMapWebKey
        INIT_MAP_OPTIONS.TIANDITUKEY = this.mapConfig.tianDiTuWebKey
        await mapService.initMap(this.$refs.mapContainer, INIT_MAP_OPTIONS)

        // wms 图层默认点击事件
        await this.setWmsClickEnabled(true)

        // wms 图层鼠标悬停样式（仅高德地图）
        if (this.currentEngine === 'AMAP') {
          mapService.setWmsHoverEnabled(true)
        }

        // 通用地图点击回调
        mapService.setMapClickCallback((coordinate) => {
          this.$emit('map-click', coordinate)
        })

        this.inited = true
        this.$emit('inited')
      } catch (error) {
        console.error('地图初始化失败', error)
      }
    })
  },
  methods: {
    getMapService () {
      return mapService
    },
    // ===== 数据新增 =====
    // 标记点
    addMarker () {
      return mapService.addMarker(...arguments)
    },
    // 热力图
    addHeatmap () {
      return mapService.addHeatmap(...arguments)
    },
    // 多边形
    drawPolygon () {
      return mapService.drawPolygon(...arguments)
    },
    addPolyline () {
      return mapService.addPolyline(...arguments)
    },
    addWmsLayer () {
      return mapService.addWmsLayer(...arguments)
    },
    refreshWmsLayers () {
      return mapService.refreshWmsLayers(...arguments)
    },
    clearLayer () {
      return mapService.clearLayer(...arguments)
    },
    // ===== 信息窗口 =====
    // 打开信息窗口（只支持 Vue 组件）
    openInfoWindow (coordinate, component, options = {}) {
      if (!component) {
        throw new Error('component is required')
      }

      // 设置当前组件和 props
      this.currentInfoWindowComponent = component
      this.currentInfoWindowProps = options.props || {}
      this.currentInfoWindowListeners = options.on || {}

      // 等待 Vue 更新 DOM 后获取 DOM 元素
      this.$nextTick(() => {
        // 窗口容器
        const container = document.getElementById('map-info-window-container')

        if (!container) {
          console.error('信息窗口容器不存在: map-info-window-container')
          return
        }

        // 再次等待，确保 Vue 组件完全渲染
        this.$nextTick(() => {
          return mapService.openInfoWindow(coordinate, container, options)
        })
      })
    },
    // 关闭信息窗口
    closeInfoWindow () {
      // 清除组件
      this.currentInfoWindowComponent = null
      this.currentInfoWindowProps = {}
      this.currentInfoWindowListeners = {}

      return mapService.closeInfoWindow()
    },
    // ===== 底图 & 引擎 =====
    // 切换底图
    switchBaseMap () {
      return mapService.switchBaseMap(...arguments)
    },
    // 图层显隐
    async setGroupVisible (groupId, visible) {
      return await mapService.setGroupVisible(groupId, visible)
    },
    startGroupBlink () {
      return mapService.startGroupBlink(...arguments)
    },
    stopGroupBlink () {
      return mapService.stopGroupBlink(...arguments)
    },
    // 切换地图
    async switchEngine (engine) {
      await mapService.switchEngine(engine)
      // 切换引擎后清理测距数据
      this.clearMeasureResults()
      this.currentEngine = engine
      this.$emit('engine-change', this.currentEngine)
      // 切换后触发中心更新
      const state = mapService.adapter?.getMapState ? mapService.adapter.getMapState() : null
      if (state && state.center) {
        this.centerText = `${Number(state.center[0]).toFixed(6)}, ${Number(state.center[1]).toFixed(6)}`
      }
      // wms 图层鼠标悬停样式（仅高德地图）
      if (engine === 'AMAP') {
        mapService.setWmsHoverEnabled(true)
      } else {
        mapService.setWmsHoverEnabled(false)
      }
    },
    getGroups () {
      return mapService.getGroups()
    },
    getGroupsByGroupType (specificGroupType) {
      return mapService.getGroupsByGroupType(specificGroupType)
    },
    getGroupsByType (type) {
      return mapService.getGroupsByType(type)
    },
    getCurrentEngine () {
      return this.currentEngine
    },
    // ===== 视图控制 =====
    // 地图缩放
    zoomIn () {
      return mapService.zoomIn()
    },
    zoomOut () {
      return mapService.zoomOut()
    },
    fitView (zoom = null, center = null) {
      return mapService.fitView(zoom, center)
    },
    // 框选放大
    enableZoomToBox (onComplete) {
      return mapService.enableZoomToBox(onComplete)
    },
    disableZoomToBox () {
      return mapService.disableZoomToBox()
    },
    zoomToBounds (bounds, center) {
      return mapService.zoomToBounds(bounds, center)
    },
    startDistanceMeasure () {
      return mapService.startDistanceMeasure()
    },
    startAreaMeasure () {
      return mapService.startAreaMeasure()
    },
    startRectangleSelect (onComplete) {
      return mapService.startRectangleSelect(onComplete)
    },
    startCircleSelect (onComplete) {
      return mapService.startCircleSelect(onComplete)
    },
    startPolygonSelect (onComplete) {
      return mapService.startPolygonSelect(onComplete)
    },
    startLineDraw (onComplete) {
      return mapService.startLineDraw(onComplete)
    },
    stopLineDraw () {
      return mapService.stopLineDraw()
    },
    stopSelectInteraction () {
      return mapService.stopSelectInteraction()
    },
    // 清理框选结果
    clearSelectResults () {
      return mapService.clearSelectResults()
    },
    // 清楚测量结果
    clearMeasureResults () {
      return mapService.clearMeasureResults()
    },
    setMapViewMode (mode) {
      return mapService.setMapViewMode(mode)
    },
    isActive (btn) {
      const action = btn.click
      return action && this.activeDock === action
    },
    emitDockClick ({ visible, btn, custom }) {
      this.$emit('dock-click', {
        visible,
        custom,
        action: btn.action,
        text: btn.text,
        click: btn.click
      })
    },
    async LayerSelect (layer) {
      console.warn('LayerSelect - layer', layer)
      await this.setGroupVisible(layer.id, !layer.visible)
      // this.$emit('update-geoserver-layer')
      this.updateGroupsByGroupType()
    },
    updateGroupsByGroupType () {
      try { // 从 mapTool 组件获取分组数据
        const groups = this.getGroupsByGroupType()
        console.warn('groups', groups)

        // 图层的详细配置信息
        const layers = this.MAP_OPTIONS?.layersIconConfig || []

        // 用于存储最终组织好的数据
        const deviceLayerPanel = []

        // 遍历每个大分类（如 "输配管线", "站场与设备"）
        groups.forEach(category => {
          // 遍历分类下的每个具体图层
          const updatedGroups = category.groups
            .filter(group => this.showGroupIdArr.includes(group.id) || group.type === 'wms')
            .map(group => {
              // 在 layers 配置中查找当前图层对应的详细信息
              const layerConfig = layers.find(layer => layer.key === group.id)
              if (layerConfig) {
                // 合并原始图层信息和配置信息，并添加新的属性
                return {
                  ...group, // 保留原有的 id, name, type, visible 等属性
                  desc: layerConfig?.desc || group.name, // 优先使用配置的 desc，否则使用 name
                  icon: layerConfig?.icon || 'unknown-icon', // 优先使用配置的 icon，否则使用默认值
                  color: layerConfig?.color || '#ff0f0f', // 优先使用配置的 color，否则使用默认值
                  // 根据 'vtb' 属性判断类型，如果不存在则默认为 'point'
                  iconType: 'vtb' in layerConfig ? 'line' : 'point'
                }
              } else {
                // 合并原始图层信息和配置信息，并添加新的属性
                return {
                  ...group, // 保留原有的 id, name, type, visible 等属性
                  desc: group?.desc || group.name, // 优先使用配置的 desc，否则使用 name
                  icon: group?.icon || group?.type || group?.groupType || 'unknown-icon', // 优先使用配置的 icon，否则使用默认值
                  color: group?.color || '#ff0f0f', // 优先使用配置的 color，否则使用默认值
                  // 根据 'vtb' 属性判断类型，如果不存在则默认为 'point'
                  iconType: group?.type || group?.groupType
                }
              }
            })

          if (updatedGroups.length !== 0) {
            // 将处理好的分类数据添加到最终结果中
            deviceLayerPanel.push({
              ...category, // 保留原有的 groupType
              groups: updatedGroups // 使用上面处理好的新 groups 数组
            })
          }
        })
        this.geoserverWmsLayer = deviceLayerPanel
        return deviceLayerPanel
      } catch (e) {
        console.error('>>>>getGroupsByGroupType', e)
      }
    },
    /**
     * 切换面板的收缩 / 展开状态
     */
    togglePanel () {
      this.collapsed = !this.collapsed
    },
    /**
     * 切换面板的收缩 状态为指定的状态
     * 默认为true收缩
     * @param {boolean} collapsed
     */
    togglePanelIsCollapsed (collapsed = true) {
      this.collapsed = collapsed
    },
    // ===== Dock 点击 =====
    handleDockClick (btn) {
      // 查询过程中不允许触发业务按钮
      if (this.queryLoading) {
        this.$message.warning(this.loadingMessage)
        return
      }
      const action = btn.click
      if (!action) return

      // 【重要】每次点击新的 dock 时，先关闭所有之前激活的工具和状态
      // 这样可以确保状态清理干净，避免残留
      this.closeAllActiveTools()

      // 是否打开（切换逻辑：如果点击的是当前激活的 dock，则关闭；否则打开新的）
      const willOpen = this.activeDock !== action
      // 如果触发了业务, 关闭 wms 默认点击事件
      this.setWmsClickEnabled(!willOpen)

      // custom：父组件接管
      if (btn.custom) {
        this.activeDock = willOpen ? action : null

        this.emitDockClick({
          visible: willOpen,
          btn,
          custom: true
        })
        return
      }

      if (!willOpen) {
        this.activeDock = ''
        return
      }

      // 非 custom：打开新 Dock
      this.activeDock = action

      this.emitDockClick({
        visible: true,
        btn,
        custom: false
      })

      // 打开内部业务卡片
      const panelButton = this.button.find(item => item.click === btn.click)
      if (panelButton?.button) {
        const position = panelButton?.buttonPosition || 'left'
        this.setBusinessCard({
          visible: true,
          title: btn.text,
          buttons: panelButton.button,
          position,
          activeButton: null
        })
      } else {
        this.setBusinessCard({
          visible: false,
          title: '',
          buttons: [],
          position: 'right',
          activeButton: null
        })
      }

      // 图幅定位数据
      if (btn.click === 'toggle-area-menu' && btn.location) {
        this.locationList = btn.location || []
        this.locationVisible = this.locationList.length > 0
      }
    },
    // ===== 业务卡片状态 =====
    // 设置业务卡片
    setBusinessCard (cardData) {
      this.businessCard = {
        ...this.businessCard,
        ...cardData
      }
    },
    // ===== 业务按钮点击处理 =====
    // 非 custom: 内部处理；custom: 上抛父组件
    async handleButtonClick (item) {
      // 查询过程中不允许触发业务按钮
      if (this.queryLoading) {
        this.$message.warning('正在查询数据，请稍候，查询完成后再尝试操作。')
        return
      }
      if (!this.inited) {
        this.$message.warning('地图未初始化')
        return
      }

      const current = this.businessCard.activeButton
      const next = item.click

      this.$emit('closeAllActiveBusiness')

      // 1. 再次点击同一个功能: 关闭并退出
      if (current === next) {
        this.cancelActiveTool()
        this.businessCard.activeButton = null
        return
      }

      // 2. 已有功能，且点击的是另一个: 先取消旧的
      if (current) {
        this.cancelActiveTool()
      }

      // 持续 选中状态
      this.businessCard.activeButton = item.click
      await this.handleButtonAction(item)
    },
    // 处理按钮动作（left 位置）
    async handleButtonAction (item) {
      switch (item.click) {
        // 核心导航 放大
        case 'zoomIn': {
          this.zoomIn()
          this.businessCard.activeButton = null
          break
        }
        // 核心导航 缩小
        case 'zoomOut': {
          this.zoomOut()
          this.businessCard.activeButton = null
          break
        }
        // 核心导航 全图
        case 'fitView': {
          this.fitView(item?.data?.zoom || null, item?.data?.center || null)
          this.businessCard.activeButton = null
          break
        }
        // 核心导航 框选放大
        case 'zoomToBox': {
          this.enableZoomToBox()
          this.tipMessage = '框选放大: 拖动框选区域'
          break
        }
        // 测量工具 距离测量
        case 'measure-distance': {
          this.tipMessage = '测距模式: 单击添加点, 双击完成'
          this.startDistanceMeasure()
          break
        }
        // 测量工具 面积测量
        case 'measure-area': {
          this.tipMessage = '测面积模式: 单击绘制, 双击闭合'
          this.startAreaMeasure()
          break
        }
        // 测量工具 清除绘制
        case 'clear-measure': {
          this.clearMeasureResults()
          this.clearSelectResults()
          this.businessCard.activeButton = null
          this.tipMessage = ''
          break
        }
        // 底图视图 矢量地图
        case 'switch-vector': {
          await this.switchBaseMap('gaode')
          this.baseActive = 'vector'
          this.businessCard.activeButton = null
          break
        }
        // 底图视图 卫星影像
        case 'switch-satellite': {
          await this.switchBaseMap('gaodeSat')
          this.baseActive = 'satellite'
          this.businessCard.activeButton = null
          break
        }
        // 底图视图 底图切换 2D/3D
        case 'toggle-3d': {
          const targetMode = this.mapViewMode === '3D' ? '2D' : '3D'
          await this.setMapViewMode(targetMode)
          this.mapViewMode = this.getMapViewMode() || targetMode
          this.businessCard.activeButton = null
          break
        }
        // 底图视图 天地图矢量地图
        case 'tdtVec': {
          await this.switchBaseMap('tdtVec')
          this.baseActive = 'tdtVec'
          this.businessCard.activeButton = null
          break
        }
        // 底图视图 天地图卫星影像
        case 'tdtImg': {
          await this.switchBaseMap('tdtImg')
          this.baseActive = 'tdtImg'
          this.businessCard.activeButton = null
          break
        }
        // 定位工具 当前定位
        case 'locate-current': {
          await this.handleLocateCurrent()
          break
        }
        // 定位工具 图幅定位
        case 'toggle-area-menu': {
          const location = item.location || []
          this.locationList = location
          this.locationVisible = location.length > 0
          break
        }
        // 选取工具 框选
        case 'select-rect': {
          this.tipMessage = '矩形框选：拖拽绘制矩形'
          this.startRectangleSelect((coords) => {
            this.$emit('panel-select', { coords, type: 'rect' })
            this.tipMessage = ''
            this.businessCard.activeButton = null
          })
          break
        }
        // 选取工具 圆形框选
        case 'select-circle': {
          this.tipMessage = '圆形框选：拖拽绘制圆形'
          this.startCircleSelect((coords) => {
            this.$emit('panel-select', { coords, type: 'circle' })
            this.tipMessage = ''
            this.businessCard.activeButton = null
          })
          break
        }
        // 选取工具 多边形选择
        case 'select-polygon': {
          this.tipMessage = '多边形选择：单击绘制，双击结束'
          this.startPolygonSelect((coords) => {
            this.$emit('panel-select', { coords, type: 'polygon' })
            this.tipMessage = ''
            this.businessCard.activeButton = null
          })
          break
        }
        default: {
          this.tipMessage = ''
          break
        }
      }
    },
    // 定位处理
    async handleLocateCurrent () {
      this.tipMessage = '定位中...'
      try {
        // 调用 mapService 的定位方法（自动根据当前引擎使用对应的定位工具）
        // 只返回坐标，不进行地图移动
        const { longitude, latitude } = await mapService.locateCurrent()
        // 在 Vue 组件中调用 fitView 移动到当前位置
        await this.fitView(17, [longitude, latitude])
        this.$message.success('定位成功')
      } catch (e) {
        console.error('定位失败', e)
        const errorMessage = e.message || '定位失败，请检查浏览器定位权限和网络连接'
        if (errorMessage.includes('权限被拒绝')) {
          this.$message.error({
            message: errorMessage,
            duration: 5000
          })
        } else {
          this.$message.error(errorMessage)
        }
      } finally {
        this.tipMessage = ''
        this.businessCard.activeButton = null
      }
    },
    // 业务按钮 选中 特殊判断
    isButtonActive (item) {
      if (item.click === 'toggle-3d') {
        return this.mapViewMode === '3D'
      }
      if (item.click === 'switch-vector') {
        return this.baseActive === 'vector'
      }
      if (item.click === 'switch-satellite') {
        return this.baseActive === 'satellite'
      }
      if (item.click === 't-switch-satellite') {
        return this.baseActive === 'tdtVec'
      }
      if (item.click === 't-switch-satellite') {
        return this.baseActive === 'tdtImg'
      }
      return this.businessCard.activeButton === item.click
    },
    // ===== 统一关闭所有激活的工具和状态 =====
    /**
     * 关闭所有激活的工具、业务卡片和状态
     * 每次点击新的 dock 按钮时，应先调用此函数清理之前的状态
     */
    closeAllActiveTools () {
      // 1. 关闭当前激活的工具功能
      this.cancelActiveTool()

      // 2. 清理测量结果
      this.clearMeasureResults()

      // 3. 清理选择结果
      this.clearSelectResults()
      this.stopSelectInteraction()

      // 4. 关闭业务卡片
      this.setBusinessCard({
        visible: false,
        title: '',
        buttons: [],
        position: 'right',
        activeButton: null
      })

      // 5. 关闭定位卡片
      this.locationVisible = false
      this.locationList = []
      this.locationActive = null

      // 6. 清除提示信息
      this.tipMessage = ''

      // 清楚框选结果
      this.clearSelectResults()
      // 关闭所有可拖拽模态框
      this.$emit('close-all-draggable-modal')
    },
    // 取消选中 关闭功能
    cancelActiveTool () {
      switch (this.businessCard.activeButton) {
        case 'zoomToBox': {
          this.disableZoomToBox()
          break
        }
        case 'measure-distance':
        case 'measure-area': {
          this.clearMeasureResults()
          break
        }
        case 'select-rect':
        case 'select-circle':
        case 'select-polygon': {
          this.stopSelectInteraction()
          this.clearSelectResults()
          break
        }
        case 'toggle-area-menu': {
          this.locationVisible = false
          this.locationList = []
          this.locationActive = null
          break
        }
        default: {
          break
        }
      }
      this.businessCard.activeButton = null
      this.tipMessage = ''
    },
    // ===== 工具状态 & 其他 =====
    getMapViewMode () {
      if (mapService.adapter && mapService.adapter.getMapViewMode) {
        return mapService.adapter.getMapViewMode()
      }
      return this.mapViewMode
    },
    // 处理定位点击（图幅定位列表）
    handlelocationClick (item) {
      this.locationActive = item.text
      this.fitView(null, item.center)
    },
    // ===== WMS 点击查询 =====
    // 开启/关闭WMS点击查询
    setWmsClickEnabled (enabled) {
      this.wmsClickEnabled = enabled
      mapService.setWmsClickEnabled(enabled)
      mapService.initWmsClickHandler()
      if (enabled) {
        // 设置WMS点击查询回调
        mapService.setWmsClickCallback((coordinate) => {
          if (this.wmsClickEnabled) {
            this.handleWmsClick(coordinate)
          }
        })
      }
    },
    // 开启/关闭通用地图点击
    setMapClickEnabled (enabled) {
      mapService.setMapClickEnabled(enabled)
    },
    // 处理WMS点击事件
    async handleWmsClick (coordinate) {
      if (!this.wmsClickEnabled || !coordinate) return
      console.warn('handleWmsClick', coordinate)

      // 获取所有WMS图层
      const wmsGroups = this.getGroupsByType('wms')
      if (!wmsGroups || wmsGroups.length === 0) {
        return
      }

      // 遍历所有可见的WMS图层并请求数据
      for (const group of wmsGroups) {
        // 只处理可见的图层
        if (!group.visible) continue

        try {
          // 获取GetFeatureInfo URL
          const url = mapService.getWmsFeatureInfoUrl(group.id, coordinate)
          if (!url) {
            continue
          }

          // 发送请求
          const response = await fetch(url)
          if (!response.ok) {
            console.error(`WMS 获取特征信息请求对指定图层失败 ${group.id}:`, response.statusText)
            continue
          }

          const data = await response.json()
          if (data.features && data.features.length > 0) {
            // 触发自定义事件，将要素信息传递给父组件
            this.$emit('wms-click', {
              layerKey: group.id,
              layerName: group.name,
              features: data.features,
              coordinate: data,
              clickedCoordinate: coordinate
            })
            break
          }
        } catch (error) {
          console.error(`WMS 获取特征信息错误，涉及的图层为： ${group.id}:`, error)
        }
      }
    }
  },
}
</script>

<style scoped>
.map-page {
  position: relative;
  width: 100%;
  height: 100%;

  /* 设置 openlayers 拖拽框 DragBox 颜色  */

  :deep(.ol-dragbox) {
    border: 2px dashed #1890ff;
    background-color: rgba(24, 144, 255, 0.25);
    box-sizing: border-box;
  }

  /* 设置高德地图 距离测量 和 面积测量,测量结果 数据标签展示样式 */

  :deep(.amap-overlay-text-container),
  :deep(.amap-ranging-label) {
    background: rgba(255, 255, 255, 0.7) !important;
    border: 1px solid rgba(24, 144, 255, 0.45) !important;
    border-radius: 12px !important;
    padding: 4px 10px !important;

    font-size: 14px !important;
    font-weight: 500 !important;
    color: #000000 !important;

    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12) !important;
  }
}

.map-container {
  width: 100%;
  height: 100%;
  position: relative;
  z-index: 1;
}

.tool-dock {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 10px;
  z-index: 2;
}

.dock-left {
  left: 2px;
}

.dock-right {
  right: 2px;
}

.dock-top-right {
  right: 12px;
  top: 70px;
}

.map-center-info {
  position: absolute;
  bottom: 20px;
  z-index: 2;
  color: #000;
  font-size: 17px;
  gap: 8px;
  display: flex;
}

.map-center-info .coord {
  font-weight: 600;
}

.map-tip {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 998;
  background: rgba(255, 255, 255, 0.75);
  border: 1px solid rgba(24, 144, 255, 0.35);
  font-size: 14px;
  color: #333;
  border-radius: 30px;
  padding: 8px 14px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  font-weight: 500;
  pointer-events: none;
}

.amap-logo-mask {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 30px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 1) 100%);
  pointer-events: none;
  z-index: 2;
}

.dock-toggle {
  position: relative;
  width: 60px;
  min-height: 60px;
  padding: 6px 4px;
  border: 1px solid #d9d9d9;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.96);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
  cursor: pointer;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  transition: all 0.2s ease;
}

.dock-toggle.active {
  background: rgba(24, 144, 255, 0.15);
  border-color: #1890ff;
}

.dock-toggle:hover {
  border-color: #1890ff;
  box-shadow: 0 4px 14px rgba(24, 144, 255, 0.25);
}

.dock-toggle img {
  width: 22px;
  height: 22px;
  object-fit: contain;
  flex-shrink: 0;
}

.dock-text {
  font-size: 11px;
  color: #333;
  line-height: 1.2;
  text-align: center;
  word-break: break-all;
  white-space: normal;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.dock-icon {
  width: 30px;
  height: 30px;
}

.dock-toggle:hover img {
  filter: brightness(0) saturate(100%) invert(40%) sepia(100%) saturate(2000%) hue-rotate(200deg) brightness(0.9);
}

/* Tooltip 样式 */
.dock-toggle::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  padding: 6px 6px;
  background: #000;
  color: #fff;
  font-size: 14px;
  white-space: nowrap;
  border-radius: 4px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 999;
}

.dock-toggle::before {
  content: '';
  position: absolute;
  bottom: calc(100% + 2px);
  left: 50%;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid #000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 999;
}

.dock-toggle:hover::after,
.dock-toggle:hover::before {
  opacity: 1;
}

.dock-tip {
  position: absolute;
  top: -8px;
  right: -8px;
  min-width: 30px;
  padding: 2px 6px;
  background: #1890ff;
  color: #fff;
  font-size: 12px;
  border-radius: 12px;
  line-height: 16px;
  text-align: center;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
  border: 2px solid #fff;
  pointer-events: none;
}

.loading-mask {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 3;
}

::v-deep .ol-scale-line {
  left: auto !important;
  right: 12px !important;
  bottom: 12px !important;
  top: auto !important;
}

.loading-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

.loading-spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #1890ff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.loading-text {
  font-size: 14px;
  color: #666;
}

.business-card {
  position: absolute;
  top: 12px;
  z-index: 2;
  background: rgba(255, 255, 255, 0.95);
  border: 1px solid #e0e0e0;
  border-radius: 14px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  min-width: 220px;
  pointer-events: auto;
  overflow: visible;
}

.business-card-left {
  left: 66px;
}

.business-card-right {
  top: 80px;
  right: 66px;
}

.business-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  border-bottom: 1px solid #e0e0e0;
}

.business-card-title {
  margin-left: 10px;
  font-size: 18px;
  color: #575757;
}

.business-card-content {
  padding: 14px;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  overflow-x: visible;
  overflow-y: visible;
}

.business-card-button {
  position: relative;
  width: 50px;
  height: 50px;
  padding: 0;
  border: 1px solid #d9d9d9;
  border-radius: 10px;
  background: #fff;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s ease;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}

.business-card-button:hover {
  border-color: #1890ff;
  box-shadow: 0 4px 8px rgba(24, 144, 255, 0.25);
  transform: translateY(-1px);
}

.business-card-button img {
  width: 28px;
  height: 28px;
  object-fit: contain;
}

.business-card-button:hover img {
  filter: brightness(0) saturate(100%) invert(40%) sepia(100%) saturate(2000%) hue-rotate(200deg) brightness(0.9);
}

.business-card-button-active {
  background: rgba(24, 144, 255, 0.15);
  border-color: #1890ff;
}

.business-card-button-active img {
  filter: brightness(0) saturate(100%) invert(40%) sepia(100%) saturate(2000%) hue-rotate(200deg) brightness(0.9);
}

.business-card-tip {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 30px;
  padding: 2px 6px;
  background: #1890ff;
  color: #fff;
  font-size: 12px;
  border-radius: 12px;
  line-height: 16px;
  text-align: center;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
  border: 2px solid #fff;
  pointer-events: none;
}

/* Tooltip 样式 */
.business-card-button::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  padding: 6px 6px;
  background: #000;
  color: #fff;
  font-size: 14px;
  white-space: nowrap;
  border-radius: 4px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 999;
}

.business-card-button::before {
  content: '';
  position: absolute;
  bottom: calc(100% + 2px);
  left: 50%;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid #000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 999;
}

.business-card-button:hover::after,
.business-card-button:hover::before {
  opacity: 1;
}

.location-card {
  position: absolute;
  top: 160px;
  z-index: 998;
  min-width: 200px;
  background: rgba(255, 255, 255, 0.96);
  border: 1px solid #e0e0e0;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  overflow: hidden;
  left: 66px;
}

.location-card-header {
  padding: 10px 12px;
  background: #f7f9fb;
  border-bottom: 1px solid #e6e6e6;
  font-size: 14px;
  font-weight: 600;
  color: #333;
}

.location-card-body {
  max-height: 220px;
  overflow-y: auto;
  padding: 8px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.location-item {
  padding: 8px 10px;
  border: 1px solid #e6e6e6;
  border-radius: 8px;
  background: #fff;
  cursor: pointer;
  transition: all 0.2s ease;
  font-size: 13px;
  color: #333;
  word-break: break-all;
}

.location-item:hover {
  border-color: #1890ff;
  color: #1890ff;
  box-shadow: 0 2px 6px rgba(24, 144, 255, 0.2);
}

.location-item.active {
  border-color: #1890ff;
  background: rgba(24, 144, 255, 0.08);
  color: #1890ff;
}

/* 固定设备图层面板样式 */
.fixed-device-panel {
  position: absolute;
  top: 20px;
  right: 12px;
  max-width: 90%;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.98) 0%, rgba(249, 250, 251, 0.95) 100%);
  border: 1px solid rgba(59, 130, 246, 0.2);
  border-radius: 16px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1),
  0 4px 20px rgba(59, 130, 246, 0.05),
  inset 0 1px 0 rgba(255, 255, 255, 0.8);
  backdrop-filter: blur(20px);
  z-index: 999;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* 收缩状态 */
.fixed-device-panel.collapsed {
  height: auto;
  min-width: 120px;
  max-width: 120px;
  right: 12px;
}

/* 面板头部 */
.device-panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 10px;
  border-bottom: 1px solid rgba(59, 130, 246, 0.1);
  background: linear-gradient(90deg, rgba(59, 130, 246, 0.03) 0%, rgba(147, 51, 234, 0.02) 100%);
  cursor: pointer;
  user-select: none;
}

.device-panel-header h4 {
  margin: 0;
  font-size: 14px;
  color: #334155;
}

.fixed-device-panel.collapsed .device-panel-header {
  justify-content: space-between;
  padding: 12px;
  border-bottom: none;
}

/* 收缩按钮 */
.device-panel-toggle {
  width: 28px;
  height: 28px;
  border: none;
  background: rgba(255, 255, 255, 0.8);
  color: #64748b;
  cursor: pointer;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* 箭头旋转动画 */
.device-panel-toggle svg {
  transition: transform 0.3s ease;
}

/* 收缩时箭头翻转 */
.fixed-device-panel.collapsed .device-panel-toggle svg {
  transform: rotate(180deg);
}

/* 内容区域 */
.device-panel-content {
  transition: all 0.3s ease;
}

/* 收缩时隐藏内容 */
.fixed-device-panel.collapsed .device-panel-content {
  max-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  opacity: 0;
}

::v-deep .amap-marker-label {
  padding: 0 !important;
  border: none !important;
  background: transparent !important;
}
</style>
