<template>
  <el-dialog
    v-model="dialogVisible"
    :title="modelName"
    width="80%"
    :before-close="handleClose"
    destroy-on-close
  >
    <div class="model-preview-container">
      <div ref="modelContainer" class="model-container">
        <!-- 光照控制按钮 -->
        <div class="light-control-btn" @click="toggleLightControl">
          <el-icon><Sunny /></el-icon>
        </div>
        
        <!-- 光照控制面板 -->
        <div v-if="showLightControl" class="light-control-panel">
          <h4>光照控制</h4>
          
          <!-- 材质透明度调整 -->
          <div class="control-item">
            <label>材质不透明度</label>
            <el-slider 
              v-model="materialOpacity" 
              :min="0.1" 
              :max="1" 
              :step="0.05" 
              @change="updateMaterialOpacity"
            />
            <span class="value">{{ materialOpacity.toFixed(2) }}</span>
          </div>
          
          <!-- 环境光强度 -->
          <div class="control-item">
            <label>环境光强度</label>
            <el-slider 
              v-model="lightSettings.ambientIntensity" 
              :min="0" 
              :max="5" 
              :step="0.1" 
              @change="updateLights"
            />
            <span class="value">{{ lightSettings.ambientIntensity.toFixed(1) }}</span>
          </div>
          
          <!-- 主平行光强度 -->
          <div class="control-item">
            <label>主光源强度</label>
            <el-slider 
              v-model="lightSettings.directionalIntensity" 
              :min="0" 
              :max="10" 
              :step="0.1" 
              @change="updateLights"
            />
            <span class="value">{{ lightSettings.directionalIntensity.toFixed(1) }}</span>
          </div>
          
          <!-- 辅助光强度 -->
          <div class="control-item">
            <label>辅助光强度</label>
            <el-slider 
              v-model="lightSettings.directionalIntensity2" 
              :min="0" 
              :max="5" 
              :step="0.1" 
              @change="updateLights"
            />
            <span class="value">{{ lightSettings.directionalIntensity2.toFixed(1) }}</span>
          </div>
          
          <!-- 主光源角度 -->
          <div class="control-item">
            <label>主光源角度</label>
            <div class="angle-controls">
              <div>
                <span>X轴</span>
                <el-slider 
                  v-model="lightSettings.directionalPosition.x" 
                  :min="-5" 
                  :max="5" 
                  :step="0.1" 
                  @change="updateLights"
                />
                <span class="value">{{ lightSettings.directionalPosition.x.toFixed(1) }}</span>
              </div>
              <div>
                <span>Y轴</span>
                <el-slider 
                  v-model="lightSettings.directionalPosition.y" 
                  :min="-5" 
                  :max="5" 
                  :step="0.1" 
                  @change="updateLights"
                />
                <span class="value">{{ lightSettings.directionalPosition.y.toFixed(1) }}</span>
              </div>
              <div>
                <span>Z轴</span>
                <el-slider 
                  v-model="lightSettings.directionalPosition.z" 
                  :min="-5" 
                  :max="5" 
                  :step="0.1" 
                  @change="updateLights"
                />
                <span class="value">{{ lightSettings.directionalPosition.z.toFixed(1) }}</span>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="model-info">
        <h3>模型信息</h3>
        <el-descriptions :column="1" border>
          <el-descriptions-item label="模型名称">{{ modelData.name }}</el-descriptions-item>
          <el-descriptions-item label="模型类型">{{ getTypeDisplayName(modelData.type) }}</el-descriptions-item>
          <el-descriptions-item label="经纬度">{{ modelData.location }}</el-descriptions-item>
          <el-descriptions-item label="提交单位">{{ modelData.uploadUnit }}</el-descriptions-item>
          <el-descriptions-item label="格式">{{ modelData.format }}</el-descriptions-item>
          <el-descriptions-item label="状态">{{ modelData.status }}</el-descriptions-item>
          <el-descriptions-item label="创建时间">{{ modelData.createTime }}</el-descriptions-item>
        </el-descriptions>
      </div>
    </div>
    <template #footer>
      <el-button @click="handleClose">关闭</el-button>
    </template>
  </el-dialog>
</template>

<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue'
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js'
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader.js'
// 导入项目的request实例
import request from '@/utils/request'
import { Sunny } from '@element-plus/icons-vue'

const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  },
  modelData: {
    type: Object,
    default: () => ({})
  }
})

const emit = defineEmits(['update:visible', 'close'])

const modelContainer = ref(null)
let scene = null
let camera = null
let renderer = null
let model = null
let controls = null
let animationId = null
const dialogVisible = ref(false)

// 光照控制相关变量
const showLightControl = ref(false)
let ambientLight = null
let directionalLight = null
let directionalLight2 = null
const lightSettings = ref({
  ambientIntensity: 2.0,
  directionalIntensity: 4.0,
  directionalIntensity2: 2.0,
  directionalPosition: {
    x: 1,
    y: 1,
    z: 1
  }
})

const materialOpacity = ref(1.0)

// 获取类型显示名称
const getTypeDisplayName = (type) => {
  const typeMapping = {
    'RESERVOIR': '水库',
    'HYDROPOWER': '水电站', 
    'IRRIGATION': '灌溉',
    'FLOOD_CONTROL': '防洪',
    'CANAL': '渠道',
    'PUMPING_STATION': '泵站'
  }
  return typeMapping[type] || type
}

