Joe
11 months ago
13 changed files with 335 additions and 124 deletions
@ -0,0 +1,28 @@ |
|||
<template> |
|||
<video controls class="video-stream" v-bind="$attrs" ref="videoContainerRef" /> |
|||
</template> |
|||
|
|||
<script> |
|||
import { openVideoStream } from "./videoStream.js" |
|||
|
|||
export default { |
|||
name: 'Video', |
|||
props: { |
|||
camId: { |
|||
type: String, |
|||
default: null |
|||
}, |
|||
url: { |
|||
type: String, |
|||
default: null |
|||
} |
|||
}, |
|||
mounted() { |
|||
openVideoStream(this.$refs.videoContainerRef, { camId: this.camId, url: this.url }) |
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
<style lang='scss' scoped> |
|||
.video-stream {} |
|||
</style> |
@ -0,0 +1,41 @@ |
|||
import flvJs from "flv.js"; |
|||
import { getCameraStream } from "@screen/pages/Home/components/RoadAndEvents/utils/httpList.js"; |
|||
|
|||
/** |
|||
* |
|||
* @param {HTMLElement} container 容器 |
|||
* @param {{camId?: string; url?: string}?} options {camId: 相机ID; url: 直播地址} |
|||
* @returns |
|||
*/ |
|||
export async function openVideoStream(container, { camId, url } = {}) { |
|||
if (camId) { |
|||
const { code, data } = await getCameraStream(camId).catch(() => ({})); |
|||
|
|||
if (code != 200) return; |
|||
|
|||
url = data.liveUrl; |
|||
} |
|||
|
|||
if (!url) return; |
|||
|
|||
const flvPlayer = flvJs.createPlayer({ |
|||
type: "flv", |
|||
url: url, |
|||
isLive: true, |
|||
hasVideo: true, |
|||
hasAudio: true, |
|||
}); |
|||
|
|||
console.log( |
|||
"%c [ flvPlayer ]-26-「videoStream.js」", |
|||
"font-size:15px; background:#b2b540; color:#f6f984;", |
|||
flvPlayer |
|||
); |
|||
|
|||
flvPlayer.attachMediaElement(container); |
|||
|
|||
flvPlayer.load(); |
|||
flvPlayer.play(); |
|||
|
|||
return flvPlayer; |
|||
} |
@ -1,47 +0,0 @@ |
|||
import flvJs from "flv.js"; |
|||
import { getCameraStream } from "./httpList"; |
|||
|
|||
/** |
|||
* |
|||
* @param {string} camId 相机ID |
|||
* @param {HTMLElement} container 容器 |
|||
* @param {DPlayerOptions?} options 配置项 |
|||
* @returns |
|||
*/ |
|||
export async function openVideoStream(camId, container) { |
|||
const { code, data } = await getCameraStream(camId).catch(() => ({})); |
|||
|
|||
if (code != 200) return; |
|||
|
|||
const flvPlayer = flvJs.createPlayer({ |
|||
type: "flv", |
|||
url: data.liveUrl, |
|||
isLive: true, |
|||
hasVideo: true, |
|||
hasAudio: true, |
|||
}); |
|||
|
|||
console.log( |
|||
"%c [ flvPlayer ]-26-「videoStream.js」", |
|||
"font-size:15px; background:#b2b540; color:#f6f984;", |
|||
flvPlayer |
|||
); |
|||
|
|||
flvPlayer.attachMediaElement(container); |
|||
|
|||
flvPlayer.load(); |
|||
flvPlayer.play(); |
|||
|
|||
return flvPlayer; |
|||
// return new DPlayer({
|
|||
// container,
|
|||
// autoplay: true,
|
|||
// ...options,
|
|||
// hotkey: false,
|
|||
// video: {
|
|||
// url: data.liveUrl,
|
|||
// type: "hls",
|
|||
// // type: "flv",
|
|||
// },
|
|||
// });
|
|||
} |
@ -1,20 +1,37 @@ |
|||
<template> |
|||
<Card class='RealTimeVideo' title="实时视频"> |
|||
RealTimeVideo |
|||
<Video class="item-video" /> |
|||
<Video class="item-video" /> |
|||
</Card> |
|||
</template> |
|||
|
|||
<script> |
|||
import Card from "./../../components/Card.vue" |
|||
|
|||
import Card from "./../../components/Card.vue"; |
|||
import Video from "@screen/components/Video" |
|||
export default { |
|||
name: 'RealTimeVideo', |
|||
components: { |
|||
Card |
|||
Card, |
|||
Video |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang='scss' scoped> |
|||
.RealTimeVideo {} |
|||
.RealTimeVideo { |
|||
::v-deep { |
|||
.content { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
gap: 9px; |
|||
} |
|||
} |
|||
|
|||
.item-video { |
|||
flex: 1; |
|||
width: calc(50% - 4.5px); |
|||
height: 100%; |
|||
} |
|||
} |
|||
</style> |
|||
|
@ -0,0 +1,150 @@ |
|||
div.el-popper { |
|||
background: #123542; |
|||
box-shadow: 2px 2px 8px 0px rgba(82, 90, 102, 0.08), |
|||
1px 1px 2px 0px rgba(82, 90, 102, 0.04); |
|||
border-radius: 4px 4px 4px 4px; |
|||
opacity: 1; |
|||
border: 0; |
|||
|
|||
.el-select-dropdown__list { |
|||
.el-select-dropdown__item { |
|||
font-size: 15px; |
|||
font-family: PingFang SC, PingFang SC; |
|||
font-weight: 500; |
|||
color: #ffffff; |
|||
/** |
|||
-webkit-background-clip: text; |
|||
-webkit-text-fill-color: transparent; |
|||
*/ |
|||
&:hover { |
|||
background: #0d5f79; |
|||
} |
|||
&.hover { |
|||
background: #0d5f79; |
|||
} |
|||
} |
|||
} |
|||
|
|||
&[x-placement^="top"] { |
|||
div.popper__arrow { |
|||
border-top-color: #00799f; |
|||
|
|||
&::after { |
|||
border-top-color: #00799f; |
|||
} |
|||
} |
|||
} |
|||
&[x-placement^="left"] { |
|||
div.popper__arrow { |
|||
border-left-color: #00799f; |
|||
|
|||
&::after { |
|||
border-left-color: #00799f; |
|||
} |
|||
} |
|||
} |
|||
&[x-placement^="right"] { |
|||
div.popper__arrow { |
|||
border-right-color: #00799f; |
|||
|
|||
&::after { |
|||
border-right-color: #00799f; |
|||
} |
|||
} |
|||
} |
|||
&[x-placement^="bottom"] { |
|||
div.popper__arrow { |
|||
border-bottom-color: #00799f; |
|||
|
|||
&::after { |
|||
border-bottom-color: #00799f; |
|||
} |
|||
} |
|||
} |
|||
&.el-select-dropdown { |
|||
&[x-placement^="top"] { |
|||
div.popper__arrow { |
|||
border-top-color: #1a3442; |
|||
|
|||
&::after { |
|||
border-top-color: #1a3442; |
|||
} |
|||
} |
|||
} |
|||
&[x-placement^="left"] { |
|||
div.popper__arrow { |
|||
border-left-color: #1a3442; |
|||
|
|||
&::after { |
|||
border-left-color: #1a3442; |
|||
} |
|||
} |
|||
} |
|||
&[x-placement^="right"] { |
|||
div.popper__arrow { |
|||
border-right-color: #1a3442; |
|||
|
|||
&::after { |
|||
border-right-color: #1a3442; |
|||
} |
|||
} |
|||
} |
|||
&[x-placement^="bottom"] { |
|||
div.popper__arrow { |
|||
border-bottom-color: #1a3442; |
|||
|
|||
&::after { |
|||
border-bottom-color: #1a3442; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
div.el-scrollbar { |
|||
.el-scrollbar__wrap { |
|||
/** |
|||
overflow: auto; |
|||
*/ |
|||
overflow-x: hidden; |
|||
} |
|||
} |
|||
|
|||
body { |
|||
input.el-input__inner { |
|||
background-color: #0d5f79; |
|||
color: #fff; |
|||
border-radius: 2px; |
|||
border: 0; |
|||
height: 100%; |
|||
min-height: fit-content; |
|||
line-height: unset; |
|||
|
|||
&::placeholder { |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
div.el-input { |
|||
input.el-input__inner { |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
div.el-textarea { |
|||
textarea.el-textarea__inner { |
|||
background: #0a3e54; |
|||
border-radius: 5px; |
|||
opacity: 1; |
|||
border: 1px solid rgba(98, 224, 254, 0.6); |
|||
} |
|||
|
|||
.el-input__count { |
|||
background-color: rgba(0, 0, 0, 0); |
|||
font-size: 12px; |
|||
font-family: PingFang SC, PingFang SC; |
|||
font-weight: 400; |
|||
color: #3de8ff; |
|||
line-height: 14px; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,39 @@ |
|||
@import url(./el-reset.scss); |
|||
|
|||
body { |
|||
input, |
|||
textarea { |
|||
caret-color: white; |
|||
} |
|||
|
|||
div { |
|||
/* 滚动条整体部分 */ |
|||
&::-webkit-scrollbar { |
|||
width: 6px !important; |
|||
height: 6px !important; |
|||
padding: 15px; |
|||
} |
|||
|
|||
/* 滚动条的轨道 */ |
|||
&::-webkit-scrollbar-track { |
|||
background: rgba(17, 72, 90, 0.4); |
|||
border-radius: 4px; |
|||
} |
|||
|
|||
/* 滚动条的滑块按钮 */ |
|||
&::-webkit-scrollbar-thumb { |
|||
background: #3785a0; |
|||
border-radius: 4px; |
|||
} |
|||
|
|||
/* 上下箭头 */ |
|||
&::-webkit-scrollbar-button { |
|||
display: none; |
|||
} |
|||
|
|||
/* 滚动条角 */ |
|||
&::-webkit-scrollbar-corner { |
|||
display: none; |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue