<template>
  <div class="call-container" v-show="dialling || calling || isDialled">
    <div class="choose" v-show="isDialled">
      <div class="title">
        {{ sponsor }}来通话啦
      </div>
      <div class="buttons">
        <div class="accept" @click="handleDebounce(onAcceptClick,500)"></div>
        <div class="refuse" @click="handleDebounce(reject,500)"></div>
      </div>
    </div>
    <div class="call" v-show="dialling || calling">
      <div class="title" v-if="dialling && currentConversationType==='1'">
        正在呼叫{{toAccount}}...
      </div>
      <div class="title" v-if="dialling && currentConversationType==='3'">
        正在呼叫...
      </div>

      <div v-show="callType === CALL_TYPE.VIDEO_CALL && calling">
        <div class="small-group" id="small-group">
          <!-- 本地视频容器 -->
          <div class="video-box1" id="local">

          </div>
          <div
            class="video-box"
            v-for="userId in callingUserList"
            :id="`video-${userId}`"
            :key="`video-${userId}`"
          ></div>
           <!--动态创建远端视频容器 -->
<!--          <span>{{"callingUserList:",callingUserList}}</span>-->

        </div>
      </div>

      <div v-show="callType === CALL_TYPE.AUDIO_CALL && calling" class="audio-box">
        <div v-show="calling" class="aduio-call">
          <img :src="myAvatar" class="audio-img" />
          <p style="text-align: center">
            <span class="nick-text">{{ myNick }}</span>
            <i v-if="isMicOn" class="el-icon-microphone micr-icon" style="color: #006FFF;"></i>
            <i v-else class="el-icon-turn-off-microphone micr-icon"></i>
          </p>
        </div>
        <div v-for="item in invitedUserInfo" class="aduio-call" :key="`video-${item.userID}`">
          <img :src="item.avatar || defaultAvatar" class="audio-img" />
          <p style="text-align: center">
            <span class="nick-text">{{ item.nickname || item.userID }}</span>
            <i
              v-if="item.isInvitedMicOn === true || item.isInvitedMicOn == undefined"
              class="el-icon-microphone micr-icon"
              style="color: #006FFF;"
            ></i>
            <i v-else class="el-icon-turn-off-microphone micr-icon"></i>
          </p>
        </div>
      </div>

      <div class="duration" v-show="calling">{{ formatDurationStr }}</div>

      <div class="buttons" v-if="callType === CALL_TYPE.VIDEO_CALL">
        <div :class="isCamOn ? 'videoOn' : 'videoOff'" @click="toggleCamera"></div>
        <div class="refuse" @click="handleDebounce(hangUp, 500)"></div>
        <div :class="isMicOn ? 'micOn' : 'micOff'" @click="toggleMic"></div>
      </div>

      <div class="buttons" v-else>
        <div class="refuse" @click="handleDebounce(hangUp, 500)"></div>
        <div :class="isMicOn ? 'micOn' : 'micOff'" @click="toggleMic"></div>
      </div>
    </div>
  </div>
</template>


