<template>
  <div class="video-box-warp" :class="{ webFullScreen: state.webFullScreen }">
    <div
      class="video-box"
      @mouseup="handleBoxMouseUp"
      :class="['warp_' + state.layoutCss, 'video-box']"
    >
      <div
        class="video-item"
        v-for="(item, index) of players"
        :class="[
          '_' + state.layoutCss,
          state.activeIndex === index ? 'active' : '',
        ]"
        :key="'item_' + index"
        @click="handleClickVideoItem(index)"
      >
        <div
          :class="{ fill: item.player != null && item.isVideoFill }"
          class="video-player"
          ref="videl_player_el"
          @dblclick="handleDbClickVideoItem(index)"
        >
          <LivePlayer
            @snap="onPlayerSnap"
            @pause="
              () => {
                onpause(item, index);
              }
            "
            @ended="
              () => {
                onended(item, index);
              }
            "
            @timeupdate="
              (t) => {
                ontimeupdate(t, item, index);
              }
            "
            ref="livePlayers"
          />
        </div>

        <div class="tool-bar-base" v-show="item.player != null">
          <div class="tool-btn" title="关闭" @click="handleCloseChannel(index)">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-close1"></use>
            </svg>
          </div>
        </div>
        <div
          class="player-loading"
          v-if="item.player != null"
          :class="{ show: item.isLoading }"
        >
          <img src="/font/player/loading.svg" width="50" alt="" />
        </div>
        <div
          class="player_btn"
          v-if="item.player != null && item.isDrawing === false"
        >
          <svg
            class="icon"
            aria-hidden="true"
            v-if="item.isPlaying"
            @click="handlePlay(item)"
          >
            <title>暂停</title>
            <use xlink:href="#icon-pausecircle-fill"></use>
          </svg>
          <svg class="icon" aria-hidden="true" v-else @click="handlePlay(item)">
            <title>播放</title>
            <use xlink:href="#icon-playcircle-fill"></use>
          </svg>
        </div>
        <div
          class="player-loading"
          v-if="item.player != null"
          :class="{ show: item.isLoading }"
        >
          <img src="/font/player/loading.svg" width="50" alt="" />
        </div>
        <div class="tool-bar-ptz" v-if="item.player != null && item.isOpenPtz">
          <div
            class="tool-bar-ptz-btn"
            @mousedown="
              handleStartAction($event, item, 'ptzControl', 'left', 'start')
            "
          >
            <svg class="icon" aria-hidden="true">
              <title>左</title>
              <use xlink:href="#icon-ptz-left"></use>
            </svg>
          </div>
          <div
            class="tool-bar-ptz-btn right"
            @mousedown="
              handleStartAction($event, item, 'ptzControl', 'right', 'start')
            "
          >
            <svg class="icon" aria-hidden="true">
              <title>右</title>
              <use xlink:href="#icon-ptz-right"></use>
            </svg>
          </div>
          <div
            class="tool-bar-ptz-btn top"
            @mousedown="
              handleStartAction($event, item, 'ptzControl', 'up', 'start')
            "
          >
            <svg class="icon" aria-hidden="true">
              <title>上</title>
              <use xlink:href="#icon-ptz-up"></use>
            </svg>
          </div>
          <div
            class="tool-bar-ptz-btn bottom"
            @mousedown="
              handleStartAction($event, item, 'ptzControl', 'down', 'start')
            "
          >
            <svg class="icon" aria-hidden="true">
              <title>下</title>
              <use xlink:href="#icon-ptz-down"></use>
            </svg>
          </div>
        </div>
        <div class="tool-bar-base bottom" v-if="item.player != null">
          <!-- <div class="tool-btn" :title="item.isVideoFill?'缩放':'铺满'" @click="item.isVideoFill=!item.isVideoFill">
            <svg class="icon" aria-hidden="true" v-if="item.isVideoFill">
              <use xlink:href="#icon-suofang-huanyuan"></use>
            </svg>
            <svg class="icon" aria-hidden="true" v-else>
              <use xlink:href="#icon-suofang"></use>
            </svg>
          </div>
          <div class="tool-btn" title="变倍+" @mousedown="handleStartAction($event,item,'zoomControl','near','start')">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-bianbei"></use>
            </svg>
          </div>
          <div class="tool-btn" title="变倍-" @mousedown="handleStartAction($event,item,'zoomControl','far','start')">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-bianbei-"></use>
            </svg>
          </div>
          <div class="tool-btn" title="光圈+" @mousedown="handleStartAction($event,item,'focusControl','near','start')">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-guangquan"></use>
            </svg>
          </div>
          <div class="tool-btn" title="光圈-" @mousedown="handleStartAction($event,item,'focusControl','far','start')"> <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-guangquan-"></use>
            </svg>
          </div> -->
          <!-- <div class="tool-btn" :title="item.isOpenIntercom?'正在对讲':'对讲'" :class="{active:item.isOpenIntercom}" @click="handleIntercom(index)">
            <svg class="icon" aria-hidden="true" v-if="item.isOpenIntercom">
              <use xlink:href="#icon-mic"></use>
            </svg>
            <svg class="icon" aria-hidden="true" v-else>
              <use xlink:href="#icon-mic-off"></use>
            </svg>
          </div> -->

          <div
            class="tool-btn"
            :title="item.isOpenAudio ? '正在播放声音' : '声音'"
            :class="{ active: item.isOpenAudio }"
            @click="handleMuted(index)"
          >
            <svg class="icon" aria-hidden="true" v-if="item.isOpenAudio">
              <use xlink:href="#icon-volume-up"></use>
            </svg>
            <svg class="icon" aria-hidden="true" v-else>
              <use xlink:href="#icon-volume-off"></use>
            </svg>
          </div>
          <div
            class="tool-btn"
            :title="item.isOpenRecord ? '正在录像' : '录像'"
            :class="{ active: item.isOpenRecord }"
            @click="handleRecord(index)"
          >
            <svg class="icon" v-if="item.isOpenRecord" aria-hidden="true">
              <use xlink:href="#icon-shexiangji"></use>
            </svg>
            <svg class="icon" v-else aria-hidden="true">
              <use xlink:href="#icon-shexiangji"></use>
            </svg>
          </div>
          <div class="tool-btn" title="拍照" @click="handleSnap(index)">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-paizhao"></use>
            </svg>
          </div>
          <!-- <div class="tool-btn" :title="item.isOpenPtz?'正在云台控制':'云台'" @click="handlePtz(index)" :class="{active:item.isOpenPtz}">
            <svg class="icon" v-if="item.isOpenPtz" aria-hidden="true">
              <use xlink:href="#icon-yuntaikongzhi"></use>
            </svg>
            <svg class="icon" v-else aria-hidden="true">
              <use xlink:href="#icon-yuntaikongzhi"></use>
            </svg>
          </div> -->
          <div class="tool-btn" title="全屏" @click="handleFullscreen(index)">
            <svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-quanping1-mianxing"></use>
            </svg>
          </div>
        </div>
        <slot :player="item" :index="index" />
      </div>
    </div>
    <div class="tool-bar" v-show="showBottomToolBar">
      <slot name="toolbar"> </slot>
      <div
        class="tool-bar-item"
        @click="handleCloseAllChannel"
        title="全部关闭"
      >
        <svg class="icon" aria-hidden="true">
          <title>全部关闭</title>
          <use xlink:href="#icon-close_all"></use>
        </svg>
      </div>
      <div
        class="tool-bar-item"
        @click="state.webFullScreen = !state.webFullScreen"
        title="网页全屏"
      >
        <svg class="icon" aria-hidden="true">
          <title>网页全屏</title>
          <use xlink:href="#icon-quanping1-mianxing"></use>
        </svg>
      </div>
      <div
        class="tool-bar-item"
        @click="state.showLayouts = true"
        title="切换布局"
      >
        <svg class="icon" aria-hidden="true">
          <title>切换布局</title>
          <use xlink:href="#icon-buju1"></use>
        </svg>
        <div
          class="icon-layout"
          :class="{ show: state.showLayouts }"
          @mouseleave="state.showLayouts = false"
        >
          <div
            class="icon-layout-item"
            @click="handleSetLayout(item)"
            v-for="(item, index) in layoutArray"
            :class="{ active: layoutStr === item }"
            :key="'icon_layout_item' + index"
          >
            <span>{{ item }}</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import ZlmRtcPlayer from "./players/zlmRtcPlayer.js";
