<template>
  <div class="scene-wrapper">
    <div ref="containerRef" class="container" />

    <!-- 固定位置的控制按钮 -->
    <div class="control-buttons">
      <el-button
        type="warning"
        @click="tranlate(new Vector3(0, 14, 13.5), new Vector3(0, 0, 0))"
        :icon="Refresh"
      />
      <!-- <el-button type="primary" @click="displayModel('area_oneFloor')" :icon="Bell" />
      <el-button type="warning" @click="displayModel('smokeDetector')" :icon="Compass" />
      <el-button type="warning" @click="displayModel('acoustoOptic')" :icon="MagicStick" />
      <el-button type="warning" @click="displayModel('manual')" :icon="Star" /> -->
      <!-- 1:左右 2:上下 3:前后 -->
      <!-- <el-button type="warning" @click="displayModel('refresh')" :icon="Refresh" />
      <el-button
        type="warning"
        @click="meshControllerArr[0].controller.startMalfunction()"
        :icon="Refresh"
      />
      <el-button
        type="warning"
        @click="meshControllerArr[0].controller.restore()"
        :icon="Refresh"
      /> -->
    </div>

    <div class="control-panel" v-show="cardisOpen">
      <el-card class="card" v-show="cardisOpen" shadow="hover" :body-style="{ padding: '10px' }">
        <h2 class="cardHead">{{ getModelDroupName(moduleType) }}</h2>

        <div class="cardBody">
          <!--  <el-row :gutter="0" class="info-row">
            <el-col :span="8">厂家</el-col>
            <el-col :span="16">
              <el-tag type="primary">海湾公司</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row">
            <el-col :span="8">投运日期</el-col>
            <el-col :span="16">
              <el-tag type="primary">2014-08-08</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row">
            <el-col :span="8">电源电压</el-col>
            <el-col :span="16">
              <el-tag type="primary">220V AC</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row">
            <el-col :span="8">布设位置</el-col>
            <el-col :span="16">
              <el-tag type="primary">35kV高压室</el-tag>
            </el-col>
          </el-row>

           <el-row :gutter="0" class="info-row">
            <el-col :span="8">供电电压</el-col>
            <el-col :span="16">
              <el-tag type="primary">18-30V DC</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row">
            <el-col :span="8">输出电流</el-col>
            <el-col :span="16">
              <el-tag type="primary">5A</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row">
            <el-col :span="8">IP等级</el-col>
            <el-col :span="16">
              <el-tag type="primary">IP30</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row">
            <el-col :span="8">相对湿度</el-col>
            <el-col :span="16">
              <el-tag type="primary">5% ~ 95%</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row">
            <el-col :span="8">接线方式</el-col>
            <el-col :span="16">
              <el-tag type="primary">两线制(L+、L-)</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row">
            <el-col :span="8">尺寸</el-col>
            <el-col :span="16">
              <el-tag type="primary">350mm x 225mm x 125mm</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row">
            <el-col :span="8">报警灵敏度</el-col>
            <el-col :span="16">
              <el-tag type="primary">0.005% 至 20%obs/m</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row">
            <el-col :span="8">运行条件</el-col>
            <el-col :span="16">
              <el-tag ref="conditionTagRef" type="primary"> 探测器环境(-5°C至45°C) </el-tag>
            </el-col>
          </el-row> -->

          <!-- bindingInfo -->
          <el-row :gutter="0" class="info-row">
            <el-col :span="8">绑定设备</el-col>
            <el-col :span="14" :offset="1"
              ><el-button
                type="primary"
                class="operation-btn"
                size="small"
                @click="dialogTableVisible = true"
                >绑定</el-button
              ></el-col
            >
          </el-row>

          <el-row :gutter="0" class="info-row" v-if="bindingInfo.id">
            <el-col :span="8">设备ID</el-col>
            <el-col :span="14" :offset="1">
              <el-tag type="primary" size="small">{{ bindingInfo.id }}</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row" v-if="bindingInfo.id">
            <el-col :span="8">设备名称</el-col>
            <el-col :span="14" :offset="1">
              <el-tag type="primary" size="small">{{ bindingInfo.name }}</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row" v-if="bindingInfo.id">
            <el-col :span="8">设备状态</el-col>
            <el-col :span="14" :offset="1">
              <el-tag size="small" :type="bindingInfo.eState === 0 ? 'success' : 'warning'">
                {{ bindingInfo.eState === 0 ? '正常' : '故障' }}
              </el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row" v-if="bindingInfo.id">
            <el-col :span="8">当前状态</el-col>
            <el-col :span="14" :offset="1">
              <el-tag size="small" v-if="bindingInfo.currentState === 0" type="success"
                >运行</el-tag
              >
              <el-tag size="small" v-else-if="bindingInfo.currentState === 1" type="info"
                >停止</el-tag
              >
              <el-tag size="small" v-else type="error">报警</el-tag>
            </el-col>
          </el-row>

          <el-row :gutter="0" class="info-row" v-if="bindingInfo.id">
            <el-col :span="8">详细信息</el-col>
            <el-col :span="14" :offset="1">
              <el-button
                type="primary"
                class="operation-btn"
                size="small"
                @click="dialogFacilityInfoVisible = true"
                >查看</el-button
              ></el-col
            >
          </el-row>

          <el-row :gutter="0" class="info-row" v-if="bindingInfo.id">
            <el-col :span="6">
              <el-button type="primary" size="small" @click="operationController('restore')"
                >还原</el-button
              ></el-col
            >
            <el-col :span="6">
              <el-button type="warning" size="small" @click="operationController('alarm')"
                >告警</el-button
              ></el-col
            >
            <el-col :span="6">
              <el-button @click="operationController('fault')" type="danger" size="small"
                >故障</el-button
              ></el-col
            >
            <el-col :span="6">
              <el-button @click="operationController('stop')" type="info" size="small"
                >停止</el-button
              ></el-col
            >
          </el-row>
          <el-row :gutter="0" class="equipment-row">
            <el-col :span="24">
              <div class="equipment-wrapper">
                <vueThreeEquipment :moduleType="moduleType" />
              </div>
            </el-col>
          </el-row>
        </div>
      </el-card>
    </div>
  </div>

  <el-dialog
    v-model="dialogFacilityInfoVisible"
    title="设备详细信息"
    width="800"
    top="3vh"
    append-to-body
  >
    <el-card class="card" v-show="cardisOpen" shadow="hover" :body-style="{ padding: '10px' }">
      <el-row :gutter="0" class="info-row">
        <el-col :span="8">厂家</el-col>
        <el-col :span="16">
          <el-tag type="primary">海湾公司</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">投运日期</el-col>
        <el-col :span="16">
          <el-tag type="primary">2014-08-08</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">电源电压</el-col>
        <el-col :span="16">
          <el-tag type="primary">220V AC</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">布设位置</el-col>
        <el-col :span="16">
          <el-tag type="primary">35kV高压室</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">供电电压</el-col>
        <el-col :span="16">
          <el-tag type="primary">18-30V DC</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">输出电流</el-col>
        <el-col :span="16">
          <el-tag type="primary">5A</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">IP等级</el-col>
        <el-col :span="16">
          <el-tag type="primary">IP30</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">相对湿度</el-col>
        <el-col :span="16">
          <el-tag type="primary">5% ~ 95%</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">接线方式</el-col>
        <el-col :span="16">
          <el-tag type="primary">两线制(L+、L-)</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">尺寸</el-col>
        <el-col :span="16">
          <el-tag type="primary">350mm x 225mm x 125mm</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">报警灵敏度</el-col>
        <el-col :span="16">
          <el-tag type="primary">0.005% 至 20%obs/m</el-tag>
        </el-col>
      </el-row>

      <el-row :gutter="0" class="info-row">
        <el-col :span="8">运行条件</el-col>
        <el-col :span="16">
          <el-tag ref="conditionTagRef" type="primary"> 探测器环境(-5°C至45°C) </el-tag>
        </el-col>
      </el-row>
    </el-card>
  </el-dialog>

  <el-dialog v-model="dialogTableVisible" title="设备绑定" width="850" top="3vh" append-to-body>
    <el-table :data="arr" style="width: 100%" max-height="500" class="full-height-table">
      <el-table-column prop="floorName" label="房间" />
      <el-table-column prop="id" label="设备ID" />
      <el-table-column prop="name" label="设备名称" />

      <el-table-column prop="isBinding" label="是否绑定">
        <template #default="{ row }">
          <el-tag :type="row.isBinding ? 'primary' : 'info'">
            {{ row.isBinding ? '绑定' : '待绑' }}
          </el-tag>
        </template>
      </el-table-column>

      <el-table-column label="设备状态">
        <template #default="{ row }">
          <el-tag :type="row.eState === 0 ? 'success' : 'warning'">
            {{ row.eState === 0 ? '正常' : '故障' }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="当前状态">
        <template #default="{ row }">
          <el-tag v-if="row.currentState === 0" type="success">运行</el-tag>
          <el-tag v-else-if="row.currentState === 1" type="info">停止</el-tag>
          <el-tag v-else type="error">报警</el-tag>
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template #default="{ row }">
          <el-button type="primary" class="operation-btn" @click="bindDevice(row)">
            绑定
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-dialog>
</template>

<script lang="ts" setup>
import { Star, Bell, MagicStick, Refresh, Compass } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { onMounted, onUnmounted, ref, reactive } from 'vue';
import {
  AxesHelper,
  Color,
  PerspectiveCamera,
  Scene,
  WebGLRenderer,
  AmbientLight,
  DirectionalLight,
  PointLight,
  Vector2,
  Raycaster,
  CanvasTexture,
  SpriteMaterial,
  Sprite,
  Box3,
  Vector3,
  Mesh,
  BoxHelper,
  ConeGeometry,
  SphereGeometry,
  MeshBasicMaterial,
  TextureLoader,
  Group
} from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
// // import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; // 未使用 // 暂时未使用
import gsap from 'gsap';
import vueThreeEquipment from '@/components/three-components/vue-three-equipment.vue'; // 暂时注释掉未找到的组件
import { modelApi } from '@/utils/request';
import emitter from '@/utils/emitter';

// 导入全局类型定义
/// <reference path="../../../global.d.ts" />

// 定义 Rec 相关的类型
interface RecRuntimeData {
  double: number;
  node: {
    name: string;
  };
}

interface RecServiceType {
  service: {
    node: {
      runtimes: Record<string, RecRuntimeData>;
    };
  };
}

interface ExtendedParentWindow extends Window {
  Rec?: RecServiceType;
}

const containerRef = ref<HTMLDivElement>();
const dialogTableVisible = ref(false);
let dialogFacilityInfoVisible = ref(false);

// 场景
const scene = new Scene();

// 创建摄像机
const camera = new PerspectiveCamera(
  45,
  containerRef.value?.clientWidth! / containerRef.value?.clientHeight!,
  0.1,
  100
);
camera.position.set(0, 14, 13.5);
camera.lookAt(0, 0, 0);

// const axesHelper = new AxesHelper(100);
// scene.add(axesHelper);

// 渲染器
const renderer = new WebGLRenderer({
  antialias: true, // 启用抗锯齿
  alpha: true, // 启用透明背景
  preserveDrawingBuffer: true // 保持绘图缓冲区
});
renderer.setClearColor(new Color('#131519'));
renderer.setSize(containerRef.value?.clientWidth!, containerRef.value?.clientHeight!);
renderer.shadowMap.enabled = true;
renderer.setPixelRatio(window.devicePixelRatio || 1); // 设置像素比率

// 轨道摄像机
const orbitControls = new OrbitControls(camera, renderer.domElement);
orbitControls.autoRotate = false;
orbitControls.autoRotateSpeed = 5;
orbitControls.dampingFactor = 0.1;
orbitControls.enableDamping = true;
orbitControls.enableRotate = true;
orbitControls.minDistance = 10;
orbitControls.maxPolarAngle = Math.PI * 0.5;

// 物体
// scene.add(new AxesHelper(20));

// 环境光：增强整体亮度
const ambientLight = new AmbientLight('#ffffff', 1.8); // 强度从 0.6 提高到 1.0
scene.add(ambientLight);

// 平行光
const directionalLight = new DirectionalLight('#ffffff', 1.8); // 强度从 0.2 提高到 0.8
scene.add(directionalLight);
directionalLight.position.set(20, 20, 10);

// // 点光源
const pointLight = new PointLight('#ffffff', 1.8, 1000); // 强度从 0.5 提高到 1.0
scene.add(pointLight);
pointLight.position.set(0, 40, 0);

function addSprite(text: string, color: string, position: Vector3) {
  const canvas = document.createElement('canvas');
  canvas.width = 150;
  canvas.height = 150;
  const ctx = canvas.getContext('2d');
  if (ctx) {
    ctx.fillStyle = color; // rgba(0,0,0,.7)
    ctx.fillRect(0, 0, 150, 60);
    ctx.fillStyle = 'white';
    ctx.font = '24px 黑体';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(text, 75, 30);
  }

  const texture = new CanvasTexture(canvas);
  const material = new SpriteMaterial({ map: texture });
  const sprite = new Sprite(material);

  sprite.position.set(position.x, position.y + 0.7, position.z);
  scene.add(sprite);
  return sprite;
}

// 创建一个悬浮的框
// const ctx = canvas.getContext('2d');
// if (ctx) {
//   ctx.fillStyle = 'rgba(0,0,0,.7)';
//   ctx.fillRect(0, 0, 200, 100);
//   ctx.fillStyle = 'white';
//   ctx.font = '21px 黑体';
//   ctx.textAlign = 'center';
//   ctx.textBaseline = 'middle';
// }
// const scaleFactor = 5;
// const texture = new CanvasTexture(canvas);
// const material = new SpriteMaterial({ map: texture });

// const sprite1 = new Sprite(material);
// sprite1.scale.set(scaleFactor, scaleFactor, scaleFactor);
// sprite1.position.set(-9.644502679789724, 5.815449539931501 + 0.5, 21.66345220492572);

//区域集合 - 修改为包含多种类型
let areaOneFloorArr: (Mesh | Sprite | BoxHelper)[] = [];
//光感报警器
let acoustoOpticArr: Mesh[] = [];
//手动报警器
let manualArr: Mesh[] = [];
// 烟雾探测器
let smokeDetectorArr: Mesh[] = [];
// 移动目标的集合
let moveArr: Mesh[] = []; // 只包含Mesh类型用于射线检测

interface meshController {
  meshName: string;
  targetMesh: any;
  geometry: Mesh;
  sprite: any;
  controller: any;
}

// node楼层节点
interface FloorNode {
  roomId: string;
  floorName: string;
  eqpList: EquipmentNode[];
}

//node
interface EquipmentNode {
  id: string; //设备ID
  name: string; //设备名称
  eState: number; //设备状态  0正常  1故障
  isBinding: boolean; //是否绑定
  currentState: number; //当前状态 0运行  1停止  2报警
  operation: boolean; //操作  true屏蔽  false取消屏蔽
}

let arr = ref<any[]>([]);
//数据初始化
async function dataInit() {
  const response = await modelApi.oneRoomFor_Equipment_get();
  if (response.code == 200 && response.data && response.data.length > 0) {
    response.data.forEach((floor: any) => {
      floor.eqpList.forEach((eqp: any) => {
        let currentState = 1;
        //故障
        if (
          (window.parent as ExtendedParentWindow).Rec?.service.node.runtimes[eqp.nodes[1]].double !=
          1
        )
          currentState = 1;
        else if (
          (window.parent as ExtendedParentWindow).Rec?.service.node.runtimes[eqp.nodes[2]].double ==
          1
        )
          currentState = 2;
        else if (
          (window.parent as ExtendedParentWindow).Rec?.service.node.runtimes[eqp.nodes[1]].double ==
          1
        )
          currentState = 0;

        let eqpNode: EquipmentNode = {
          id: eqp.id,
          name:
            (window.parent as ExtendedParentWindow).Rec?.service.node.runtimes[eqp.nodes[0]].node
              .name || '',
          eState:
            (window.parent as ExtendedParentWindow).Rec?.service.node.runtimes[eqp.nodes[0]]
              .double || 0,
          currentState: currentState,
          isBinding: eqp.isBinding,
          operation:
            (window.parent as ExtendedParentWindow).Rec?.service.node.runtimes[eqp.nodes[3]]
              .double == 1
        };
        arr.value.push({
          ...eqpNode,
          floorName: floor.roomName,
          roomId: floor.roomId
        });
      });
    });
    ElMessage.success('获取接口数据成功');
  } else {
    ElMessage.error('获取接口数据失败');
  }
}
dataInit();

function operationController(controller: string) {
  console.log(bindingObj, controller);
  console.log(meshControllerArr);
  let obj = meshControllerArr.find((item) => item.meshName === bindingObj.name);
  if (obj) {
    if (controller == 'restore') {
      obj.controller.restore();
    } else if (controller == 'alarm') {
      obj.controller.startAlarm();
    } else if (controller == 'fault') {
      obj.controller.startMalfunction();
    } else if (controller == 'stop') {
      obj.controller.stop();
    }
  }
}

let bindingArr: any[] = [];
async function getListBinding() {
  const response = await modelApi.getListBinding_get();
  if (response.code == 200 && response.data && response.data.length > 0) {
    bindingArr = response.data;
  } else {
    ElMessage.error('获取接口数据失败');
  }
}
getListBinding();

let meshControllerArr: meshController[] = [];
const loader = new GLTFLoader();
const textureLoader = new TextureLoader();
//alpha贴图
// F:\vue\workspace\maotu-webtopo\public\models\texture\alpha.png
const material = new MeshBasicMaterial({ color: 0x409eff, transparent: true, opacity: 0.3 });
const alphaTexture = textureLoader.load('/models/texture/alpha01.png');
const alphaMaterial = new MeshBasicMaterial({
  color: 0x409eff,
  alphaMap: alphaTexture, //alpha贴图
  transparent: true // 允许透明
});
// const dracoLoader = new DRACOLoader();
// loader.setDRACOLoader(dracoLoader);
//public\models\groundFloor\ground_floor.gltf
let bindingColor = 'rgba(33,61,91,0.70)';
loader.load('/models/groundFloor/ground_floor08.gltf', (gltf: any) => {
  gltf.scene.children.forEach((child: Mesh) => {
    // 区域
    if (child.name.includes('area_oneFloor')) {
      const duckGeometry = child.geometry;
      duckGeometry.computeBoundingBox();
      duckGeometry.center();
      const duckBox = duckGeometry.boundingBox?.clone() || new Box3();
      child.updateWorldMatrix(true, true);
      duckBox.applyMatrix4(child.matrixWorld);
      const duckBoxHelper = new BoxHelper(child, 0xf0f0f0);
      // 设置包围盒材质的透明度
      (duckBoxHelper.material as any).transparent = true;
      (duckBoxHelper.material as any).opacity = 0.38; // 50%透明度
      scene.add(duckBoxHelper);

      // 获取child对象的世界坐标
      // 添加精灵
      const worldPosition = new Vector3();
      child.getWorldPosition(worldPosition);

      // 创建文字精灵
      const canvas = document.createElement('canvas');
      // 提高Canvas分辨率以获得更清晰的文字
      const scale = window.devicePixelRatio || 1;
      canvas.width = 512 * scale;
      canvas.height = 256 * scale;
      canvas.style.width = '512px';
      canvas.style.height = '256px';

      const ctx = canvas.getContext('2d');

      if (ctx) {
        // 缩放上下文以匹配设备像素比率
        ctx.scale(scale, scale);

        // 设置文字样式
        ctx.fillStyle = 'rgba(0, 0, 0, 0)';
        ctx.fillRect(0, 0, 512, 256);
        ctx.fillStyle = 'white';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        // 使用更大的字体和更清晰的字体族
        ctx.font = '24px 微软雅黑, Arial, sans-serif';
        ctx.fillText(getAreaOneFloorGetName(child.name), 256, 128);
      }

      // 创建精灵材质和对象
      const texture = new CanvasTexture(canvas);
      const spriteMaterial = new SpriteMaterial({ map: texture });
      const sprite = new Sprite(spriteMaterial);

      // 设置精灵大小和位置
      sprite.scale.set(4, 2, 1); // 调整大小以适配新的Canvas尺寸
      sprite.position.copy(worldPosition);
      sprite.position.y += 1.5; // 稍微抬高一点
      scene.add(sprite);

      sprite.visible = false;
      duckBoxHelper.visible = false;
      child.visible = false;

      areaOneFloorArr.push(sprite); // 将精灵也加入数组
      areaOneFloorArr.push(duckBoxHelper);
      areaOneFloorArr.push(child);
      moveArr.push(child as any);
    } else if (child.name.includes('acoustoOptic')) {
      let acoustoPosition = child.position;
      const geometry = new SphereGeometry(0.6, 20, 16);

      const sphere = new Mesh(geometry, material);
      sphere.position.set(acoustoPosition.x, acoustoPosition.y, acoustoPosition.z);
      scene.add(sphere);

      let text = '未绑定';
      let color = 'rgba(0,0,0,.5)';
      //如果bindingArr集合中的objId和child.name匹配，则设置文字
      if (bindingArr.some((item: any) => item.objId === child.name)) {
        text = '已绑定';
        // rgba(45,72,31,0.70)  rgba(33,61,91,0.70)  rgba(33,61,91,0.70)
        color = bindingColor;
      }
      let sprite = addSprite(
        text,
        color,
        new Vector3(acoustoPosition.x, acoustoPosition.y - 0.2, acoustoPosition.z + 0.3)
      );

      child.visible = true;
      sphere.visible = true;
      acoustoOpticArr.push(sphere);
      acoustoOpticArr.push(child);

      meshControllerArr.push({
        meshName: child.name,
        targetMesh: child,
        geometry: sphere,
        sprite: sprite,
        controller: setupAlarmEffect(sphere)
      });
      moveArr.push(child as any);
    } else if (child.name.includes('manual')) {
      let manualPosition = child.position;
      const geometry = new SphereGeometry(0.6, 20, 16);
      const sphere = new Mesh(geometry, material);
      let text = '未绑定';
      let color = 'rgba(0,0,0,.5)';
      //如果bindingArr集合中的objId和child.name匹配，则设置文字
      if (bindingArr.some((item: any) => item.objId === child.name)) {
        text = '已绑定';
        // rgba(45,72,31,0.70)  rgba(33,61,91,0.70)  rgba(33,61,91,0.70)
        color = bindingColor;
      }
      let sprite = addSprite(
        text,
        color,
        new Vector3(manualPosition.x, manualPosition.y - 0.2, manualPosition.z - 0.3)
      );

      sphere.position.set(manualPosition.x, manualPosition.y, manualPosition.z);
      scene.add(sphere);
      child.visible = true;
      sphere.visible = true;

      manualArr.push(sphere);
      manualArr.push(child);

      meshControllerArr.push({
        meshName: child.name,
        targetMesh: child,
        geometry: sphere,
        sprite: sprite,
        controller: setupAlarmEffect(sphere)
      });

      moveArr.push(child as any);
    } else if (child.name.includes('smokeDetecto')) {
      // 烟感报警器
      let smokePosition = child.position;

      const geometry = new ConeGeometry(1.8, 1.2, 16, 1, true);
      const cone = new Mesh(geometry, alphaMaterial);
      cone.position.set(smokePosition.x, smokePosition.y - 0.5, smokePosition.z + 0.028);

      let text = '未绑定';
      let color = 'rgba(0,0,0,.5)';
      //如果bindingArr集合中的objId和child.name匹配，则设置文字
      if (bindingArr.some((item: any) => item.objId === child.name)) {
        text = '已绑定';
        // rgba(45,72,31,0.70)  rgba(33,61,91,0.70)  rgba(33,61,91,0.70)
        color = bindingColor;
      }
      // let text:string[] = ['x：'+child.position.x.toString() , 'y：'+child.position.y.toString() , 'z：'+child.position.z.toString()];
      // console.log(child.name+'  x：'+child.position.x.toString() , 'y：'+child.position.y.toString() , 'z：'+child.position.z.toString());
      // 烟感报警器
      let sprite = addSprite(text, color, cone.position);

      scene.add(cone);
      cone.visible = true;
      child.visible = true;

      smokeDetectorArr.push(cone);
      smokeDetectorArr.push(child);

      meshControllerArr.push({
        meshName: child.name,
        targetMesh: child,
        geometry: cone,
        sprite: sprite,
        controller: setupAlarmEffect(cone)
      });

      moveArr.push(child as any);
    }
  });
  scene.add(gltf.scene);
});

// 安全的报警效果设置函数
function setupAlarmEffect(object: Mesh) {
  // 安全检查 material 是否存在
  if (!object.material) {
    console.warn('对象没有材质属性:', object);
    return;
  }

  // 处理材质可能是数组的情况
  const materialArray = Array.isArray(object.material) ? object.material : [object.material];
  const firstMaterial = materialArray[0];

  // 保存原始材质
  // 确保材质有color属性
  if (!('color' in firstMaterial)) {
    console.warn('材质没有color属性:', firstMaterial);
    return;
  }

  const originalMaterial = firstMaterial.clone();
  const alarmMaterial = firstMaterial.clone();
  (alarmMaterial as any).color.set(0xe6a23c);
  const faultMaterial = firstMaterial.clone();
  (faultMaterial as any).color.set(0xf56c6c);

  let isAlarming = false;
  let isMalfunctioning = false;
  let isRestoring = false;
  let alarmInterval: number | null = null;

  // 报警控制函数 - 渐变闪烁版本
  function startAlarm() {
    // if (isAlarming) return;
    // isAlarming = true;

    object.material = alarmMaterial;
    object.visible = true;
    // 保存原始颜色
    // const originalColor = object.material.color.clone();

    const tl = gsap.timeline({ repeat: -1, yoyo: true });

    // 只在黄色和透明之间切换，不显示原始颜色
    tl.to(object.material, {
      opacity: 0.7, // 完全不透明的黄色
      duration: 0.5,
      ease: 'sine.inOut'
    }).to(object.material, {
      opacity: 0.2, // 半透明的黄色
      duration: 0.5,
      ease: 'sine.inOut'
    });
    // object._alarmTimeline = tl;
    // object._originalColor = originalColor; // 保存原始颜色用于恢复
  }

  //故障
  function startMalfunction() {
    // if (isMalfunctioning) return;
    // isMalfunctioning = true;

    object.material = faultMaterial;
    object.visible = true;
    // 保存原始颜色
    // const originalColor = object.material.color.clone();

    const tl = gsap.timeline({ repeat: -1, yoyo: true });

    // 只在黄色和透明之间切换，不显示原始颜色
    tl.to(object.material, {
      opacity: 0.7, // 完全不透明的黄色
      duration: 0.5,
      ease: 'sine.inOut'
    }).to(object.material, {
      opacity: 0.2, // 半透明的黄色
      duration: 0.5,
      ease: 'sine.inOut'
    });
    // object._alarmTimeline = tl;
    // object._originalColor = originalColor; // 保存原始颜色用于恢复
  }

  //还原
  function restore() {
    // if (!isRestoring) return;
    // isRestoring = true;

    if (alarmInterval !== null) {
      clearInterval(alarmInterval);
      alarmInterval = null;
    }

    // 恢复原始状态
    object.visible = true;
    object.material = originalMaterial;
  }

  //停止 - 隐藏对象以节约性能
  function stop() {
    // 停止所有动画
    if (alarmInterval !== null) {
      clearInterval(alarmInterval);
      alarmInterval = null;
    }

    // 隐藏对象
    object.visible = false;

    // 也可以设置材质完全透明
    // object.material.opacity = 0;
    // object.material.transparent = true;
  }

  // 扩展对象类型以支持动态方法
  (object as any).startAlarm = startAlarm;
  (object as any).restore = restore;
  (object as any).startMalfunction = startMalfunction;
  (object as any).stop = stop;

  // 返回对象本身，支持链式调用
  return object;
}

function getAreaOneFloorGetName(areaOneFloorName: string): string {
  switch (areaOneFloorName) {
    case 'area_oneFloor_35kV':
      return '35kV高压室';
    case 'area_oneFloor_220kV':
      return '220kV保护室';
    case 'area_oneFloor_14':
      return '蓄电池室';
    case 'area_oneFloor_3':
      return '站用电柜室';
    case 'area_oneFloor_13':
      return '380kV配电室';
    case 'area_oneFloor_4':
      return '1站用变室';
    case 'area_oneFloor_6':
      return '消弧线圈1室';
    case 'area_oneFloor_7':
      return '2号接地变室';
    case 'area_oneFloor_8':
      return '消弧线圈3室';
    case 'area_oneFloor_9':
      return '2站用变室';
    case 'area_oneFloor_10':
      return '110kV电缆间';
    case 'area_oneFloor_12':
      return '安全工器具间';
    case 'area_oneFloor_11':
      return '消弧线圈4室';
    default:
      return '未知';
  }
}

function animate() {
  requestAnimationFrame(animate);
  orbitControls.update();
  renderer.render(scene, camera);
}

// ResizeObserver 监听容器尺寸变化
let resizeObserver: ResizeObserver | null = null;

//补间动画
const timeline1 = gsap.timeline();
const timeline2 = gsap.timeline();

//相机移动
function tranlate(position: Vector3, target: Vector3) {
  timeline1.to(camera.position, {
    x: position.x,
    y: position.y,
    z: position.z,
    duration: 1,
    ease: 'power2.inOut'
  });

  timeline2.to(orbitControls.target, {
    x: target.x,
    y: target.y,
    z: target.z,
    duration: 1,
    ease: 'power2.inOut'
  });
}

function displayModel(modelName: string) {
  tranlate(new Vector3(0, 14, 13.5), new Vector3(0, 0, 0));
  if (modelName === 'area_oneFloor') {
    areaOneFloorArr.forEach((obj) => {
      obj.visible = true;
    });
    acoustoOpticArr.forEach((obj) => {
      obj.visible = false;
    });
    manualArr.forEach((obj) => {
      obj.visible = false;
    });
    smokeDetectorArr.forEach((obj) => {
      obj.visible = false;
    });
  } else if (modelName === 'acoustoOptic') {
    areaOneFloorArr.forEach((obj) => {
      obj.visible = false;
    });
    acoustoOpticArr.forEach((obj) => {
      obj.visible = true;
    });
    manualArr.forEach((obj) => {
      obj.visible = false;
    });
    smokeDetectorArr.forEach((obj) => {
      obj.visible = false;
    });
  } else if (modelName === 'manual') {
    areaOneFloorArr.forEach((obj) => {
      obj.visible = false;
    });
    acoustoOpticArr.forEach((obj) => {
      obj.visible = false;
    });
    manualArr.forEach((obj) => {
      obj.visible = true;
    });
    smokeDetectorArr.forEach((obj) => {
      obj.visible = false;
    });
  } else if (modelName === 'smokeDetector') {
    areaOneFloorArr.forEach((obj) => {
      obj.visible = false;
    });
    acoustoOpticArr.forEach((obj) => {
      obj.visible = false;
    });
    manualArr.forEach((obj) => {
      obj.visible = false;
    });
    smokeDetectorArr.forEach((obj) => {
      obj.visible = true;
    });
  } else if (modelName === 'refresh') {
    areaOneFloorArr.forEach((obj) => {
      obj.visible = false;
    });
    acoustoOpticArr.forEach((obj) => {
      obj.visible = false;
    });
    manualArr.forEach((obj) => {
      obj.visible = false;
    });
    smokeDetectorArr.forEach((obj) => {
      obj.visible = false;
    });
  }
}

// 绑定
async function bindDevice(row: any) {
  if (!bindingObj) ElMessage.warning('请选择要绑定的模型');
  let id = null;
  if (bindingObj.bindingMap && bindingObj.bindingMap.id) id = bindingObj.bindingMap.id;

  const response = await modelApi.binding_post({ id, objId: bindingObj.name, facilityId: row.id });
  if (response.code == 200 && response.data == true) {
    emitter.emit('binding-data-update');
    // bindingObj.name
    // 根据 meshName 匹配并修改 sprite 颜色
    const matchedController = meshControllerArr.find((item) => item.meshName === bindingObj.name);
    if (matchedController && matchedController.sprite) {
      // 获取原来 sprite 的位置
      debugger;
      const oldPosition = matchedController.sprite.position.clone();
      // 移除原来的 sprite
      scene.remove(matchedController.sprite);
      // 创建新的淡绿色精灵，位置保持一致
      const newSprite = addSprite(
        '已绑定',
        bindingColor,
        new Vector3(oldPosition.x, oldPosition.y - 0.7, oldPosition.z)
      );
      // 更新控制器中的sprite引用
      matchedController.sprite = newSprite;
    }

    ElMessage.success('绑定成功');
  } else ElMessage.error('绑定失败');
  dialogTableVisible.value = false;
}

async function getBinding(objId: string | null, facilityId: string | null) {
  const response = await modelApi.getBinding_post({ objId: objId, facilityId: facilityId });
  if (response.code == 200 && response.data) {
    return response.data;
  }
  return null;
}

let bindingInfo: any = reactive({});
//获取绑定信息
function getBindingInfo(facilityId: string) {
  console.log('获取绑定信息:', facilityId, arr);
  for (const item of arr.value) {
    if (item.id == facilityId) {
      // 使用 Object.assign 保持响应式
      Object.assign(bindingInfo, {
        currentState: item.currentState,
        eState: item.eState,
        floorName: item.floorName,
        id: item.id,
        name: item.name,
        operation: item.operation,
        roomId: item.roomId
      });
      break;
    }
  }
}

function clearBoxHelper(boxHelper: BoxHelper | null) {
  // 正确的资源清理顺序
  if (boxHelper) {
    scene.remove(boxHelper); // 从场景中移除
    boxHelper.geometry.dispose(); // 释放几何体内存
    if (boxHelper.material) {
      if (Array.isArray(boxHelper.material)) {
        boxHelper.material.forEach((material) => material.dispose());
      } else {
        boxHelper.material.dispose();
      }
    }
    boxHelper = null; // 清空引用
  }
}

//绑定的元素
let bindingObj: any = null;
let boxHelper = <BoxHelper | null>null;

let cardisOpen = ref(false);
let moduleType = ref('');
onMounted(() => {
  const container = containerRef.value!;
  container.appendChild(renderer.domElement);

  // 初始化摄像机和渲染器尺寸
  camera.aspect = container.clientWidth / container.clientHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(container.clientWidth, container.clientHeight);

  // 监听容器尺寸变化
  resizeObserver = new ResizeObserver(() => {
    camera.aspect = container.clientWidth / container.clientHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(container.clientWidth, container.clientHeight);
  });
  resizeObserver.observe(container);

  // 创建射线检测器
  const raycaster = new Raycaster();
  const mouse = new Vector2();

  // 添加点击事件监听
  renderer.domElement.addEventListener('click', async (event: MouseEvent) => {
    const rect = container.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;

    mouse.x = (x / container.clientWidth) * 2 - 1;
    mouse.y = -(y / container.clientHeight) * 2 + 1;

    raycaster.setFromCamera(mouse, camera);
    // 合并所有需要检测的数组并过滤出Mesh类型
    const targetObjects = [...moveArr].filter((obj) => obj.visible);
    const intersects = raycaster.intersectObjects(targetObjects, true);

    // const targetScenes = scene.children.filter((obj) => obj.name == 'Scene');
    // console.log('targetScenes[0].children:', targetScenes[0].children);
    // const intersects = raycaster.intersectObjects(targetScenes[0].children, true);

    if (intersects.length > 0) {
      let position: Vector3 | undefined;
      let x = 0;
      let y = 0;
      let z = 0;
      let targetObj: any;
      if (
        intersects[0].object.name.includes('acoustoSon') ||
        intersects[0].object.name.includes('manualSon') ||
        intersects[0].object.name.includes('smokeSon')
      ) {
        targetObj = intersects[0].object.parent;
        position = intersects[0].object.parent?.position || new Vector3(0, 0, 0);
        x = -0.3;
        y = 0.5;
        z = 0.5;
      } else {
        targetObj = intersects[0].object;
        position = intersects[0].object.position;
        x = -1;
        y = 3;
        z = 3;
      }
      targetObj.bindingMap = await getBinding(targetObj.name, null);
      cardisOpen.value = true;
      moduleType.value = targetObj.name;
      bindingObj = targetObj;
      if (targetObj.bindingMap) getBindingInfo(targetObj.bindingMap.facilityId);
      else
        Object.keys(bindingInfo).forEach((key) => {
          delete bindingInfo[key];
        });
      if (position) {
        tranlate(
          new Vector3(position.x + x, position.y + y, position.z + z),
          new Vector3(position.x, position.y, position.z)
        );
      }
      clearBoxHelper(boxHelper);
      // 创建包围盒辅助器
      boxHelper = new BoxHelper(targetObj, 0xffff00);
      scene.add(boxHelper);
    } else {
      cardisOpen.value = false;
      moduleType.value = '';
      bindingObj = null;
      clearBoxHelper(boxHelper);
      // 清空对象而不是重新创建
      Object.keys(bindingInfo).forEach((key) => {
        delete bindingInfo[key];
      });
    }
  });

  animate();
});

function getModelDroupName(moduleType: string): string {
  if (moduleType.includes('acoustoOptic')) return '声光报警器';
  else if (moduleType.includes('manual')) return '手动报警器';
  else if (moduleType.includes('smokeDetector')) return '烟感报警器';
  else return '未知';
}

emitter.on('binding-obj-facility-move', async (value: any) => {
  const response = await getBinding(null, value);
  if (!response) ElMessage.warning('该数据未绑定模型');
  else {
    console.log('getBinding:', response);
    let targetObj: any;
    let targetControllerObj: any;
    targetObj = moveArr.find((obj) => obj.name === response.objId);
    cardisOpen.value = true;
    targetObj.visible = true;

    //meshControllerArr
    moduleType.value = targetObj.name;

    targetControllerObj = meshControllerArr.find((obj) => obj.meshName === response.objId);
    targetControllerObj.geometry.visible = true;

    getBindingInfo(response.facilityId);
    clearBoxHelper(boxHelper);
    // 创建包围盒辅助器
    boxHelper = new BoxHelper(targetObj, 0xffff00);
    scene.add(boxHelper);

    // position
    let position = targetObj?.position;
    if (position) {
      tranlate(
        new Vector3(position.x - 0.3, position.y + 0.5, position.z + 0.5),
        new Vector3(position.x, position.y, position.z)
      );
    }
  }
});

onUnmounted(() => {
  console.log('删除');
  if (resizeObserver) {
    resizeObserver.disconnect();
    resizeObserver = null;
  }
  emitter.off('binding-obj-facility-move');
});
</script>

<style scoped>
.scene-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
}