<script>
import { v4 as uuidv4 } from 'uuid';
import { mapGetters, mapState } from 'vuex';
import { formatDuration } from '@/utils/formatDuration';
import { CALL_TYPE } from '@/constant/call';
import { getOpenIM } from '@/utils/openIM';
import Trtc,{createLocalAudioTrack,createLocalVideoTrack} from '@/utils/trtc';
import beCalledSound from '@/assets/audio/beCalled.mp3';
export default {
  name: 'CallLayer',
  data() {
    return {
      acceptToken: '',
      acceptURL: '',
      acceptRoomID: '',
      faceImages:"",
      nickName:"",
      callType: '',
      inviteID: '',
      inviteData: {},
      sponsor: '',
      callingUserList: [],
      isCamOn: true,
      isMicOn: true,
      start: 0,
      duration: 0,
      dialling: false,
      calling: false,
      isDialled: false,
      invitedUserInfo: [],
      room: null,
      localTracks: [],
      remoteUsers: [],
      OpenIM: null,
      durationTimer: null,
      defaultAvatar: 'https://imgcache.qq.com/open/qcloud/video/act/webim-avatar/avatar-3.png',
      isInvitedMicOn: true,
      ringtone: null,
      ringtoneType: '',
    };
  },
  computed: {
    CALL_TYPE() {
      return CALL_TYPE;
    },
    ...mapGetters(['toAccount', 'currentConversationType']),
    ...mapState({
      currentConversation: state => state.conversation.currentConversation,
      currentUserProfile: state => state.imuser.currentUserProfile,
      callingInfo: state => state.conversation.callingInfo,
      userID: state => state.imuser.userID,
    }),
    formatDurationStr() {
      return formatDuration(this.duration);
    },
    myAvatar() {
      console.log("我的相关信息",this.currentUserProfile)
      return this.currentUserProfile.faceURL || this.defaultAvatar
    },
    myNick() {
      return this.currentUserProfile.nickname || this.userID
    }
  },
  created() {
    this.OpenIM = getOpenIM();
    //document.addEventListener('click', this.initAudio, { once: true })
    this.setupEventListeners();
  },
  beforeDestroy() {
    this.cleanup();
  },
  methods: {

    micHandler() { // 是否打开麦克风
      if (this.isMicOn) {
        this.toggleMic()
        this.isMicOn = false
      } else {
        this.toggleMic()
        this.isMicOn = true
      }
    },
    // 初始化事件监听
    setupEventListeners() {
      this.OpenIM.on('OnReceiveNewInvitation', this.handleNewInvitation);
      this.OpenIM.on('OnInviteeAccepted', this.handleInviteeAccepted);
      this.OpenIM.on('OnInviteeRejected', this.handleInviteeRejected);
      this.OpenIM.on('OnInvitationTimeout', this.handleInvitationTimeout);
      this.OpenIM.on('OnHangUp', this.handleHangUp);

      this.$bus.$on('video-call', () => this.startCall('video'));
      this.$bus.$on('audio-call', () => this.startCall('audio'));
    },

    // 清理资源
    cleanup() {
      //this.stopRingtone();
      clearInterval(this.durationTimer);

      if (this.room) {
        this.room.disconnect();
        this.room = null;
      }

      this.OpenIM.off('OnReceiveNewInvitation', this.handleNewInvitation);
      this.OpenIM.off('OnInviteeAccepted', this.handleInviteeAccepted);
      this.OpenIM.off('OnInviteeRejected', this.handleInviteeRejected);
      this.OpenIM.off('OnInvitationTimeout', this.handleInvitationTimeout);
      this.OpenIM.off('OnHangUp', this.handleHangUp);

      this.$bus.$off('video-call');
      this.$bus.$off('audio-call');
    },

    // 播放铃声
    initAudio(type = 'callee') {
      try {
        const audio = new Audio(beCalledSound);
        audio.play().catch(err => {
          console.warn("播放声音失败", err);
        });
        this.ringtone = new Audio(beCalledSound);
        this.ringtone.loop = true;
        this.ringtone.preload = 'auto';
        this.ringtoneType = type;

        this.ringtone.addEventListener('error', (e) => {
          console.error('音频加载错误:', e);
        });

        this.ringtone.play().catch((err) => {
          console.warn('播放铃声失败，可能未解锁音频权限:', err);
        });
      } catch (e) {
        console.error('音频初始化失败:', e);
      }
    },
    playRingtone() {
      if (!this.ringtone) {
        this.initAudio()
      }

      this.ringtone.loop = true
      this.ringtone.play().catch(e => {
        console.error('播放被阻止:', e)
        // 可以在这里显示"点击允许音频"的提示
      })
    },
    stopRingtone() {
      if (this.ringtone) {
        this.ringtone.pause();
        this.ringtone.currentTime = 0;
        this.ringtone = null;
        this.ringtoneType = '';
      }
    },

    // 处理新邀请
    async handleNewInvitation(data) {
      console.log("返回的参数data", data)
      this.inviteID = data.data.inviteID
      this.inviteData = data.data.invitation
      this.callType = data.data.invitation.mediaType
      this.sponsor = data.data.participant.userInfo.nickname
      this.isDialled = true

      // 提前预热权限（耗时 1-2 秒，提前做）
      this.prewarmMediaPermission()

      // 提前执行 signalingAccept，拿到 token/url（非真正入会）
      try {
        const res = await this.OpenIM.signalingAccept({
          opUserID: this.userID,
          invitation: this.inviteData
        });
        this.acceptToken = res.data.token
        this.acceptURL = res.data.liveURL
        this.acceptRoomID = this.inviteData.roomID
      } catch (err) {
        console.error("提前 accept 接口失败", err)
      }

      document.addEventListener('click', () => {
        this.initAudio('callee');
      }, { once: true })

      this.updateInvitedUserInfo(data.data.invitation.inviteeUserIDList)
    },

    // 更新被邀请用户信息
    async updateInvitedUserInfo(userIDs) {
      const users = await Promise.all(
        userIDs.map(userID => this.OpenIM.getUsersInfo([userID]))
      );
      console.log("查询的用户信息",users)
      this.invitedUserInfo = users.map(user => ({
        userID: user.userID,
        nickname: user.nickname,
        avatar: user.faceURL,
        isMicOn: true
      }));
    },

    // 发起通话
    async startCall(type) {
      console.log("发起通话",this.toAccount)
      if (this.calling || this.dialling) return;

      try {
        this.callType = type;
        console.log("通话方式",this.callType)
        this.dialling = true;
        const roomId = uuidv4();

        // 1. 先发送邀请，等待被叫方响应（这里需要监听被叫方的接受事件）
        const { token, liveURL, roomID, inviteID } = await this.sendCallInvitation(roomId, type);
        this.initAudio('caller');
        this.inviteID = inviteID; // 保存 inviteID，等待对方接听后再 joinRoom
        this.roomToken = token;
        this.roomURL = liveURL;
        this.roomID = roomID;
        console.log("生成的token和url",this.roomToken, this.roomURL)
      } catch (error) {
        console.error('发起通话失败:', error);
        this.resetCallState();
      }
    },
    // 被叫方接受邀请后，主叫方和被叫方都调用
    /*async joinRoom(roomID,roomToken,roomURL) {
      console.log(roomID)
      const callData = {
        // 移除外层 operationID（SDK 会自动添加）
        invitation: {
          inviterUserID: this.userID,
          inviteeUserIDList: ["D79"],
          groupID: '',
          roomID: roomID,
          timeout: 60,
          mediaType: this.callType,
          sessionType: 1,
          platformID: 5
        },
        offlinePushInfo: {
          title: 'You have a call invitation',
          desc: 'You have a call invitation',
          ex: '',
          iOSPushSound: '',
          iOSBadgeCount: true
        }
      };
      const res = await this.OpenIM.signalingAccept(callData);
      console.log(res)
      if (res.errCode !== 0) {
        console.error("获取房间 token 失败:", res.errMsg);
        return;
      }
      this.room = await Trtc.joinRoom(roomToken, roomURL, this.userID, roomID, {
        video: this.callType === 'video',
        audio: true
      });

      this.setupRoomListeners();
      if (this.callType === 'video'){
        await this.publishLocalVideo();
        await this.publishLocalAudio();
      }
    },*/

    // 发送通话邀请
    async sendCallInvitation(roomId, type) {
      console.log(" this.callingInfo.memberList", this.userID)
      const callData = {
        invitation: {
          inviterUserID: this.userID,
          inviteeUserIDList: [this.toAccount],
          groupID: '',
          roomID: roomId,
          timeout: 60,
          mediaType: this.callType,
          sessionType: 1,
          platformID: 5
        },
        offlinePushInfo: {
          title: '来电提示',
          desc: this.callType === 'video'? '视频通话':'语音通话',
          ex: '',
          iOSPushSound: '',
          iOSBadgeCount: true
        }
      };
      console.log("callData",callData)
      const res = await this.OpenIM.signalingInvite(callData);
      this.inviteID = res.data.inviteID;
      console.log("sendCallInvitation返回值",res)
      return {
        token: res.data.token,
        liveURL: res.data.liveURL,
        roomID: res.data.roomID,
        inviteID: res.data.inviteID,
      };
    },
    // 设置房间事件监听
    setupRoomListeners() {
      console.log("触发setupRoomListeners")
      /*this.room.on('participantConnected', participant => {
        console.log('participantConnected:', participant.identity);
        if (!this.callingUserList.includes(participant.identity)) {
          this.callingUserList = [...this.callingUserList, participant.identity];
          this.updateParticipantInfo(participant.identity);
        }
      });

      this.room.on('trackSubscribed', (track, participant) => {
        console.log('trackSubscribed:', track.kind, participant.identity);
        this.attachRemoteTrack(track, participant);
      });*/

      this.room.on('trackPublished', publication => {
        console.log('trackPublished:', publication.trackKind);
      });
    },
    async prewarmMediaPermission() {
      try {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: this.callType === 'video' });
        stream.getTracks().forEach(track => track.stop()); // 不播放，只为触发授权
        console.log("预热媒体权限成功");
      } catch (err) {
        console.warn("权限预热失败:", err);
      }
    },
    async onAcceptClick() {
      try {
        await this.prewarmMediaPermission(); // 权限预热（防止卡住）
        await this.accept();                 // 原来的接听逻辑
      } catch (e) {
        console.error("接听过程异常:", e);
      }
    },
    // 发布本地视频
    async publishLocalVideo() {
      const localContainer = document.getElementById('local');
      if (!localContainer) return;

      // 确保容器有尺寸
      localContainer.style.width = '320px';
      localContainer.style.height = '240px';
      localContainer.style.backgroundColor = 'black';
      localContainer.innerHTML = '';

      const devices = await navigator.mediaDevices.enumerateDevices();
      const hasCam = devices.some(d => d.kind === 'videoinput');

      if (!hasCam) {
        console.warn('无可用摄像头，显示蓝色占位');
        this.showBluePlaceholder(localContainer, '无摄像头');
        return;
      }

      try {
        const videoTrack = await createLocalVideoTrack();
        await this.room.localParticipant.publishTrack(videoTrack);
        this.localTracks.push(videoTrack);

        // 挂载本地视频轨道
        const videoEl = document.createElement('video');
        videoEl.autoplay = true;
        videoEl.muted = true;
        videoEl.playsInline = true;
        videoEl.style.width = '100%';
        videoEl.style.height = '100%';
        localContainer.appendChild(videoEl);
        videoTrack.attach(videoEl);
      } catch (err) {
        console.error('本地视频初始化失败:', err);
        //this.showBluePlaceholder(localContainer, '摄像头不可用');
      }
    },
    // 渲染蓝色占位
    showBluePlaceholder(container, text = '') {
      const placeholder = document.createElement('div');
      placeholder.style.width = '100%';
      placeholder.style.height = '100%';
      placeholder.style.backgroundColor = 'blue';
      placeholder.style.display = 'flex';
      placeholder.style.alignItems = 'center';
      placeholder.style.justifyContent = 'center';
      placeholder.style.color = '#fff';
      placeholder.style.fontSize = '18px';
      placeholder.innerText = text;
      container.innerHTML = ''; // 清空容器
      container.appendChild(placeholder);
    },

    async publishLocalAudio() {
      const devices = await navigator.mediaDevices.enumerateDevices();
      const hasMic = devices.some(d => d.kind === 'audioinput');
      if (!hasMic) {
        console.warn('无可用麦克风，跳过音频轨道发布');
        return;
      }
      const audioTrack = await createLocalAudioTrack();
      await this.room.localParticipant.publishTrack(audioTrack);
      this.localTracks.push(audioTrack);
    },

    // 接听通话
    async accept() {
      this.stopRingtone()
      try {
        console.time("joinRoom");

        this.room = await Trtc.joinRoom(
          this.acceptToken,
          this.acceptURL,
          this.userID,
          (track, participant) => {
            this.updateParticipantInfo(participant.identity)
            this.attachRemoteTrack(track, participant)
          }
        )

        console.timeEnd("joinRoom");
        console.log("Room 对象:", this.room);

        this.setupRoomListeners();
        this.isDialled = false;
        this.calling = true;
        this.startCallTimer();
        // 接听后挂载本地音视频
        if (this.callType === 'video') {
          await this.publishLocalVideo()
        }
        await this.publishLocalAudio()
      } catch (error) {
        console.error('接听失败:', error);
        this.resetCallState();
      }
    },

    // 拒绝通话
    async reject() {
      this.stopRingtone();
      try {
        console.log('接收到的邀请数据：', this.inviteData);
        //this.stopRingtone();
        await this.OpenIM.signalingReject({
          opUserID: this.userID,      // 当前用户ID
          invitation: this.inviteData //  完整 invitation 对象
        });
        this.resetCallState();
      } catch (error) {
        console.error('拒绝失败:', error);
        //message.error(t('toast.rejectFailed'));
      }
    },

    // 挂断通话
    async hangUp() {
      console.log("接听还是拨打",this.inviteData)
      console.log("接听还是拨打",this.dialling,this.calling)
      this.stopRingtone();
      try {
        if (this.dialling) {
          await this.OpenIM.signalingCancel({
            opUserID: this.userID,      // 当前用户ID
            invitation: this.inviteData //  完整 invitation 对象
          });
        } else if (this.calling) {
          await this.OpenIM.signalingHungUp({
            opUserID: this.userID,      // 当前用户ID
            invitation: this.inviteData //  完整 invitation 对象
          });
        }

        // 离开房间
        if (Trtc) {
          await Trtc.leaveRoom();
          await this.sleep(500)
        }

        this.resetCallState();

      } catch (error) {
        console.error('挂断失败:', error);
        //message.error(t('toast.hangUpFailed'));
      }
    },
    sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms))
    },
    // 防抖处理
    handleDebounce(func, wait) {
      if (this.timeout) clearTimeout(this.timeout)
      this.timeout = setTimeout(() => {
        func()
      }, wait)
    },
    // 开始通话计时
    startCallTimer() {
      this.start = Date.now();
      this.durationTimer = setInterval(() => {
        this.duration = Math.floor((Date.now() - this.start) / 1000);
      }, 1000);
    },

    // 重置通话状态
    resetCallState() {
      clearInterval(this.durationTimer);
      this.duration = 0;
      this.dialling = false;
      this.calling = false;
      this.isDialled = false;
      this.localTracks = [];
      this.remoteUsers = [];
      this.callingUserList = [];
      this.inviteID = '';
      this.inviteData = {};
      this.roomToken = '';
      this.roomURL = '';
      this.roomID = '';
      this.room = null;
      this.acceptToken = '';
      this.acceptURL = '';
      this.acceptRoomID = '';
    },

    // 切换摄像头状态
    async toggleCamera() {
      try {
        this.isCamOn = !this.isCamOn;
        const videoTrack = this.localTracks.find(t => t.kind === 'video');
        if (videoTrack) {
          this.isCamOn ? await videoTrack.unmute() : await videoTrack.mute();
        }
      } catch (error) {
        console.error('切换摄像头失败:', error);
        this.isCamOn = !this.isCamOn;
      }
    },

    // 切换麦克风状态
    async toggleMic() {
      try {
        this.isMicOn = !this.isMicOn;
        const audioTrack = this.localTracks.find(t => t.kind === 'audio');
        if (audioTrack) {
          this.isMicOn ? await audioTrack.unmute() : await audioTrack.mute();
        }
      } catch (error) {
        console.error('切换麦克风失败:', error);
        this.isMicOn = !this.isMicOn;
      }
    },

    // 处理参与者接受邀请
    async handleInviteeAccepted(data) {
      if (data.inviteID !== this.inviteID) return
      this.stopRingtone()
      this.inviteData = data.data.invitation
      try {
        // joinRoom，发布本地轨道 & 挂载远端轨道都在这里完成
        this.room = await Trtc.joinRoom(
          this.roomToken,
          this.roomURL,
          this.userID,
          (track, participant) => {
            this.updateParticipantInfo(participant.identity)
            this.attachRemoteTrack(track, participant)
          }
        )
        console.log("Room 对象:", this.room);
        this.setupRoomListeners();
        this.calling = true
        this.dialling = false
        this.isDialled = false
        this.startCallTimer()
        // 加上本地轨道挂载
        if (this.callType === 'video') {
          await this.publishLocalVideo()
        }
        await this.publishLocalAudio()
      } catch (err) {
        console.error('主叫方 joinRoom 出错', err)
      }
    },


    // 处理参与者拒绝邀请
    handleInviteeRejected(data) {
      console.log(123456789)
      this.stopRingtone();
      if (data.inviteID === this.inviteID) {
        this.invitedUserInfo = this.invitedUserInfo.filter(
          user => user.userID !== data.data.invitation.inviteeUserID
        );
      }
    },

    // 处理邀请超时
    handleInvitationTimeout(data) {
      this.stopRingtone();
      if (data.inviteID === this.inviteID) {
        //message.warning(t('toast.callTimeout'));
        this.resetCallState();
      }
    },

    // 处理挂断
    handleHangUp(data) {

      this.stopRingtone();
      if (data.inviteID === this.inviteID) {
        //message.info(t('toast.callEnded'));
        this.resetCallState();
      }
    },

    // 更新参与者信息
    updateParticipantInfo(userID) {
      if (!this.callingUserList.includes(userID)) {
        this.callingUserList.push(userID); // ✅ 先 push
      }
      this.OpenIM.getUsersInfo([userID])
        .then(({ data }) => {
          console.log("查询用户信息",data)
          this.faceImages = data[0].faceURL
          this.nickName = data[0].nickname
          console.log("更新参与者信息", this.invitedUserInfo)
          const user = this.invitedUserInfo.find(u => u.userID === userID);
          console.log(this.faceImages)
          console.log(this.nickName)
          if (!user) {
            this.invitedUserInfo.push({
              userID,
              nickname: this.nickName,
              avatar: this.faceImages,
              isMicOn: true
            });
          }

          // data: 查询到的用户信息列表
        })
        .catch(({ errCode, errMsg }) => {
          // 调用失败attachRemoteTrack
        });

    },

    // 附加远端轨道
    attachRemoteTrack(track, participant, retryCount = 0) {
      const kind = track.kind;
      const uid = participant.identity;

      if (kind === 'audio') {
        const audioEl = document.createElement('audio');
        audioEl.autoplay = true;
        audioEl.playsInline = true;
        track.attach(audioEl);
        document.body.appendChild(audioEl); // 直接挂到 body，避免容器找不到
        return;
      }

      if (kind === 'video') {
        const containerId = `video-${uid}`;
        let container = document.getElementById(containerId);

        if (!container) {
          if (retryCount < 20) {
            setTimeout(() => this.attachRemoteTrack(track, participant, retryCount + 1), 200);
            return;
          }
          console.warn(`找不到容器: ${containerId}`);
          return;
        }

        container.innerHTML = '';
        const videoEl = document.createElement('video');
        videoEl.autoplay = true;
        videoEl.playsInline = true;
        videoEl.style.width = '100%';
        videoEl.style.height = '100%';
        container.appendChild(videoEl);
        track.attach(videoEl);
      }
    }
  }
};
</script>