// 初始化场景
const initScene = () => {
  if (!modelContainer.value) return

  // 创建场景
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0xf0f0f0)

  // 创建相机
  camera = new THREE.PerspectiveCamera(
    75,
    modelContainer.value.clientWidth / modelContainer.value.clientHeight,
    0.1,
    1000
  )
  // 增加相机初始位置，让相机离模型更远，以便能看到整个模型
  camera.position.z = 10
  camera.position.y = 2

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(modelContainer.value.clientWidth, modelContainer.value.clientHeight)
  modelContainer.value.appendChild(renderer.domElement)

  // 添加光源
  ambientLight = new THREE.AmbientLight(0xffffff, lightSettings.value.ambientIntensity)
  scene.add(ambientLight)

  directionalLight = new THREE.DirectionalLight(0xffffff, lightSettings.value.directionalIntensity)
  directionalLight.position.set(
    lightSettings.value.directionalPosition.x,
    lightSettings.value.directionalPosition.y,
    lightSettings.value.directionalPosition.z
  )
  scene.add(directionalLight)
  
  // 添加第二个平行光，从不同角度照射，增强照明效果
  directionalLight2 = new THREE.DirectionalLight(0xffffff, lightSettings.value.directionalIntensity2)
  directionalLight2.position.set(-1, 1, -1)
  scene.add(directionalLight2)

  // 添加网格辅助线
  const gridHelper = new THREE.GridHelper(10, 10)
  scene.add(gridHelper)

  // 加载模型
  if (props.modelData) {
    loadModel()
  }

  // 添加鼠标控制
  initControls()

  // 添加三维坐标轴
  addAxesHelper()

  // 开始渲染
  animate()

  // 监听窗口大小变化
  window.addEventListener('resize', handleResize)
  
  // 添加光照控制面板事件阻止
  addLightControlEventPrevent()
}

// 初始化控制器
const initControls = () => {
  // 简单的鼠标控制实现 - 控制相机视角
  let isDragging = false
  let isPanning = false // 中键平移状态
  let previousMousePosition = { x: 0, y: 0 }
  
  // 相机目标点（看向的点）
  let cameraTarget = new THREE.Vector3(0, 0, 0)
  
  // 更新相机目标点为模型中心
  const updateCameraTarget = () => {
    if (model) {
      model.updateMatrixWorld(true)
      const box = new THREE.Box3().setFromObject(model)
      cameraTarget = box.getCenter(new THREE.Vector3())
      console.log('相机目标点已更新为模型中心:', cameraTarget)
    }
  }
  
  // 初始化时更新目标点
  updateCameraTarget()

  const container = modelContainer.value
  
  // 检查事件是否来自光照控制面板
  const isFromLightControl = (e) => {
    let target = e.target
    while (target) {
      if (target.classList && (target.classList.contains('light-control-panel') || target.classList.contains('light-control-btn'))) {
        return true
      }
      target = target.parentElement
    }
    return false
  }

  container.addEventListener('mousedown', (e) => {
    // 如果事件来自光照控制面板，不处理
    if (isFromLightControl(e)) return
    
    // 检查是否是中键
    if (e.button === 1) { // 中键
      isPanning = true
    } else if (e.button === 0) { // 左键
      isDragging = true
    }
    
    previousMousePosition = { x: e.offsetX, y: e.offsetY }
  })

  container.addEventListener('mousemove', (e) => {
    // 如果事件来自光照控制面板，不处理
    if (isFromLightControl(e)) return
    
    const deltaMove = {
      x: e.offsetX - previousMousePosition.x,
      y: e.offsetY - previousMousePosition.y
    }

    // 中键平移相机
    if (isPanning && camera) {
      // 计算平移距离
      const distance = camera.position.distanceTo(cameraTarget)
      const panSpeed = distance * 0.001
      
      // 计算相机的右方向和上方向
      const right = new THREE.Vector3()
      const up = new THREE.Vector3()
      camera.getWorldDirection(right)
      right.crossVectors(camera.up, right).normalize()
      up.copy(camera.up).normalize()
      
      // 计算平移向量
      const pan = new THREE.Vector3()
      pan.addScaledVector(right, deltaMove.x * panSpeed)
      pan.addScaledVector(up, deltaMove.y * panSpeed)
      
      // 平移相机和目标点
      camera.position.add(pan)
      cameraTarget.add(pan)
      
      // 相机看向目标点
      camera.lookAt(cameraTarget)
    }
    // 左键旋转相机
    else if (isDragging && camera) {
      // 控制相机围绕目标点旋转
      // 计算相机到目标点的距离
      const distance = camera.position.distanceTo(cameraTarget)
      
      // 限制垂直旋转范围，避免相机翻转
      const currentPosition = new THREE.Vector3().copy(camera.position)
      const direction = new THREE.Vector3().subVectors(currentPosition, cameraTarget).normalize()
      
      // 水平旋转（围绕Y轴）
      const horizontalRotation = new THREE.Matrix4().makeRotationY(-deltaMove.x * 0.01)
      // 垂直旋转（围绕X轴，限制范围）
      const verticalRotation = new THREE.Matrix4().makeRotationX(-deltaMove.y * 0.005)
      
      // 应用旋转
      const newDirection = direction.applyMatrix4(horizontalRotation).applyMatrix4(verticalRotation)
      
      // 设置新的相机位置
      camera.position.copy(cameraTarget).add(newDirection.multiplyScalar(distance))
      
      // 相机看向目标点
      camera.lookAt(cameraTarget)
    }

    previousMousePosition = {
      x: e.offsetX,
      y: e.offsetY
    }
  })

  container.addEventListener('mouseup', (e) => {
    // 如果事件来自光照控制面板，不处理
    if (isFromLightControl(e)) return
    
    isDragging = false
    isPanning = false
  })

  container.addEventListener('mouseleave', (e) => {
    // 如果事件来自光照控制面板，不处理
    if (isFromLightControl(e)) return
    
    isDragging = false
    isPanning = false
  })

  // 滚轮缩放 - 控制相机距离目标点的距离
  container.addEventListener('wheel', (e) => {
    // 如果事件来自光照控制面板，不处理
    if (isFromLightControl(e)) return
    
    e.preventDefault()
    if (camera) {
      // 计算相机到目标点的向量
      const direction = new THREE.Vector3().subVectors(camera.position, cameraTarget)
      const distance = direction.length()
      
      // 限制最小和最大距离
      const minDistance = 0.5
      const maxDistance = 50
      
      // 计算新的距离
      const newDistance = Math.max(minDistance, Math.min(maxDistance, distance + e.deltaY * 0.01))
      
      // 设置新的相机位置
      direction.normalize().multiplyScalar(newDistance)
      camera.position.copy(cameraTarget).add(direction)
      
      // 相机看向目标点
      camera.lookAt(cameraTarget)
    }
  })
}

