Commit 0a54817f authored by zhanglw's avatar zhanglw

安全帽sip语音通信

parent 33f3923a
...@@ -5,14 +5,14 @@ ENV = 'development' ...@@ -5,14 +5,14 @@ ENV = 'development'
#VUE_APP_BASE_API = 'http://39.164.225.220:5002' #VUE_APP_BASE_API = 'http://39.164.225.220:5002'
#VUE_APP_LOCAL_API = 'http://39.164.225.220:5002' #VUE_APP_LOCAL_API = 'http://39.164.225.220:5002'
VUE_APP_BASE_API = 'http://192.168.3.23:9092' #VUE_APP_BASE_API = 'http://192.168.3.23:9092'
VUE_APP_LOCAL_API = 'http://192.168.3.23:9092' #VUE_APP_LOCAL_API = 'http://192.168.3.23:9092'
#VUE_APP_BASE_API = 'http://192.168.3.216:9092' VUE_APP_BASE_API = 'http://192.168.3.216:9092'
#VUE_APP_LOCAL_API = 'http://192.168.3.216:9092' VUE_APP_LOCAL_API = 'http://192.168.3.216:9092'
VUE_APP_LOCAL_API2 = 'http://8.143.203.103:9091/' VUE_APP_LOCAL_API2 = 'http://192.168.3.216:9092/'
VUE_APP_WS_API = 'ws://8.143.203.103:9092/webSocket' VUE_APP_WS_API = 'ws://192.168.3.216:9092/webSocket'
# 是否启用 babel-plugin-dynamic-import-node插件 # 是否启用 babel-plugin-dynamic-import-node插件
VUE_CLI_BABEL_TRANSPILE_MODULES = true VUE_CLI_BABEL_TRANSPILE_MODULES = true
...@@ -3000,6 +3000,22 @@ var HttpReq = function(){ ...@@ -3000,6 +3000,22 @@ var HttpReq = function(){
responseType: 'blob' responseType: 'blob'
}) })
}, },
//获取安全帽拨号通话sip相关信息
propleGetSipInfo: function(param){
return request({
url: '/tab/perequipment/getdevicemsg',
method: 'get',
params:param,
})
},
//获取安全帽SOS通话sip相关信息
propleGetSOSSipInfo: function(param){
return request({
url: '/tab/perequipment/getdeviceroomid',
method: 'get',
params:param,
})
},
propleGetHisout: function(param){ propleGetHisout: function(param){
return request({ return request({
url: '/tab/perhis/hisout', url: '/tab/perhis/hisout',
...@@ -3150,7 +3166,6 @@ var HttpReq = function(){ ...@@ -3150,7 +3166,6 @@ var HttpReq = function(){
}, },
......
<template> <template>
<section class="app-main"> <section class="app-main">
<dial-view ref="dialView" />
<transition name="fade-transform" mode="out-in"> <transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews"> <keep-alive :include="cachedViews">
<router-view :key="key" /> <router-view :key="key" />
...@@ -12,14 +13,16 @@ ...@@ -12,14 +13,16 @@
</div> --> </div> -->
<!-- <div class="page-inline"> <!-- <div class="page-inline">
</div> --> </div> -->
</section> </section>
</template> </template>
<script> <script>
import dialView from "./dialView";
export default { export default {
name: 'AppMain', name: 'AppMain',
components: { dialView },
computed: { computed: {
cachedViews() { cachedViews() {
return this.$store.state.tagsView.cachedViews return this.$store.state.tagsView.cachedViews
...@@ -27,7 +30,15 @@ export default { ...@@ -27,7 +30,15 @@ export default {
key() { key() {
return this.$route.path return this.$route.path
} }
} },
mounted() {
this.$nextTick(() => {
this.$refs.dialView.init()
// setTimeout(()=>{
// this.$refs.dialView.init('123456')
// },5000)
})
},
} }
</script> </script>
...@@ -52,7 +63,7 @@ export default { ...@@ -52,7 +63,7 @@ export default {
.hasTagsView { .hasTagsView {
.app-main { .app-main {
/* 84 = navbar + tags-view = 50 + 34 /* 84 = navbar + tags-view = 50 + 34
min-height: calc(100vh - 84px);*/ min-height: calc(100vh - 84px);*/
} }
......
<template>
<!-- 表单渲染 -->
<div ref="dragArea" v-show="visible" class="fixed-View" :class="isMousedown?'grabbing':'grab'">
<div class="fixed-View-subTitle">安全帽SOS请求通话:</div>
<div v-show="status" class="corrugation">
<span style="--d: 7"></span>
<span style="--d: 6"></span>
<span style="--d: 5"></span>
<span style="--d: 4"></span>
<span style="--d: 3"></span>
<span style="--d: 2"></span>
<span style="--d: 1"></span>
<span style="--d: 0"></span>
<span style="--d: 1"></span>
<span style="--d: 2"></span>
<span style="--d: 3"></span>
<span style="--d: 4"></span>
<span style="--d: 5"></span>
<span style="--d: 6"></span>
<span style="--d: 7"></span>
</div>
<div v-show="!status" class="corrugation-s">
<span style="--d: 7"></span>
<span style="--d: 6"></span>
<span style="--d: 5"></span>
<span style="--d: 4"></span>
<span style="--d: 3"></span>
<span style="--d: 2"></span>
<span style="--d: 1"></span>
<span style="--d: 0"></span>
<span style="--d: 1"></span>
<span style="--d: 2"></span>
<span style="--d: 3"></span>
<span style="--d: 4"></span>
<span style="--d: 5"></span>
<span style="--d: 6"></span>
<span style="--d: 7"></span>
</div>
<div style="text-align: center">
<i v-if="status" class="el-icon-phone-outline el-icon--left"/>
<i v-else class="el-icon-phone el-icon--left"/>
{{ message }}
</div>
<audio id="audioElement"></audio>
<audio id="localVideo"></audio>
<div class="fixed-footer" style="text-align: center">
<el-button type="success" style="width:120px;font-size:20px" @click="uaCall">接听<i class="el-icon-video-play el-icon--right"></i></el-button>
<el-button type="danger" style="width:120px;font-size:20px" @click="uaHangup">挂断<i class="el-icon-video-pause el-icon--right"></i></el-button>
<el-button style="width:120px;font-size:20px" @click="cancelView">关闭<i class="el-icon-circle-close el-icon--right"></i></el-button>
</div>
</div>
</template>
<script>
import {HttpReq} from '@/assets/js/common.js';
import JsSIP from 'jssip'
export default {
data() {
return {
isMousedown: false,
visible: false,
title: '安全帽SOS请求通话',
userAgent: null,
session: null,
uaSipInfo: null,
callSipId: null,
status: 0,
isReady: false,
message: '正在建立链接,等待服务器响应...',
sosDialTimer: null
}
},
mounted() {
this.$nextTick(() => {
// 获取DOM元素
const dragArea = this.$refs.dragArea
// 缓存 clientX clientY 的对象: 用于判断是点击事件还是移动事件
const clientOffset = {}
dragArea.addEventListener('mousedown', (event) => {
this.isMousedown = true
// const offsetX = dragArea.getBoundingClientRect().left // 获取当前的x轴距离
const offsetY = dragArea.getBoundingClientRect().top // 获取当前的y轴距离
// const innerX = event.clientX - offsetX // 获取鼠标在方块内的x轴距
const innerY = event.clientY - offsetY // 获取鼠标在方块内的y轴距
// 缓存 clientX clientY
clientOffset.clientX = event.clientX
clientOffset.clientY = event.clientY
document.onmousemove = (event) => {
// dragArea.style.left = event.clientX - innerX + 'px'
dragArea.style.top = event.clientY - innerY + 'px'
const dragAreaTop = window.innerHeight - dragArea.getBoundingClientRect().height
// const dragAreaLeft = window.innerWidth - dragArea.getBoundingClientRect().width - 160
// if (dragArea.getBoundingClientRect().left <= 0) {
// dragArea.style.left = '0px'
// }
// if (dragArea.getBoundingClientRect().left >= dragAreaLeft) {
// dragArea.style.left = dragAreaLeft + 'px'
// }
if (dragArea.getBoundingClientRect().top <= 100) {
dragArea.style.top = '100px'
}
if (dragArea.getBoundingClientRect().top >= dragAreaTop) {
dragArea.style.top = dragAreaTop + 'px'
}
}
document.onmouseup = () => {
document.onmousemove = null
document.onmouseup = null
this.isMousedown = false
}
}, false)
// 绑定鼠标松开事件
dragArea.addEventListener('mouseup', (event) => {
// const clientX = event.clientX
// const clientY = event.clientY
// if (clientX === clientOffset.clientX && clientY === clientOffset.clientY) {
// console.log('click 事件')
// } else {
// console.log('drag 事件')
// }
})
})
},
methods: {
uaRegister() {
let sip_uri_ = `sip:${this.uaSipInfo.adminsip_id}@${this.uaSipInfo.adminwsip_host}`;
let sip_password_ = `${this.uaSipInfo.adminsip_pwd}`;
let ws_uri_ = `${this.uaSipInfo.adminwss_url}`;
console.info("get input info: sip_uri = ", sip_uri_, " sip_password = ", sip_password_, " ws_uri = ", ws_uri_);
let socket = new JsSIP.WebSocketInterface(ws_uri_);
let configuration = {
sockets: [socket],
uri: sip_uri_,
password: sip_password_,
session_timers: false, // 启用会话计时器(根据RFC 4028)
user_agent: "Aegis WebRTC v1.0",
contact_uri: sip_uri_,
autostart: true, // 自动连接
register: true, // 自动就绪
};
this.userAgent = new JsSIP.UA(configuration);
this.userAgent.on("connecting", (args) => {
this.message = `开始尝试连接...`;
console.info("开始尝试连接", args);
});
this.userAgent.on('registered', (data) => {
console.info("registered: ", data.response.status_code, ",", data.response.reason_phrase);
this.message = `监测到安全帽SOS通话请求,请接听...`;
this.isReady = true
});
this.userAgent.on('registrationFailed', (data) => {
console.log("registrationFailed, ", data);
});
this.userAgent.on('registrationExpiring', () => {
console.warn("registrationExpiring");
});
this.userAgent.on('newRTCSession', (e) => {
this.message = `注意:您有新的${e.originator === "local" ? "外呼" : "来电"}`;
console.log(`新的${e.originator === "local" ? "外呼" : "来电"}`, e);
const session = e.session;
this.session = session;
const peerconnection = session.connection;
if (e.originator === "local") {
// 打电话
peerconnection.addEventListener("addstream", (event) => {
const audio = document.getElementById("audioElement");
audio.srcObject = event.stream;
});
} else {
document.getElementById("localVideo").play();
// 接电话
this.dialogVisible = true;
this.isg = true;
this.callers = session.remote_identity.uri.user;
}
// 接通,在这一步可以处理音频播放
// 接通并不代表对方已经接受,接通代表 滴 滴 滴
session.on("confirmed", () => {
console.info("接通中");
this.message = `已接通,请通话...`;
this.status = 1;
const audioElement = document.getElementById("audioElement");
audioElement.autoplay = true;
const stream = new MediaStream();
const receivers = session.connection.getReceivers();
if (receivers) {
receivers.forEach((receiver) => stream.addTrack(receiver.track));
}
audioElement.srcObject = stream;
audioElement.play();
});
// 接听失败
session.on("failed", (mdata) => {
const myAuto = document.getElementById("localVideo");
myAuto.pause();
myAuto.load();
this.message = `来电的时拒接或,未接听对方就挂断...`;
console.info("来电的时候 拒接或者 还没接听对方自己就挂断了");
});
// 接听成功
session.on("accepted", (response, cause) => {
// 嘟嘟嘟
this.message = `接听成功...`;
this.status = 1;
console.info("接听成功");
});
// 接听成功后 挂断
session.on("ended", () => {
this.dialogVisible = false;
this.InCall = false;
});
// 通话被挂起
session.on("hold", (data) => {
const org = data.originator;
if (org === "local") {
this.message = `通话被本地挂起...`;
console.log("通话被本地挂起:", org);
} else {
this.message = `通话被对方挂起...`;
console.log("通话被对方挂起:", org);
}
});
// 通话被继续
session.on("unhold", (data) => {
const org = data.originator;
if (org === "local") {
} else {
this.message = `对方要求继续通话...`;
console.log("对方要求继续通话:", org);
}
});
});
this.userAgent.on('newMessage', (data) => {
if (data.originator == 'local') {
console.info('onNewMessage , OutgoingRequest - ', data.request);
} else {
console.info('onNewMessage , IncomingRequest - ', data.request);
}
});
console.info("call register");
this.userAgent.start();
},
uaCall() {
if (this.isReady || this.userAgent) {
let sip_phone_number_ = `sip:${this.uaSipInfo.room_id}@${this.uaSipInfo.adminwsip_host}`;
let options = {
'pcConfig': {
'rtcpMuxPolicy': "negotiate",
},
'rtcOfferConstraints': {
'offerToReceiveAudio': '1',
'offerToReceiveVideo': '0',
},
'eventHandlers': {
'progress': (e) => {
console.log('call is in progress');
},
'failed': (e) => {
console.log('call failed: ', e);
},
'ended': (e) => {
console.log('call ended : ', e);
console.log('通话结束');
this.message = `通话结束...`
this.status = 0
this.isReady = false
},
'confirmed': (e) => {
console.log('call confirmed');
}
},
'mediaConstraints': {
'audio': true,
'video': false,
},
};
this.userAgent.call(sip_phone_number_, options);
} else {
this.$message({
message: "尚未建立链接无法拨号通话,请确保链接通畅且对方在线!",
type: 'error'
});
}
},
uaHangup() {
if (this.isReady || this.userAgent) {
this.isReady = false
this.userAgent.terminateSessions();
const myAuto = document.getElementById("localVideo");
myAuto.pause();
myAuto.load();
const audioElement = document.getElementById("audioElement");
audioElement.pause();
audioElement.load();
}
},
init() {
this.message = '正在建立链接,等待服务器响应...'
this.sosDialTimer = setInterval(() => {
if (this.isReady) {
return
}
HttpReq.truckDispatching.propleGetSOSSipInfo({}).then((res) => {
if (res.msg) {
this.$notify({
title: res.msg,
type: 'error',
});
}
if (res.data && res.data.room_id) {
this.uaSipInfo = res.data
this.showView()
this.uaRegister()
}
})
}, 5000)
},
showView() {
this.visible = true
},
hideView() {
this.visible = false
this.uaHangup()
},
cancelView() {
this.hideView()
}
},
beforeDestroy() {
this.hideView()
if (this.sosDialTimer) {
clearInterval(this.sosDialTimer);
this.sosDialTimer = null;
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.touch {
cursor: pointer;
}
.grab {
cursor: grab;
}
.grabbing {
cursor: grabbing;
}
.fixed-View {
position: fixed;
margin-left: 0;
padding: 10px;
width: 520px;
height: 226px;
right: 1vw;
bottom: 6vh;
background: #FFFFFF;
border: 1px solid rgba(0, 0, 0, 0.8);
box-shadow: 1px 2px 8px 0 rgba(0, 0, 0, 0.8);
border-radius: 10px;
font-weight: 400;
user-select: none;
z-index: 99;
.cell-input {
margin: 5px 0;
}
.fixed-footer {
width: 100%;
padding: 20px;
}
.fixed-View-subTitle {
color: #333;
font-size: 18px;
padding-top: 10px;
padding-bottom: 5px;
}
.fixed-View-btn {
padding: 10px;
width: 100%;
text-align: center;
.btn {
margin: auto;
width: 140px;
padding: 6px;
background: #0156E5;
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 5px;
color: white;
font-size: 16px;
opacity: 0.8;
}
.btn:hover {
opacity: 1;
}
}
.fixed-View-title {
text-align: center;
color: #0342AB;
font-size: 20px;
}
.fixed-View-location {
height: 38px;
position: relative;
color: #666;
font-size: 16px;
img {
position: absolute;
top: 9px;
left: 236px;
}
div {
position: absolute;
top: 12px;
left: 260px;
}
}
}
.corrugation-s {
height: 80px;
width: 118px;
margin: auto;
display: flex;
align-items: center;
position: relative;
}
.corrugation-s span {
background: linear-gradient(to top, #d299c2 0%, #fef9d7 100%);
width: 4px;
height: 60%;
border-radius: 4px;
margin-right: 4px;
}
.corrugation-s span:last-child {
margin-right: 0;
}
.corrugation {
height: 80px;
width: 118px;
margin: auto;
display: flex;
align-items: center;
position: relative;
}
.corrugation span {
background: linear-gradient(to top, #d299c2 0%, #fef9d7 100%);
width: 4px;
height: 20%;
border-radius: 10px;
margin-right: 4px;
animation: loading 2.5s infinite linear;
animation-delay: calc(0.2s * var(--d));
}
.corrugation span:last-child {
margin-right: 0;
}
@keyframes loading {
0% {
background-image: linear-gradient(to right, #fa709a 0%, #fee140 100%);
height: 20%;
border-radius: calc(var(--h) * 0.2 * 0.5);
}
50% {
background-image: linear-gradient(to top, #d299c2 0%, #fef9d7 100%);
height: 100%;
border-radius: calc(var(--h) * 1 * 0.5);
}
100% {
background-image: linear-gradient(to top, #a8edea 0%, #fed6e3 100%);
height: 20%;
border-radius: calc(var(--h) * 0.2 * 0.5);
}
}
</style>
<template>
<!-- 表单渲染 -->
<el-dialog append-to-body :close-on-click-modal="false" destroy-on-close :before-close="cancelView" :visible="visible" :title="title" width="520px">
<div v-show="status" class="corrugation">
<span style="--d: 7"></span>
<span style="--d: 6"></span>
<span style="--d: 5"></span>
<span style="--d: 4"></span>
<span style="--d: 3"></span>
<span style="--d: 2"></span>
<span style="--d: 1"></span>
<span style="--d: 0"></span>
<span style="--d: 1"></span>
<span style="--d: 2"></span>
<span style="--d: 3"></span>
<span style="--d: 4"></span>
<span style="--d: 5"></span>
<span style="--d: 6"></span>
<span style="--d: 7"></span>
</div>
<div v-show="!status" class="corrugation-s">
<span style="--d: 7"></span>
<span style="--d: 6"></span>
<span style="--d: 5"></span>
<span style="--d: 4"></span>
<span style="--d: 3"></span>
<span style="--d: 2"></span>
<span style="--d: 1"></span>
<span style="--d: 0"></span>
<span style="--d: 1"></span>
<span style="--d: 2"></span>
<span style="--d: 3"></span>
<span style="--d: 4"></span>
<span style="--d: 5"></span>
<span style="--d: 6"></span>
<span style="--d: 7"></span>
</div>
<div style="text-align: center">
<i v-if="status" class="el-icon-phone-outline el-icon--left" />
<i v-else class="el-icon-phone el-icon--left" />
{{message}}
</div>
<audio id="audioElement"></audio>
<audio id="localVideo"></audio>
<div slot="footer" class="dialog-footer" style="text-align: center">
<el-button type="success" style="width:120px;font-size:20px" @click="uaCall">拨号<i class="el-icon-video-play el-icon--right"></i></el-button>
<el-button type="danger" style="width:120px;font-size:20px" @click="uaHangup">挂断<i class="el-icon-video-pause el-icon--right"></i></el-button>
<el-button style="width:120px;font-size:20px" @click="cancelView">关闭<i class="el-icon-circle-close el-icon--right"></i></el-button>
</div>
</el-dialog>
</template>
<script>
import {HttpReq} from '@/assets/js/common.js';
import JsSIP from 'jssip'
export default {
data() {
return {
visible: false,
title: '安全帽语音通话',
userAgent: null,
session: null,
uaSipInfo: {},
status: 0,
isReady: false,
message: '正在建立链接,等待服务器响应...'
}
},
mounted() {
this.$nextTick(() => {
})
},
methods: {
uaRegister() {
let sip_uri_ = `sip:${this.uaSipInfo.adminsip_id}@${this.uaSipInfo.adminwsip_host}`;
let sip_password_ = `${this.uaSipInfo.adminsip_pwd}`;
let ws_uri_ = `${this.uaSipInfo.adminwss_url}`;
console.info("get input info: sip_uri = ", sip_uri_, " sip_password = ", sip_password_, " ws_uri = ", ws_uri_);
let socket = new JsSIP.WebSocketInterface(ws_uri_);
let configuration = {
sockets: [socket],
uri: sip_uri_,
password: sip_password_,
session_timers: false, // 启用会话计时器(根据RFC 4028)
user_agent: "Aegis WebRTC v1.0",
contact_uri: sip_uri_,
autostart: true, // 自动连接
register: true, // 自动就绪
};
this.userAgent = new JsSIP.UA(configuration);
this.userAgent.on("connecting", (args) => {
this.message = `开始尝试连接...`;
console.info("开始尝试连接", args);
});
this.userAgent.on('registered', (data) => {
console.info("registered: ", data.response.status_code, ",", data.response.reason_phrase);
this.message = `已接通到服务器,监测到对方安全帽在线,请拨号...`;
this.isReady = true
});
this.userAgent.on('registrationFailed', (data) => {
console.log("registrationFailed, ", data);
});
this.userAgent.on('registrationExpiring', () => {
console.warn("registrationExpiring");
});
this.userAgent.on('newRTCSession', (e) => {
this.message = `注意:您有新的${e.originator === "local" ? "外呼" : "来电"}`;
console.log(`新的${e.originator === "local" ? "外呼" : "来电"}`, e);
const session = e.session;
this.session = session;
const peerconnection = session.connection;
if (e.originator === "local") {
// 打电话
peerconnection.addEventListener("addstream", (event) => {
const audio = document.getElementById("audioElement");
audio.srcObject = event.stream;
});
} else {
document.getElementById("localVideo").play();
// 接电话
this.dialogVisible = true;
this.isg = true;
this.callers = session.remote_identity.uri.user;
}
// 接通,在这一步可以处理音频播放
// 接通并不代表对方已经接受,接通代表 滴 滴 滴
session.on("confirmed", () => {
console.info("接通中");
this.message = `已接通,请通话...`;
this.status = 1;
const audioElement = document.getElementById("audioElement");
audioElement.autoplay = true;
const stream = new MediaStream();
const receivers = session.connection.getReceivers();
if (receivers) {
receivers.forEach((receiver) => stream.addTrack(receiver.track));
}
audioElement.srcObject = stream;
audioElement.play();
});
// 接听失败
session.on("failed", (mdata) => {
const myAuto = document.getElementById("localVideo");
myAuto.pause();
myAuto.load();
this.message = `来电的时拒接或,未接听对方就挂断...`;
console.info("来电的时候 拒接或者 还没接听对方自己就挂断了");
});
// 接听成功
session.on("accepted", (response, cause) => {
// 嘟嘟嘟
this.message = `接听成功...`;
this.status = 1;
console.info("接听成功");
});
// 接听成功后 挂断
session.on("ended", () => {
this.dialogVisible = false;
this.InCall = false;
});
// 通话被挂起
session.on("hold", (data) => {
const org = data.originator;
if (org === "local") {
this.message = `通话被本地挂起...`;
console.log("通话被本地挂起:", org);
} else {
this.message = `通话被对方挂起...`;
console.log("通话被对方挂起:", org);
}
});
// 通话被继续
session.on("unhold", (data) => {
const org = data.originator;
if (org === "local") {
} else {
this.message = `对方要求继续通话...`;
console.log("对方要求继续通话:", org);
}
});
});
this.userAgent.on('newMessage', (data) => {
if (data.originator == 'local') {
console.info('onNewMessage , OutgoingRequest - ', data.request);
} else {
console.info('onNewMessage , IncomingRequest - ', data.request);
}
});
console.info("call register");
this.userAgent.start();
},
uaCall() {
if(this.isReady || this.userAgent){
let sip_phone_number_ = `sip:${this.uaSipInfo.sip_id}@${this.uaSipInfo.adminwsip_host}`;
let options = {
'pcConfig': {
'rtcpMuxPolicy': "negotiate",
},
'rtcOfferConstraints': {
'offerToReceiveAudio': '1',
'offerToReceiveVideo': '0',
},
'eventHandlers': {
'progress': (e) => {
console.log('call is in progress');
},
'failed': (e) => {
console.log('call failed: ', e);
},
'ended': (e) => {
console.log('call ended : ', e);
console.log('通话结束');
this.message = `通话结束...`
this.status = 0
this.isReady = false
},
'confirmed': (e) => {
console.log('call confirmed');
}
},
'mediaConstraints': {
'audio': true,
'video': false,
},
};
this.userAgent.call(sip_phone_number_, options);
} else {
this.$message({
message: "尚未建立链接无法拨号通话,请确保链接通畅且对方在线!",
type: 'error'
});
}
},
uaHangup() {
if(this.isReady || this.userAgent){
console.log('主动挂断')
this.userAgent.terminateSessions();
const myAuto = document.getElementById("localVideo");
myAuto.pause();
myAuto.load();
const audioElement = document.getElementById("audioElement");
audioElement.pause();
audioElement.load();
} else {
this.$message({
message: "尚未建立通信链接!",
type: 'error'
});
}
},
init(safetyhatmac) {
this.showView()
this.message = '正在建立链接,等待服务器响应...'
HttpReq.truckDispatching.propleGetSipInfo({safetyhatmac}).then((res) => {
if(res.data){
this.uaSipInfo = res.data;
if(!this.uaSipInfo.sip_id){
this.message = '对方安全帽未在线,无法通话!!'
} else {
this.uaRegister()
}
}else{
this.message = '服务器通信失败!!'
this.$notify({
title: res.msg,
type: 'error',
});
}
})
},
showView() {
this.visible = true
},
hideView() {
this.visible = false
this.uaHangup()
},
cancelView() {
this.hideView()
}
},
beforeDestroy() {
this.hideView()
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.corrugation-s {
height: 80px;
width: 118px;
margin: auto;
display: flex;
align-items: center;
position: relative;
}
.corrugation-s span {
background: linear-gradient(to top, #d299c2 0%, #fef9d7 100%);
width: 4px;
height: 60%;
border-radius: 4px;
margin-right: 4px;
}
.corrugation-s span:last-child {
margin-right: 0;
}
.corrugation {
height: 80px;
width: 118px;
margin: auto;
display: flex;
align-items: center;
position: relative;
}
.corrugation span {
background: linear-gradient(to top, #d299c2 0%, #fef9d7 100%);
width: 4px;
height: 20%;
border-radius: 10px;
margin-right: 4px;
animation: loading 2.5s infinite linear;
animation-delay: calc(0.2s * var(--d));
}
.corrugation span:last-child {
margin-right: 0;
}
@keyframes loading {
0% {
background-image: linear-gradient(to right, #fa709a 0%, #fee140 100%);
height: 20%;
border-radius: calc(var(--h) * 0.2 * 0.5);
}
50% {
background-image: linear-gradient(to top, #d299c2 0%, #fef9d7 100%);
height: 100%;
border-radius: calc(var(--h) * 1 * 0.5);
}
100% {
background-image: linear-gradient(to top, #a8edea 0%, #fed6e3 100%);
height: 20%;
border-radius: calc(var(--h) * 0.2 * 0.5);
}
}
</style>
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
<el-table-column prop="phone" label="电话" align="center"></el-table-column> <el-table-column prop="phone" label="电话" align="center"></el-table-column>
<el-table-column label="操作" align="center" fixed="right"> <el-table-column label="操作" align="center" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
<span class="link-cell" @click="openDialView(scope.row)">实时通话</span>
<span class="link-cell" @click="openTrailView(scope.row)">轨迹回放</span> <span class="link-cell" @click="openTrailView(scope.row)">轨迹回放</span>
<span class="link-cell" @click="openPosView(scope.row)">轨迹数据</span> <span class="link-cell" @click="openPosView(scope.row)">轨迹数据</span>
<span v-show="scope.row.userid" class="link-cell" @click="openvideoView(scope.row)">视频回放</span> <span v-show="scope.row.userid" class="link-cell" @click="openvideoView(scope.row)">视频回放</span>
...@@ -104,6 +105,7 @@ ...@@ -104,6 +105,7 @@
</el-dialog> </el-dialog>
<!-- 视频 --> <!-- 视频 -->
<el-dialog append-to-body :close-on-click-modal="false" :before-close="cancelFormViedoRtc" :visible="videoRtc" title="实况" width="800px"> <el-dialog append-to-body :close-on-click-modal="false" :before-close="cancelFormViedoRtc" :visible="videoRtc" title="实况" width="800px">
<el-button style="position:absolute;top:70px;right:30px;z-index:99" @click="screenShot">截屏</el-button>
<video id="remoteVideo" controls style="width:100%;height:440px;"></video> <video id="remoteVideo" controls style="width:100%;height:440px;"></video>
</el-dialog> </el-dialog>
<el-dialog append-to-body :close-on-click-modal="false" :before-close="cancelFormViedo" :visible="videoDia" title="回放" width="800px"> <el-dialog append-to-body :close-on-click-modal="false" :before-close="cancelFormViedo" :visible="videoDia" title="回放" width="800px">
...@@ -153,7 +155,7 @@ ...@@ -153,7 +155,7 @@
<el-button type="primary" @click="nextP()">下一页<i class="el-icon-arrow-right el-icon--right"></i></el-button> <el-button type="primary" @click="nextP()">下一页<i class="el-icon-arrow-right el-icon--right"></i></el-button>
</div> </div>
</el-dialog> </el-dialog>
<dial-view ref="dialView" />
</div> </div>
</template> </template>
...@@ -163,15 +165,17 @@ import {JSWebrtc} from '@/assets/js/jswebrtc.js'; ...@@ -163,15 +165,17 @@ import {JSWebrtc} from '@/assets/js/jswebrtc.js';
import 'video.js/dist/video-js.css' import 'video.js/dist/video-js.css'
import videojs from 'video.js' import videojs from 'video.js'
import 'videojs-contrib-hls' import 'videojs-contrib-hls'
import html2canvas from 'html2canvas'
import mars3dViewerMap from "../../../components/mars3d/Map5.vue"; import mars3dViewerMap from "../../../components/mars3d/Map5.vue";
import * as mars3d from "mars3d"; import * as mars3d from "mars3d";
import * as Cesium from "mars3d-cesium"; import * as Cesium from "mars3d-cesium";
import peopleIcon from "../../../assets/images/point.png"; import peopleIcon from "../../../assets/images/point.png";
import dialView from "./dialView";
export default { export default {
name: 'peopleLogData', name: 'peopleLogData',
components: { components: {
mars3dViewerMap, mars3dViewerMap, dialView
}, },
data() { data() {
const basePathUrl = window.basePathUrl || '' const basePathUrl = window.basePathUrl || ''
...@@ -244,6 +248,10 @@ export default { ...@@ -244,6 +248,10 @@ export default {
this.map = map; this.map = map;
this.graphicLayer = graphicLayer; this.graphicLayer = graphicLayer;
}, },
openDialView(item) {
this.peoItem = item;
this.$refs.dialView.init(this.peoItem.safetyhatmac)
},
drawTrail() { drawTrail() {
let map = this.map; let map = this.map;
let graphicLayer = this.graphicLayer; let graphicLayer = this.graphicLayer;
...@@ -590,6 +598,30 @@ export default { ...@@ -590,6 +598,30 @@ export default {
} }
this.trailView = false; this.trailView = false;
}, },
// 视频截图
screenShot() {
let video = document.getElementById('remoteVideo')
html2canvas(video, {
allowTaint: true,
useCORS: true
}).then((canvas) => {
const capture = canvas.toDataURL('image/png')
const saveInfo = {
'download': `MAC_${this.peoItem.safetyhatmac}_${this.getNowTime()}.png`,
'href': capture
}
const element = document.createElement('a')
element.style.display = 'none'
for (const key in saveInfo) {
element.setAttribute(key, saveInfo[key])
}
document.body.appendChild(element)
element.click()
setTimeout(() => {
document.body.removeChild(element)
}, 300)
})
},
// 点击搜索 // 点击搜索
toSearch() { toSearch() {
this.page = 1; this.page = 1;
...@@ -626,6 +658,14 @@ export default { ...@@ -626,6 +658,14 @@ export default {
this.pageP += 1; this.pageP += 1;
this.loadDataP() this.loadDataP()
}, },
//获取当前时间
getNowTime() {
let date = new Date();
return '' + date.getFullYear() + this.addZero(date.getMonth() + 1) + this.addZero(date.getDate()) + this.addZero(date.getHours()) + this.addZero(date.getMinutes()) + this.addZero(date.getSeconds());
},
addZero(s) {
return s < 10 ? ('0' + s) : s;
},
}, },
} }
</script> </script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment