<template>
  <el-container class="container">
    <!-- 侧边栏 --start -->
    <el-aside :class="asideWidth" id="el-aside">
      <el-menu
        ref="menu"
        :collapse="isCollapse"
        :uniqueOpened="true"
        default-active=""
        class="el-menu-vertical-demo"
        text-color="#303133"
        background-color="#f8f9fa"
        active-text-color="#409eff"
        :collapse-transition="false"
      >
        <!-- 展开收缩控制按钮 -->
        <el-menu-item index="0" @click="isCollapse=!isCollapse" id="fold">
          <i
            class="iconfont iconshouqi iconfont2"
            style="display:block;margin:0;text-align:center"
            :class="isCollapse?'rotate':'rotate2'"
          ></i>
        </el-menu-item>

        <!-- 加载数据 -->
        <el-sub-menu index="1">
          <template #title>
            <i class="iconfont iconshuju iconfont2"></i>
            <span>数据服务</span>
          </template>
          <el-sub-menu v-for="(data,index) in server_config" :key="data.id" :index="data.id" popper-append-to-body="false">
            <template #title>{{data.name}}</template>
            <div class="box" :index="index">
              <div
                class="imgbox"
                v-for="data2 in data.children"
                :key="data2.name"
                @click="addDatas(data.id,data2)"
              >
                <img :src="data2.thumbnail" alt class="img" />
                <img src="/img/common/cross.png" alt class="cross" v-show="data2.state != 0" />
                <span>{{data2.name}}</span>
                <el-popconfirm
                  title="确定删除吗？"
                  confirmButtonText="确认"
                  cancelButtonText="取消"
                  @confirm="DeleteDates(data.id,data2)"
                >
                  <template #reference>
                    <CircleClose
                      v-show="data2.state != 0 && data.id !='baseLayer'"
                      title="删除"
                      class="circle-close-icon"
                    />
                  </template>
                </el-popconfirm>
              </div>
            </div>
          </el-sub-menu>
          
          <!-- 本地服务二级菜单 -->
          <el-sub-menu index="1-4">
            <template #title>自定义服务</template>
            <el-menu-item 
              v-for="(service, index) in addCustomServices" 
              :key="service.id || index" 
              :index="'1-4-' + (service.id || index)"
              @dblclick="loadCustomService(service)"
              class="custom-service-item"
            >
              <span class="service-name" :class="{ 'service-loaded': isServiceLoaded(service) }">{{ service.name }}</span>
              <el-popconfirm
                v-if="isServiceLoaded(service)"
                title="确定卸载吗？"
                confirmButtonText="确认"
                cancelButtonText="取消"
                @confirm="unloadCustomService(service)"
              >
                <template #reference>
                  <el-icon class="delete-service-icon" title="卸载">
                    <CircleClose />
                  </el-icon>
                </template>
              </el-popconfirm>
            </el-menu-item>
          </el-sub-menu>
          
          <el-menu-item index="1-5" @click="addCustomService" class="no-active-style">
            <el-icon @click.stop="addCustomService" class="square-plus-icon"><Plus /></el-icon>
          </el-menu-item>
        </el-sub-menu>

        <!-- 加载组件 -->
        <el-sub-menu v-for="(data,index) in config" :key="index" :index="data.id">
          <template #title>
            <i :class="data.icon" class="iconfont2"></i>
            <span>{{data.name}}</span>
          </template>
          <div class="box">
            <div
                class="imgbox"
                v-for="data2 in data.children"
                :key="data2.component"
                @click="data2.component && change(data2.component,data2.destroy)"
              >
                <img :src="data2.imgSrc" alt class="img" />
                <img
                  src="/img/common/cross.png"
                  alt
                  class="cross"
                  v-show="data2.component && (data2.component === view || data2.component === view2)"
                />
                <span>{{data2.name}}</span>
              </div>
          </div>
        </el-sub-menu>

        <!-- 模型菜单 -->
        <el-sub-menu index="model" v-if="modelConfig.id">
          <template #title>
            <i :class="modelConfig.icon" class="iconfont2"></i>
            <span>{{modelConfig.name}}</span>
          </template>
          <el-sub-menu 
            v-for="(secondLevel, firstLevelKey) in groupedModels" 
            :key="firstLevelKey" 
            :index="'model-' + firstLevelKey"
            popper-append-to-body="false"
          >
            <template #title>
              <span>{{getFirstLevelName(firstLevelKey)}}</span>
              <el-tag size="small" type="info" style="margin-left: 8px;">{{getTotalCount(secondLevel)}}</el-tag>
            </template>
            <el-sub-menu 
              v-for="(models, secondLevelKey) in secondLevel" 
              :key="secondLevelKey" 
              :index="'model-' + firstLevelKey + '-' + secondLevelKey"
              popper-append-to-body="false"
            >
              <template #title>
                <span>{{getSecondLevelName(secondLevelKey)}}</span>
              </template>
              <el-menu-item 
                v-for="model in models" 
                :key="model.id" 
                :index="'model-' + firstLevelKey + '-' + secondLevelKey + '-' + model.id"
                @dblclick="loadModel(model)"
                class="model-menu-item"
              >
                <span class="model-name" :class="{ 'model-loaded': isModelLoaded(model.id) }">{{ model.name }}</span>
                <el-popconfirm
                  v-if="isModelLoaded(model.id)"
                  title="确定删除吗？"
                  confirmButtonText="确认"
                  cancelButtonText="取消"
                  @confirm="removeModel(model)"
                >
                  <template #reference>
                    <el-icon 
                      class="delete-model-icon" 
                      title="删除模型"
                    >
                      <CircleClose />
                    </el-icon>
                  </template>
                </el-popconfirm>
              </el-menu-item>
            </el-sub-menu>
          </el-sub-menu>
        </el-sub-menu>

        <!-- 台风菜单 -->
        <el-sub-menu index="typhoon">
          <template #title>
            <img src="/img/typhoon.png" alt="" class="typhoon-icon" />
            <span>台风</span>
          </template>
        </el-sub-menu>
      </el-menu>
    </el-aside>
    <!-- 侧边栏部分--end -->

    <!-- 右侧内容展示部分 -->
    <el-main>
      <loading-bar></loading-bar>
      <!-- 添加自定义服务组件 -->
      <component
        v-if="addService"
        :is="addService"
        :clear-callback="addCustomService"
        :add-callback="addCallback"
        :get-layer-name="getName"
      ></component>
      <!-- viewer组件 -->
      <component v-if="initViewer" :is="initViewer" :after-initviewer="removeLoad" :opening-animation="true"></component>
      <!-- 分析功能组件 -->
      <keep-alive>
        <component
          v-if="view"
          :is="view"
          :key="view"
          :delete-callback="deleteCallback"
          data-url="/data/netcdf/result_100_200_9_40.nc"  
          skylineSpatialAnalysisUrl="http://www.supermapol.com/realspace/services/spatialAnalysis-data_all/restjsr/spatialanalyst/geometry/3d/skylinesectorbody.json"
        ></component>
      </keep-alive>
      <!-- 地质体组件,单独展示，需要销毁 -->
      <component v-if="view2" :is="view2" :key="view2"></component>
    </el-main>
  </el-container>
</template>

<script>
import config from "../../config/views_config.js";  //组件配置
import server_config from "../../config/server_config.js";  //服务配置
import server_flyTo_config from "../../config/server_position_config.js";  //服务坐标配置
import layerManagement from "../../js/common/layerManagement.js";  //图层管理封装方法
import camera from "../../js/common/camera.js";  //相机操作
import loadingBar from "../../components/loading.vue";  //加载动画
import { CircleClose, Plus, CirclePlus } from '@element-plus/icons-vue';  //删除图标
import { listModel } from '@/api/watershed/model';  //模型API
import { getDefaultMapConfig, saveMapConfig } from '@/api/cesium/mapConfig';  //地图配置API
import serviceApi from '@/api/watershed/service';  //自定义服务API
import { ElMessage } from 'element-plus';
import { getToken } from '@/utils/auth'
import axios from 'axios'