// 为光照控制面板添加事件阻止
const addLightControlEventPrevent = () => {
  const container = modelContainer.value
  if (!container) return
  
  // 为光照控制面板添加事件监听器，阻止事件传播
  const lightControlPanel = container.querySelector('.light-control-panel')
  const lightControlBtn = container.querySelector('.light-control-btn')
  
  const preventEvents = (element) => {
    if (element) {
      element.addEventListener('mousedown', (e) => {
        e.stopPropagation()
      })
      element.addEventListener('mousemove', (e) => {
        e.stopPropagation()
      })
      element.addEventListener('mouseup', (e) => {
        e.stopPropagation()
      })
      element.addEventListener('wheel', (e) => {
        e.stopPropagation()
        e.preventDefault()
      })
    }
  }
  
  preventEvents(lightControlPanel)
  preventEvents(lightControlBtn)
}

// 添加三维坐标轴
const addAxesHelper = () => {
  // 移除现有的坐标轴
  if (scene) {
    scene.traverse((object) => {
      if (object.isAxesHelper || object.userData.isCustomAxes) {
        scene.remove(object)
      }
    })
  }
  
  // 创建带箭头的坐标轴
  if (scene) {
    const axisLength = 1
    const arrowSize = 0.1
    
    // X轴 - 红色
    const xArrow = new THREE.ArrowHelper(
      new THREE.Vector3(1, 0, 0),  // 方向
      new THREE.Vector3(0, 0, 0),  // 起点
      axisLength,                  // 长度
      0xff0000,                    // 颜色
      arrowSize,                   // 箭头大小
      arrowSize                    // 箭头宽度
    )
    xArrow.userData.isCustomAxes = true
    scene.add(xArrow)
    
    // Y轴 - 绿色
    const yArrow = new THREE.ArrowHelper(
      new THREE.Vector3(0, 1, 0),
      new THREE.Vector3(0, 0, 0),
      axisLength,
      0x00ff00,
      arrowSize,
      arrowSize
    )
    yArrow.userData.isCustomAxes = true
    scene.add(yArrow)
    
    // Z轴 - 蓝色
    const zArrow = new THREE.ArrowHelper(
      new THREE.Vector3(0, 0, 1),
      new THREE.Vector3(0, 0, 0),
      axisLength,
      0x0000ff,
      arrowSize,
      arrowSize
    )
    zArrow.userData.isCustomAxes = true
    scene.add(zArrow)
    
    console.log('带箭头的三维坐标轴已添加到场景原点')
  }
}

// 加载模型
const loadModel = () => {
  console.log('========================================')
  console.log('开始加载模型流程')
  console.log('========================================')
  
  if (!props.modelData || !props.modelData.format) {
    console.error('模型数据不完整:', { modelData: props.modelData })
    console.log('========================================')
    console.log('加载模型流程结束 - 数据不完整')
    console.log('========================================')
    return
  }

  console.log('模型基本信息:', {
    modelId: props.modelData.id,
    modelFormat: props.modelData.format,
    modelName: props.modelData.name
  })

  // 打印完整的模型数据，查看是否包含文件路径或URL
  console.log('完整模型数据:', props.modelData)
  console.log('模型数据所有属性:', Object.keys(props.modelData))

  const format = props.modelData.format.toUpperCase()
  
  // 清除现有模型
  if (model) {
    scene.remove(model)
    model = null
    console.log('已清除现有模型')
  }

  try {
    // 检查模型数据中是否包含文件路径或URL
    let modelUrl = null
    
    // 尝试从模型数据中获取文件路径或URL
    if (props.modelData.path) {
      modelUrl = props.modelData.path
      console.log('✓ 从modelData.path获取模型路径:', modelUrl)
    } else if (props.modelData.url) {
      modelUrl = props.modelData.url
      console.log('✓ 从modelData.url获取模型路径:', modelUrl)
    } else if (props.modelData.filePath) {
      // 后端返回的filePath是相对路径，需要添加/profile前缀
      modelUrl = `/profile/${props.modelData.filePath}`
      console.log('✓ 从modelData.filePath获取模型路径并添加前缀:', props.modelData.filePath, '→', modelUrl)
    } else if (props.modelData.file_path) {
      // 检查file_path是否已经包含/profile前缀
      if (props.modelData.file_path.startsWith('/profile')) {
        // 已经包含/profile前缀，直接使用
        modelUrl = props.modelData.file_path
        console.log('✓ 从modelData.file_path获取模型路径（已包含/profile前缀）:', modelUrl)
      } else {
        // 后端返回的file_path是相对路径，需要添加/profile前缀
        modelUrl = `/profile/${props.modelData.file_path}`
        console.log('✓ 从modelData.file_path获取模型路径并添加前缀:', props.modelData.file_path, '→', modelUrl)
      }
    } else if (props.modelData.fileUrl) {
      modelUrl = props.modelData.fileUrl
      console.log('✓ 从modelData.fileUrl获取模型路径:', modelUrl)
    } else if (props.modelData.storagePath) {
      modelUrl = props.modelData.storagePath
      console.log('✓ 从modelData.storagePath获取模型路径:', modelUrl)
    } else if (props.modelData.filename) {
      // 直接使用filename构建路径，添加/profile/upload前缀
      modelUrl = `/profile/upload/${props.modelData.filename}`
      console.log('✓ 从modelData.filename获取模型路径:', modelUrl)
    } else if (props.modelData.fileName) {
      // 直接使用fileName构建路径，添加/profile/upload前缀
      modelUrl = `/profile/upload/${props.modelData.fileName}`
      console.log('✓ 从modelData.fileName获取模型路径:', modelUrl)
    } else if (props.modelData.id) {
      // 如果没有找到文件路径，尝试使用ID构建路径
      // 尝试多种可能的静态文件路径，添加/profile前缀
      const modelId = props.modelData.id
      const possiblePaths = [
        `/profile/upload/${modelId}.${props.modelData.format.toLowerCase()}`,
        `/profile/model/${modelId}.${props.modelData.format.toLowerCase()}`
      ]
      
      // 尝试每个路径
      console.log('开始尝试构建模型路径:')
      for (const path of possiblePaths) {
        console.log('  尝试路径:', path)
      }
      
      // 使用第一个可能的路径
      modelUrl = possiblePaths[0]
      console.log('✓ 使用ID构建模型路径:', modelUrl)
    }

    // 如果找到了模型路径
    if (modelUrl) {
      // 确保路径是完整的URL
      if (!modelUrl.startsWith('http://') && !modelUrl.startsWith('https://')) {
        // 检查是否已经是绝对路径（以/开头）
        if (!modelUrl.startsWith('/')) {
          // 如果是相对路径，添加基础路径
          const oldUrl = modelUrl
          modelUrl = `/${modelUrl}`
          console.log('✓ 添加斜杠前缀:', oldUrl, '→', modelUrl)
        }
        
        // 检查是否需要添加/upload前缀
        // 根据后端代码，FileUploadUtils.upload()返回的路径已经包含了upload前缀
        // 所以这里不需要再添加/upload/model/前缀
        console.log('✓ 路径处理完成:', modelUrl)
      }
      
      console.log('========================================')
      console.log('最终确定的模型路径:', modelUrl)
      console.log('========================================')
      
      // 根据模型格式加载
      switch (format) {
        case 'GLTF':
        case 'GLB':
          console.log('开始加载GLTF/GLB模型')
          loadGLTFModel(modelUrl)
          break
        case 'OBJ':
          console.log('开始加载OBJ模型')
          loadOBJModel(modelUrl)
          break
        case 'FBX':
          console.log('开始加载FBX模型')
          loadFBXModel(modelUrl)
          break
        case 'STL':
          console.log('开始加载STL模型')
          loadSTLModel(modelUrl)
          break
        default:
          console.error('不支持的模型格式:', format)
          // 显示默认模型
          createDefaultModel()
          console.log('========================================')
          console.log('加载模型流程结束 - 格式不支持')
          console.log('========================================')
      }
    } else {
      console.error('❌ 模型数据中未找到文件路径或URL')
      // 显示默认模型
      createDefaultModel()
      console.log('========================================')
      console.log('加载模型流程结束 - 未找到路径')
      console.log('========================================')
    }
  } catch (error) {
    console.error('❌ 加载模型出错:', error)
    console.error('错误详情:', error.message)
    console.error('错误堆栈:', error.stack)
    // 显示默认模型
    createDefaultModel()
    console.log('========================================')
    console.log('加载模型流程结束 - 发生错误')
    console.log('========================================')
  }
}

