diff --git a/src/plugins/screens/README.md b/src/plugins/screens/README.md new file mode 100644 index 00000000..00ea1336 --- /dev/null +++ b/src/plugins/screens/README.md @@ -0,0 +1,61 @@ +# lives + +> A Vue.js project + +## 使用 + +1. 安装依赖 + +``` +// 安装 +npm install --save flv.js +npm install --save js-md5 +npm install --save js-base64 +npm install --save axios + +// 依赖包 +"dependencies": { + "axios": "^0.27.2", + "flv.js": "^1.6.2", + "js-base64": "^3.7.2", + "js-md5": "^0.7.3", +} +``` + +2. 引入插件 + +``` + // Test.vue + import Live from '@/utils' +``` + +3. 调用 api + +``` + + + // 调用 init 方法,传入绑定的 dom 元素注入分屏插件 + mounted () { + // 1. 登录 + Live.login('http://122.112.239.62', '9000', 'jxj', 'admin123') + // 2. 绑定插件 + this.screens = Live.init(document.getElementById('wrapper')) + // 3. 配置参数加载视频 + this.screens.setOptions(/* 这里传入配置对象 */ { + deviceId: '1202291000447', + channelNum: 1, + streamType: 0, + mediaType: 'FLV', + recordTimeStart: '2022-07-16 04:00:00', + recordTimeEnd: '2022-07-16 06:00:00', + source: 'device', + isDownload: 0, + tokenType: 'Dynamic', + expireTime: '0', + https: false + }) + }, +``` diff --git a/src/plugins/screens/api.js b/src/plugins/screens/api.js new file mode 100644 index 00000000..68eb80ac --- /dev/null +++ b/src/plugins/screens/api.js @@ -0,0 +1,25 @@ +import http from './request' + +export const apiLogin = (baseURL, Authorization, data = {}) => { + return http({ + baseURL, + url: '/login', + method: 'post', + data, + headers: { + Authorization + } + }) +} + +export const apiQueryPlaybackUri = (baseURL, token, data) => { + return http({ + baseURL, + url: '/queryPlaybackUri', + method: 'post', + data, + headers: { + token + } + }) +} diff --git a/src/plugins/screens/index.css b/src/plugins/screens/index.css new file mode 100644 index 00000000..dc883e6d --- /dev/null +++ b/src/plugins/screens/index.css @@ -0,0 +1,39 @@ +.live-screens-screen-wrap { + position: relative; + background-color: #000; +} + +.live-screens-screen-item { + box-sizing: border-box; + border: 1px solid #fff; +} + +.live-screens-screen-close { + position: absolute; + width: 60px; + height: 30px; + line-height: 30px; + text-align: center; + color: red; + cursor: pointer; +} + +.live-setting-btn-wrap { + margin-top:8px; + display: flex; + justify-content: flex-end; +} + +.live-setting-btn-item { + margin-right: 10px; + width: 60px; + height: 30px; + line-height: 30px; + text-align:center; + border: 1px solid #666; + cursor: pointer; +} + +.actived { + border: 1px solid orangered !important; +} diff --git a/src/plugins/screens/index.js b/src/plugins/screens/index.js new file mode 100644 index 00000000..ecd2aa0e --- /dev/null +++ b/src/plugins/screens/index.js @@ -0,0 +1,204 @@ +import flvjs from 'flv.js' +import md5 from 'js-md5' +import { encode } from 'js-base64' +import { apiLogin, apiQueryPlaybackUri } from './api' +import './index.css' + +let baseURL = '' +let token = '' +let Authorization = '' +const screenTypes = [ + {text: '一屏', value: 1}, + {text: '二屏', value: 2}, + {text: '四屏', value: 4}, + {text: '六屏', value: 6} +] + +const createVideoEl = (vm, index = 0, width = '100%', height = '100%') => { + const videoEl = document.createElement('video') + videoEl.setAttribute('muted', 'muted') + // videoEl.setAttribute('controls', 'controls') + videoEl.setAttribute('width', width) + videoEl.setAttribute('height', height) + videoEl.className = 'live-screens-screen-item' + videoEl.addEventListener('click', e => { + vm.currentScreen = e.target + vm.screenIndex = index + vm.screens.map(screen => screen.classList.remove('actived')) + e.target.classList.add('actived') + }) + return videoEl +} + +const createScreenWrap = (el) => { + const width = el.offsetWidth + const height = el.offsetHeight - 40 + const screenWrap = document.createElement('div') + screenWrap.style.cssText = `width: ${width}px;height: ${height}px;` + screenWrap.className = 'live-screens-screen-wrap' + return screenWrap +} + +const createScreens = (vm, screenWrapEl, screens, screenCount) => { + const w = screenWrapEl.offsetWidth + const h = screenWrapEl.offsetHeight + let width = '' + let height = '' + switch (screenCount) { + case 2: + width = w / 2 + 'px' + height = h + 'px' + break + case 4: + width = w / 2 + 'px' + height = h / 2 + 'px' + break + case 6: + width = w / 3 + 'px' + height = h / 2 + 'px' + break + default: + width = '100%' + height = '100%' + break + } + const list = new Array(screenCount).fill(0) + screens.map(child => screenWrapEl.removeChild(child)) + screens.splice(0) + list.map((item, index) => { + const videoEl = createVideoEl(vm, index, width, height) + screenWrapEl.appendChild(videoEl) + screens.push(videoEl) + }) +} + +const createScreenBtns = (ins) => { + const screenBtnGroupEl = document.createElement('div') + screenBtnGroupEl.className = 'live-setting-btn-wrap' + screenTypes.map(type => { + const btnEl = document.createElement('div') + btnEl.className = 'live-setting-btn-item' + btnEl.innerText = type.text + btnEl.addEventListener('click', () => { + ins.setScreenCount(type.value) + }) + screenBtnGroupEl.appendChild(btnEl) + }) + return screenBtnGroupEl +} + +const createCloseEl = (vm) => { + const w = vm.currentScreen.offsetWidth + // const h = vm.currentScreen.offsetHeight + const left = vm.currentScreen.offsetLeft + const top = vm.currentScreen.offsetTop + + const el = document.createElement('div') + el.className = 'live-screens-screen-close' + el.innerText = '关闭' + el.style.top = top + 10 + 'px' + el.style.left = left + w - 60 + 'px' + el.setAttribute('data-index', vm.screenIndex) + el.addEventListener('click', e => { + const index = e.target.getAttribute('data-index') + const videoEl = vm.screens[index] + videoEl.removeAttribute('controls') + videoEl.removeAttribute('src') + vm.screenWrapEl.removeChild(e.target) + }) + vm.screenWrapEl.appendChild(el) + vm.currentScreen = null +} + +const Initial = class { + constructor (el) { + const screen1 = createVideoEl(this) + const screenWrapEl = createScreenWrap(el) + screenWrapEl.appendChild(screen1) + el.appendChild(screenWrapEl) + el.appendChild(createScreenBtns(this)) + this.currentScreen = screen1 + this.screenCount = 1 + this.screenIndex = 0 + this.wrapEl = el + this.screenWrapEl = screenWrapEl + this.screens = [screen1] + this.players = [] + } + + setOptions (options = { + deviceId: '1202291000447', + channelNum: 1, + streamType: 0, + mediaType: 'FLV', + recordTimeStart: '2022-07-16 04:00:00', + recordTimeEnd: '2022-07-16 06:00:00', + source: 'device', + isDownload: 0, + tokenType: 'Dynamic', + expireTime: '0', + https: false + }) { + if (!this.currentScreen || this.currentScreen.src) { + return false + } + (async () => { + const res = await apiQueryPlaybackUri(baseURL, token, options).catch(console.log) + if (res.status === 200) { + const url = res.data.uri + this.player = this.getVideoPlayer(url) + this.currentScreen.setAttribute('controls', 'controls') + createCloseEl(this) + } + })() + // return this + } + + getVideoPlayer (url) { + if (flvjs.isSupported()) { + const videoEl = this.currentScreen + const flvPlayer = flvjs.createPlayer({ + type: 'flv', + url: url.replace('http://:9050', 'http://122.112.239.62:9050') + }) + flvPlayer.attachMediaElement(videoEl) + flvPlayer.load() + // flvPlayer.play() + return flvPlayer + } + } + + setScreenCount (screenCount) { + this.screenCount = screenCount + const closeEls = document.getElementsByClassName('live-screens-screen-close') + ;[].slice.call(closeEls).map(el => this.screenWrapEl.removeChild(el)) + createScreens(this, this.screenWrapEl, this.screens, screenCount) + } +} + +const init = (el) => { + const screen = new Initial(el) + return { + setOptions: screen.setOptions.bind(screen) + } +} + +const encryption = (host, port, username, pwd) => { + baseURL = `${host}:${port}` + const md5Pwd = md5(pwd) + Authorization = 'Basic ' + encode(username + ':' + md5Pwd) +} + +const login = async (host, port, username, pwd) => { + encryption(host, port, username, pwd) + + const res = await apiLogin(baseURL, Authorization).catch(console.log) + if (res.status === 200) { + token = res.headers.token + } +} + +export default { + login, + init +} diff --git a/src/plugins/screens/request.js b/src/plugins/screens/request.js new file mode 100644 index 00000000..b360c6af --- /dev/null +++ b/src/plugins/screens/request.js @@ -0,0 +1,7 @@ +import axios from 'axios' + +const http = axios.create({ + // baseURL: 'http://122.112.239.62:9000' +}) + +export default http