export default {
  name: "layout-aside",
  components: {
    loadingBar,
    CircleClose
  },
  data() {
    return {
      isCollapse: false,
      asideWidth: "asideWidth1",
      view: "",
      view2: "",
      initViewer: "",
      addService: "",
      sceneURL:
        "http://www.supermapol.com/realspace/services/3D-ZF_normal/rest/realspace",
      config: config,
      server_config: server_config,
      baseLayerObj: server_config[1].children[0],
      terrainLayerObj: null,
      addCustomServices: [],
      getNames: [],  //记录自定义服务名称
      varName: null, //临时保存当前自定义名称
      loadedCustomServiceIds: [],  //已加载的自定义服务ID
      modelConfig: {},  //模型菜单配置
      modelData: [],  //模型数据
      loadedModelEntities: [],  //已加载的模型实体
      saveConfigTimer: null,  //保存配置的防抖定时器
      lastSaveTime: 0,  //上次保存时间戳
    };
  },

  computed: {
    groupedModels() {
      const grouped = {}
      this.modelData.forEach(model => {
        const type = model.type || '5/5-1'
        const parts = type.split('/')
        const firstLevel = parts[0] || '5'
        const secondLevel = parts[1] || '5-1'
        
        if (!grouped[firstLevel]) {
          grouped[firstLevel] = {}
        }
        if (!grouped[firstLevel][secondLevel]) {
          grouped[firstLevel][secondLevel] = []
        }
        grouped[firstLevel][secondLevel].push(model)
      })
      return grouped
    }
  },

  methods: {
    async fetchCustomServices() {
      try {
        console.log('开始从数据库加载自定义服务...');
        const response = await serviceApi.getServiceList({});
        console.log('获取到的自定义服务:', response);
        
        if (response && response.rows) {
          this.addCustomServices = response.rows.map(service => ({
            id: service.id || service.serviceId,
            name: service.name || service.serviceName,
            type: service.type || service.serviceType,
            url: service.url || service.serviceUrl,
            tokenRequired: service.tokenRequired || service.token_required,
            token: service.token || service.serviceToken,
            status: service.status,
            layers: [{
              type: service.type || service.serviceType,
              layerName: service.name || service.serviceName
            }]
          }));
          console.log('处理后的自定义服务列表:', this.addCustomServices);
        }
      } catch (error) {
        console.error('加载自定义服务失败:', error);
      }
    },

    getModelTypeOptions() {
      return [
        {
          value: '1',
          label: '水利工程实体',
          children: [
            { value: '1-1', label: '水库工程' },
            { value: '1-2', label: '水闸工程' },
            { value: '1-3', label: '泵站工程' },
            { value: '1-4', label: '灌区工程' },
            { value: '1-5', label: '堤防与护岸工程' }
          ]
        },
        {
          value: '2',
          label: '水系水利设施',
          children: [
            { value: '2-1', label: '河流' },
            { value: '2-2', label: '湖泊与水库水面' },
            { value: '2-3', label: '渠道与输水管道' },
            { value: '2-4', label: '河口与海岸带' }
          ]
        },
        {
          value: '3',
          label: '地理环境要素',
          children: [
            { value: '3-1', label: '地形地貌' },
            { value: '3-2', label: '行政区划' },
            { value: '3-3', label: '重要地物' }
          ]
        },
        {
          value: '4',
          label: '自然生态景观',
          children: [
            { value: '4-1', label: '湖泊湿地' },
            { value: '4-2', label: '森林公园' },
            { value: '4-3', label: '地质公园' },
            { value: '4-4', label: '海岸带景观' }
          ]
        },
        {
          value: '5',
          label: '模型集与项目',
          children: [
            { value: '5-1', label: '待分类模型' },
            { value: '5-2', label: 'XX市防洪排涝工程' }
          ]
        }
      ]
    },

    getFirstLevelName(firstLevelKey) {
      const options = this.getModelTypeOptions()
      const option = options.find(opt => opt.value === firstLevelKey)
      return option ? option.label : firstLevelKey
    },

    getSecondLevelName(secondLevelKey) {
      const options = this.getModelTypeOptions()
      for (const opt of options) {
        if (opt.children) {
          const child = opt.children.find(c => c.value === secondLevelKey)
          if (child) return child.label
        }
      }
      return secondLevelKey
    },

    getTotalCount(secondLevel) {
      let count = 0
      for (const key in secondLevel) {
        count += secondLevel[key].length
      }
      return count
    },

    getTypeDisplayName(type) {
      const typeMapping = {
        'RESERVOIR': '水库',
        'HYDROPOWER': '水电站',
        'IRRIGATION': '灌溉',
        'FLOOD_CONTROL': '防洪',
        'CANAL': '渠道',
        'PUMPING_STATION': '泵站',
        'OTHER': '其他'
      }
      
      if (typeMapping[type]) {
        return typeMapping[type]
      }
      
      return type
    },

    async fetchModels() {
      try {
        const data = await listModel({})
        const modelList = data.rows || []
        console.log('获取到的模型数据:', modelList)
        
        this.modelData = modelList.map(model => {
          console.log('模型详情:', model)
          return {
            id: model.id,
            name: model.name,
            type: model.type,
            format: model.format,
            uploadUnit: model.uploadUnit || '未知单位',
            filePath: model.filePath || model.file_path || model.url || '',
            coordinates: model.coordinates,
            originalData: model
          }
        })
        
        console.log('处理后的模型数据:', this.modelData)
        
        if (this.modelData.length > 0) {
          this.modelConfig = {
            id: 'model',
            icon: 'iconfont iconmoxing',
            name: '模型'
          }
        }
      } catch (error) {
        console.error('获取模型数据错误:', error)
      }
    },

    async loadModel(model, shouldFlyTo = true) {
      console.log('========== 开始加载模型 ==========')
      console.log('模型名称:', model.name)
      console.log('模型路径:', model.filePath)
      console.log('经纬度:', model.coordinates)
      console.log('模型格式:', model.format)
      console.log('viewer状态:', viewer)

      if (!viewer) {
        ElMessage.error('Cesium viewer 未初始化')
        return
      }

      if (!viewer.scene) {
        ElMessage.error('Cesium scene 未初始化')
        return
      }

      console.log('检查模型是否已加载:', model.id)
      console.log('已加载的模型实体:', this.loadedModelEntities)
      console.log('isModelLoaded结果:', this.isModelLoaded(model.id))

      if (this.isModelLoaded(model.id)) {
        console.log('模型已加载，先卸载再重新加载')
        this.removeModel(model)
      }

      try {
        if (!model.filePath) {
          ElMessage.warning('模型文件路径不存在，请检查数据库中的filePath字段')
          console.error('模型路径为空，模型数据:', model)
          return
        }

        let modelUrl = model.filePath
        
        console.log('原始模型路径:', modelUrl)
        
        // 修复路径中的双斜杠问题
        modelUrl = modelUrl.replace(/\/+/g, '/')
        console.log('修复后的模型路径:', modelUrl)
        
        // 检查是否是本地路径或相对路径
        const isLocalPath = modelUrl.startsWith('/') || modelUrl.startsWith('./') || modelUrl.startsWith('../') || !modelUrl.startsWith('http')
        
        if (isLocalPath) {
          console.log('检测到本地路径，通过后端API获取模型文件...')
          const baseURL = import.meta.env.VITE_APP_BASE_API || ''
          const apiUrl = baseURL + "/common/download/resource?resource=" + encodeURIComponent(modelUrl)
          console.log('API URL:', apiUrl)
          
          try {
            const response = await axios({
              method: 'get',
              url: apiUrl,
              responseType: 'blob',
              headers: { 'Authorization': 'Bearer ' + getToken() }
            })
            
            console.log('API响应状态:', response.status)
            console.log('Content-Type:', response.headers['content-type'])
            console.log('响应数据大小:', response.data.size, 'bytes')
            
            if (response.data.size === 0) {
              console.error('下载的模型文件为空')
              ElMessage.error('模型文件为空，请检查文件是否有效')
              return
            }
            
            let mimeType = 'model/gltf-binary'
            const format = model.format ? model.format.toUpperCase() : 'GLB'
            const fileExtension = model.filePath ? model.filePath.split('.').pop().toLowerCase() : ''
            
            console.log('模型格式:', format)
            console.log('文件扩展名:', fileExtension)
            
            if (format === 'GLTF' || fileExtension === 'gltf') {
              mimeType = 'model/gltf+json'
            } else if (format === 'GLB' || fileExtension === 'glb') {
              mimeType = 'model/gltf-binary'
            } else if (format === 'OBJ' || fileExtension === 'obj') {
              mimeType = 'model/obj'
            }
            
            console.log('使用的MIME类型:', mimeType)
            
            const blob = new Blob([response.data], { type: mimeType })
            modelUrl = URL.createObjectURL(blob)
            console.log('创建的Blob URL:', modelUrl)
            
            // ElMessage.success('模型文件下载成功，开始加载...')
          } catch (apiError) {
            console.error('通过API获取模型文件失败:', apiError)
            console.error('错误详情:', apiError.response)
            ElMessage.error('无法获取模型文件，请检查文件路径或权限')
            return
          }
        } else {
          console.log('使用远程URL直接加载模型:', modelUrl)
        }

        let position
        if (model.coordinates && model.coordinates.trim() !== '' && model.coordinates !== '未设置') {
          try {
            const coords = model.coordinates.split(',').map(c => parseFloat(c.trim()))
            console.log('解析后的坐标数组:', coords)
            
            if (coords.length >= 2 && !isNaN(coords[0]) && !isNaN(coords[1])) {
              const lon = coords[0]
              const lat = coords[1]
              const height = coords[2] || 0
              
              // 获取地面高度
              const cartographic = Cesium.Cartographic.fromDegrees(lon, lat)
              const terrainHeight = viewer.scene.globe.getHeight(cartographic)
              const groundHeight = terrainHeight || 0
              
              // 模型高度 = 地面高度 + 用户指定的高度
              position = Cesium.Cartesian3.fromDegrees(lon, lat, groundHeight + height)
              console.log('使用经纬度定位 - 经度:', lon, '纬度:', lat, '地面高度:', groundHeight, '模型高度:', height, '总高度:', groundHeight + height)
            } else {
              console.warn('经纬度格式不正确或为NaN，使用默认位置')
              position = Cesium.Cartesian3.fromDegrees(116.39, 39.9, 0)
            }
          } catch (e) {
            console.error('解析经纬度失败:', e)
            position = Cesium.Cartesian3.fromDegrees(116.39, 39.9, 0)
          }
        } else {
          console.warn('经纬度为空或未设置，使用默认位置')
          position = Cesium.Cartesian3.fromDegrees(116.39, 39.9, 0)
        }

        console.log('最终位置:', position)

        if (!position) {
          ElMessage.error('位置计算失败')
          return
        }

        const entity = viewer.entities.add({
          name: model.id,
          position: position,
          model: {
            uri: modelUrl,
            minimumPixelSize: 0,
            maximumScale: 1,
            scale: 1.0,
            show: true,
            distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 50000000.0),
            heightReference: Cesium.HeightReference.NONE
          }
        })

        console.log('实体已添加:', entity)
        console.log('模型URL:', modelUrl)
        console.log('模型URI:', entity.model.uri)

        this.loadedModelEntities.push(entity)

        if (shouldFlyTo) {
          setTimeout(() => {
            try {
              viewer.flyTo(entity, {
                duration: 2,
                offset: new Cesium.HeadingPitchRange(Cesium.Math.toRadians(0), Cesium.Math.toRadians(-30), 5)
              })
              console.log('开始飞行到模型位置')
            } catch (flyError) {
              console.error('飞行失败:', flyError)
              ElMessage.warning('模型已加载，但跳转失败')
            }
          }, 100)
        }

        this.saveLoadedServices()

        // ElMessage.success(`模型 "${model.name}" 加载成功`)
        console.log('========== 模型加载完成 ==========')
      } catch (error) {
        console.error('========== 加载模型错误 ==========')
        console.error('错误信息:', error)
        console.error('错误堆栈:', error.stack)
        ElMessage.error('加载模型失败: ' + (error.message || '未知错误'))
      }
    },

    isModelLoaded(modelId) {
      return this.loadedModelEntities.some(entity => entity.name === modelId)
    },

    removeModel(model) {
      const index = this.loadedModelEntities.findIndex(entity => entity.name === model.id)
      if (index !== -1) {
        const entity = this.loadedModelEntities[index]
        viewer.entities.remove(entity)
        this.loadedModelEntities.splice(index, 1)
        this.saveLoadedServices()
        // ElMessage.success(`模型 "${model.name}" 已删除`)
      }
    },

    // 区分地质体组件（需销毁）和其他组件
    change(val, val2) {
      if (val2) {
        this.view = "";
        if (val === this.view2) {
          this.view2 = "";
          return;
        }
        this.view2 = val;
      } else {
        this.view2 = "";
        if (val === this.view) {
          this.view = "";
          return;
        }
        this.view = val;
      }
    },

    //添加公共服务
    addWebServe(obj, shouldFlyTo = true) {
      if (obj.state === 0) {
        // add mvt
        if (obj.type === "MVT") {
          layerManagement.addMvtLayer(obj.proxiedUrl, obj.name, () => {
            obj.state = 1;
            window.store.actions.setChangeLayers();
            this.saveLoadedServices();
          });
          return;
        }
        // add scene
        layerManagement.addScene(
          obj.proxiedUrl,
          { autoSetView: false },
          layers => {
            obj.state = 1;
            window.store.actions.setChangeLayers();
            // 白膜添加线框
            if (obj.style && obj.style.fillStyle) {
              layers[0].style3D.lineColor = Cesium.Color.fromCssColorString(
                "rgb(67,67,67)"
              );
              layers[0].style3D.fillStyle =
                Cesium.FillStyle[obj.style.fillStyle];
            }
            this.saveLoadedServices();
            if (shouldFlyTo) {
              this.flyTo(obj.name, server_flyTo_config);
            }
          }
        );
      } else {
        if (shouldFlyTo) {
          this.flyTo(obj.name, server_flyTo_config);
        }
      }
    },
    // 添加底图
    addBaseLayer(obj) {
      if (this.baseLayerObj.type === obj.type) return;
      this.baseLayerObj.state = 0;
      obj.state = 1;
      this.baseLayerObj = obj;
      let type = obj.type;
      let url = obj.proxiedUrl;
      let imageryLayerCollection = viewer.scene.globe._imageryLayerCollection;
      let layer = imageryLayerCollection.get(0);
      let imageryProvider;
      if (imageryLayerCollection.get(2)) {
        imageryLayerCollection.remove(imageryLayerCollection.get(2));
      }
      if (imageryLayerCollection.get(1)) {
        imageryLayerCollection.remove(imageryLayerCollection.get(1));
      }
      switch (type) {
        case "BINGMAP":
          imageryProvider = new Cesium.BingMapsImageryProvider({
            url: url,
            key:
              "Aq0D7MCY5ErORA9vrwFtfE9aancUq5J6uNjw0GieF0ostaIrVuJZ8ScXxNHHvEwS"
          });
          break;
        case "TIANDITU":
          imageryProvider = new Cesium.TiandituImageryProvider({
            url: url,
            token: "3fb1e9fda20ee995dc815c8243553ce8"
          });
          break;
        case "IMAGE":
          imageryProvider = new Cesium.SingleTileImageryProvider({
            url: url
          });
          break;
        case "OSM":
          imageryProvider = new Cesium.createOpenStreetMapImageryProvider({
            url: url
          });
          break;
        case "MAPBOX":
          imageryProvider = new Cesium.MapboxImageryProvider({
            mapId: "mapbox.dark"
          });
          break;
        case "SUPERMAPDARK":
          imageryProvider = new Cesium.SuperMapImageryProvider({
            url: url
          });
          break;
        case "SUPERMAPLIGHT":
          imageryProvider = new Cesium.SuperMapImageryProvider({
            url: url
          });
          break;
        case "GRIDIMAGERY":
          imageryProvider = imageryProvider;
          break;
        default:
          imageryProvider = new Cesium.SingleTileImageryProvider({
            url: url
          });
          break;
      }
      if (type != "GRIDIMAGERY") {
        imageryLayerCollection.addImageryProvider(imageryProvider, 0);
        imageryLayerCollection.remove(layer);
      }
      if (type == "GRIDIMAGERY") {
        imageryLayerCollection.addImageryProvider(
          new Cesium.TileCoordinatesImageryProvider(),
          1
        );
        imageryLayerCollection.addImageryProvider(
          new Cesium.GridImageryProvider(),
          2
        );
      }
      this.saveLoadedServices();
    },
    // 添加在线地形
    addOnlineTerrain(obj) {
      if (this.terrainLayerObj) this.terrainLayerObj.state = 0;
      obj.state = 1;
      this.terrainLayerObj = obj;
      let type = obj.type;
      let url = obj.proxiedUrl;
      switch (type) {
        case "STKTerrain":
          viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
            url: url,
            isSct: false
          });
          break;
        case "tianDiTuTerrain":
          var t_Provider = new Cesium.TiandituTerrainProvider({
            token: "3fb1e9fda20ee995dc815c8243553ce8"
          });
          viewer.terrainProvider = t_Provider;
          break;
        case "supermapOnlineTerrain":
          viewer.terrainProvider = new Cesium.SCTTerrainProvider({
            urls: [url]
          });
          break;
        default:
          break;
      }
      this.saveLoadedServices();
    },

    // 移除地形
    removeTerrainLayer() {
      viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider({
        ellipsoid: viewer.scene.globe.ellipsoid
      });
      this.terrainLayerObj = null;
    },

    addDatas(id, obj, shouldFlyTo = true) {
      switch (id) {
        case "webServe":
          this.addWebServe(obj, shouldFlyTo);
          break;
        case "baseLayer":
          this.addBaseLayer(obj);
          break;
        case "onlineTerrain":
          this.addOnlineTerrain(obj);
          break;
      }
    },
    
    // 初始化viewer后的传入回调：添加底图和清除加载动画
    async removeLoad() {
      this.isRestoring = true; // 标记正在恢复，禁止保存
      
      setTimeout(() => {
        let loading = document.getElementById("loadingbar");
        if (loading) loading.remove(); //移除加载动画
        document.getElementById("el-aside").classList.remove("disable"); //解除禁止点击
      }, 1000);
      
      // 等待自定义服务加载完成后再恢复
      setTimeout(async () => {
        await this.fetchCustomServices();
        await this.restoreLoadedServices();
        this.isRestoring = false; // 恢复完成，允许保存
      }, 1500);
    },

    // 删除场景公共服务
    DeleteDates(datatype, obj) {
      switch (datatype) {
        case "webServe":
          obj.layers.forEach(layer => {
            layerManagement.layersDelete(layer.type, layer.layerName, () => {
              obj.state = 0;
              window.store.actions.setChangeLayers();
              this.saveLoadedServices();
            });
          });
          break;
        case "baseLayer":
          break;
        case "onlineTerrain":
          this.removeTerrainLayer();
          obj.state = 0;
          this.saveLoadedServices();
          break;
      }
    },

    isServiceLoaded(service) {
      if (!service) {
        return false;
      }
      const serviceId = service.id || service.serviceId;
      return this.loadedCustomServiceIds.includes(serviceId);
    },

    async loadCustomService(service, flyTo = true, shouldSave = true) {
      console.log('========== 开始加载自定义服务 ==========');
      console.log('服务名称:', service.name);
      console.log('服务类型:', service.type);
      console.log('服务URL:', service.url);
      console.log('是否跳转视角:', flyTo);
      console.log('viewer状态:', viewer);

      if (!viewer) {
        ElMessage.error('Cesium viewer 未初始化');
        return;
      }

      if (this.isServiceLoaded(service)) {
        console.log('服务已加载，执行定位');
        if (flyTo) {
          const type = service.type || (service.layers && service.layers[0] ? service.layers[0].type : null);
          if (type === 'SCENE' || type === 'S3M') {
            const layerNames = service.loadedLayerNames || [service.name];
            let foundLayer = null;
            for (const name of layerNames) {
              foundLayer = viewer.scene.layers.find(name);
              if (foundLayer) break;
            }
            if (foundLayer) {
              console.log('跳转到图层:', foundLayer.name);
              viewer.flyTo(foundLayer, { duration: 2 });
            } else if (viewer.scene.layers.layerQueue && viewer.scene.layers.layerQueue.length > 0) {
              viewer.flyTo(viewer.scene.layers.layerQueue[0], { duration: 2 });
            }
          } else {
            const layerName = service.name;
            camera.flyByLayerName(type, layerName);
          }
        }
        return;
      }

      try {
        const type = service.type || (service.layers && service.layers[0] ? service.layers[0].type : null);
        const url = service.url;
        const layerName = service.name;
        const token = service.token;
        const tokenRequired = service.tokenRequired;
        const serviceId = service.id || service.serviceId;

        const markAsLoaded = () => {
          if (!this.loadedCustomServiceIds.includes(serviceId)) {
            this.loadedCustomServiceIds.push(serviceId);
          }
        };

        switch (type) {
          case 'SCENE':
            let sceneOptions = {
              autoSetView: flyTo
            };
            if (tokenRequired && token) {
              sceneOptions.SceneToken = token;
            }
            const beforeLayersCount = viewer.scene.layers ? viewer.scene.layers.layerQueue.length : 0;
            console.log('加载前图层数量:', beforeLayersCount);
            console.log('是否自动跳转视角:', flyTo);
            layerManagement.addScene(url, sceneOptions, (layers) => {
              console.log('SCENE加载成功:', layers);
              markAsLoaded();
              const afterLayers = viewer.scene.layers ? viewer.scene.layers.layerQueue : [];
              const newLayers = afterLayers.slice(beforeLayersCount);
              console.log('新添加的图层:', newLayers);
              const newLayerNames = newLayers.map(l => l.name);
              console.log('新图层名称:', newLayerNames);
              service.loadedLayerNames = newLayerNames;
              const currentPosition = viewer.camera.positionCartographic;
              service.defaultCameraPosition = {
                longitude: currentPosition.longitude,
                latitude: currentPosition.latitude,
                height: currentPosition.height,
                heading: viewer.camera.heading,
                pitch: viewer.camera.pitch,
                roll: viewer.camera.roll
              };
              console.log('记录默认视口位置:', service.defaultCameraPosition);
              if (flyTo && newLayers.length > 0) {
                camera.flyByLayerName('SCENE', newLayers[0].name);
              }
            });
            break;
          case 'S3M':
            let scps = [{ url: url, options: { name: layerName } }];
            layerManagement.addS3mLayers(scps, (layers) => {
              console.log('S3M加载成功:', layers);
              markAsLoaded();
              if (flyTo) {
                camera.flyByLayerName('S3M', layerName);
              }
            });
            break;
          case 'IMG':
            let imgLayer = layerManagement.addImageLayer(url);
            console.log('IMG加载成功:', imgLayer);
            markAsLoaded();
            if (flyTo) {
              camera.flyByLayerName('IMG', layerName);
            }
            break;
          case 'TERRAIN':
            let terrainProvider = layerManagement.addTerrainLayer(url, false);
            console.log('TERRAIN加载成功:', terrainProvider);
            markAsLoaded();
            break;
          case 'MVT':
            layerManagement.addMvtLayer(url, layerName, (mvtlayer) => {
              console.log('MVT加载成功:', mvtlayer);
              markAsLoaded();
            });
            break;
          default:
            ElMessage.warning('不支持的服务类型: ' + type);
            return;
        }

        if (shouldSave) {
          ElMessage.success(`服务 "${service.name}" 加载成功`);
        }
        console.log('========== 自定义服务加载完成 ==========');
        
        if (shouldSave) {
          this.saveLoadedServices();
        }
      } catch (error) {
        console.error('加载自定义服务失败:', error);
        ElMessage.error('加载服务失败: ' + (error.message || '未知错误'));
      }
    },

    unloadCustomService(service) {
      console.log('开始卸载服务:', service);
      if (!service) {
        console.warn('服务对象为空');
        return;
      }
      
      const serviceId = service.id || service.serviceId;
      const serviceType = service.type || 'SCENE';
      
      if (serviceType === 'SCENE' && service.loadedLayerNames && service.loadedLayerNames.length > 0) {
        console.log('使用loadedLayerNames卸载SCENE图层:', service.loadedLayerNames);
        service.loadedLayerNames.forEach((layerName, index) => {
          console.log('卸载图层:', layerName);
          const isLast = index === service.loadedLayerNames.length - 1;
          layerManagement.layersDelete('S3M', layerName, () => {
            console.log('图层已卸载:', layerName);
            if (isLast) {
              const idx = this.loadedCustomServiceIds.indexOf(serviceId);
              if (idx > -1) {
                this.loadedCustomServiceIds.splice(idx, 1);
                console.log('已从loadedCustomServiceIds中移除服务:', serviceId);
              }
              window.store.actions.setChangeLayers();
              this.saveLoadedServices();
            }
          });
        });
      } else if (service.layers && service.layers.length > 0) {
        service.layers.forEach((layer, index) => {
          console.log('卸载图层:', layer.type, layer.layerName);
          const isLast = index === service.layers.length - 1;
          layerManagement.layersDelete(layer.type, layer.layerName, () => {
            console.log('图层已卸载:', layer.layerName);
            if (isLast) {
              const idx = this.loadedCustomServiceIds.indexOf(serviceId);
              if (idx > -1) {
                this.loadedCustomServiceIds.splice(idx, 1);
                console.log('已从loadedCustomServiceIds中移除服务:', serviceId);
              }
              window.store.actions.setChangeLayers();
              this.saveLoadedServices();
            }
          });
        });
      } else {
        const type = service.type || 'SCENE';
        const layerName = service.name;
        console.log('卸载参数 - serviceId:', serviceId, 'type:', type, 'layerName:', layerName);
        layerManagement.layersDelete(type, layerName, () => {
          console.log('服务已卸载:', service.name);
          const idx = this.loadedCustomServiceIds.indexOf(serviceId);
          if (idx > -1) {
            this.loadedCustomServiceIds.splice(idx, 1);
          }
          window.store.actions.setChangeLayers();
          this.saveLoadedServices();
        });
      }
    },

    // 控制自定义服务组件显隐
    addCustomService() {
      if (this.addService === "") {
        this.addService = "Sm3dCustomService";
        // 重置面板位置到默认值，使用setTimeout确保组件完全渲染
        setTimeout(() => {
          const panel = document.getElementById('CustomService-panel');
          if (panel) {
            panel.style.left = '35%';
            panel.style.top = '25%';
          }
        }, 100);
      } else {
        this.addService = "";
      }
      // 移除自定义服务菜单项的选中状态
      this.$nextTick(() => {
        const menu = this.$refs.menu;
        if (menu) {
          menu.activeIndex = "";
        }
      });
    },
    // 自定义服务添加回调函数
    addCallback(layers, add_type, serviceInfo) {
      console.log('接收到addCallback调用:', layers, add_type, serviceInfo);
      
      if (!Array.isArray(layers)) {
        layers = [layers];
      }
      let serviceOption = [];
      let serviceUrl = serviceInfo ? serviceInfo.url : "";
      let serviceToken = serviceInfo ? serviceInfo.token : "";
      let isAddToken = serviceInfo ? serviceInfo.tokenRequired : false;
      
      try {
        for (let i = 0; i < layers.length; i++) {
          if (!layers[i]) {
            console.log('layers[' + i + '] 是 undefined 或 null，跳过');
            continue;
          }
          if (layers[i].hasOwnProperty("_isS3MB")) {
            let option = {
              type: "S3M",
              layerName: layers[i].name
                ? layers[i].name
                : "s3m_" + new Date().getTime().toFixed(6)
            };
            serviceOption.push(option);
            if (!layers[i].maxVisibleAltitude)
              layers[i].maxVisibleAltitude = 8000;
          } else if (viewer.imageryLayers.contains(layers[i])) {
            let option = {
              type: "IMG",
              layerName: layers[i].imageryProvider.tablename
                ? layers[i].imageryProvider.tablename
                : "image" + new Date().getTime().toFixed(6)
            };
            serviceOption.push(option);
          } else if (
            layers[i].imageryLayer &&
            layers[i].imageryLayer._imageryProvider instanceof
              Cesium.MvtProviderGL
          ) {
            let option = {
              type: "MVT",
              layerName: layers[i].name
                ? layers[i].name
                : "mvt" + new Date().getTime().toFixed(6)
            };
            serviceOption.push(option);
            let index = this.addCustomServices.length;
            let obj = {
              name: layers[i].name ? layers[i].name : "自定义服务" + index,
              layers: serviceOption
            };
            this.addCustomServices.push(obj);
            this.addService = "";
            
            // 存储服务到数据库
            console.log('准备调用saveServiceToDatabase (MVT):', serviceInfo, add_type, obj.name);
            if (serviceInfo && serviceUrl) {
              console.log('调用saveServiceToDatabase (MVT)');
              this.saveServiceToDatabase(serviceInfo, add_type, obj.name);
            } else {
              console.log('serviceInfo或serviceUrl为空 (MVT):', serviceInfo, serviceUrl);
            }
            
            return;
          } else {
            let option = {
              type: "TERRAIN",
              layerName: layers[i].tablename ? layers[i].tablename : "terrain"
            };
            serviceOption.push(option);
          }
        }
      } catch (error) {
        console.error('处理layers时发生错误:', error);
      }
      
      if (this.varName) this.getNames.push(this.varName);
      let index = this.addCustomServices.length;
      let len = this.getNames.length - 1;
      let obj = {
        name: this.varName ? this.varName : "自定义服务" + index,
        layers: serviceOption
      };
      this.addCustomServices.push(obj);
      this.addService = "";
      this.varName = undefined;
      
      // 存储服务到数据库
      console.log('准备调用saveServiceToDatabase (非MVT):', serviceInfo, add_type, obj.name);
      if (serviceInfo && serviceUrl) {
        console.log('调用saveServiceToDatabase (非MVT)');
        this.saveServiceToDatabase(serviceInfo, add_type, obj.name);
      } else {
        console.log('serviceInfo或serviceUrl为空 (非MVT):', serviceInfo, serviceUrl);
      }
      
      if ((add_type && add_type === "SCENE") || add_type === "TERRAIN") return;
      camera.flyByLayerName(add_type, obj.layers[0].layerName); //定位
    },
    
    // 保存服务到数据库
    saveServiceToDatabase(serviceInfo, serviceType, serviceName) {
      console.log('开始保存服务到数据库:', serviceInfo, serviceType, serviceName);
      
      const serviceData = {
        name: serviceName,
        type: serviceType,
        url: serviceInfo.url,
        tokenRequired: serviceInfo.tokenRequired ? 1 : 0,
        token: serviceInfo.token,
        status: 'NORMAL'
      };
      
      console.log('准备保存服务:', serviceData);
      
      serviceApi.addService(serviceData)
        .then(response => {
          console.log('服务保存成功:', response);
          const newServiceId = response.data || response.serviceId;
          if (newServiceId) {
            const service = this.addCustomServices.find(s => s.name === serviceName);
            if (service) {
              service.id = newServiceId;
              service.url = serviceInfo.url;
              service.token = serviceInfo.token;
              service.tokenRequired = serviceInfo.tokenRequired;
              service.type = serviceType;
            }
            if (!this.loadedCustomServiceIds.includes(newServiceId)) {
              this.loadedCustomServiceIds.push(newServiceId);
            }
          }
        })
        .catch(error => {
          console.error('服务保存失败:', error);
          if (error.response) {
            console.error('错误响应状态:', error.response.status);
            console.error('错误响应数据:', error.response.data);
          } else if (error.request) {
            console.error('错误请求:', error.request);
          } else {
            console.error('错误信息:', error.message);
          }
        });
    },

    // 自定义服务获取名称回调
    getName(name) {
      this.varName = name;
    },

    // 添加服务飞行函数(公共服务配置好的定位)
    flyTo(webName, obj) {
      let cameraParam = obj[webName];
      if (cameraParam) {
        viewer.scene.camera.flyTo({
          destination: new Cesium.Cartesian3(
            cameraParam.Cartesian3.x,
            cameraParam.Cartesian3.y,
            cameraParam.Cartesian3.z
          ),
          orientation: {
            heading: cameraParam.heading,
            pitch: cameraParam.pitch,
            roll: cameraParam.roll
          },
          duration: 0
        });
        return;
      } else {
      }
    },

    //图层管理右键删除回调
    deleteCallback(node_rightClick) {
      this.server_config[0].children.forEach(sceneObj => {
        sceneObj.layers.forEach(layerObj => {
          if (layerObj.layerName === node_rightClick.label) {
            sceneObj.state = 0;
            return;
          }
        });
      });
    },

    // 保存已加载的服务到数据库 (带防抖)
    saveLoadedServices() {
      if (this.isRestoring) {
        console.log('正在恢复配置，跳过保存');
        return;
      }
      
      if (this.saveConfigTimer) {
        clearTimeout(this.saveConfigTimer);
      }
      
      this.saveConfigTimer = setTimeout(async () => {
        const now = Date.now();
        if (now - this.lastSaveTime < 2000) {
          console.log('距离上次保存不足2秒，跳过保存');
          return;
        }
        
        try {
          const loadedServices = {
            baseLayer: this.baseLayerObj ? {
              type: this.baseLayerObj.type,
              name: this.baseLayerObj.name,
              proxiedUrl: this.baseLayerObj.proxiedUrl
            } : null,
            terrainLayer: this.terrainLayerObj ? {
              type: this.terrainLayerObj.type,
              name: this.terrainLayerObj.name,
              proxiedUrl: this.terrainLayerObj.proxiedUrl
            } : null,
            webServices: this.server_config[0].children
              .filter(service => service.state === 1)
              .map(service => ({
                type: service.type,
                name: service.name,
                proxiedUrl: service.proxiedUrl,
                layers: service.layers,
                style: service.style
              }))
          };
          
          const loadedModels = this.loadedModelEntities.map(entity => {
            const model = this.modelData.find(m => m.id === entity.name);
            return model ? {
              id: model.id,
              name: model.name,
              type: model.type,
              filePath: model.filePath,
              coordinates: model.coordinates,
              format: model.format
            } : null;
          }).filter(m => m !== null);

          const loadedCustomServices = this.addCustomServices
            .filter(service => this.loadedCustomServiceIds.includes(service.id || service.serviceId))
            .map(service => ({
              id: service.id || service.serviceId,
              name: service.name,
              type: service.type,
              url: service.url,
              tokenRequired: service.tokenRequired,
              token: service.token,
              loadedLayerNames: service.loadedLayerNames || []
            }));

          const configData = {
            configName: '默认配置',
            baseLayerType: loadedServices.baseLayer ? loadedServices.baseLayer.type : '',
            baseLayerName: loadedServices.baseLayer ? loadedServices.baseLayer.name : '',
            baseLayerUrl: loadedServices.baseLayer ? loadedServices.baseLayer.proxiedUrl : '',
            terrainLayerType: loadedServices.terrainLayer ? loadedServices.terrainLayer.type : '',
            terrainLayerName: loadedServices.terrainLayer ? loadedServices.terrainLayer.name : '',
            terrainLayerUrl: loadedServices.terrainLayer ? loadedServices.terrainLayer.proxiedUrl : '',
            webServices: JSON.stringify(loadedServices.webServices),
            loadedModels: JSON.stringify(loadedModels),
            loadedCustomServices: JSON.stringify(loadedCustomServices)
          };

          console.log('========== 保存地图配置 ==========');
          await saveMapConfig(configData);
          this.lastSaveTime = Date.now();
          console.log('地图配置已保存到数据库');
        } catch (error) {
          console.error('保存地图配置失败:', error);
          console.error('错误详情:', error.message);
          if (error.response) {
            console.error('响应状态:', error.response.status);
            console.error('响应数据:', error.response.data);
          }
        }
      }, 500);
    },

    // 从数据库恢复已加载的服务和模型
    async restoreLoadedServices() {
      try {
        console.log('========== 开始恢复地图配置 ==========');
        const response = await getDefaultMapConfig();
        console.log('API响应:', response);
        
        if (!response || !response.data) {
          console.log('没有找到保存的地图配置，使用默认配置');
          return;
        }

        const config = response.data;
        console.log('保存的配置:', config);
        
        let loadedServices = null;
        let loadedModels = null;

        // 保存需要恢复的自定义服务信息（不立即设置loadedCustomServiceIds，避免跳过加载步骤）
        let customServicesToLoad = [];
        if (config.loadedCustomServices) {
          try {
            const savedCustomServices = JSON.parse(config.loadedCustomServices);
            console.log('解析的自定义服务配置:', savedCustomServices);
            if (savedCustomServices && savedCustomServices.length > 0) {
              customServicesToLoad = savedCustomServices.map(s => ({
                id: s.id,
                loadedLayerNames: s.loadedLayerNames || []
              }));
              console.log('需要恢复的自定义服务:', customServicesToLoad);
            }
          } catch (e) {
            console.error('解析自定义服务配置失败:', e);
          }
        }

        // 解析服务配置
        if (config.webServices) {
          try {
            loadedServices = JSON.parse(config.webServices);
            console.log('解析的服务配置:', loadedServices);
          } catch (e) {
            console.error('解析服务配置失败:', e);
          }
        }

        // 解析模型配置
        if (config.loadedModels) {
          try {
            loadedModels = JSON.parse(config.loadedModels);
            console.log('解析的模型配置:', loadedModels);
          } catch (e) {
            console.error('解析模型配置失败:', e);
          }
        }

        // 恢复底图
        if (config.baseLayerType) {
          const baseLayer = this.server_config[1].children.find(
            layer => layer.type === config.baseLayerType
          );
          if (baseLayer) {
            console.log('恢复底图:', baseLayer.name);
            await new Promise(resolve => {
              this.addBaseLayer(baseLayer);
              setTimeout(resolve, 500);
            });
          }
        }

        // 恢复地形
        if (config.terrainLayerType) {
          const terrainLayer = this.server_config[2].children.find(
            layer => layer.type === config.terrainLayerType
          );
          if (terrainLayer) {
            await new Promise(resolve => {
              this.addOnlineTerrain(terrainLayer);
              setTimeout(resolve, 500);
            });
          }
        }

        // 恢复公共服务
        if (loadedServices && loadedServices.length > 0) {
          for (const webService of loadedServices) {
            const service = this.server_config[0].children.find(
              s => s.name === webService.name
            );
            if (service) {
              console.log('恢复公共服务:', service.name);
              await new Promise(resolve => {
                service.state = 0;
                this.addWebServe(service, false);
                setTimeout(resolve, 500);
              });
            }
          }
        }

        // 恢复模型
        if (loadedModels && loadedModels.length > 0) {
          for (const modelData of loadedModels) {
            const model = this.modelData.find(m => m.id === modelData.id);
            if (model && !this.isModelLoaded(model.id)) {
              await new Promise(resolve => {
                this.loadModel(model, false);
                setTimeout(resolve, 1000);
              });
            }
          }
        }

        // 恢复自定义服务 (初始化时不跳转视角，不保存)
        if (customServicesToLoad && customServicesToLoad.length > 0) {
          for (const serviceInfo of customServicesToLoad) {
            const customService = this.addCustomServices.find(
              s => (s.id || s.serviceId) === serviceInfo.id
            );
            if (customService && !this.isServiceLoaded(customService)) {
              // 恢复 loadedLayerNames
              if (serviceInfo.loadedLayerNames && serviceInfo.loadedLayerNames.length > 0) {
                customService.loadedLayerNames = serviceInfo.loadedLayerNames;
                console.log('恢复服务loadedLayerNames:', customService.name, serviceInfo.loadedLayerNames);
              }
              console.log('恢复自定义服务:', customService.name);
              await new Promise(resolve => {
                this.loadCustomService(customService, false, false);
                setTimeout(resolve, 1000);
              });
            }
          }
        }

        console.log('地图配置恢复完成');
      } catch (error) {
        console.error('恢复地图配置失败:', error);
        console.error('错误详情:', error.message);
        console.error('错误堆栈:', error.stack);
        if (error.response) {
          console.error('响应状态:', error.response.status);
          console.error('响应数据:', error.response.data);
        }
      }
    },

    // 清除所有持久化数据
    clearPersistence() {
      localStorage.removeItem('cesium_loaded_services');
      localStorage.removeItem('cesium_loaded_models');
      console.log('持久化数据已清除');
    }
  },
  
  watch: {
    isCollapse(val) {
      if (val) {
        this.asideWidth = "asideWidth2";
      } else {
        this.asideWidth = "asideWidth1";
      }
    }
  },
  mounted() {
    document.getElementById("el-aside").classList.add("disable"); //禁止点击
    // 直接初始化 viewer，不使用 window.onload
    this.$nextTick(() => {
      this.initViewer = "Sm3dViewer";
      // 获取模型数据
      this.fetchModels();
      // 从数据库加载自定义服务
      this.fetchCustomServices();
    });
  }
};
</script>

