萤石云 ezuikit-js 视频监控

父组件

复制代码
<template>
  <div class="securityProtectLargeScreen" v-if="waterWorks?.length > 0">
    <div class="leftSide">
      <ul class="leftItems flexColumnCenter">
        <li
          v-for="(item, index) in waterWorks"
          :key="index"
          @click="clickWaterWork(index)"
          :class="[
            activeWaterWork === index ? 'waterWorkSelectStyle' : '',
            'currentItem',
          ]"
          :title="item.name"
        >
          {{ item.name }}
        </li>
      </ul>
    </div>
    <div
      class="content-area"
      v-loading="loading"
      v-if="videoRecorderList.length > 0 && !loading"
    >
      <div class="jk">
        <div class="marginBottom15">
          <svg-icon
            iconName="icon-task-dange"
            :class="[
              activeNameIcon === 'singleIcon' ? 'selectStyle' : '',
              'marginRight20',
            ]"
            @click="selectCurrent('singleIcon')"
          ></svg-icon>
          <svg-icon
            iconName="icon-task-sige"
            :class="[activeNameIcon === 'fourIcon' ? 'selectStyle' : '']"
            @click="selectCurrent('fourIcon')"
          ></svg-icon>
        </div>
        <div class="items">
          <li
            v-for="(item, index) in videoRecorderList"
            :key="index"
            @click="clickLocation(index)"
            :class="[
              activeLocation === index ? 'locationSelectStyle' : '',
              'currentItem',
            ]"
            :title="item.thoroughfare_name"
          >
            {{ item.thoroughfare_name }}
          </li>
        </div>
      </div>
      <!-- 视频监控 -->
      <div v-if="videoList.length > 0" :key="Math.random()">
        <RecorderLook
          :width="`calc(100vw - 440px)`"
          :height="`calc(100vh - 188px)`"
          ref="recorderLook"
          :activeNameIcon="activeNameIcon"
          :videoList="videoList"
          @videoListIndex="getVideoListIndex"
        />
      </div>
    </div>
  </div>
  <!-- 无数据 -->
  <HomeNoData class="securityProtectLargeScreen" v-else />
</template>

<script setup>
import { ref, onMounted, nextTick } from "vue";
import RecorderLook from "@/components/videoSurveillance/RecorderLook.vue";
import { waterworksConfigList } from "@/api/waterPlantSystem";
import { waterConfigList } from "@/api/directDrinkingWaterSystem";
import { filterArrayByType } from "@/utils/deduplication";
import { useGlobalStore } from "@/stores/modules/global";
import { dvrCameraList } from "@/api/EquipmentManagementSystem/index.js";
import HomeNoData from "@/components/homeNoData/index.vue";
const props = defineProps({
  type: {
    type: String, // 判断是哪个系统
  },
});
const waterWorks = ref([]);
const videoRecorderList = ref([]);
const videoList = ref([]);

const globalStore = useGlobalStore();
const activeWaterWork = ref(0);
const activeLocation = ref(0);
const activeNameIcon = ref("singleIcon");
const fourVideoActive = ref(0); // 四个的选中
const loading = ref(false);
const codeString = ref(null);

const clickWaterWork = (index) => {
  activeWaterWork.value = index;
  videoRecorderList.value = waterWorks.value[index].recorder;
  let recorder = videoRecorderList.value;
  const idsString = recorder.map((item) => item.id).join(",");
  // 获取当前水厂的监控设备
  getDvrCameraList(idsString);
};

const recorderLook = ref(null);

const clickLocation = (index) => {
  activeLocation.value = index;
  if (activeNameIcon.value === "singleIcon") {
    videoList.value[0] = videoRecorderList.value[index];
  }
  if (activeNameIcon.value === "fourIcon") {
    videoList.value[fourVideoActive.value] = videoRecorderList.value[index];
  }
};

const getVideoListIndex = (index) => {
  if (activeNameIcon.value === "fourIcon") {
    fourVideoActive.value = index;
  }
};

const selectCurrent = (val) => {
  activeNameIcon.value = val;
  // 视频监控的第一个id
  const index = videoRecorderList.value?.findIndex(
    (item) => item.id === videoList?.value[0]?.id
  );
  activeLocation.value = index;
};

const getWaterWorks = () => {
  let data = filterArrayByType(globalStore.subAuthList, props.type);
  codeString.value = data.map((item) => item.code).join(",");
  if (props.type === "ist_water") getrecorderInfo(waterConfigList);
  if (props.type === "ist_water_purification_plant")
    getrecorderInfo(waterworksConfigList);
};

const getrecorderInfo = (apiFunction) => {
  apiFunction({ codes: codeString.value })
    .then((res) => {
      if (res.status === 200) {
        let data = res.data;
        // 过滤掉有监控设备的子项目
        waterWorks.value = data.filter((item) => item?.recorder?.length > 0);
        if (waterWorks?.value.length === 0) {
          return;
        }

        let recorder = waterWorks.value[0].recorder;
        const idsString = recorder.map((item) => item.id).join(",");
        // 获取当前子项目的监控设备
        getDvrCameraList(idsString);
      }
    })
    .catch((error) => {});
};