import { getMediaUrl, record, recordHeartbeat } from "@/api/device";
import { invoke, invokeControl } from "@/api/device";
import lodash from "lodash";
import linq from "linq";
import LivePlayer from "./players/livePlayer.vue";
import { getConfigByKeys } from "@/api/system/config";
import { mapGetters } from "vuex";

// 使用vue2的写法来保证兼容性
export default {
  components: {
    LivePlayer,
  },
  props: {
    defaultLayout: {
      type: String,
      default: "1x1",
    },
    showBottomToolBar: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      config: {},
      state: {
        activeIndex: 0,
        layouts: new Array(),
        currentLayout: 4,
        showLayouts: false,
        doing: {},
        snapIndex: -1,
        layoutCss: "",
        webFullScreen: false,
      },
      players: [],

      layouts: {
        "1x1": 1,
        "1x2": 2,
        "2x1": 2,
        "2x2": 4,
        "2x3": 6,
        "3x3": 9,
        "3x4": 12,
        "4x4": 16,
        "4x6": 24,
        // "4x8": 32,
        1: "1x1",
        2: "1x2",
        4: "2x2",
        6: "2x3",
        9: "3x3",
        12: "3x4",
        16: "4x4",
        24: "4x6",
        // 32: "4x8",
      },
    };
  },
  computed: {
    layoutStr() {
      return this.layouts[this.state.currentLayout];
    },
    layoutArray() {
      const temp = [];
      for (const key in this.layouts) {
        if (new RegExp("\\d[x]\\d").test(key)) {
          temp.push(key);
        }
      }
      return temp;
    },
    ...mapGetters(["systemParams"]),
  },
  created() {
    this.players = this.state.layouts;

    getConfigByKeys([
      "EXTRANET_ADDRESS",
      "INTRANET_MEDIA_URL",
      "EXTRANET_MEDIA_URL",
      "VIRTUAL_RTC_MEDIAURL",
    ]).then((res) => {
      const config = {};
      res.data.forEach((x) => {
        config[x.configKey] = x.configValue;
      });
      config.PREFIX =
        location.hostname === config.EXTRANET_ADDRESS ? "EXTRANET" : "INTRANET";
      config.mediaHost = config[config.PREFIX + "_MEDIA_URL"];
      this.config = config;
    });
  },
  mounted() {
    this.handleSetLayout(this.defaultLayout);
  },
  destroyed() {
    this.players.forEach((element) => {
      if (element && element.player) {
        element.player.destroy();
      }
    });
  },
  methods: {
    handlePlay(item) {
      if (item.isPlaying) {
        item.player.pause();
        item.isPlaying = false;
      } else {
        item.player.replay();
        item.isPlaying = true;
      }
    },
    onpause(player, index) {
      this.$emit("pause", {
        player,
        index,
      });
    },
    pause() {
      this.$refs.livePlayers[0].pause();
    },
    ontimeupdate(t, player, index) {
      this.$emit("timeupdate", {
        t,
        player,
        index,
      });
    },
    onended(player, index) {
      this.$emit("ended", {
        t,
        player,
        index,
      });
    },
    /**
     * 设置布局
     */
    handleSetLayout(layout) {
      this.state.layoutCss = layout;
      const layoutLength = this.layouts[layout];
      if (this.state.activeIndex > layoutLength) {
        this.state.activeIndex = layoutLength - 1;
      }
      const playerObj = {
        deviceId: "",
        channelId: "",
        deviceCode: "",
        channelCode: "",
        container: null,
        player: null,
        playerType: "zl",
        streamID: null,
        //正在播放
        isPlaying: true,
        //画面比例，是填充，否包含
        isVideoFill: true,
        //开启音频
        isOpenAudio: false,
        //开启对讲
        isOpenIntercom: false,
        //开启云台
        isOpenPtz: false,
        //开启录像
        isOpenRecord: false,
        //正在加载
        isLoading: false,
        //正在绘制区域
        isDrawing: false,
        //录像心跳计时器
        recordTimer: null,
      };
      //切换布局就需要销毁一些播放器。
      const delArray = [];
      for (let index = layoutLength; index < this.players.length; index++) {
        const element = this.players[index];
        if (element && element.player) {
          element.player.destroy();
          element.player = null;
        }
        delArray.push(element);
      }
      this.players = linq
        .from(this.players)
        .where((x) => !delArray.includes(x))
        .toArray();
      for (let index = this.players.length; index < layoutLength; index++) {
        this.players.push(lodash.cloneDeep(playerObj));
      }
      this.state.currentLayout = layoutLength;
    },
    getPlayerEl(index) {
      return this.$refs.videl_player_el[index];
    },
    handleCloseChannel(index) {
      const oldObj = this.players[index];
      //如果播放器已经初始化则销毁
      if (oldObj && oldObj.player) {
        oldObj.player.destroy();
        oldObj.player = null;
      }
      this.$emit("closeChannel", index);
    },
    handleCloseAllChannel() {
      for (let index = 0; index < this.players.length; index++) {
        this.handleCloseChannel(index);
      }
    },
    /**
     * 打开回放
     * videoUrl 回放地址，time 播放进度
     */
    async openRecord({ videoUrl, time, playerType = "live" }) {
      const me = this;
      return new Promise((resolve) => {
        const playerObj = this.players[this.state.activeIndex];
        //如果播放器已经初始化则销毁
        if (playerObj && playerObj.player) {
          playerObj.player.destroy();
          playerObj.player = null;
        }
        playerObj.playerType = "";
        playerObj.deviceId = 0;
        playerObj.channelId = 0;
        playerObj.deviceCode = 0;
        playerObj.channelCode = 0;
        playerObj.container = me.getPlayerEl(this.state.activeIndex);
        playerObj.isVideoFill = true;
        playerObj.isOpenAudio = false;
        playerObj.isOpenIntercom = false;
        playerObj.isOpenPtz = false;
        playerObj.isOpenRecord = false;
        playerObj.isLoading = false;
        playerObj.playerType = playerType;
        let player = null;
        switch (playerType) {
          case "live":
            player = this.$refs.livePlayers[this.state.activeIndex];
            player.show();
            playerObj.player = player;
            playerObj.isLoading = true;
            this.$nextTick(() => {
              player.play(videoUrl, time);
              playerObj.isLoading = false;
              me.$emit("changeIndex", {
                index: me.state.activeIndex,
                player: playerObj,
              });
              me.updateActiveIndex();
              resolve();
            });
            break;
        }
      });
    },
    /**
     * 打开通道
     */
    async openChannel({
      deviceId,
      deviceCode,
      channelId,
      channelCode,
      playerType = "zl",
      protocol = "WEBRTC",
      replaceVirtualURL = true,
      noAlert = false,
    }) {
      const me = this;
      const mediaData = await getMediaUrl(deviceCode, channelCode, noAlert);
      const streamID = mediaData.data.StreamID;
      let videoUrl = mediaData.data[protocol];
      if (replaceVirtualURL) {
        videoUrl = videoUrl.replace(
          this.config["VIRTUAL_RTC_MEDIAURL"],
          this.config.mediaHost
        );
        console.log("videoUrl", videoUrl);
      }
      return new Promise((resolve) => {
        const playerObj = this.players[this.state.activeIndex];
        //如果播放器已经初始化则销毁
        if (playerObj && playerObj.player) {
          playerObj.player.destroy();
          playerObj.player = null;
        }
        playerObj.playerType = "";
        playerObj.deviceId = deviceId;
        playerObj.channelId = channelId;
        playerObj.deviceCode = deviceCode;
        playerObj.channelCode = channelCode;
        playerObj.container = me.getPlayerEl(this.state.activeIndex);
        playerObj.isVideoFill = true;
        playerObj.isOpenAudio = false;
        playerObj.isOpenIntercom = false;
        playerObj.isOpenPtz = false;
        playerObj.isOpenRecord = false;
        playerObj.isLoading = false;
        playerObj.playerType = playerType;
        playerObj.streamID = streamID;
        playerObj.recordTimer = null;
        let player = null;
        console.log("[GAB] playerType: " + playerType);
        switch (playerType) {
          case "zl":
            player = new ZlmRtcPlayer({
              container: playerObj.container,
              onplaying() {
                // playerObj.isLoading = false
                // me.$emit('changeIndex', { index: me.activeIndex, player: playerObj })
                // me.updateActiveIndex();
              },
              onpause() {
                playerObj.isPlaying = false;
              },
            });
            playerObj.player = player;
            playerObj.isLoading = true;
            this.$nextTick(() => {
              player.init().then(() => {
                player.play(videoUrl);
                playerObj.isLoading = false;
                me.$emit("changeIndex", {
                  index: me.activeIndex,
                  player: playerObj,
                });
                me.updateActiveIndex();
                resolve(mediaData);
              });
            });
            break;
          case "live":
            player = this.$refs.livePlayers[this.state.activeIndex];
            player.show();
            playerObj.player = player;
            playerObj.isLoading = true;
            this.$nextTick(() => {
              player.play(videoUrl);
              playerObj.isLoading = false;
              me.$emit("changeIndex", {
                index: me.state.activeIndex,
                player: playerObj,
              });
              me.updateActiveIndex();
              resolve(mediaData);
            });
            break;
        }
      });
    },
    /**
     * 双击视频窗口
     */
    handleDbClickVideoItem(index) {
      this.handleFullscreen(index);
    },
    /**
     * 全屏
     */
    handleFullscreen(index) {
      const oldObj = this.players[index];
      if (oldObj && oldObj.player) {
        try {
          oldObj.player.setFullscreen();
        } catch (error) {
          console.log(error);
        }
      }
    },
    /**
     * 截图
     */
    handleSnap(index) {
      const oldObj = this.players[index];
      this.snapIndex = index;
      if (oldObj && oldObj.player) {
        try {
          oldObj.player.snap((blob) => {
            if (oldObj.playerType === "zl") {
              var link = document.createElement("a");
              link.download =
                new Date()
                  .toLocaleString()
                  .replace(/\//g, "")
                  .replace(/ /g, "")
                  .replace(/上午/g, "")
                  .replace(/下午/g, "")
                  .replace(/:/g, "") + ".jpg";
              link.href = URL.createObjectURL(blob);
              link.click();
              link = null;
            }
          });
        } catch (error) {
          console.log(error);
        }
      }
    },
    dataURLtoBlob(dataurl) {
      const arr = dataurl.split(",");
      const bstr = atob(arr[1]);
      let n = bstr.length;
      const mime = arr[0].match(/:(.*?);/)[1];
      const u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], { type: mime });
    },
    onPlayerSnap(base64) {
      if (this.snapIndex !== -1) {
        const blob = this.dataURLtoBlob(base64);
        var link = document.createElement("a");
        link.download =
          new Date()
            .toLocaleString()
            .replace(/\//g, "")
            .replace(/ /g, "")
            .replace(/上午/g, "")
            .replace(/下午/g, "")
            .replace(/:/g, "") + ".jpg";
        link.href = URL.createObjectURL(blob);
        link.click();
        link = null;
      }
    },

    /**
     * 设置/取消静音
     */
    handleMuted(index) {
      const oldObj = this.players[index];
      if (oldObj && oldObj.player) {
        try {
          oldObj.isOpenAudio = !oldObj.isOpenAudio;
          oldObj.player.setMuted(oldObj.isOpenAudio);
        } catch (error) {
          console.log(error);
        }
      }
    },
    /**
     * 打开或关闭对讲
     */
    async handleIntercom(index) {
      const oldObj = this.players[index];
      if (oldObj && oldObj.player) {
        try {
          oldObj.isOpenIntercom = !oldObj.isOpenIntercom;
        } catch (error) {
          console.log(error);
        }
      }
    },

    /**
     * 录像
     */
    async handleRecord(index) {
      const oldObj = this.players[index];
      if (oldObj && oldObj.player) {
        try {
          record(oldObj.streamID, oldObj.isOpenRecord === true ? 1 : 0).then(
            (res) => {
              oldObj.isOpenRecord = !oldObj.isOpenRecord;
              if (oldObj.isOpenRecord === false) {
                if (res.data.RecordList && res.data.RecordList.length > 0) {
                  res.data.RecordList[0].DownloadURL =
                    res.data.RecordList[0].DownloadURL.replace(
                      this.systemParams.VIRTUAL_FLV_MEDIAURL,
                      this.systemParams.FLV_MEDIA_URL
                    );
                  const a = document.createElement("a");
                  a.setAttribute("href", res.data.RecordList[0].DownloadURL);
                  a.setAttribute("target", "_blank");
                  a.click();
                }
              }
              if (oldObj.isOpenRecord) {
                if (oldObj.recordTimer) {
                  clearInterval(oldObj.recordTimer);
                }
                oldObj.recordTimer = setInterval(() => {
                  recordHeartbeat(oldObj.streamID);
                }, 10000);
              }
              if (oldObj.isOpenRecord === false) {
                clearInterval(oldObj.recordTimer);
              }
            }
          );
        } catch (error) {
          console.log(error);
        }
      }
    },
    /**
     * 开启云台
     */
    async handlePtz(index) {
      const oldObj = this.players[index];
      if (oldObj && oldObj.player) {
        try {
          oldObj.isOpenPtz = !oldObj.isOpenPtz;
        } catch (error) {
          console.log(error);
        }
      }
    },
    /**
     * 调用设备功能
     */
    invokeDevice(deviceCode, channelCode, commandCode, action, state) {
      const params = this.tranInvokeParams(commandCode, action, state);
      invoke({
        commandCode: commandCode,
        channelId: channelCode,
        deviceId: deviceCode,
        functionId: "ptz",
        params,
      });
    },
    /**
     * 转换设备指令
     */
    tranInvokeParams(commandCode, action, state) {
      switch (commandCode) {
        case "ptzControl":
          return {
            direct: action,
            action: state,
          };
        case "focusControl":
          return {
            focus: action,
            action: state,
          };
        case "zoomControl":
          return {
            zoom: action,
            action: state,
          };
      }
    },
    /**
     * 云台控制
     */
    handleStartAction(e, item, commandCode, action, state) {
      const me = this;
      e.target.classList.add("active");
      this.state.doing = {
        action,
        params: [e.target, item],
        func: function () {
          me.state.doing.params[0].classList.remove("active");
          me.invokeDevice(
            item.deviceCode,
            item.channelId,
            commandCode,
            action,
            "stop"
          );
          // 调用 API 或者 抛出
          me.$emit("actionstop", me.state.doing);
        },
      };
      this.invokeDevice(
        item.deviceCode,
        item.channelId,
        commandCode,
        action,
        state
      );
      this.$emit("actionstart", me.state.doing);
    },

    /**
     * 统一鼠标抬起处理
     */
    handleBoxMouseUp() {
      if (this.state.doing && this.state.doing.func) {
        this.state.doing.func();
        this.state.doing = {};
      }
      return true;
    },
    /**
     * 更新当前容器索引
     */
    updateActiveIndex() {
      if (this.state.activeIndex < this.players.length - 1) {
        this.state.activeIndex++;
      } else {
        this.state.activeIndex = 0;
      }
      this.$emit("changeIndex", {
        index: this.state.activeIndex,
        player: this.players[this.state.activeIndex],
      });
    },
    /**
     * 点击播放器容器
     */
    handleClickVideoItem(index) {
      this.state.activeIndex = index;
      this.$emit("changeIndex", {
        index,
        player: this.players[index],
      });
    },
  },
};
</script>