<style lang="scss" scoped>
.container {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: auto;
}

/* 侧边栏宽度控制 */
.asideWidth1 {
  width: 280px !important;
  transition-duration: 0.3s;
  height: 100% !important;
}
.asideWidth2 {
  transition-duration: 0.5s;
  width: 40px !important;
  height: 100% !important;
  display: flex !important;
  justify-content: center !important;
}

/* 确保el-container能够铺满整个容器 */
.el-container {
  height: 100% !important;
  width: 100% !important;
  pointer-events: auto;
}

/* 确保el-aside能够正确接收点击事件 */
.el-aside {
  position: relative;
  z-index: 1000;
  pointer-events: auto;
}

/* 确保el-main能够铺满整个容器 */
.el-main {
  position: relative;
  z-index: 1;
  height: 100% !important;
  width: 100% !important;
  padding: 0 !important;
  margin: 0 !important;
  pointer-events: auto;
}

/* 确保cesiumContainer能够铺满整个el-main */
#cesiumContainer {
  position: relative;
  z-index: 10;
  height: 100% !important;
  width: 100% !important;
  pointer-events: auto;
}

/* 确保cesium-viewer能够铺满整个cesiumContainer */
.cesium-viewer {
  height: 100% !important;
  width: 100% !important;
  pointer-events: auto;
}