// 加载GLTF/GLB模型
const loadGLTFModel = (url) => {
  console.log('开始加载GLTF/GLB模型:', url)
  
  // 使用后端接口获取文件
  // 直接传递包含/profile前缀的完整路径，后端会处理前缀
  const resourcePath = url
  const apiUrl = `/common/download/resource?resource=${encodeURIComponent(resourcePath)}`
  console.log('使用后端接口获取文件:', apiUrl)
  
  request({
    url: apiUrl,
    method: 'get',
    responseType: 'blob'
  })
    .then(response => {
      const blob = response
      console.log('响应是Blob，大小:', blob.size)
      console.log('Blob类型:', blob.type)
      
      // 使用Blob创建临时URL
      const blobUrl = URL.createObjectURL(blob)
      console.log('创建Blob URL:', blobUrl)
      
      // 使用Blob URL加载模型
      const loader = new GLTFLoader()
      loader.load(
        blobUrl,
        (gltf) => {
          console.log('GLTF/GLB模型加载成功:', gltf)
          model = gltf.scene
          scene.add(model)
          // 使用模型自身的原始坐标，不进行中心调整
          console.log('模型添加到场景，使用原始坐标')
          console.log('模型原始位置:', model.position)
          console.log('模型原始旋转:', model.rotation)
          console.log('模型原始缩放:', model.scale)
          // 调整相机位置，使模型在视角中心且完整可见
          adjustCameraForModel()
          console.log('相机位置调整完成')
          // 修复半透明材质太透的问题
          fixTransparentMaterials(model)
          // 释放Blob URL
          URL.revokeObjectURL(blobUrl)
        },
        (xhr) => {
          console.log('GLTF/GLB模型加载进度:', (xhr.loaded / xhr.total * 100) + '% loaded')
        },
        (error) => {
          console.error('GLTF加载错误:', error)
          console.error('错误详情:', error.message)
          console.error('错误堆栈:', error.stack)
          // 释放Blob URL
          URL.revokeObjectURL(blobUrl)
          createDefaultModel()
        }
      )
    })
    .catch(error => {
      console.error('后端接口请求错误:', error)
      console.error('错误详情:', error.message)
      console.error('错误堆栈:', error.stack)
      createDefaultModel()
    })
}

// 加载OBJ模型
const loadOBJModel = (url) => {
  console.log('开始加载OBJ模型:', url)
  
  // 使用后端接口获取文件
  // 直接传递包含/profile前缀的完整路径，后端会处理前缀
  const resourcePath = url
  const apiUrl = `/common/download/resource?resource=${encodeURIComponent(resourcePath)}`
  console.log('使用后端接口获取文件:', apiUrl)
  
  request({
    url: apiUrl,
    method: 'get',
    responseType: 'blob'
  })
    .then(response => {
      const blob = response
      console.log('OBJ模型响应是Blob，大小:', blob.size)
      console.log('Blob类型:', blob.type)
      
      // 使用Blob创建临时URL
      const blobUrl = URL.createObjectURL(blob)
      console.log('创建OBJ Blob URL:', blobUrl)
      
      // 使用Blob URL加载模型
      const loader = new OBJLoader()
      loader.load(
        blobUrl,
        (obj) => {
          console.log('OBJ模型加载成功:', obj)
          model = obj
          // 添加材质
          const material = new THREE.MeshStandardMaterial({ color: 0x409eff })
          obj.traverse((child) => {
            if (child.isMesh) {
              child.material = material
            }
          })
          scene.add(model)
          // 使用模型自身的原始坐标，不进行中心调整
          console.log('模型添加到场景，使用原始坐标')
          console.log('模型原始位置:', model.position)
          console.log('模型原始旋转:', model.rotation)
          console.log('模型原始缩放:', model.scale)
          // 调整相机位置，使模型在视角中心且完整可见
          adjustCameraForModel()
          console.log('相机位置调整完成')
          // 修复半透明材质太透的问题
          fixTransparentMaterials(model)
          // 释放Blob URL
          URL.revokeObjectURL(blobUrl)
        },
        (xhr) => {
          console.log('OBJ模型加载进度:', (xhr.loaded / xhr.total * 100) + '% loaded')
        },
        (error) => {
          console.error('OBJ加载错误:', error)
          console.error('错误详情:', error.message)
          console.error('错误堆栈:', error.stack)
          // 释放Blob URL
          URL.revokeObjectURL(blobUrl)
          createDefaultModel()
        }
      )
    })
    .catch(error => {
      console.error('后端接口请求错误:', error)
      console.error('错误详情:', error.message)
      console.error('错误堆栈:', error.stack)
      createDefaultModel()
    })
}