<style lang="stylus" scoped>
  .call-container
    background-size cover
    position absolute
    z-index 999

  .accept, .refuse, .videoOn, .videoOff, .micOn, .micOff
    height 50px
    width 50px
    box-sizing border-box
    border-radius 50%
    cursor: pointer

  .accept
    background center no-repeat url("../../../assets/image/call.png")
    background-size 60%
    background-color $success

  .refuse
    background center no-repeat url("../../../assets/image/hangup.png")
    background-size 70%
    background-color $danger

  .videoOn
    background center no-repeat url("../../../assets/image/big-camera-on.png")

  .videoOff
    background center no-repeat url("../../../assets/image/big-camera-off.png")

  .micOn
    background center no-repeat url("../../../assets/image/big-mic-on.png")

  .micOff
    background center no-repeat url("../../../assets/image/big-mic-off.png")

  .buttons
    position absolute
    z-index 20
    width 70%
    top 75%
    display flex
    justify-content space-around
    margin 0 15% 0 15%
  .audio-box
    position absolute
    z-index 20
    width 70%
    top 200px
    display flex
    justify-content center
    margin 0 15% 0 15%
  .aduio-call
    box-sizing border-box
    width 140px
    height 100px
  .audio-img
    display block
    width 60px
    height 60px
    border-radius 50%
    margin 0 auto 13px
  .micr-icon
    cursor pointer
    font-size 28px
  /*display block*/
  /*text-align center*/
  .nick-text
    color #dddddd
    font-size 12px
    margin-right 5px
    vertical-align super

  .duration
    color #fff
    position absolute
    z-index 20
    width 100%
    top 70%
    display flex
    justify-content center

  .mask
    position absolute
    z-index 10
    background #D8D8D8
    height 100%
    width 100%
    display flex
    align-items center
    justify-content center

    space
    .image
      margin-left 15%

    .notice
      color #888888

  .choose, .call
    color #fff
    background-color rgba(0, 0, 0, 0.8)
    height 100%
    width 100%

  .title
    margin 25% 0 0 0
    text-align center
    width 100%
    position absolute
    z-index 10
    color #fff
    font-size 40px
    font-weight 700

  .big
    position absolute
    height 100%
    width 100%

  .small
    position absolute
    margin-left 74.8%
    z-index 999
    border-style solid
    border-width 1px
    border-color #808080
    height 44.8%
    width 25.2%
  .big-group
    height 60vh
    width 100%

  .small-group
    display: flex
    flex-wrap: wrap
    position: absolute
    width: 100%
    height: 60vh

  .video-box
    width: 100%  // 根据参与者数量调整
    height: 100%
    background: #000
    position: relative

    video
      width: 100%
      height: 100%
      object-fit: cover


</style>