/* 确保cesium-widget能够铺满整个cesium-viewer */
.cesium-widget {
  height: 100% !important;
  width: 100% !important;
  pointer-events: auto;
}

/* 确保canvas能够铺满整个cesium-widget */
.cesium-widget canvas {
  position: relative;
  z-index: 5;
  height: 100% !important;
  width: 100% !important;
  pointer-events: auto;
}

/* 确保侧边栏菜单能够正确接收点击事件 */
.el-menu-vertical-demo {
  position: relative;
  z-index: 1001;
  pointer-events: auto;
}

/* 确保加载动画不影响点击事件 */
#loadingbar {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 9999;
  pointer-events: none;
}

/* 侧边栏样式增强 */
.el-aside {
  background-color: #f8f9fa;
  overflow-y: scroll;
  overflow-x: hidden;
  scrollbar-width: none;
  /* firefox */
  -ms-overflow-style: none;
  height: 100% !important;
  box-shadow: 2px 0 10px rgba(0, 0, 0, 0.05);

  .el-menu--collapse {
    width: 40px;
    height: 100% !important;
  }
  
  :deep(.el-menu--collapse.el-menu) {
    width: 40px !important;
    margin: 0 auto !important;
  }
  
  :deep(.el-menu--collapse .el-menu-item),
  :deep(.el-menu--collapse .el-submenu__title),
  :deep(.el-menu--collapse .el-sub-menu__title) {
    padding: 0 !important;
    text-align: center !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    position: relative !important;
    left: 0 !important;
    right: 0 !important;
    width: 40px !important;
    height: 45px !important;
    margin: 0 auto !important;
    /* 强制开启hover触发，解决折叠后无法识别子项问题 */
    pointer-events: auto !important;
    cursor: pointer !important;
  }
  
  :deep(.el-menu--collapse .el-sub-menu) {
    width: 40px !important;
    /* 二级弹框容器相对定位，让三级能基于它定位 */
    position: relative !important;
  }
  
  :deep(.el-menu--collapse .el-menu-item > *),
  :deep(.el-menu--collapse .el-submenu__title > *),
  :deep(.el-menu--collapse .el-sub-menu__title > *) {
    margin: 0 !important;
    padding: 0 !important;
    position: static !important;
    left: auto !important;
    right: auto !important;
    top: auto !important;
    bottom: auto !important;
    transform: none !important;
    float: none !important;
    display: inline-block !important;
    width: auto !important;
    height: auto !important;
  }
  
  :deep(.el-menu--collapse .el-menu-item i.rotate),
  :deep(.el-menu--collapse .el-submenu__title i.rotate),
  :deep(.el-menu--collapse .el-sub-menu__title i.rotate) {
    margin: 0 !important;
    padding: 0 !important;
    display: inline-block !important;
    text-align: center !important;
    width: auto !important;
    height: auto !important;
    position: static !important;
    left: auto !important;
    right: auto !important;
    transform: rotate(-90deg) !important;
    line-height: normal !important;
    float: none !important;
  }
  
  :deep(.el-menu--collapse .el-submenu__title .iconfont2),
  :deep(.el-menu--collapse .el-menu-item .iconfont2),
  :deep(.el-menu--collapse .el-sub-menu__title .iconfont2) {
    margin: 0 !important;
    padding: 0 !important;
    display: inline-block !important;
    text-align: center !important;
    width: auto !important;
    height: auto !important;
    position: static !important;
    left: auto !important;
    right: auto !important;
    transform: none !important;
    float: none !important;
  }
  
  :deep(.el-menu--collapse .el-sub-menu__title .typhoon-icon) {
    margin: 0 !important;
    padding: 0 !important;
    display: inline-block !important;
    text-align: center !important;
    width: 20px !important;
    height: 20px !important;
    position: static !important;
    left: auto !important;
    right: auto !important;
    transform: none !important;
    float: none !important;
  }
  
  :deep(.el-menu--collapse .el-submenu__title span),
  :deep(.el-menu--collapse .el-menu-item span),
  :deep(.el-menu--collapse .el-sub-menu__title span) {
    display: none !important;
  }
  
  :deep(.el-menu--collapse .el-submenu__icon-arrow),
  :deep(.el-menu--collapse .el-sub-menu__icon-arrow) {
    display: none !important;
  }

  .el-menu {
    border-right: none;
    height: 100% !important;
    .el-menu-item,
    .el-submenu__title {
      height: 45px;
      line-height: 45px;
    }
    
    :deep(.el-menu--collapse .el-menu-item),
    :deep(.el-menu--collapse .el-submenu__title),
    :deep(.el-menu--collapse .el-sub-menu__title) {
      padding: 0 !important;
      text-align: center !important;
      display: flex !important;
      align-items: center !important;
      justify-content: center !important;
      position: relative !important;
      left: 0 !important;
      right: 0 !important;
      width: 40px !important;
      height: 45px !important;
      line-height: normal !important;
    }

    #fold {
      height: 35px;
      transition-duration: 1s;
      color: #303133 !important;
      padding: 0 !important;
      text-align: center !important;
      line-height: 35px !important;
      display: flex !important;
      align-items: center !important;
      justify-content: center !important;
      background-color: transparent !important;
    }
    
    #fold.is-active {
      background-color: transparent !important;
      color: #303133 !important;
    }
    
    #fold:hover {
      background-color: rgba(64, 158, 255, 0.1) !important;
    }
  }
}