// 处理FBX模型的特殊问题
const processFBXModel = (fbxModel) => {
  console.log('开始专业处理FBX模型')
  
  // 1. FBX模型坐标系转换
  console.log('处理FBX坐标系...')
  
  // FBX通常使用Y-up坐标系，Three.js使用Y-up，所以不需要翻转
  // 但需要确保缩放和位置正确
  
  // 2. 统一模型缩放
  console.log('处理FBX模型缩放...')
  console.log('原始模型缩放:', fbxModel.scale)
  
  // 计算模型的边界框，用于确定合适的缩放
  let tempBox = new THREE.Box3().setFromObject(fbxModel)
  let tempSize = tempBox.getSize(new THREE.Vector3())
  console.log('原始模型边界框大小:', tempSize)
  
  // 计算模型的整体尺寸
  const maxDimension = Math.max(tempSize.x, tempSize.y, tempSize.z)
  console.log('模型最大尺寸:', maxDimension)
  
  // 计算合适的缩放因子，确保模型大小适中
  let scaleFactor = 1
  if (maxDimension > 10) {
    scaleFactor = 5 / maxDimension
    console.log('模型过大，需要缩小，缩放因子:', scaleFactor)
  } else if (maxDimension < 1) {
    scaleFactor = 2 / maxDimension
    console.log('模型过小，需要放大，缩放因子:', scaleFactor)
  }
  
  // 应用缩放因子到整个模型
  if (scaleFactor !== 1) {
    fbxModel.scale.multiplyScalar(scaleFactor)
    console.log('缩放调整完成，新的模型缩放:', fbxModel.scale)
  }
  
  // 3. 强制更新所有矩阵
  console.log('强制更新所有模型矩阵...')
  fbxModel.traverse((child) => {
    if (child.isObject3D) {
      child.updateMatrix()
      child.updateMatrixWorld(true)
    }
  })
  
  // 4. 计算模型边界框
  console.log('计算FBX模型边界框...')
  const box = new THREE.Box3().setFromObject(fbxModel)
  const size = box.getSize(new THREE.Vector3())
  const center = box.getCenter(new THREE.Vector3())
  
  console.log('FBX模型边界框大小:', size)
  console.log('FBX模型边界框中心:', center)
  
  // 5. 处理材质
  console.log('处理FBX模型材质...')
  let materialCount = 0
  
  fbxModel.traverse((child) => {
    if (child.isMesh) {
      console.log('处理网格:', child.name)
      
      try {
        // 为所有FBX网格添加默认材质，确保每个网格都有材质
        console.log('为', child.name, '添加默认材质')
        const defaultMaterial = new THREE.MeshStandardMaterial({
          color: 0x409eff,
          metalness: 0.3,
          roughness: 0.7,
          transparent: false,
          opacity: 1,
          side: THREE.FrontSide
        })
        child.material = defaultMaterial
        materialCount++
      } catch (error) {
        console.error('处理材质时出错:', error.message)
        const fallbackMaterial = new THREE.MeshStandardMaterial({
          color: 0x409eff,
          metalness: 0.3,
          roughness: 0.7,
          side: THREE.FrontSide
        })
        child.material = fallbackMaterial
        materialCount++
      }
    }
  })
  
  console.log('材质处理完成，添加了', materialCount, '个默认材质')
  
  // 6. 最终矩阵更新
  fbxModel.updateMatrixWorld(true)
  console.log('FBX模型处理完成')
  
  return {
    model: fbxModel,
    box: box,
    size: size,
    center: center
  }
}

// 加载FBX模型
const loadFBXModel = (url) => {
  console.log('开始加载FBX模型:', url)
  
  // 使用后端接口获取文件
  // 直接传递包含/profile前缀的完整路径，后端会处理前缀
  const resourcePath = url
  const apiUrl = `/common/download/resource?resource=${encodeURIComponent(resourcePath)}`
  console.log('使用后端接口获取文件:', apiUrl)
  
  request({
    url: apiUrl,
    method: 'get',
    responseType: 'blob'
  })
    .then(response => {
      const blob = response
      console.log('FBX模型响应是Blob，大小:', blob.size)
      console.log('Blob类型:', blob.type)
      
      // 使用Blob创建临时URL
      const blobUrl = URL.createObjectURL(blob)
      console.log('创建FBX Blob URL:', blobUrl)
      
      // 使用Blob URL加载模型
      const loader = new FBXLoader()
      loader.load(
        blobUrl,
        (fbx) => {
          console.log('FBX模型加载成功:', fbx)
          
          // 专业处理FBX模型
          const processed = processFBXModel(fbx)
          model = processed.model
          
          // 添加到场景
          scene.add(model)
          console.log('FBX模型添加到场景')
          
          // 计算最终边界框
          console.log('计算最终模型边界框...')
          model.updateMatrixWorld(true)
          const finalBox = new THREE.Box3().setFromObject(model)
          const finalSize = finalBox.getSize(new THREE.Vector3())
          const finalCenter = finalBox.getCenter(new THREE.Vector3())
          
          console.log('最终模型边界框大小:', finalSize)
          console.log('最终模型边界框中心:', finalCenter)
          console.log('模型实际位置:', model.position)
          
          // 调整相机位置
          console.log('调整相机位置...')
          adjustCameraForModel()
          console.log('相机位置调整完成')
          // 修复半透明材质太透的问题
          fixTransparentMaterials(model)
          
          // 释放Blob URL
          URL.revokeObjectURL(blobUrl)
          console.log('FBX模型加载和处理完成')
        },
        (xhr) => {
          console.log('FBX模型加载进度:', (xhr.loaded / xhr.total * 100) + '% loaded')
        },
        (error) => {
          console.error('FBX加载错误:', error)
          console.error('错误详情:', error.message)
          console.error('错误堆栈:', error.stack)
          // 释放Blob URL
          URL.revokeObjectURL(blobUrl)
          createDefaultModel()
        }
      )
    })
    .catch(error => {
      console.error('后端接口请求错误:', error)
      console.error('错误详情:', error.message)
      console.error('错误堆栈:', error.stack)
      createDefaultModel()
    })
}