.container {
  width: 100%;
  height: 100%;
  position: relative;
}

.control-panel {
  position: absolute;
  top: 50%;
  right: 2%;
  transform: translateY(-50%); /* 垂直居中 */
  display: flex;
  flex-direction: column;
  gap: 20px;
  z-index: 101;
  align-items: flex-end; /* 改为右对齐 */
  /* background: rgba(0, 0, 0, 0.7); */
  width: 35%;
  height: 70%;
}

.control-buttons {
  position: absolute;
  top: 50%;
  left: 2%;
  transform: translateY(-50%); /* 垂直居中 */
  display: flex;
  flex-direction: column;
  gap: 20px;
  z-index: 100;
  align-items: flex-start; /* 确保所有按钮左对齐 */
}

/* Element Plus圆形按钮样式调整 */
.control-buttons :deep(.el-button) {
  width: 40px !important;
  height: 40px !important;
  min-width: 40px !important;
  padding: 0 !important;
  display: flex !important;
  align-items: center !important;
  margin: 0 !important;
  box-sizing: border-box !important;
}

.control-btn {
  padding: 8px 16px;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  border: 1px solid #4fc3f7;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.3s ease;
  min-width: 80px;
}

.card {
  /* height: 100%; */
  width: 100%;
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;

  background-color: rgba(0, 0, 0, 0.5) !important;
  backdrop-filter: blur(5px);
  border: none;
  box-shadow: 0 2px 12px rgba(255, 0, 0, 0.1);
}