/* 修复Element Plus 2.x 子菜单标题样式 */
.el-submenu__title {
  padding: 0 12px !important;
}

.el-menu--vertical > .el-menu-item {
  padding: 0 12px !important;
}

/* 确保标题框尺寸正确 */
.el-submenu__title .el-submenu__icon-arrow {
  margin-top: -4px !important;
}

/* 修复图标和文字对齐 */
.iconfont2 {
  font-size: 20px !important;
  margin-right: 10px;
  vertical-align: middle;
  color: #303133;
}

/* 台风图标样式 */
.typhoon-icon {
  width: 20px;
  height: 20px;
  margin-right: 10px;
  vertical-align: middle;
}

/* 子菜单项文字颜色 */
.el-menu--vertical .el-sub-menu .el-menu-item {
  color: #303133 !important;
  font-size: 0.875rem !important;
  line-height: 1.5;
}

/* 本地服务菜单项文字向左移动 */
.custom-service-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-left: 50px !important;
}

.custom-service-item.is-active {
  background-color: transparent !important;
}

.custom-service-item .service-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.custom-service-item .service-name.service-loaded {
  color: #409eff;
  font-weight: 500;
}

.custom-service-item .delete-service-icon {
  margin-left: 8px;
  cursor: pointer;
  color: #909399;
  transition: color 0.3s;
}