// 加载STL模型
const loadSTLModel = (url) => {
  console.log('开始加载STL模型:', url)
  
  // 使用后端接口获取文件
  // 直接传递包含/profile前缀的完整路径，后端会处理前缀
  const resourcePath = url
  const apiUrl = `/common/download/resource?resource=${encodeURIComponent(resourcePath)}`
  console.log('使用后端接口获取文件:', apiUrl)
  
  request({
    url: apiUrl,
    method: 'get',
    responseType: 'blob'
  })
    .then(response => {
      const blob = response
      console.log('STL模型响应是Blob，大小:', blob.size)
      console.log('Blob类型:', blob.type)
      
      // 使用Blob创建临时URL
      const blobUrl = URL.createObjectURL(blob)
      console.log('创建STL Blob URL:', blobUrl)
      
      // 使用Blob URL加载模型
      const loader = new STLLoader()
      loader.load(
        blobUrl,
        (geometry) => {
          console.log('STL模型加载成功，几何体顶点数:', geometry.attributes.position.count)
          const material = new THREE.MeshStandardMaterial({ color: 0x409eff })
          const mesh = new THREE.Mesh(geometry, material)
          model = mesh
          scene.add(mesh)
          // 使用模型自身的原始坐标，不进行中心调整
          console.log('模型添加到场景，使用原始坐标')
          console.log('模型原始位置:', model.position)
          console.log('模型原始旋转:', model.rotation)
          console.log('模型原始缩放:', model.scale)
          // 调整相机位置，使模型在视角中心且完整可见
          adjustCameraForModel()
          console.log('相机位置调整完成')
          // 修复半透明材质太透的问题
          fixTransparentMaterials(model)
          // 释放Blob URL
          URL.revokeObjectURL(blobUrl)
        },
        (xhr) => {
          console.log('STL模型加载进度:', (xhr.loaded / xhr.total * 100) + '% loaded')
        },
        (error) => {
          console.error('STL加载错误:', error)
          console.error('错误详情:', error.message)
          console.error('错误堆栈:', error.stack)
          // 释放Blob URL
          URL.revokeObjectURL(blobUrl)
          createDefaultModel()
        }
      )
    })
    .catch(error => {
      console.error('后端接口请求错误:', error)
      console.error('错误详情:', error.message)
      console.error('错误堆栈:', error.stack)
      createDefaultModel()
    })
}

// 创建默认模型
const createDefaultModel = () => {
  // 创建一个简单的立方体作为默认模型
  const geometry = new THREE.BoxGeometry(2, 2, 2)
  const material = new THREE.MeshStandardMaterial({ 
    color: 0x409eff,
    wireframe: true
  })
  model = new THREE.Mesh(geometry, material)
  scene.add(model)
}

// 调整相机位置，使模型在视角中心且完整可见
const adjustCameraForModel = () => {
  if (!model || !camera) return

  console.log('=======================================')
  console.log('开始调整相机位置')
  console.log('当前模型位置:', model.position)
  console.log('当前相机位置:', camera.position)

  // 增强：强制更新所有模型和子对象的矩阵
  console.log('强制更新模型和子对象矩阵...')
  model.traverse((child) => {
    if (child.isObject3D) {
      child.updateMatrix()
      child.updateMatrixWorld(true)
    }
  })
  console.log('模型矩阵更新完成')

  // 计算模型边界框
  const box = new THREE.Box3().setFromObject(model)
  const size = box.getSize(new THREE.Vector3())
  const center = box.getCenter(new THREE.Vector3())

  console.log('模型边界框大小:', size)
  console.log('模型边界框中心:', center)
  console.log('边界框最小值:', box.min)
  console.log('边界框最大值:', box.max)

  // 增强：检查边界框是否有效
  if (box.isEmpty()) {
    console.warn('模型边界框为空，使用默认相机位置')
    // 使用默认相机位置
    camera.position.set(5, 5, 5)
    camera.lookAt(0, 0, 0)
    camera.updateProjectionMatrix()
    console.log('使用默认相机位置:', camera.position)
    console.log('相机位置调整完成')
    console.log('=======================================')
    return
  }

  // 计算模型对角线长度
  const modelDiagonal = Math.sqrt(
    size.x * size.x + 
    size.y * size.y + 
    size.z * size.z
  )
  
  console.log('模型对角线长度:', modelDiagonal)

  // 根据模型大小计算合适的相机距离
  const fov = camera.fov * (Math.PI / 180) // 转换为弧度
  
  // 增强：使用动态安全系数，根据模型大小调整
  let safetyFactor = 1.3
  if (modelDiagonal < 5) {
    safetyFactor = 1.5 // 小模型使用更大的安全系数
  } else if (modelDiagonal > 20) {
    safetyFactor = 1.1 // 大模型使用更小的安全系数
  }
  
  console.log('使用的安全系数:', safetyFactor)
  const cameraDistance = (modelDiagonal / 2) / Math.tan(fov / 2) * safetyFactor
  
  console.log('计算的相机距离:', cameraDistance)
  console.log('当前相机到模型中心距离:', camera.position.distanceTo(center))

  // 增强：确保相机距离不会太小
  const minCameraDistance = Math.max(2, modelDiagonal * 0.5)
  const finalCameraDistance = Math.max(minCameraDistance, cameraDistance)
  console.log('最终相机距离:', finalCameraDistance, '(最小距离:', minCameraDistance, ')')

  // 增强：对于FBX模型，确保相机位置计算考虑模型的实际位置
  console.log('模型实际位置:', model.position)
  console.log('边界框中心相对于模型位置:', center.clone().sub(model.position))

  // 设置相机位置，从斜上方看向模型中心
  // 这样可以获得更好的视角
  const cameraHeight = finalCameraDistance * 0.4 // 相机高度，40%的距离
  
  // 增强：考虑模型的实际位置
  const cameraPosition = new THREE.Vector3(
    center.x + finalCameraDistance * 0.2,  // 稍微偏右
    center.y + cameraHeight,               // 上方
    center.z + finalCameraDistance * 0.9    // 前方
  )
  
  console.log('计算的相机位置:', cameraPosition)
  camera.position.copy(cameraPosition)
  
  // 相机看向模型中心
  camera.lookAt(center)
  
  console.log('调整后相机位置:', camera.position)
  console.log('相机看向:', center)
  console.log('调整后相机到模型中心距离:', camera.position.distanceTo(center))

  // 确保相机矩阵更新
  camera.updateProjectionMatrix()
  console.log('相机投影矩阵已更新')

  // 增强：重置相机的旋转和缩放
  console.log('重置相机旋转和缩放...')
  camera.rotation.set(0, 0, 0)
  camera.scale.set(1, 1, 1)
  console.log('相机旋转和缩放已重置')

  console.log('相机位置调整完成，现在应该能完整看到模型')
  console.log('=======================================')
}

