<template>
<div style="height: 100vh">
<el-row style="height: 100%">
<el-col :span="4" style="display: flex;flex-direction: column;">
<!-- <div style="height: 200px;border:1px solid #ccc;border-radius: 5px;">
<div style="font-weight: bold;margin-top: 10px;margin-left: 10px;margin-bottom:10px;">
视图
</div>
<div style="border-top: 1px solid #ccc;" class="onehuaStyle" @click="huaClick('1')">单画面</div>
<div class="onehuaStyle" @click="huaClick('4')">四画面</div>
<div class="onehuaStyle" @click="huaClick('9')">九画面</div>
<div style="border-bottom: 0px;" class="onehuaStyle" @click="huaClick('12')">十二画面</div>
</div> -->
<div style="flex:7;border-radius: 5px;background-color: rgb(36,48,79)">
<div style="font-weight: bold;margin-left: 10px;margin-bottom:10px;color: #ffffff;padding: 10px 0px;">
<div>设备机构名称</div>
</div>
<el-form :model="formData" ref="vForm" :rules="rules" label-width="140px" @submit.prevent class="zq-form">
<div style="width: 100%;padding: 0px 10px;">
<el-input class="el-inputStyle" v-model="filterText" placeholder="" size="small" :suffix-icon="Search" />
</div>
<el-row style="height: 60vh;overflow: auto;margin-top:10px;">
<el-col>
<el-form-item label="" label-width="10px" prop="nodeSort">
<el-tree ref="treeRef" :data="treedata" node-key="id" :props="twodefaultProps"
:filter-node-method="filterNode" @node-click="handleNodeClick" :expand-on-click-node="false"
class="sheThreeStyle" default-expand-all :auto-expand-parent="false">
<template #default="{ node, data }">
<span class="custom-tree-node">
<span>{{ node.label }}</span>
<span v-if="data.type == 'device'">
<span v-if="data.status == '0'" style="
display: inline-block;
width: 10px;
height: 10px;
border: 1rpx solid red;
border-radius: 100px;
background-color: red;
margin-left: 10px;
"></span>
<span v-if="data.status == '1'" style="
display: inline-block;
width: 10px;
height: 10px;
border: 1rpx solid green;
border-radius: 100px;
background-color: green;
margin-left: 10px;
"></span>
</span>
</span>
</template>
</el-tree>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<div style="flex:3;border-radius: 5px;margin-top: 10px;background-color: rgb(36,48,79)">
<div style="padding:10px 0px">
<div style="font-weight: bold;margin-top: 10px;margin-left: 10px;margin-bottom:10px;color: #ffffff;">
记忆收藏夹
</div>
</div>
<el-row style="height: 180px;overflow: auto;background-color: rgb(36,48,79)">
<el-col>
<el-form-item label="" label-width="10px" prop="nodeSort">
<el-tree :data="dataSource" node-key="id" :props="defaultProps" :expand-on-click-node="false"
@node-click="sheClick" style="background: rgb(46, 61, 97);" class="sheThreeStyle">
<template #default="{ node, data }">
<span class="custom-tree-node">
<span style="margin-right: 15px;">{{ node.label }}</span>
<span v-if="data.type == 'bookmark'">
<a @click="append(data)" style="color: green;"> 添加设备 </a>
<a style="margin-left: 8px;color: green" @click="updates(node, data)">
修改收藏夹
</a>
<a style="margin-left: 8px;color:red;" @click="remove(node, data)">
删除
</a>
</span>
<span v-if="data.type == 'device'">
<a style="margin-left: 8px;color:red;" @click="removeDevice(node, data)">
删除
</a>
<span v-if="data.status == '0'" style="
display: inline-block;
width: 10px;
height: 10px;
border: 1rpx solid red;
border-radius: 100px;
background-color: red;
margin-left: 10px;
"></span>
<span v-if="data.status == '1'" style="
display: inline-block;
width: 10px;
height: 10px;
border: 1rpx solid green;
border-radius: 100px;
background-color: green;
margin-left: 10px;
"></span>
</span>
</span>
</template>
</el-tree>
</el-form-item>
<div style="
color: rgb(79, 158, 254);
cursor: pointer;
font-size: 14px;
margin-right: 10px;
display: flex;
justify-content: center;
" @click="addCollect">
<div
style="width:90px;font-size:15px;border:1px solid rgb(54,121,211);color: rgb(169,175,190);text-align: center;border-radius: 5px;">
添加收藏夹
</div>
</div>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="20" style="padding:0 0 0 15px;display: flex;flex-direction: column;">
<el-row style="flex: 8;">
<!-- 点击画面循环,下标 -->
<el-col v-for="(item, index) in generatedItems" :key="index" :span="splitScreen"
style="background-color: rgb(33,37,41);" @click="generatedItemsClick(item, index, $event)">
<div class="oneMyfle" :class="Indexcol == index ? 'Indexcol' : ''">
<video :id="'myFlvVideo' + index" autoplay :controls="fasle" :class="myFlvVideo" />
<div :class="myClassName">
<div class="mar-le" :id="'shename' + index">{{ sheName(index) }}</div>
</div>
<div style="display: flex;align-items: center;">
<div style="font-size: 20px;color:red;position: absolute;right: 5px;bottom: 5px;cursor: pointer;"
@click="closeClick(index, $event)" v-if="Indexcol == index && isCloseShow">X</div>
<div style="font-size: 20px;color:red;position: absolute;right: 30px;bottom: 5px;cursor: pointer;"
@click="takeClick(index, $event)" v-if="Indexcol == index && isCloseShow">
<img src="@/assets/images/zhua.png" style="height: 20px;" alt="">
</div>
</div>
</div>
</el-col>
</el-row>
<!-- 下边图片 -->
<div style="flex:2;margin-top:10px;">
<div style="background-color: rgb(36,48,79);width: 100%;height: 100%;">
<div style="display: flex;justify-content: space-around;align-items: center;width: 100%;height: 100%;">
<img src="@/assets/images/1p.png" class="imgStyle" @click="huaClick('1')">
<img src="@/assets/images/4p.png" class="imgStyle" alt="" @click="huaClick('4')">
<img src="@/assets/images/9p.png" class="imgStyle" alt="" @click="huaClick('9')">
<img src="@/assets/images/12p.png" class="imgStyle" alt="" @click="huaClick('12')">
</div>
</div>
</div>
</el-col>
</el-row>
</div>
<AddCollect @doRefresh="resfre" ref="AddCollectRef"></AddCollect>
<EditDeviceTree @doRefresh="resfre" ref="EditDeviceTreeRef"></EditDeviceTree>
<AddDeviceTree @doRefresh="resfre" ref="AddDeviceTreeRef"></AddDeviceTree>
</template>
<script setup>
import {
defineComponent,
toRefs,
reactive,
getCurrentInstance,
ref,
onMounted,
onBeforeUnmount,
computed,
watch,
nextTick,
} from "vue";
import AddCollect from "./addCollect.vue";
import { useStore } from "@zqxx/store";
import {
videoInvokeDeviceTree,
videoInvokeBookmarkTree,
videoInvokeDele,
videoInvokeDeleDevice,
videoInvokeDeviceInfo,
} from "./api/scenicaArea";
import AddDeviceTree from "./addDeviceTree.vue";
import EditDeviceTree from "./EditDeviceTree.vue";
import { Search } from '@element-plus/icons-vue'
import { cloneObject, DateFormat } from "@zqxx/utils";
const store = useStore();
console.log(store, '999999999999999')
import flvjs from "flv.js";
let url = ref([]);
let myClassName = ref('oneoneMyfles');
let myFlvVideo = ref('myFlvVideoClass');
let oneoneMyfle = ref(true);
let twoMyfle = ref(false);
let threeMyfle = ref(false);
let fiveMyfle = ref(false);
let twourl = ref([]);
onMounted(() => {
getdeviceTree();
getInvokeBookmarkTree();
// 进入页面折叠菜单
store.app.setIsCollapseChange(true)
});
onBeforeUnmount(() => { });
// 收藏夹树
const getInvokeBookmarkTree = async () => {
let res = await videoInvokeBookmarkTree();
dataSource.value = res.data;
console.log(res, "ssssss");
};
let treedata = ref([]);
const getdeviceTree = async () => {
let res = await videoInvokeDeviceTree();
treedata.value = res.data;
};
let huaNum = ref("1");
const huaClick = (value) => {
huaNum.value = value;
Indexcol.value = '0'
if (value == "1") {
myClassName.value = 'oneoneMyfles'
myFlvVideo.value = 'myFlvVideoClass'
} else if (value == "4") {
myClassName.value = 'twoMyfles'
myFlvVideo.value = 'twomyFlvVideoClass'
} else if (value == "9") {
myClassName.value = 'threeMyfles'
myFlvVideo.value = 'threemyFlvVideoClass'
} else if (value == "12") {
myClassName.value = 'fiveMyfles'
myFlvVideo.value = 'fivemyFlvVideoClass'
}
};
const splitScreen = computed(() => {
switch (huaNum.value) {
case "1":
return 24;
break;
case "4":
return 12;
break;
case "9":
return 8;
break;
case "12":
return 8;
break;
}
});
const generatedItems = computed(() => [
...Array(parseInt(huaNum.value)).keys(),
]);
const isCloseShow = computed(() => {
console.log(Indexcol.value, "Indexcol.value");
return url.value.some(item => item.index == Indexcol.value)
})
const sheName = computed(() => {
return function (index) {
return url.value.find((item) => item.index == index)?.shename ?? null
}
})
const closeClick = (index, e) => {
url.value.splice(url.value.findIndex(item => (item.index == index)), 1)
destoryVideo(flvPlayer.value.find(item => item.index == index)["player"])
flvPlayer.value.splice(flvPlayer.value.findIndex(item => (item.index == index)), 1)
}
const takeClick = (index, e) => {
const url=[
{
id:'1',
aa:'2',
index:'0'
},
{
id:'2',
aa:'33',
index:'2'
}
]
const item = url.find(item => item.index == index)
console.log(item, 'item')
}
let flvPlayer = ref([]);
let arr = ref([])
const init = (i, id) => {
console.log(i, id, "i-id");
if (url.value && url.value.length) {
// 拿到点击的树形id那一项和数组里url一项id匹配
const item = url.value.find(item => item.id == id)
console.log(url.value, "init url");
console.log(item);
let player = null;
var videoElement = document.getElementById("myFlvVideo" + i);
console.log(videoElement, "videoElement");
player = flvjs.createPlayer(
{
type: "flv",
url: item["url"],
},
{
cors: true, // 是否跨域
enableWorker: false,
autoCleanupSourceBuffer: true, //对SourceBuffer进行自动清理缓存
enableStashBuffer: false, //关闭IO隐藏缓冲区
stashInitialSize: 128, //减少首帧显示等待时长
fixAudioTimestampGap: false, //音频同步
}
);
player.attachMediaElement(videoElement);
player.load();
setTimeout(function () {
player.play() // 播放数据流
}, 300)
player.on(flvjs.Events.ERROR, (errorInfo, errType, errDetail) => {
if (errorInfo.code == 404) {
this.$message.error('流媒体代理服务未找到,请检查');
}
// if (player) {
// destoryVideo(player)
// console.log(player, 'player')
// }
});
flvPlayer.value = flvPlayer.value.filter(item => item.index != i)
flvPlayer.value.push({ "id": id, "player": player, "index": i })
console.log(flvPlayer.value, 'flvPlayer.valueflvPlayer.valueflvPlayer.value')
}
}
const destoryVideo = (flvPlayer) => {
console.log(flvPlayer, 'flvPlayer1')
if (flvPlayer && flvPlayer !== null) {
try {
flvPlayer.unload();
flvPlayer.detachMediaElement();
flvPlayer.destroy();
console.log("销毁销毁销毁销毁");
} catch (error) {
}
}
};
let Indexcol = ref(0)
const generatedItemsClick = (item, index, e) => {
Indexcol.value = index
console.log("当前的INDEX", Indexcol.value);
};
const filterText = ref("");
const treeRef = ref("");
watch(filterText, (val) => {
treeRef.value?.filter(val);
});
const filterNode = (value, data, node) => {
let names = getParents(node, node.data.name, 'name');
let isName = names.indexOf(value) !== -1;
return !value || isName ? true : false
};
const getParents = (node, name, key) => {
if (node.parent && node.parent.data[key]) {
name += node.parent.data[key]
return getParents(node.parent, name, key)
}
return name
}
const onClickAddNew = (row) => {
handleAddPage(row);
};
let shename = ref([]);
let Gonetree = ref([]);
let gonVis = ref(false);
const handleNodeClick = async (data) => {
if (data && data.type == "device") {
sheClick(data)
}
};
const deviceInfo = async (data, index) => {
// 监控设备
console.log(data, "data22222222222222");
let params = {
deviceId: data.deviceId,
id: data.id,
name: data.name,
parentName: data.parentName,
};
let res = await videoInvokeDeviceInfo(params);
url.value = url.value.filter(item => item.index != index)
url.value.push({ "url": res.data.cameraImages[0].FlvUrl, "id": res.data.id, "shename": res.data.name, "index": index });
};
const sheClick = async (data) => {
if (data && data.type == "device" && data.status == "1") {
// 获取树形id
const id = data.id
console.log(url.value, 'value99')
// 默认设置索引Indexcol----0
await deviceInfo(data, parseInt(Indexcol.value));
if (huaNum.value == '1') {
try {
console.log(flvPlayer.value, 'flvValue')
destoryVideo(flvPlayer.value[0]["player"])
} catch (error) {
}
flvPlayer.value = []
console.log(url.value, '2222222222222')
url.value = [url.value[url.value.length - 1]]
init(0, id)
} else {
const item = flvPlayer.value.find(item => item.index == Indexcol.value
)
console.log(item, "console.log(item);");
if (item && item.hasOwnProperty("player") && item["player"]) {
destoryVideo(item["player"])
}
init(Indexcol.value, id)
}
}
};
const resfre = () => {
getInvokeBookmarkTree();
};
const defaultProps = ref({
children: "children",
label: "name",
id: "id",
});
const twodefaultProps = ref({
children: "children",
label: "name",
id: "id",
});
let formData = ref({});
let AddCollectRef = ref("");
// 收藏
const addCollect = () => {
AddCollectRef.value.show();
};
let AddDeviceTreeRef = ref("");
const append = async (data) => {
AddDeviceTreeRef.value.show(data);
};
let EditDeviceTreeRef = ref("");
const updates = (node, data) => {
EditDeviceTreeRef.value.show(data);
};
const remove = (node, data) => {
console.log(node, "node");
console.log(data, "data");
ElMessageBox.confirm(
"确定要删除收藏夹?如果删除该收藏夹下收藏的设备也会被删除",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
}
)
.then(() => {
videoInvokeDele(data.id).then((res) => {
if (res.code == 200) {
getInvokeBookmarkTree();
}
});
})
.catch(() => {
ElMessage({
type: "info",
message: "已取消",
});
});
};
const removeDevice = (node, data) => {
ElMessageBox.confirm("确定删除该设备?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
})
.then(() => {
videoInvokeDeleDevice(data.id).then((res) => {
if (res.code == 200) {
getInvokeBookmarkTree();
}
});
})
.catch(() => {
ElMessage({
type: "info",
message: "已取消",
});
});
};
const dataSource = ref([]);
</script>
<style lang="scss" scoped>
.Indexcol {
border: 4px solid rgb(11, 63, 234);
height: 100%;
}
video:not(video[src]) {
background-image: url("@/assets/images/notavailable.png");
background-repeat: no-repeat;
background-size: 45px;
background-position: center
}
.onehuaStyle {
border-bottom: 1px solid #ccc;
display: flex;
padding: 10px;
justify-content: center;
align-items: center;
font-weight: bold;
cursor: pointer;
}
.onehuaStyle:hover {
color: rgb(79, 158, 254);
}
.displayheader {
display: flex;
justify-content: space-between;
align-items: center;
}
::v-deep {
.el-tree-node:focus>.el-tree-node__content {
background: rgb(59, 101, 199) !important;
}
.sheThreeStyle {
background-color: rgb(46, 61, 79, 0.6);
color: rgb(78, 149, 252);
width: 100%;
}
.sheThreeStyle .el-tree-node__content:hover {
background: rgb(59, 101, 199);
}
.sheThreeStyle .el-tree-node__content {
background: rgb(46, 61, 97);
}
.sheThreeStyle .el-tree-node__content :focus {
background: red;
}
.el-inputStyle .el-input__inner {
background: rgb(46, 61, 79);
color: white;
}
.el-inputStyle .el-input__suffix-inner {
background: rgb(78, 149, 252);
color: white;
}
.el-inputStyle .el-input__wrapper {
background: rgb(78, 149, 252);
}
.imgStyle:hover {
transform: scale(1.7);
transition: all 0.3s ease-in-out;
}
.imgStyle {
height: 55px;
cursor: pointer;
}
.myFlvVideoClass {
width: 100%;
height: 80vh;
object-fit: fill;
border: 5px solid #cccccc1c;
}
.twomyFlvVideoClass {
width: 100%;
height: 40vh;
object-fit: fill;
border: 5px solid #cccccc1c;
}
.threemyFlvVideoClass {
width: 100%;
height: 26.6vh;
object-fit: fill;
border: 5px solid #cccccc1c;
}
.fivemyFlvVideoClass {
width: 100%;
height: 20vh;
object-fit: fill;
border: 5px solid #cccccc1c;
}
.el-card__body {
height: 250px;
overflow: auto;
}
.el-tree__empty-text {
display: none;
}
::-webkit-scrollbar {
width: 0px;
height: 0px;
}
::-webkit-scrollbar-thumb {
background-color: #ccc;
}
}
.point {
width: 12rpx;
height: 12rpx;
border: 1rpx solid red;
border-radius: 100px;
background-color: red;
}
.twopoint {
width: 12rpx;
height: 12rpx;
border: 1rpx solid green;
border-radius: 100px;
background-color: green;
}
.oneMyfle {
position: relative;
margin: 0px 3px;
}
.oneoneMyfles {
display: flex;
align-items: center;
position: absolute;
top: 35px;
margin-left: 25px;
font-size: 25px;
}
.mar-le {
margin-left: 10px;
font-weight: bold;
color: white;
}
.twoMyfles {
display: flex;
align-items: center;
position: absolute;
top: 20px;
margin-left: 10px;
font-size: 18px;
}
.threeMyfles {
display: flex;
align-items: center;
position: absolute;
top: 10px;
margin-left: 5px;
font-size: 10px;
}
.fiveMyfles {
display: flex;
align-items: center;
position: absolute;
top: 10px;
margin-left: 5px;
font-size: 10px;
}
video::-webkit-media-controls-enclosure {
display: none;
}
.normal {
background-color: red;
}
.box-card {}
</style>