.custom-service-item .delete-service-icon:hover {
  color: #f56c6c;
}

/* 自定义服务菜单项移除选中样式 */
.no-active-style {
  background-color: transparent !important;
}
.no-active-style.is-active {
  background-color: transparent !important;
}

/* 模型菜单项样式 */
.model-menu-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-left: 50px !important;
}

.model-menu-item.is-active {
  background-color: transparent !important;
}

.model-menu-item .model-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding-left: 10px;
}

.model-menu-item .model-name.model-loaded {
  color: #409eff;
  font-weight: 500;
}

.model-menu-item .delete-model-icon {
  margin-left: 8px;
  cursor: pointer;
  color: #909399;
  transition: color 0.3s;
}

.model-menu-item .delete-model-icon:hover {
  color: #f56c6c;
}

/* 滚动条隐藏 */
.el-aside::-webkit-scrollbar {
  display: none;
}

/* 功能模块网格布局 */
.box {
  font-family: "Microsoft Yahei";
  display: flex;
  width: 100%;
  padding: 0 10px 0 28px;
  justify-content: space-between;
  box-sizing: border-box;
  flex-wrap: wrap;

  .imgbox {
    position: relative;
    width: 100px;
    height: 100px;
    display: flex;
    box-sizing: border-box;
    margin-bottom: 5px;
    flex-wrap: wrap;
    justify-content: center;
    span {
      font-size: 12px;
      color: #303133;
    }
    .img {
      width: 100%;
      height: 72px;
      border-radius: 4px;
      background-color: #585858;
      border: 1px solid #e4e7ed;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
      transition: all 0.3s ease;
    }
    .img:hover {
      border: 2px solid #409eff;
      box-shadow: 0 4px 8px rgba(64, 158, 255, 0.2);
      transform: translateY(-2px);
    }
    .cross {
      width: 25px;
      height: 25px;
      position: absolute;
      top: 0;
      left: 0;
    }
  }
}