// 自动调整模型位置和大小（保留但不再使用）
const centerModel = () => {
  if (!model || !camera) return

  console.log('=======================================')
  console.log('开始调整模型位置和大小')
  console.log('调整前模型位置:', model.position)
  console.log('调整前模型缩放:', model.scale)
  console.log('调整前模型旋转:', model.rotation)
  console.log('调整前模型世界矩阵:', model.matrixWorld.elements)

  // 重置模型旋转，确保计算边界框时不受旋转影响
  model.rotation.set(0, 0, 0)
  console.log('重置模型旋转后:', model.rotation)

  // 确保模型矩阵更新
  model.updateMatrixWorld(true)
  console.log('模型矩阵已更新')
  console.log('重置旋转后模型世界矩阵:', model.matrixWorld.elements)

  // 计算模型边界框
  const box = new THREE.Box3().setFromObject(model)
  const size = box.getSize(new THREE.Vector3())
  const center = box.getCenter(new THREE.Vector3())

  console.log('模型边界框大小:', size)
  console.log('模型边界框中心:', center)
  console.log('边界框最小值:', box.min)
  console.log('边界框最大值:', box.max)

  // 直接设置模型位置到原点，确保在世界中心
  console.log('准备调整模型位置到原点...')
  console.log('计算的位置调整值:', -center.x, -center.y, -center.z)
  model.position.set(-center.x, -center.y, -center.z)
  console.log('模型调整后位置:', model.position)
  console.log('模型位置是否接近原点:', 
    Math.abs(model.position.x) < 0.001 && 
    Math.abs(model.position.y) < 0.001 && 
    Math.abs(model.position.z) < 0.001
  )

  // 确保模型矩阵更新
  model.updateMatrixWorld(true)
  console.log('位置调整后模型矩阵已更新')
  console.log('位置调整后模型世界矩阵:', model.matrixWorld.elements)
  
  // 重新计算调整后的边界框，验证位置是否正确
  const positionAdjustedBox = new THREE.Box3().setFromObject(model)
  const positionAdjustedCenter = positionAdjustedBox.getCenter(new THREE.Vector3())
  console.log('位置调整后模型边界框中心:', positionAdjustedCenter)
  console.log('边界框中心是否接近原点:', 
    Math.abs(positionAdjustedCenter.x) < 0.001 && 
    Math.abs(positionAdjustedCenter.y) < 0.001 && 
    Math.abs(positionAdjustedCenter.z) < 0.001
  )

  // 自动调整模型大小 - 使用更大的基准值，确保模型不会太小
  const maxSize = Math.max(size.x, size.y, size.z)
  if (maxSize > 0) {
    // 使用 5 作为基准值，而不是 3，让模型更大一些
    const scale = 5 / maxSize
    console.log('准备调整模型缩放...')
    console.log('计算的缩放比例:', scale)
    model.scale.set(scale, scale, scale)
    console.log('模型调整后缩放:', model.scale)
    console.log('调整后模型最大尺寸:', maxSize * scale)
  }

  // 确保模型矩阵更新
  model.updateMatrixWorld(true)
  console.log('模型缩放后矩阵已更新')
  console.log('缩放后模型世界矩阵:', model.matrixWorld.elements)
  
  // 重新计算调整后的边界框
  const adjustedBox = new THREE.Box3().setFromObject(model)
  const adjustedSize = adjustedBox.getSize(new THREE.Vector3())
  const adjustedCenter = adjustedBox.getCenter(new THREE.Vector3())
  console.log('调整后模型边界框大小:', adjustedSize)
  console.log('调整后模型边界框中心:', adjustedCenter)
  console.log('最终边界框中心是否接近原点:', 
    Math.abs(adjustedCenter.x) < 0.001 && 
    Math.abs(adjustedCenter.y) < 0.001 && 
    Math.abs(adjustedCenter.z) < 0.001
  )

  // 动态调整相机位置，确保相机能够完整看到模型
  const modelDiagonal = Math.sqrt(
    adjustedSize.x * adjustedSize.x + 
    adjustedSize.y * adjustedSize.y + 
    adjustedSize.z * adjustedSize.z
  )
  
  // 根据模型对角线长度计算合适的相机距离
  const fov = camera.fov * (Math.PI / 180) // 转换为弧度
  const cameraDistance = (modelDiagonal / 2) / Math.tan(fov / 2) * 1.5 // 1.5 是安全系数
  
  console.log('模型对角线长度:', modelDiagonal)
  console.log('计算的相机距离:', cameraDistance)

  // 设置相机位置，确保从适当的距离和角度观察模型
  camera.position.set(0, cameraDistance * 0.3, cameraDistance)
  camera.lookAt(0, 0, 0)
  
  console.log('调整后相机位置:', camera.position)
  console.log('相机看向:', new THREE.Vector3(0, 0, 0))
  console.log('相机到原点距离:', camera.position.distanceTo(new THREE.Vector3(0, 0, 0)))

  // 确保相机矩阵更新
  camera.updateProjectionMatrix()
  console.log('相机投影矩阵已更新')

  console.log('模型位置调整完成，现在应该在世界坐标系原点')
  console.log('=======================================')
}

// 渲染动画
const animate = () => {
  animationId = requestAnimationFrame(animate)
  if (renderer && scene && camera) {
    renderer.render(scene, camera)
  }
}

// 处理窗口大小变化
const handleResize = () => {
  if (!camera || !renderer || !modelContainer.value) return

  const width = modelContainer.value.clientWidth
  const height = modelContainer.value.clientHeight

  camera.aspect = width / height
  camera.updateProjectionMatrix()
  renderer.setSize(width, height)
}