<style lang="scss" scoped>
// $main_color: #0E66F1; //#ffcc00
$main_color: #006686;
$main_color_2: #2e8eb4; //#ffdd57

.video-box-warp {
  &.webFullScreen {
    position: fixed;
    z-index: 19999;
    top: 0;
    left: 0;
  }

  position: relative;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;

  & * {
    box-sizing: border-box;
  }

  .video-box {
    flex: 1;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    border: 1px solid #000;
    box-sizing: border-box;
    background-color: transparent;

    &.warp_2x1 {
      flex-direction: column;
    }

    .video-item {
      border: 1px solid #000;
      flex: 0 0 50%;
      background-color: transparent;
      position: relative;

      &._1x1 {
        flex: 0 0 100%;
      }

      &._2x1 {
        flex: 100% 100% 0;
      }

      &._2x2 {
      }

      &._2x3 {
        flex: 0 0 33.33%;
      }

      &._3x3 {
        flex: 0 0 33.33%;
      }

      &._3x4 {
        flex: 0 0 25%;
      }

      &._4x4 {
        flex: 0 0 25%;
      }

      &._4x6 {
        flex: 0 0 16.66%;
      }

      &._4x8 {
        flex: 0 0 12.5%;
      }

      &.active {
        border-color: $main_color;
      }

      .player-loading {
        width: 100%;
        height: 100%;
        position: absolute;
        display: none;
        justify-content: center;
        align-content: center;
        align-items: center;
        justify-items: center;
        top: 0;
        left: 0;

        &.show {
          display: flex;
        }
      }

      .player_btn {
        width: 100%;
        height: 100%;
        position: absolute;
        display: none;
        justify-content: center;
        align-content: center;
        align-items: center;
        justify-items: center;
        top: 0;
        left: 0;

        .icon {
          cursor: pointer;
          width: 15%;
          height: 15%;
        }
      }

      .video-player {
        width: 100%;
        height: 100%;
        position: relative;
      }

      &:hover {
        .tool-bar-base {
          display: flex;
        }

        .player_btn {
          display: flex;
        }
      }

      .tool-bar-base {
        top: 0;
        width: 100%;
        height: 30px;
        z-index: 3;
        display: none;
        justify-content: flex-end;
        justify-items: flex-end;
        align-content: center;
        align-items: center;
        position: absolute;
        flex-direction: row;
        background-color: rgba(0, 0, 0, 0.5);

        .tool-btn {
          display: flex;
          justify-content: flex-end;
          justify-items: flex-end;
          flex-direction: row;
          align-content: center;
          align-items: center;
          height: 100%;
          cursor: pointer;

          &.active {
            .icon {
              fill: $main_color;
            }
          }
        }

        .icon {
          fill: #ffffff;
          margin-right: 0.3rem;
          pointer-events: none;
        }

        &.bottom {
          top: unset;
          bottom: 0;
        }
      }

      .tool-bar-ptz {
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;

        .tool-bar-ptz-btn {
          position: absolute;
          width: 50px;
          height: 50px;
          top: calc(50% - 25px);
          left: calc(50% - 75px);
          display: flex;
          opacity: 0.7;
          cursor: pointer;

          &:hover {
            opacity: 0.7;
          }

          &.active {
            opacity: 0.7;

            .icon {
              animation: changefillcolor_active 3s infinite linear;
            }
          }

          justify-content: center;
          justify-items: center;
          align-content: center;
          align-items: center;

          &.right {
            top: calc(50% - 25px);
            left: calc(50% + 25px);
          }

          &.top {
            top: calc(50% - 75px);
            left: calc(50% - 25px);
          }

          &.bottom {
            top: calc(50% + 25px);
            left: calc(50% - 25px);
          }

          .icon {
            width: 1.5rem;
            height: 1.5rem;
            fill: #000000;
            pointer-events: none;
            animation: changefillcolor 5s infinite linear;
          }
        }
      }
    }
  }

  .tool-bar {
    height: 40px;
    padding: 5px;
    display: flex;
    justify-content: flex-end;
    justify-items: flex-end;
    flex-direction: row;
    align-content: center;
    align-items: center;
    width: 100%;
    background-color: transparent;
    border: 2px solid #000;
    border-top: 0;
    border-bottom: 0;

    .tool-bar-item {
      display: flex;
      position: relative;
      height: 100%;
      justify-content: center;
      justify-items: center;
      align-content: center;
      align-items: center;
      cursor: pointer;

      .icon-layout {
        &.show {
          display: grid;
        }

        display: none;
        position: absolute;
        width: 200px;
        height: 200px;
        bottom: 35px;
        right: -5px;
        background-color: rgb(0, 225, 255);
        border: 2px solid #000;
        border-bottom: 0;

        grid-template-columns: repeat(3, 33.33%);
        grid-template-rows: repeat(3, 33.33%);
        grid-row-gap: 2px;
        grid-column-gap: 2px;

        .icon-layout-item {
          color: #fff;
          display: flex;
          justify-content: center;
          justify-items: center;
          align-content: center;
          align-items: center;
          cursor: pointer;

          span {
            color: rgb(29, 29, 29);
            font-weight: bold;
          }

          &.active {
            color: $main_color;
          }
        }
      }
    }

    .icon {
      fill: #ffffff;
      margin-right: 0.3rem;
      pointer-events: none;
    }
  }
}
.video-box-warp.webFullScreen {
  .video-item {
    background-color: #0e224e;
  }
}

@keyframes changefillcolor {
  0% {
    fill: #000000;
  }

  25% {
    fill: #888888;
  }

  50% {
    fill: #ffffff;
  }

  75% {
    fill: #777777;
  }

  100% {
    fill: #000000;
  }
}

@keyframes changefillcolor_active {
  0% {
    fill: $main_color;
  }

  25% {
    fill: $main_color_2;
  }

  50% {
    fill: #ffffff;
  }

  75% {
    fill: $main_color_2;
  }

  100% {
    fill: $main_color;
  }
}
</style>
<style>
.video-player.fill .video_player_zlm {
  object-fit: fill;
}

.video_player_zlm {
  width: 100%;
  height: 100%;
  position: absolute;
  object-fit: contain;
}

.video-box-warp .vjs-control-bar {
  display: none !important;
}
</style>