/* 删除图标样式 */
.circle-close-icon {
  position: absolute;
  right: 0px;
  top: 3px;
  color: #ffffff;
  cursor: pointer;
  width: 16px;
  height: 16px;
  font-size: 16px;
  outline: none;
}
.circle-close-icon:focus,
.circle-close-icon:active {
  outline: none;
  box-shadow: none;
}

/* el-menu-item 内的删除图标样式 */
.el-menu-item .circle-close-icon {
  top: 50%;
  transform: translateY(-50%);
  color: #000000;
  right: 25px;
}

/* 展开/收缩按钮动画 */
.rotate2 {
  transform: rotate(0deg);
  -ms-transform: rotate(0); /* IE 9 */
  -moz-transform: rotate(0); /* Firefox */
  -webkit-transform: rotate(0); /* Safari 和 Chrome */
  -o-transform: rotate(0); /* Opera */
  transition-duration: 1s;
}

.rotate {
  margin-left: 8px !important;
  line-height: 52px !important;
  transform: rotate(-90deg);
  -ms-transform: rotate(-90deg); /* IE 9 */
  -moz-transform: rotate(-90deg); /* Firefox */
  -webkit-transform: rotate(-90deg); /* Safari 和 Chrome */
  -o-transform: rotate(-90deg); /* Opera */
  transition-duration: 1s;
}