.card :deep(.el-card__body) {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
}

.cardHead {
  margin: 0 0 15px 0;
  padding: 0;
  font-size: 16px;
  font-weight: bold;
  text-align: center;
  color: #ffffff;
}

.cardBody {
  font-size: 12px;
  width: 100%;
}

.info-row {
  margin-bottom: 5px;
  display: flex;
  align-items: center;
  width: 100%;
  font-size: 12px;

  /* border: 1px solid red; */
  margin-bottom: 5px !important;
  padding: 0 !important;
}

/* 让组件继承父容器宽度 */
.full-width-component {
  width: 100% !important;
  max-width: 100% !important;
}

.equipment-container {
  width: 100%;
  height: auto;
}

/* 确保设备组件行与信息行宽度一致 */
.equipment-row {
  width: 100%;
  margin-top: 10px; /* 与其他行保持间距 */
}

/* 确保设备组件继承父容器宽度 */
.equipment-wrapper {
  width: 100% !important;
  height: 150px; /* 设置固定高度或根据需要调整 */
  position: relative;
}

.equipment-wrapper :deep(.div3D) {
  width: 100% !important;
  height: 100% !important;
}

.equipment-component {
  width: 100% !important;
  display: block !important;
  box-sizing: border-box;
}

/* 确保所有行都有相同的宽度基准 */
.info-row,
.equipment-row {
  max-width: 100%;
  box-sizing: border-box;
}

/* 控制标签文字大小 */
.info-row :deep(.el-tag) {
  font-size: 10.5px;
}

/* 统一内边距 */
.cardBody {
  /* padding: 10px; */
}

.cardBody .el-row {
  width: 100%;
  margin-bottom: 2px;
}

/* 控制表头文字大小 */
.full-height-table :deep(.el-table__header th) {
  font-size: 13px;
  font-weight: bold;
}

/* 控制表格内容文字大小 */
.full-height-table :deep(.el-table__body td) {
  font-size: 11.5px;
  color: 12px;
}

/* 控制标签文字大小 */
.full-height-table :deep(.el-tag) {
  font-size: 11px;
}

/* 控制按钮文字大小 */
.full-height-table :deep(.el-button) {
  font-size: 11px;
}

.operation-btn {
  font-size: 10px;
  width: 50px;
  min-width: 55px;
  height: 20px;
  padding: 8px 12px;
}

.info-row :deep(.el-col) {
  display: flex;
  align-items: center;
}

.info-row :deep(.el-tag) {
  justify-content: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
  display: flex;
  align-items: center;
  /* height: 100%; */
}
</style>