// 当前子项目摄像头列表
const getDvrCameraList = (idsString) => {
  loading.value = true;
  dvrCameraList({ dvr_id: idsString })
    .then((res) => {
      loading.value = false;
      if (res.status === 200) {
        videoRecorderList.value = res.data?.list;
        videoList.value = res.data?.list.slice(0, 4);
        activeLocation.value = 0;
      }
    })
    .catch((error) => {
      loading.value = false;
    });
};

getWaterWorks();
onMounted(() => {});
</script>

<style lang="scss" scoped>
.securityProtectLargeScreen {
  width: 100vw;
  height: calc(100vh - 100px);
  padding: 6px 10px 40px 10px;
  display: flex;
}
.leftSide {
  height: calc(100vh - 146px);
  width: 195px;
  background: transparent;
  border: 1px solid #0862ad;
  box-shadow: inset 0 0 12px rgba(0, 206, 255, 0.51);
  padding: 18px 25px;
  overflow-y: auto;
}
.leftItems {
  list-style-type: none;
  padding: 0;
}
.currentItem {
  cursor: pointer;
  width: 144px;
  height: 38px;
  line-height: 36px;
  background: linear-gradient(359.57deg, #075281 0%, #032c46 100%);
  border: 1px solid #15598e;
  font-weight: 500;
  font-size: 16px;
  text-align: center;
  color: #338ac1;
  margin-bottom: 22px;
  z-index: 9999;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  padding: 0 4px;
}
.waterWorkSelectStyle {
  background: linear-gradient(359.57deg, #1c6fa3 0%, #033f65 100%);
  border: 1px solid #05d9ff;
  box-shadow: inset 0 0 12px #7cb4ff;
  color: #fff;
}
.locationSelectStyle {
  background: #05436a;
  border: 1px solid #05c5ff;
  box-shadow: inset 0 0 12px #7cb4ff;
  color: #fff;
}

:deep(.svg-icon) {
  width: 30px;
  height: 30px;
  background: linear-gradient(359.57deg, #075281 0%, #032c46 100%);
  color: rgba(0, 206, 255, 0.51);
}
.selectStyle {
  background: linear-gradient(359.57deg, #1c6fa3 0%, #033f65 100%);
  color: rgba(0, 206, 255);
}
.content-area {
  flex: 1;
  margin-left: 16px;
  box-shadow: inset 0 0 12px rgba(0, 206, 255, 0.51);
  padding: 20px;
  border: 1px solid #0862ad;
  display: flex;
  justify-content: space-between;
  .jk {
    overflow-y: auto;
  }
}
</style>

监控子组件

复制代码
<template>
  <div
    class="hello-ezuikit-js"
    :style="{ width: props.width, height: props.height }"
    ref="videoBox"
  >
    <!-- 最多4格 -->
    <div
      v-for="(key, index) in 4"
      :key="key"
      :class="props.activeNameIcon == 'singleIcon' ? 'width' : 'width2'"
      style="position: relative"
      :loading="loading"
      @click="changeVideo(index)"
      v-loading="loading"
    >
      <div
        :id="'video-cover' + index"
        class="video-cover"
        :class="{
          'video-active':
            selectVideo === index && props.activeNameIcon !== 'singleIcon',
        }"
      >
        <div
          class="videoTitle"
          v-if="props.fromPage !== 'SecondaryWpsHomePage'"
        >
          {{ titleArr[index] }}
        </div>
        <div :id="'video-container' + index + props.second"></div>
      </div>
    </div>
  </div>
</template>

<script setup>
import {
  ref,
  reactive,
  computed,
  watch,
  watchEffect,
  onMounted,
  onBeforeUnmount,
  nextTick,
} from "vue";
import { dvrCameraLive } from "@/api/EquipmentManagementSystem/index.js";
const loading = ref(false);
import EZUIKit from "ezuikit-js";
const props = defineProps({
  videoList: {
    type: Array,
    required: true,
  },
  activeNameIcon: {
    type: String,
    default: () => {
      return "singleIcon";
    },
  },
  fromPage: {
    type: String,
    default: () => {
      return "";
    },
  },
  width: {
    type: String,
  },
  height: {
    type: String,
  },
  second: {
    type: String,
    default: () => {
      return "";
    },
  },
});

const titleArr = ref([]);
const selectVideo = ref(null); // 当前选中的video序号
// 打开监控
const showVideo = (id, titleName, index) => {
  titleArr.value[index] = titleName;
  loading.value = true;
  getDvrCameraLive(id, index);
};
const UIKitDEMO = ref(null);

const videoBox = ref(null);

// 获取直播信息
const getDvrCameraLive = (id, index) => {
  console.log(8888888, id, index);
  dvrCameraLive(id).then((res) => {
    loading.value = false;
    if (res.status === 200) {
      let width = null;
      let height = null;
      if (props.activeNameIcon === "singleIcon") {
        width = videoBox?.value?.offsetWidth;
        if (props.fromPage === "SecondaryWpsHomePage") {
          height = videoBox?.value?.offsetHeight + 36;
        } else {
          height = videoBox?.value?.offsetHeight + 4;
        }
      } else {
        width = videoBox?.value?.offsetWidth / 2 - 2;
        height = videoBox?.value?.offsetHeight / 2 + 1.5;
      }

      if (res?.data?.url && res?.data?.access_token) {
        var player = new EZUIKit.EZUIKitPlayer({
          id: `video-container${index}${props.second}`, // 视频容器ID
          url: res.data.url,
          width: width,
          height: height,
          plugin: ["talk"],
          template: "pcLive",
          accessToken: res.data.access_token,
        });
        props.videoList[index].player = player;
        console.log(" UIKitDEMO.value", UIKitDEMO.value);
      }
    }
  });
};

const emits = defineEmits(["videoListIndex"]);
const changeVideo = (index) => {
  selectVideo.value = index;
  // alert(index)
  emits("videoListIndex", index);
};

const getResizeCss = () => {
  props.videoList.forEach((item, index) => {
    console.log("getResizeCss", item, index);
    if (props.activeNameIcon === "singleIcon") {
      nextTick(() => {
        // 二供首页无监控标题
        if (props.fromPage === "SecondaryWpsHomePage") {
          item?.player?.reSize(
            videoBox?.value?.offsetWidth,
            videoBox?.value?.offsetHeight + 36
          );
        } else {
          item?.player?.reSize(
            videoBox?.value?.offsetWidth,
            videoBox?.value?.offsetHeight + 4
          );
        }
      });
    } else {
      nextTick(() => {
        item?.player?.reSize(
          videoBox?.value?.offsetWidth / 2 - 2,
          videoBox?.value?.offsetHeight / 2 + 1.5
        );
      });
    }
  });
};

onMounted(() => {
  if (props.activeNameIcon === "singleIcon") {
    const firstVideo = props.videoList[0];
    showVideo(firstVideo.id, firstVideo.thoroughfare_name, 0);
  } else {
    props.videoList.forEach((item, index) => {
      console.log(999999, item, index);
      showVideo(item.id, item.thoroughfare_name, index);
    });
  }
  window.addEventListener("resize", getResizeCss);
});

// 需要销毁,不然会导致页面卡死问题
onBeforeUnmount(() => {
  props.videoList.forEach((item) => {
    if (item.player) {
      item.player.stop();
      // 假设ezuikit - js有closeInputStream方法
      if (item.player.closeInputStream) {
        item.player.closeInputStream();
      }
    }
  });
  window.removeEventListener("resize", getResizeCss);
  const audiolefts = document.body.querySelectorAll("#audioleft");
  audiolefts.forEach((div) => {
    div.remove();
  });
  const audiorights = document.body.querySelectorAll("#audioright");
  audiorights.forEach((div) => {
    div.remove();
  });
});

// 暴露方法
defineExpose({ showVideo });
</script>
<style lang="scss" scoped>
.videoTitle {
  height: 44px;
  background: #090a0a;
  color: #fff;
  font-size: 16px;
  padding-left: 20px;
  line-height: 44px;
}

:deep(.el-loading-mask) {
  background-color: #000;
}

:deep(.header-controls) {
  display: none !important;
}

.hello-ezuikit-js {
  // width: calc(100vw - 440px);
  // height: calc(100vh - 188px);
  display: flex;
  flex-wrap: wrap;
  overflow: hidden;
  background: #000;

  .width {
    width: 100%;
    height: 100%;
  }

  .width2 {
    width: 50%;
    height: 50%;
  }
}

.video-cover {
  display: flex;
  flex-direction: column;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 5;
  box-sizing: border-box;
}

.video-active {
  border: 1px solid red !important;
}
</style>
相关推荐
黄智勇3 分钟前
xlsx-handlebars 一个用于处理 XLSX 文件 Handlebars 模板的 Rust 库,支持多平台使
前端
brzhang1 小时前
为什么 OpenAI 不让 LLM 生成 UI?深度解析 OpenAI Apps SDK 背后的新一代交互范式
前端·后端·架构
brzhang1 小时前
OpenAI Apps SDK ,一个好的 App,不是让用户知道它该怎么用,而是让用户自然地知道自己在做什么。
前端·后端·架构
爱看书的小沐2 小时前
【小沐学WebGIS】基于Three.JS绘制飞行轨迹Flight Tracker(Three.JS/ vue / react / WebGL)
javascript·vue·webgl·three.js·航班·航迹·飞行轨迹
井柏然2 小时前
前端工程化—实战npm包深入理解 external 及实例唯一性
前端·javascript·前端工程化
IT_陈寒3 小时前
Redis 高性能缓存设计:7个核心优化策略让你的QPS提升300%
前端·人工智能·后端
aklry3 小时前
elpis之动态组件机制
javascript·vue.js·架构
井柏然3 小时前
从 npm 包实战深入理解 external 及实例唯一性
前端·javascript·前端工程化
羊锦磊4 小时前
[ vue 前端框架 ] 基本用法和vue.cli脚手架搭建
前端·vue.js·前端框架
brzhang4 小时前
高通把Arduino买了,你的“小破板”要变“AI核弹”了?
前端·后端·架构