/* 禁用状态 */
.disable {
  pointer-events: none;
}

/* 图标样式 */
.iconfont2 {
  font-size: 20px !important;
  margin-right: 10px;
}

/* 方形加号图标 */
.square-plus-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: 1.5px solid #909399;
  border-radius: 4px;
  font-size: 16px;
  margin-left: 10px;
}

// ########### 关键修复：折叠状态下 二级弹框保留原位置 + 三级强制弹出 ###########
// 1. 折叠状态二级弹框：强制保留原有正确位置，不做任何改动
:deep(.el-menu--collapse .el-sub-menu > .el-sub-menu__popper) {
  position: fixed !important;
  margin-left: 0 !important;
  transform: none !important;
  z-index: 9998 !important;
}

// 2. 折叠状态二级弹框容器：hover时强制显示三级内容，核心触发逻辑
:deep(.el-menu--collapse .el-sub-menu__popper) {
  pointer-events: auto !important;
  &:hover .box {
    display: flex !important;
  }
}

// 3. 折叠状态三级内容（box）：强制定位在二级弹框右侧，顶对齐
:deep(.el-menu--collapse .el-sub-menu__popper .box) {
  position: absolute !important;
  left: 100% !important; // 紧贴二级弹框右侧
  top: 0 !important;     // 和二级弹框顶对齐
  z-index: 9999 !important;
  width: 300px !important; // 适配你的imgbox布局
  background: #f8f9fa !important;
  border: 1px solid #e4e7ed !important;
  border-left: none !important;
  box-shadow: 2px 2px 10px rgba(0,0,0,0.05) !important;
  padding: 10px !important;
  margin: 0 !important;
  // 强制显示，解决折叠后被隐藏问题
  display: flex !important;
  pointer-events: auto !important;
}

// 4. 折叠状态三级imgbox布局适配：清除多余间距，正常显示
:deep(.el-menu--collapse .el-sub-menu__popper .box .imgbox) {
  margin: 0 10px 10px 0 !important;
}

// 5. 展开状态：恢复原有布局，不影响任何效果
:deep(.el-menu--not-collapse .el-sub-menu__popper .box) {
  position: static !important;
  width: 100% !important;
  box-shadow: none !important;
  border: none !important;
}
</style>