// 处理关闭
const handleClose = () => {
  dialogVisible.value = false
  emit('update:visible', false)
  emit('close')
}

// 监听可见性变化
watch(() => props.visible, (newVal) => {
  dialogVisible.value = newVal
  if (newVal) {
    // 延迟初始化，确保DOM已更新
    setTimeout(() => {
      initScene()
    }, 100)
  }
})

// 组件挂载时初始化
onMounted(() => {
  dialogVisible.value = props.visible
  if (props.visible) {
    initScene()
  }
})

// 组件卸载时清理
onUnmounted(() => {
  if (animationId) {
    cancelAnimationFrame(animationId)
  }
  if (renderer) {
    renderer.dispose()
  }
  if (modelContainer.value) {
    window.removeEventListener('resize', handleResize)
  }
})

// 计算属性
const modelName = ref('')
watch(() => props.modelData, (newVal) => {
  if (newVal) {
    modelName.value = newVal.name || '模型预览'
  }
}, { immediate: true })

// 光照控制方法
const toggleLightControl = () => {
  showLightControl.value = !showLightControl.value
}

// 更新光源设置
const updateLights = () => {
  // 保存相机当前位置和目标点
  let cameraPosition = null
  let cameraTarget = null
  if (camera) {
    cameraPosition = camera.position.clone()
    // 获取相机看向的点
    const vector = new THREE.Vector3()
    camera.getWorldDirection(vector)
    cameraTarget = camera.position.clone().add(vector)
  }
  
  // 更新光源属性
  if (ambientLight) {
    ambientLight.intensity = lightSettings.value.ambientIntensity
  }
  if (directionalLight) {
    directionalLight.intensity = lightSettings.value.directionalIntensity
    directionalLight.position.set(
      lightSettings.value.directionalPosition.x,
      lightSettings.value.directionalPosition.y,
      lightSettings.value.directionalPosition.z
    )
  }
  if (directionalLight2) {
    directionalLight2.intensity = lightSettings.value.directionalIntensity2
  }
  
  // 恢复相机位置和目标点
  if (camera && cameraPosition) {
    camera.position.copy(cameraPosition)
    camera.lookAt(cameraTarget)
    camera.updateProjectionMatrix()
  }
}

// 修复半透明材质太透的问题
const fixTransparentMaterials = (modelObject) => {
  if (!modelObject) return
  
  let fixedCount = 0
  
  modelObject.traverse((child) => {
    if (child.isMesh && child.material) {
      const materials = Array.isArray(child.material) ? child.material : [child.material]
      
      materials.forEach((material) => {
        // 检查是否使用了透明度贴图
        const hasAlphaMap = material.alphaMap && material.alphaMap !== null
        const isTransparent = material.transparent === true
        const opacity = material.opacity
        
        // 如果有透明度贴图或设置了transparent
        if (hasAlphaMap || isTransparent) {
          // 确保透明模式开启
          material.transparent = true
          
          // 启用双面渲染，确保半透明效果正确显示
          material.side = THREE.DoubleSide
          
          // 如果opacity太低或等于1（全透/全不透），设置为一个合适的值
          if (opacity === undefined || opacity >= 1 || opacity < 0.1) {
            material.opacity = 0.8
            fixedCount++
          }
          
          // 修复depthWrite问题 - 对于半透明材质，depthWrite通常应为false
          material.depthWrite = false
          material.needsUpdate = true
        }
      })
    }
  })
  
  console.log('修复了', fixedCount, '个半透明材质的透明度')
}

// 更新模型材质的不透明度
const updateMaterialOpacity = () => {
  if (!model) return
  
  const opacity = materialOpacity.value
  
  model.traverse((child) => {
    if (child.isMesh && child.material) {
      const materials = Array.isArray(child.material) ? child.material : [child.material]
      
      materials.forEach((material) => {
        if (material.transparent === true || material.opacity < 1) {
          material.opacity = opacity
          material.needsUpdate = true
        }
      })
    }
  })
}
</script>

<style scoped>
.model-preview-container {
  display: flex;
  gap: 20px;
  height: 600px;
}

.model-container {
  flex: 1;
  background-color: #fafafa;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
}

.model-info {
  width: 300px;
  background-color: #ffffff;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  overflow-y: auto;
}

.model-info h3 {
  margin-top: 0;
  margin-bottom: 20px;
  font-size: 18px;
  font-weight: 600;
  color: #303133;
}

@media (max-width: 768px) {
  .model-preview-container {
    flex-direction: column;
  }

  .model-info {
    width: 100%;
    max-height: 300px;
  }
}

/* 光照控制样式 */
.light-control-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 40px;
  height: 40px;
  background-color: rgba(255, 255, 255, 0.9);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  z-index: 1000;
  transition: all 0.3s ease;
}

.light-control-btn:hover {
  background-color: #ffffff;
  transform: scale(1.1);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

.light-control-panel {
  position: absolute;
  top: 60px;
  right: 10px;
  width: 300px;
  background-color: rgba(255, 255, 255, 0.95);
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  z-index: 1000;
  backdrop-filter: blur(5px);
  pointer-events: auto;
  user-select: none;
}

.light-control-panel h4 {
  margin: 0 0 15px 0;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.control-item {
  margin-bottom: 20px;
}

.control-item label {
  display: block;
  margin-bottom: 8px;
  font-size: 14px;
  font-weight: 500;
  color: #606266;
}

.control-item .value {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 12px;
  color: #909399;
  min-width: 40px;
  text-align: right;
}

.angle-controls > div {
  position: relative;
  margin-bottom: 12px;
}

.angle-controls > div > span {
  display: inline-block;
  width: 40px;
  font-size: 12px;
  color: #909399;
  margin-right: 10px;
}

.angle-controls .el-slider {
  display: inline-block;
  width: calc(100% - 100px);
  vertical-align: middle;
}

.angle-controls .value {
  position: static;
  display: inline-block;
  transform: none;
  vertical-align: middle;
}

/* 响应式调整 */
@media (max-width: 768px) {
  .light-control-panel {
    width: 250px;
    right: 5px;
  }
  
  .angle-controls .el-slider {
    width: calc(100% - 90px);
  }
}
</style>