Commit d81f3f3a7d840952aca9fca11655e9435b09588b
1 parent
d34371a9
feat: 新增水印
Showing
9 changed files
with
227 additions
and
178 deletions
src/main/resources/Aserver.keystore
0 → 100644
No preview for this file type
src/main/resources/application-dev.yml
| ... | ... | @@ -13,13 +13,13 @@ spring: |
| 13 | 13 | # REDIS数据库配置 |
| 14 | 14 | redis: |
| 15 | 15 | # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 |
| 16 | - host: 127.0.0.1 | |
| 16 | + host: 192.168.168.124 | |
| 17 | 17 | # [必须修改] 端口号 |
| 18 | 18 | port: 6379 |
| 19 | 19 | # [可选] 数据库 DB |
| 20 | 20 | database: 7 |
| 21 | 21 | # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 |
| 22 | - password: luna | |
| 22 | +# password: luna | |
| 23 | 23 | # [可选] 超时时间 |
| 24 | 24 | timeout: 10000 |
| 25 | 25 | # mysql数据源 |
| ... | ... | @@ -30,9 +30,9 @@ spring: |
| 30 | 30 | master: |
| 31 | 31 | type: com.zaxxer.hikari.HikariDataSource |
| 32 | 32 | driver-class-name: com.mysql.cj.jdbc.Driver |
| 33 | - url: jdbc:mysql://127.0.0.1:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true | |
| 33 | + url: jdbc:mysql://192.168.168.124:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true | |
| 34 | 34 | username: root |
| 35 | - password: root123 | |
| 35 | + password: guzijian | |
| 36 | 36 | hikari: |
| 37 | 37 | connection-timeout: 20000 # 是客户端等待连接池连接的最大毫秒数 |
| 38 | 38 | initialSize: 50 # 连接池初始化连接数 |
| ... | ... | @@ -60,36 +60,36 @@ sip: |
| 60 | 60 | # 如果要监听多张网卡,可以使用逗号分隔多个IP, 例如: 192.168.1.4,10.0.0.4 |
| 61 | 61 | # 如果不明白,就使用0.0.0.0,大部分情况都是可以的 |
| 62 | 62 | # 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。 |
| 63 | - ip: 172.19.128.50 | |
| 63 | + ip: 192.168.168.124 | |
| 64 | 64 | # [可选] 28181服务监听的端口 |
| 65 | - port: 8116 | |
| 65 | + port: 5060 | |
| 66 | 66 | # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) |
| 67 | 67 | # 后两位为行业编码,定义参照附录D.3 |
| 68 | 68 | # 3701020049标识山东济南历下区 信息行业接入 |
| 69 | 69 | # [可选] |
| 70 | - domain: 4101050000 | |
| 70 | + domain: 3402000000 | |
| 71 | 71 | # [可选] |
| 72 | - id: 41010500002000000001 | |
| 72 | + id: 34020000002000000001 | |
| 73 | 73 | # [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验 |
| 74 | - password: bajiuwulian1006 | |
| 74 | + password: 12345678 | |
| 75 | 75 | # 是否存储alarm信息 |
| 76 | 76 | alarm: true |
| 77 | 77 | |
| 78 | 78 | #zlm 默认服务器配置 |
| 79 | 79 | media: |
| 80 | - id: zlmediakit-local | |
| 80 | + id: your_server_id | |
| 81 | 81 | # [必须修改] zlm服务器的内网IP |
| 82 | - ip: 172.19.128.50 | |
| 82 | + ip: 192.168.168.124 | |
| 83 | 83 | # [必须修改] zlm服务器的http.port |
| 84 | - http-port: 9092 | |
| 84 | + http-port: 9090 | |
| 85 | 85 | # [可选] 返回流地址时的ip,置空使用 media.ip |
| 86 | - stream-ip: 172.19.128.50 | |
| 86 | + stream-ip: 61.169.120.202 | |
| 87 | 87 | # [可选] wvp在国标信令中使用的ip,此ip为摄像机可以访问到的ip, 置空使用 media.ip |
| 88 | - sdp-ip: 172.19.128.50 | |
| 88 | + sdp-ip: 192.168.168.124 | |
| 89 | 89 | # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip |
| 90 | - hook-ip: 172.19.128.50 | |
| 90 | + hook-ip: 192.168.168.124 | |
| 91 | 91 | # [可选] zlm服务器的http.sslport, 置空使用zlm配置文件配置 |
| 92 | - http-ssl-port: 1443 | |
| 92 | + http-ssl-port: 7443 | |
| 93 | 93 | # [可选] zlm服务器的hook.admin_params=secret |
| 94 | 94 | secret: 10000 |
| 95 | 95 | # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 |
| ... | ... | @@ -97,9 +97,9 @@ media: |
| 97 | 97 | # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 |
| 98 | 98 | enable: true |
| 99 | 99 | # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功 |
| 100 | - port-range: 50000,50300 # 端口范围 | |
| 100 | + port-range: 30000,30500 # 端口范围 | |
| 101 | 101 | # [可选] 国标级联在此范围内选择端口发送媒体流, |
| 102 | - send-port-range: 50000,50300 # 端口范围 | |
| 102 | + send-port-range: 30000,30500 # 端口范围 | |
| 103 | 103 | # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用 |
| 104 | 104 | record-assist-port: 18081 |
| 105 | 105 | # [根据业务需求配置] | ... | ... |
web_src/build/utils.js
| ... | ... | @@ -95,7 +95,7 @@ exports.createNotifierCallback = () => { |
| 95 | 95 | title: packageConfig.name, |
| 96 | 96 | message: severity + ': ' + error.name, |
| 97 | 97 | subtitle: filename || '', |
| 98 | - icon: path.join(__dirname, 'logo.png') | |
| 98 | + icon: path.join(__dirname, 'favicon_tuohua.ico') | |
| 99 | 99 | }) |
| 100 | 100 | } |
| 101 | 101 | } | ... | ... |
web_src/config/index.js
| ... | ... | @@ -12,14 +12,14 @@ module.exports = { |
| 12 | 12 | assetsPublicPath: '/', |
| 13 | 13 | proxyTable: { |
| 14 | 14 | '/debug': { |
| 15 | - target: 'http://127.0.0.1:18082', | |
| 15 | + target: 'https://192.169.1.31:18080', | |
| 16 | 16 | changeOrigin: true, |
| 17 | 17 | pathRewrite: { |
| 18 | 18 | '^/debug': '/' |
| 19 | 19 | } |
| 20 | 20 | }, |
| 21 | 21 | '/static/snap': { |
| 22 | - target: 'http://127.0.0.1:18082', | |
| 22 | + target: 'https://192.169.1.31:18080', | |
| 23 | 23 | changeOrigin: true, |
| 24 | 24 | // pathRewrite: { |
| 25 | 25 | // '^/static/snap': '/static/snap' | ... | ... |
web_src/src/components/Login.vue
| 1 | 1 | <template> |
| 2 | -<div class="login" id="login"> | |
| 3 | - <div class="limiter"> | |
| 4 | - <div class="container-login100"> | |
| 5 | - <div class="wrap-login100"> | |
| 6 | - <span class="login100-form-title p-b-26">WVP视频平台</span> | |
| 7 | - <span class="login100-form-title p-b-48"> | |
| 8 | - <i class="fa fa-video-camera"></i> | |
| 9 | - </span> | |
| 2 | + <div class="login-container"> | |
| 3 | + <div class="login" id="login"> | |
| 4 | + <div class="limiter"> | |
| 5 | + <div class="container-login100"> | |
| 6 | + <div class="wrap-login100"> | |
| 7 | + <span class="login100-form-title p-b-26">综合视频平台</span> | |
| 8 | + <span class="login100-form-title p-b-48"> | |
| 9 | + <i class="fa fa-video-camera"></i> | |
| 10 | + </span> | |
| 10 | 11 | |
| 11 | - <div class="wrap-input100 validate-input" data-validate = "Valid email is: a@b.c"> | |
| 12 | - <input :class="'input100 ' + (username==''?'':'has-val')" type="text" v-model="username" name="username"> | |
| 13 | - <span class="focus-input100" data-placeholder="用户名"></span> | |
| 14 | - </div> | |
| 12 | + <div class="wrap-input100 validate-input" data-validate="Valid email is: a@b.c"> | |
| 13 | + <input :class="'input100 ' + (username == '' ? '' : 'has-val')" type="text" v-model="username" | |
| 14 | + name="username"> | |
| 15 | + <span class="focus-input100" data-placeholder="用户名"></span> | |
| 16 | + </div> | |
| 15 | 17 | |
| 16 | - <div class="wrap-input100 validate-input" data-validate="Enter password"> | |
| 17 | - <span class="btn-show-pass"> | |
| 18 | - <i :class="'fa ' + (!showPassword?'fa-eye':'fa-eye-slash')" @click="showPassword = !showPassword"></i> | |
| 19 | - </span> | |
| 20 | - <input :class="'input100 ' + (password==''?'':'has-val')" :type="(!showPassword?'password':'text')" v-model="password" name="password"> | |
| 21 | - <span class="focus-input100" data-placeholder="密码"></span> | |
| 22 | - </div> | |
| 18 | + <div class="wrap-input100 validate-input" data-validate="Enter password"> | |
| 19 | + <span class="btn-show-pass"> | |
| 20 | + <i :class="'fa ' + (!showPassword ? 'fa-eye' : 'fa-eye-slash')" | |
| 21 | + @click="showPassword = !showPassword"></i> | |
| 22 | + </span> | |
| 23 | + <input :class="'input100 ' + (password == '' ? '' : 'has-val')" | |
| 24 | + :type="(!showPassword ? 'password' : 'text')" v-model="password" name="password"> | |
| 25 | + <span class="focus-input100" data-placeholder="密码"></span> | |
| 26 | + </div> | |
| 23 | 27 | |
| 24 | - <div class="container-login100-form-btn"> | |
| 25 | - <div class="wrap-login100-form-btn" :class="{'login-loading': isLoging}" v-loading="isLoging" element-loading-background="rgb(0 0 0 / 0%);" element-loading-custom-class="login-loading-class"> | |
| 26 | - <div class="login100-form-bgbtn"></div> | |
| 27 | - <button class="login100-form-btn" @click="login">登录</button> | |
| 28 | + <div class="container-login100-form-btn"> | |
| 29 | + <div class="wrap-login100-form-btn" :class="{ 'login-loading': isLoging }" v-loading="isLoging" | |
| 30 | + element-loading-background="rgb(0 0 0 / 0%);" element-loading-custom-class="login-loading-class"> | |
| 31 | + <div class="login100-form-bgbtn"></div> | |
| 32 | + <button class="login100-form-btn" @click="login">登录</button> | |
| 33 | + </div> | |
| 28 | 34 | </div> |
| 29 | 35 | </div> |
| 36 | + </div> | |
| 37 | + <div class="company-author"> | |
| 38 | + <span>@2024 上海巴士拓华科技发展有限公司 版权所有</span> | |
| 39 | + </div> | |
| 30 | 40 | </div> |
| 31 | 41 | </div> |
| 32 | 42 | </div> |
| 33 | -</div> | |
| 43 | + | |
| 34 | 44 | </template> |
| 35 | 45 | |
| 36 | 46 | <script> |
| 37 | -import crypto from 'crypto' | |
| 47 | +import crypto from 'crypto'; | |
| 38 | 48 | import userService from "./service/UserService"; |
| 39 | 49 | export default { |
| 40 | 50 | name: 'Login', |
| 41 | - data(){ | |
| 42 | - return { | |
| 51 | + data() { | |
| 52 | + return { | |
| 43 | 53 | isLoging: false, |
| 44 | 54 | showPassword: false, |
| 45 | 55 | loginLoading: false, |
| 46 | - username: '', | |
| 47 | - password: '' | |
| 48 | - } | |
| 56 | + username: '', | |
| 57 | + password: '' | |
| 58 | + } | |
| 49 | 59 | }, |
| 50 | - created(){ | |
| 60 | + created() { | |
| 51 | 61 | var that = this; |
| 52 | - document.onkeydown = function(e) { | |
| 62 | + document.onkeydown = function (e) { | |
| 53 | 63 | var key = window.event.keyCode; |
| 54 | 64 | if (key == 13) { |
| 55 | 65 | that.login(); |
| 56 | 66 | } |
| 57 | 67 | } |
| 58 | 68 | }, |
| 59 | - methods:{ | |
| 69 | + methods: { | |
| 60 | 70 | |
| 61 | - //登录逻辑 | |
| 62 | - login(){ | |
| 63 | - if(this.username!='' && this.password!=''){ | |
| 64 | - this.toLogin(); | |
| 65 | - } | |
| 66 | - }, | |
| 71 | + //登录逻辑 | |
| 72 | + login() { | |
| 73 | + if (this.username != '' && this.password != '') { | |
| 74 | + this.toLogin(); | |
| 75 | + } | |
| 76 | + }, | |
| 67 | 77 | |
| 68 | - //登录请求 | |
| 69 | - toLogin(){ | |
| 70 | - //需要想后端发送的登录参数 | |
| 71 | - let loginParam = { | |
| 72 | - username: this.username, | |
| 73 | - password: crypto.createHash('md5').update(this.password, "utf8").digest('hex') | |
| 74 | - } | |
| 78 | + //登录请求 | |
| 79 | + toLogin() { | |
| 80 | + //需要想后端发送的登录参数 | |
| 81 | + let loginParam = { | |
| 82 | + username: this.username, | |
| 83 | + password: crypto.createHash('md5').update(this.password, "utf8").digest('hex') | |
| 84 | + } | |
| 75 | 85 | var that = this; |
| 76 | 86 | //设置在登录状态 |
| 77 | 87 | this.isLoging = true; |
| 78 | - let timeoutTask = setTimeout(()=>{ | |
| 88 | + let timeoutTask = setTimeout(() => { | |
| 79 | 89 | that.$message.error("登录超时"); |
| 80 | 90 | that.isLoging = false; |
| 81 | 91 | }, 1000) |
| 82 | 92 | |
| 83 | 93 | this.$axios({ |
| 84 | - method: 'get', | |
| 85 | - url:"/api/user/login", | |
| 94 | + method: 'get', | |
| 95 | + url: "/api/user/login", | |
| 86 | 96 | params: loginParam |
| 87 | 97 | }).then(function (res) { |
| 88 | 98 | window.clearTimeout(timeoutTask) |
| 89 | 99 | console.log(res); |
| 90 | 100 | console.log("登录成功"); |
| 91 | - if (res.data.code === 0 ) { | |
| 92 | - userService.setUser(res.data.data) | |
| 93 | - //登录成功后 | |
| 94 | - that.cancelEnterkeyDefaultAction(); | |
| 95 | - that.$router.push('/'); | |
| 96 | - }else{ | |
| 97 | - that.isLoging = false; | |
| 98 | - that.$message({ | |
| 99 | - showClose: true, | |
| 100 | - message: '登录失败,用户名或密码错误', | |
| 101 | - type: 'error' | |
| 102 | - }); | |
| 103 | - } | |
| 101 | + if (res.data.code === 0) { | |
| 102 | + userService.setUser(res.data.data) | |
| 103 | + //登录成功后 | |
| 104 | + that.cancelEnterkeyDefaultAction(); | |
| 105 | + that.$router.push('/'); | |
| 106 | + } else { | |
| 107 | + that.isLoging = false; | |
| 108 | + that.$message({ | |
| 109 | + showClose: true, | |
| 110 | + message: '登录失败,用户名或密码错误', | |
| 111 | + type: 'error' | |
| 112 | + }); | |
| 113 | + } | |
| 104 | 114 | }).catch(function (error) { |
| 105 | 115 | console.log(error) |
| 106 | 116 | window.clearTimeout(timeoutTask) |
| ... | ... | @@ -108,8 +118,8 @@ export default { |
| 108 | 118 | that.isLoging = false; |
| 109 | 119 | }); |
| 110 | 120 | }, |
| 111 | - cancelEnterkeyDefaultAction: function() { | |
| 112 | - document.onkeydown = function(e) { | |
| 121 | + cancelEnterkeyDefaultAction: function () { | |
| 122 | + document.onkeydown = function (e) { | |
| 113 | 123 | var key = window.event.keyCode; |
| 114 | 124 | if (key == 13) { |
| 115 | 125 | return false; |
| ... | ... | @@ -119,4 +129,11 @@ export default { |
| 119 | 129 | } |
| 120 | 130 | } |
| 121 | 131 | </script> |
| 122 | - | |
| 132 | +<style scoped> | |
| 133 | +.container-login100 { | |
| 134 | + background: url("../assets/login-bg.jpg") no-repeat; | |
| 135 | + background-size: 100% 100%; | |
| 136 | + width: 100vw; | |
| 137 | + height: 100vh; | |
| 138 | +} | |
| 139 | +</style> | ... | ... |
web_src/src/components/common/easyPlayer.vue
| 1 | 1 | <template> |
| 2 | - <div id="easyplayer" ></div> | |
| 2 | + <div id="easyplayer"></div> | |
| 3 | 3 | </template> |
| 4 | 4 | |
| 5 | 5 | <script> |
| 6 | +import userService from '../service/UserService'; | |
| 6 | 7 | export default { |
| 7 | - name: 'player', | |
| 8 | - data() { | |
| 9 | - return { | |
| 10 | - easyPlayer: null | |
| 11 | - }; | |
| 8 | + name: 'player', | |
| 9 | + data() { | |
| 10 | + return { | |
| 11 | + timer: null, | |
| 12 | + easyPlayer: null, | |
| 13 | + config: { | |
| 14 | + userName: userService.getUser().username, | |
| 15 | + nowTime: "2024-03-01 12:00:00" | |
| 16 | + } // 水印 | |
| 17 | + }; | |
| 18 | + }, | |
| 19 | + props: ['videoUrl', 'error', 'hasaudio', 'height'], | |
| 20 | + mounted() { | |
| 21 | + let paramUrl = decodeURIComponent(this.$route.params.url) | |
| 22 | + this.$nextTick(() => { | |
| 23 | + if (typeof (this.videoUrl) == "undefined") { | |
| 24 | + this.videoUrl = paramUrl; | |
| 25 | + } | |
| 26 | + console.log("初始化时的地址为: " + this.videoUrl) | |
| 27 | + this.play(this.videoUrl) | |
| 28 | + }) | |
| 29 | + }, | |
| 30 | + watch: { | |
| 31 | + videoUrl(newData, oldData) { | |
| 32 | + this.play(newData) | |
| 12 | 33 | }, |
| 13 | - props: ['videoUrl', 'error', 'hasaudio', 'height'], | |
| 14 | - mounted () { | |
| 15 | - let paramUrl = decodeURIComponent(this.$route.params.url) | |
| 16 | - this.$nextTick(() =>{ | |
| 17 | - if (typeof (this.videoUrl) == "undefined") { | |
| 18 | - this.videoUrl = paramUrl; | |
| 19 | - } | |
| 20 | - console.log("初始化时的地址为: " + this.videoUrl) | |
| 21 | - this.play(this.videoUrl) | |
| 22 | - }) | |
| 34 | + immediate: true | |
| 35 | + }, | |
| 36 | + methods: { | |
| 37 | + play: function (url) { | |
| 38 | + console.log(this.height) | |
| 39 | + if (this.easyPlayer != null) { | |
| 40 | + this.easyPlayer.destroy(); | |
| 41 | + } | |
| 42 | + if (typeof (this.height) == "undefined") { | |
| 43 | + this.height = false | |
| 44 | + } | |
| 45 | + this.easyPlayer = new WasmPlayer(null, 'easyplayer', this.eventcallbacK, { Height: this.height }) | |
| 46 | + this.easyPlayer.play(url, 1) | |
| 23 | 47 | }, |
| 24 | - watch:{ | |
| 25 | - videoUrl(newData, oldData){ | |
| 26 | - this.play(newData) | |
| 27 | - }, | |
| 28 | - immediate:true | |
| 29 | - }, | |
| 30 | - methods: { | |
| 31 | - play: function (url) { | |
| 32 | - console.log(this.height) | |
| 33 | - if (this.easyPlayer != null) { | |
| 34 | - this.easyPlayer.destroy(); | |
| 35 | - } | |
| 36 | - if (typeof (this.height) == "undefined") { | |
| 37 | - this.height = false | |
| 38 | - } | |
| 39 | - this.easyPlayer = new WasmPlayer(null, 'easyplayer', this.eventcallbacK, {Height: this.height}) | |
| 40 | - this.easyPlayer.play(url, 1) | |
| 41 | - }, | |
| 42 | - pause: function () { | |
| 43 | - this.easyPlayer.destroy(); | |
| 44 | - this.easyPlayer = null | |
| 45 | - }, | |
| 46 | - eventcallbacK: function(type, message) { | |
| 47 | - // console.log("player 事件回调") | |
| 48 | - // console.log(type) | |
| 49 | - // console.log(message) | |
| 50 | - } | |
| 51 | - }, | |
| 52 | - destroyed() { | |
| 48 | + pause: function () { | |
| 53 | 49 | this.easyPlayer.destroy(); |
| 50 | + this.easyPlayer = null | |
| 54 | 51 | }, |
| 52 | + eventcallbacK: function (type, message) { | |
| 53 | + // console.log("player 事件回调") | |
| 54 | + // console.log(type) | |
| 55 | + // console.log(message) | |
| 56 | + } | |
| 57 | + }, | |
| 58 | + destroyed() { | |
| 59 | + this.easyPlayer.destroy(); | |
| 60 | + }, | |
| 55 | 61 | } |
| 56 | 62 | </script> |
| 57 | 63 | |
| 58 | 64 | <style> |
| 59 | - .LodingTitle { | |
| 60 | - min-width: 70px; | |
| 61 | - } | |
| 62 | - /* 隐藏logo */ | |
| 63 | - .iconqingxiLOGO { | |
| 64 | - display: none !important; | |
| 65 | - } | |
| 65 | +.LodingTitle { | |
| 66 | + min-width: 70px; | |
| 67 | +} | |
| 66 | 68 | |
| 69 | +/* 隐藏logo */ | |
| 70 | +.iconqingxiLOGO { | |
| 71 | + display: none !important; | |
| 72 | +} | |
| 67 | 73 | </style> | ... | ... |
web_src/src/components/common/jessibuca.vue
| 1 | 1 | <template> |
| 2 | 2 | <div ref="container" @dblclick="fullscreenSwich" |
| 3 | - style="width:100%; height: 100%; background-color: #000000;margin:0 auto;position: relative;"> | |
| 3 | + style="width:100%; height: 100%; background-color: #000000;margin:0 auto;position: relative;"> | |
| 4 | 4 | <div class="buttons-box" id="buttonsBox"> |
| 5 | 5 | <div class="buttons-box-left"> |
| 6 | 6 | <i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick"></i> |
| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | <!-- <i class="iconfont icon-file-record1 jessibuca-btn"></i>--> |
| 15 | 15 | <!-- <i class="iconfont icon-xiangqing2 jessibuca-btn" ></i>--> |
| 16 | 16 | <i class="iconfont icon-camera1196054easyiconnet jessibuca-btn" @click="screenshot" |
| 17 | - style="font-size: 1rem !important"></i> | |
| 17 | + style="font-size: 1rem !important"></i> | |
| 18 | 18 | <i class="iconfont icon-shuaxin11 jessibuca-btn" @click="playBtnClick"></i> |
| 19 | 19 | <i v-if="!fullscreen" class="iconfont icon-weibiaoti10 jessibuca-btn" @click="fullscreenSwich"></i> |
| 20 | 20 | <i v-if="fullscreen" class="iconfont icon-weibiaoti11 jessibuca-btn" @click="fullscreenSwich"></i> |
| ... | ... | @@ -24,6 +24,9 @@ |
| 24 | 24 | </template> |
| 25 | 25 | |
| 26 | 26 | <script> |
| 27 | +import watermark from '../../../utils/waterMark.js'; | |
| 28 | +import userService from '../service/UserService'; | |
| 29 | + | |
| 27 | 30 | let jessibucaPlayer = {}; |
| 28 | 31 | export default { |
| 29 | 32 | name: 'jessibuca', |
| ... | ... | @@ -43,6 +46,11 @@ export default { |
| 43 | 46 | rotate: 0, |
| 44 | 47 | vod: true, // 点播 |
| 45 | 48 | forceNoOffscreen: false, |
| 49 | + watermarkTimer: null, | |
| 50 | + config: { | |
| 51 | + userName: userService.getUser().username, | |
| 52 | + nowTime: "2024-03-01 12:00:00" | |
| 53 | + } // 水印 | |
| 46 | 54 | }; |
| 47 | 55 | }, |
| 48 | 56 | props: ['videoUrl', 'error', 'hasAudio', 'height'], |
| ... | ... | @@ -56,6 +64,7 @@ export default { |
| 56 | 64 | this.videoUrl = paramUrl; |
| 57 | 65 | } |
| 58 | 66 | this.btnDom = document.getElementById("buttonsBox"); |
| 67 | + this.watermarkTimer = watermark(this.$refs.container, this.config); | |
| 59 | 68 | }) |
| 60 | 69 | }, |
| 61 | 70 | // mounted() { |
| ... | ... | @@ -140,7 +149,7 @@ export default { |
| 140 | 149 | wcsUseVideoRender: true |
| 141 | 150 | }; |
| 142 | 151 | console.log("Jessibuca -> options: ", options); |
| 143 | - jessibucaPlayer[this._uid] = new window.Jessibuca({...options}); | |
| 152 | + jessibucaPlayer[this._uid] = new window.Jessibuca({ ...options }); | |
| 144 | 153 | |
| 145 | 154 | let jessibuca = jessibucaPlayer[this._uid]; |
| 146 | 155 | let _this = this; |
| ... | ... | @@ -267,6 +276,7 @@ export default { |
| 267 | 276 | this.playing = false; |
| 268 | 277 | this.loaded = false; |
| 269 | 278 | this.performance = ""; |
| 279 | + clearInterval(this.watermarkTimer); | |
| 270 | 280 | }, |
| 271 | 281 | } |
| 272 | 282 | </script> | ... | ... |
web_src/src/components/dialog/rtcPlayer.vue
| ... | ... | @@ -2,36 +2,49 @@ |
| 2 | 2 | <div id="rtcPlayer"> |
| 3 | 3 | <video id='webRtcPlayerBox' controls autoplay style="text-align:left;"> |
| 4 | 4 | Your browser is too old which doesn't support HTML5 video. |
| 5 | - </video> | |
| 5 | + </video> | |
| 6 | 6 | </div> |
| 7 | 7 | </template> |
| 8 | 8 | |
| 9 | 9 | <script> |
| 10 | +import watermark from '../../../utils/waterMark.js'; | |
| 11 | +import userService from '../service/UserService'; | |
| 10 | 12 | let webrtcPlayer = null; |
| 11 | 13 | export default { |
| 12 | 14 | name: 'rtcPlayer', |
| 13 | 15 | data() { |
| 14 | 16 | return { |
| 15 | - timer: null | |
| 17 | + timer: null, | |
| 18 | + watermarkTimer: null, | |
| 19 | + config: { | |
| 20 | + userName: userService.getUser().username, | |
| 21 | + nowTime: "2024-03-01 12:00:00" | |
| 22 | + } | |
| 16 | 23 | }; |
| 17 | 24 | }, |
| 18 | 25 | props: ['videoUrl', 'error', 'hasaudio'], |
| 19 | - mounted () { | |
| 20 | - let paramUrl = decodeURIComponent(this.$route.params.url) | |
| 21 | - this.$nextTick(() =>{ | |
| 22 | - if (typeof (this.videoUrl) == "undefined") { | |
| 23 | - this.videoUrl = paramUrl; | |
| 24 | - } | |
| 25 | - console.log("初始化时的地址为: " + this.videoUrl) | |
| 26 | - this.play(this.videoUrl) | |
| 26 | + mounted() { | |
| 27 | + let paramUrl = decodeURIComponent(this.$route.params.url) | |
| 28 | + this.$nextTick(() => { | |
| 29 | + if (typeof (this.videoUrl) == "undefined") { | |
| 30 | + this.videoUrl = paramUrl; | |
| 31 | + } | |
| 32 | + console.log("初始化时的地址为: " + this.videoUrl) | |
| 33 | + this.play(this.videoUrl) | |
| 27 | 34 | }) |
| 28 | 35 | }, |
| 29 | - watch:{ | |
| 30 | - videoUrl(newData, oldData){ | |
| 36 | + watch: { | |
| 37 | + videoUrl(newData, oldData) { | |
| 31 | 38 | this.pause(); |
| 32 | 39 | this.play(newData); |
| 33 | 40 | }, |
| 34 | - immediate:true | |
| 41 | + immediate: true | |
| 42 | + }, | |
| 43 | + created() { | |
| 44 | + this.$nextTick(() => { | |
| 45 | + this.rtcPlayer = document.getElementById("rtcPlayer"); | |
| 46 | + this.watermarkTimer = watermark(this.rtcPlayer, this.config); | |
| 47 | + }) | |
| 35 | 48 | }, |
| 36 | 49 | methods: { |
| 37 | 50 | play: function (url) { |
| ... | ... | @@ -45,22 +58,22 @@ export default { |
| 45 | 58 | videoEnable: true, |
| 46 | 59 | recvOnly: true, |
| 47 | 60 | }) |
| 48 | - webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,(e)=>{// ICE 协商出错 | |
| 61 | + webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, (e) => {// ICE 协商出错 | |
| 49 | 62 | console.error('ICE 协商出错') |
| 50 | 63 | this.eventcallbacK("ICE ERROR", "ICE 协商出错") |
| 51 | 64 | }); |
| 52 | 65 | |
| 53 | - webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,(e)=>{//获取到了远端流,可以播放 | |
| 54 | - console.log('播放成功',e.streams) | |
| 66 | + webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, (e) => {//获取到了远端流,可以播放 | |
| 67 | + console.log('播放成功', e.streams) | |
| 55 | 68 | this.eventcallbacK("playing", "播放成功") |
| 56 | 69 | }); |
| 57 | 70 | |
| 58 | - webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED,(e)=>{// offer anwser 交换失败 | |
| 59 | - console.error('offer anwser 交换失败',e) | |
| 71 | + webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, (e) => {// offer anwser 交换失败 | |
| 72 | + console.error('offer anwser 交换失败', e) | |
| 60 | 73 | this.eventcallbacK("OFFER ANSWER ERROR ", "offer anwser 交换失败") |
| 61 | - if (e.code ==-400 && e.msg=="流不存在"){ | |
| 74 | + if (e.code == -400 && e.msg == "流不存在") { | |
| 62 | 75 | console.log("流不存在") |
| 63 | - this.timer = setTimeout(()=>{ | |
| 76 | + this.timer = setTimeout(() => { | |
| 64 | 77 | this.webrtcPlayer.close(); |
| 65 | 78 | this.play(url) |
| 66 | 79 | }, 100) |
| ... | ... | @@ -68,7 +81,7 @@ export default { |
| 68 | 81 | } |
| 69 | 82 | }); |
| 70 | 83 | |
| 71 | - webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,(s)=>{// 获取到了本地流 | |
| 84 | + webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM, (s) => {// 获取到了本地流 | |
| 72 | 85 | |
| 73 | 86 | // document.getElementById('selfVideo').srcObject=s; |
| 74 | 87 | this.eventcallbacK("LOCAL STREAM", "获取到了本地流") |
| ... | ... | @@ -82,7 +95,7 @@ export default { |
| 82 | 95 | } |
| 83 | 96 | |
| 84 | 97 | }, |
| 85 | - eventcallbacK: function(type, message) { | |
| 98 | + eventcallbacK: function (type, message) { | |
| 86 | 99 | console.log("player 事件回调") |
| 87 | 100 | console.log(type) |
| 88 | 101 | console.log(message) |
| ... | ... | @@ -90,25 +103,28 @@ export default { |
| 90 | 103 | }, |
| 91 | 104 | destroyed() { |
| 92 | 105 | clearTimeout(this.timer); |
| 106 | + clearInterval(this.watermarkTimer); | |
| 93 | 107 | }, |
| 94 | 108 | } |
| 95 | 109 | </script> |
| 96 | 110 | |
| 97 | 111 | <style> |
| 98 | - .LodingTitle { | |
| 99 | - min-width: 70px; | |
| 100 | - } | |
| 101 | - #rtcPlayer{ | |
| 102 | - width: 100%; | |
| 103 | - } | |
| 104 | - #webRtcPlayerBox{ | |
| 105 | - width: 100%; | |
| 106 | - max-height: 56vh; | |
| 107 | - background-color: #000; | |
| 108 | - } | |
| 109 | - /* 隐藏logo */ | |
| 110 | - /* .iconqingxiLOGO { | |
| 112 | +.LodingTitle { | |
| 113 | + min-width: 70px; | |
| 114 | +} | |
| 115 | + | |
| 116 | +#rtcPlayer { | |
| 117 | + width: 100%; | |
| 118 | +} | |
| 119 | + | |
| 120 | +#webRtcPlayerBox { | |
| 121 | + width: 100%; | |
| 122 | + max-height: 56vh; | |
| 123 | + background-color: #000; | |
| 124 | +} | |
| 125 | + | |
| 126 | +/* 隐藏logo */ | |
| 127 | +/* .iconqingxiLOGO { | |
| 111 | 128 | display: none !important; |
| 112 | 129 | } */ |
| 113 | - | |
| 114 | 130 | </style> | ... | ... |