Browse Source
# Conflicts: # web_src/src/components/UiHeader.vue # web_src/src/components/devicePosition.vue # web_src/src/components/live.vue # web_src/src/router/index.jspull/446/head
648540858
3 years ago
17 changed files with 2317 additions and 2129 deletions
@ -1,349 +1,350 @@ |
|||
<template> |
|||
<div id="app"> |
|||
<el-container> |
|||
<el-header> |
|||
<uiHeader></uiHeader> |
|||
</el-header> |
|||
<el-main> |
|||
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> |
|||
<span style="font-size: 1rem; font-weight: bold;">设备列表</span> |
|||
<div style="position: absolute; right: 1rem; top: 0.3rem;"> |
|||
<el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading" @click="getDeviceList()"></el-button> |
|||
</div> |
|||
</div> |
|||
<!-- <devicePlayer ref="devicePlayer"></devicePlayer> --> |
|||
<!--设备列表--> |
|||
<el-table :data="deviceList" border style="width: 100%;font-size: 12px;" :height="winHeight"> |
|||
<el-table-column prop="name" label="名称" align="center"> |
|||
</el-table-column> |
|||
<el-table-column prop="deviceId" label="设备编号" width="180" align="center"> |
|||
</el-table-column> |
|||
<el-table-column label="地址" width="180" align="center"> |
|||
<template slot-scope="scope"> |
|||
<div slot="reference" class="name-wrapper"> |
|||
<el-tag size="medium">{{ scope.row.hostAddress }}</el-tag> |
|||
</div> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="manufacturer" label="厂家" align="center"> |
|||
</el-table-column> |
|||
<el-table-column label="流传输模式" align="center" width="120"> |
|||
<template slot-scope="scope"> |
|||
<el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择"> |
|||
<el-option key="UDP" label="UDP" value="UDP"></el-option> |
|||
<el-option key="TCP-ACTIVE" label="TCP主动模式" :disabled="true" value="TCP-ACTIVE"></el-option> |
|||
<el-option key="TCP-PASSIVE" label="TCP被动模式" value="TCP-PASSIVE"></el-option> |
|||
</el-select> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="channelCount" label="通道数" align="center"> |
|||
</el-table-column> |
|||
<el-table-column label="状态" width="120" align="center"> |
|||
<template slot-scope="scope"> |
|||
<div slot="reference" class="name-wrapper"> |
|||
<el-tag size="medium" v-if="scope.row.online == 1">在线</el-tag> |
|||
<el-tag size="medium" type="info" v-if="scope.row.online == 0">离线</el-tag> |
|||
</div> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="keepaliveTime" label="最近心跳" align="center" width="140"> |
|||
</el-table-column> |
|||
<el-table-column prop="registerTime" label="最近注册" align="center" width="140"> |
|||
</el-table-column> |
|||
<el-table-column prop="updateTime" label="更新时间" align="center" width="140"> |
|||
</el-table-column> |
|||
<el-table-column prop="createTime" label="创建时间" align="center" width="140"> |
|||
</el-table-column> |
|||
<div id="app" style="width: 100%"> |
|||
<div class="page-header"> |
|||
<div class="page-title">设备列表</div> |
|||
<div class="page-header-btn"> |
|||
<el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading" |
|||
@click="getDeviceList()"></el-button> |
|||
</div> |
|||
</div> |
|||
<!-- <devicePlayer ref="devicePlayer"></devicePlayer> --> |
|||
<!--设备列表--> |
|||
<el-table :data="deviceList" border style="width: 100%;font-size: 12px;" :height="winHeight"> |
|||
<el-table-column prop="name" label="名称" align="center"> |
|||
</el-table-column> |
|||
<el-table-column prop="deviceId" label="设备编号" width="180" align="center"> |
|||
</el-table-column> |
|||
<el-table-column label="地址" width="180" align="center"> |
|||
<template slot-scope="scope"> |
|||
<div slot="reference" class="name-wrapper"> |
|||
<el-tag size="medium">{{ scope.row.hostAddress }}</el-tag> |
|||
</div> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="manufacturer" label="厂家" align="center"> |
|||
</el-table-column> |
|||
<el-table-column label="流传输模式" align="center" width="120"> |
|||
<template slot-scope="scope"> |
|||
<el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择"> |
|||
<el-option key="UDP" label="UDP" value="UDP"></el-option> |
|||
<el-option key="TCP-ACTIVE" label="TCP主动模式" :disabled="true" value="TCP-ACTIVE"></el-option> |
|||
<el-option key="TCP-PASSIVE" label="TCP被动模式" value="TCP-PASSIVE"></el-option> |
|||
</el-select> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="channelCount" label="通道数" align="center"> |
|||
</el-table-column> |
|||
<el-table-column label="状态" width="120" align="center"> |
|||
<template slot-scope="scope"> |
|||
<div slot="reference" class="name-wrapper"> |
|||
<el-tag size="medium" v-if="scope.row.online == 1">在线</el-tag> |
|||
<el-tag size="medium" type="info" v-if="scope.row.online == 0">离线</el-tag> |
|||
</div> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="keepaliveTime" label="最近心跳" align="center" width="140"> |
|||
</el-table-column> |
|||
<el-table-column prop="registerTime" label="最近注册" align="center" width="140"> |
|||
</el-table-column> |
|||
<el-table-column prop="updateTime" label="更新时间" align="center" width="140"> |
|||
</el-table-column> |
|||
<el-table-column prop="createTime" label="创建时间" align="center" width="140"> |
|||
</el-table-column> |
|||
|
|||
<el-table-column label="操作" width="450" align="center" fixed="right"> |
|||
<template slot-scope="scope"> |
|||
<el-button size="mini" v-if="scope.row.online!=0" icon="el-icon-refresh" @click="refDevice(scope.row)" @mouseover="getTooltipContent(scope.row.deviceId)">刷新</el-button> |
|||
<el-button-group> |
|||
<el-button size="mini" icon="el-icon-video-camera-solid" v-bind:disabled="scope.row.online==0" type="primary" @click="showChannelList(scope.row)">通道</el-button> |
|||
<el-button size="mini" icon="el-icon-location" v-bind:disabled="scope.row.online==0" type="primary" @click="showDevicePosition(scope.row)">定位</el-button> |
|||
<el-button size="mini" icon="el-icon-edit" type="primary" @click="edit(scope.row)">编辑</el-button> |
|||
<el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteDevice(scope.row)">删除</el-button> |
|||
</el-button-group> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<el-pagination |
|||
style="float: right" |
|||
@size-change="handleSizeChange" |
|||
@current-change="currentChange" |
|||
:current-page="currentPage" |
|||
:page-size="count" |
|||
:page-sizes="[15, 25, 35, 50]" |
|||
layout="total, sizes, prev, pager, next" |
|||
:total="total"> |
|||
</el-pagination> |
|||
<deviceEdit ref="deviceEdit" ></deviceEdit> |
|||
<syncChannelProgress ref="syncChannelProgress" ></syncChannelProgress> |
|||
</el-main> |
|||
</el-container> |
|||
</div> |
|||
<el-table-column label="操作" width="450" align="center" fixed="right"> |
|||
<template slot-scope="scope"> |
|||
<el-button size="mini" v-if="scope.row.online!=0" icon="el-icon-refresh" @click="refDevice(scope.row)" |
|||
@mouseover="getTooltipContent(scope.row.deviceId)">刷新 |
|||
</el-button> |
|||
<el-button-group> |
|||
<el-button size="mini" icon="el-icon-video-camera-solid" v-bind:disabled="scope.row.online==0" |
|||
type="primary" @click="showChannelList(scope.row)">通道 |
|||
</el-button> |
|||
<el-button size="mini" icon="el-icon-location" v-bind:disabled="scope.row.online==0" type="primary" |
|||
@click="showDevicePosition(scope.row)">定位 |
|||
</el-button> |
|||
<el-button size="mini" icon="el-icon-edit" type="primary" @click="edit(scope.row)">编辑</el-button> |
|||
<el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteDevice(scope.row)">删除</el-button> |
|||
</el-button-group> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<el-pagination |
|||
style="float: right" |
|||
@size-change="handleSizeChange" |
|||
@current-change="currentChange" |
|||
:current-page="currentPage" |
|||
:page-size="count" |
|||
:page-sizes="[15, 25, 35, 50]" |
|||
layout="total, sizes, prev, pager, next" |
|||
:total="total"> |
|||
</el-pagination> |
|||
<deviceEdit ref="deviceEdit"></deviceEdit> |
|||
<syncChannelProgress ref="syncChannelProgress"></syncChannelProgress> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import uiHeader from './UiHeader.vue' |
|||
import deviceEdit from './dialog/deviceEdit.vue' |
|||
import syncChannelProgress from './dialog/SyncChannelProgress.vue' |
|||
export default { |
|||
name: 'app', |
|||
components: { |
|||
uiHeader, |
|||
deviceEdit, |
|||
syncChannelProgress, |
|||
}, |
|||
data() { |
|||
return { |
|||
deviceList: [], //设备列表 |
|||
currentDevice: {}, //当前操作设备对象 |
|||
import uiHeader from '../layout/UiHeader.vue' |
|||
import deviceEdit from './dialog/deviceEdit.vue' |
|||
import syncChannelProgress from './dialog/SyncChannelProgress.vue' |
|||
|
|||
videoComponentList: [], |
|||
updateLooper: 0, //数据刷新轮训标志 |
|||
currentDeviceChannelsLenth:0, |
|||
winHeight: window.innerHeight - 200, |
|||
currentPage:1, |
|||
count:15, |
|||
total:0, |
|||
getDeviceListLoading: false, |
|||
}; |
|||
}, |
|||
computed: { |
|||
getcurrentDeviceChannels: function() { |
|||
let data = this.currentDevice['channelMap']; |
|||
let channels = null; |
|||
if (data) { |
|||
channels = Object.keys(data).map(key => { |
|||
return data[key]; |
|||
}); |
|||
this.currentDeviceChannelsLenth = channels.length; |
|||
} |
|||
return channels; |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.initData(); |
|||
this.updateLooper = setInterval(this.initData, 10000); |
|||
}, |
|||
destroyed() { |
|||
this.$destroy('videojs'); |
|||
clearTimeout(this.updateLooper); |
|||
}, |
|||
methods: { |
|||
initData: function() { |
|||
this.getDeviceList(); |
|||
}, |
|||
currentChange: function(val){ |
|||
this.currentPage = val; |
|||
this.getDeviceList(); |
|||
}, |
|||
handleSizeChange: function(val){ |
|||
this.count = val; |
|||
this.getDeviceList(); |
|||
}, |
|||
getDeviceList: function() { |
|||
let that = this; |
|||
this.getDeviceListLoading = true; |
|||
this.$axios({ |
|||
method: 'get', |
|||
url:`/api/device/query/devices`, |
|||
params: { |
|||
page: that.currentPage, |
|||
count: that.count |
|||
} |
|||
}).then(function (res) { |
|||
that.total = res.data.total; |
|||
that.deviceList = res.data.list; |
|||
that.getDeviceListLoading = false; |
|||
}).catch(function (error) { |
|||
console.error(error); |
|||
that.getDeviceListLoading = false; |
|||
}); |
|||
export default { |
|||
name: 'app', |
|||
components: { |
|||
uiHeader, |
|||
deviceEdit, |
|||
syncChannelProgress, |
|||
}, |
|||
data() { |
|||
return { |
|||
deviceList: [], //设备列表 |
|||
currentDevice: {}, //当前操作设备对象 |
|||
|
|||
}, |
|||
deleteDevice: function(row) { |
|||
let msg = "确定删除此设备?" |
|||
if (row.online !== 0) { |
|||
msg = "在线设备删除后仍可通过注册再次上线。<br/>如需彻底删除请先将设备离线。<br/><strong>确定删除此设备?</strong>" |
|||
videoComponentList: [], |
|||
updateLooper: 0, //数据刷新轮训标志 |
|||
currentDeviceChannelsLenth: 0, |
|||
winHeight: window.innerHeight - 200, |
|||
currentPage: 1, |
|||
count: 15, |
|||
total: 0, |
|||
getDeviceListLoading: false, |
|||
}; |
|||
}, |
|||
computed: { |
|||
getcurrentDeviceChannels: function () { |
|||
let data = this.currentDevice['channelMap']; |
|||
let channels = null; |
|||
if (data) { |
|||
channels = Object.keys(data).map(key => { |
|||
return data[key]; |
|||
}); |
|||
this.currentDeviceChannelsLenth = channels.length; |
|||
} |
|||
return channels; |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.initData(); |
|||
this.updateLooper = setInterval(this.initData, 10000); |
|||
}, |
|||
destroyed() { |
|||
this.$destroy('videojs'); |
|||
clearTimeout(this.updateLooper); |
|||
}, |
|||
methods: { |
|||
initData: function () { |
|||
this.getDeviceList(); |
|||
}, |
|||
currentChange: function (val) { |
|||
this.currentPage = val; |
|||
this.getDeviceList(); |
|||
}, |
|||
handleSizeChange: function (val) { |
|||
this.count = val; |
|||
this.getDeviceList(); |
|||
}, |
|||
getDeviceList: function () { |
|||
let that = this; |
|||
this.getDeviceListLoading = true; |
|||
this.$axios({ |
|||
method: 'get', |
|||
url: `/api/device/query/devices`, |
|||
params: { |
|||
page: that.currentPage, |
|||
count: that.count |
|||
} |
|||
this.$confirm(msg, '提示', { |
|||
dangerouslyUseHTMLString : true, |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
center: true, |
|||
type: 'warning' |
|||
}).then(() => { |
|||
this.$axios({ |
|||
method: 'delete', |
|||
url:`/api/device/query/devices/${row.deviceId}/delete` |
|||
}).then((res)=>{ |
|||
this.getDeviceList(); |
|||
}).catch((error) =>{ |
|||
console.error(error); |
|||
}); |
|||
}).catch(() => { |
|||
}).then(function (res) { |
|||
that.total = res.data.total; |
|||
that.deviceList = res.data.list; |
|||
that.getDeviceListLoading = false; |
|||
}).catch(function (error) { |
|||
console.error(error); |
|||
that.getDeviceListLoading = false; |
|||
}); |
|||
|
|||
}, |
|||
deleteDevice: function (row) { |
|||
let msg = "确定删除此设备?" |
|||
if (row.online !== 0) { |
|||
msg = "在线设备删除后仍可通过注册再次上线。<br/>如需彻底删除请先将设备离线。<br/><strong>确定删除此设备?</strong>" |
|||
} |
|||
this.$confirm(msg, '提示', { |
|||
dangerouslyUseHTMLString: true, |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
center: true, |
|||
type: 'warning' |
|||
}).then(() => { |
|||
this.$axios({ |
|||
method: 'delete', |
|||
url: `/api/device/query/devices/${row.deviceId}/delete` |
|||
}).then((res) => { |
|||
this.getDeviceList(); |
|||
}).catch((error) => { |
|||
console.error(error); |
|||
}); |
|||
}).catch(() => { |
|||
|
|||
}); |
|||
|
|||
|
|||
}, |
|||
showChannelList: function(row) { |
|||
this.$router.push(`/channelList/${row.deviceId}/0/15/1`); |
|||
}, |
|||
showDevicePosition: function(row) { |
|||
this.$router.push(`/devicePosition/${row.deviceId}/0/15/1`); |
|||
}, |
|||
}, |
|||
showChannelList: function (row) { |
|||
this.$router.push(`/channelList/${row.deviceId}/0/15/1`); |
|||
}, |
|||
showDevicePosition: function (row) { |
|||
this.$router.push(`/devicePosition/${row.deviceId}/0/15/1`); |
|||
}, |
|||
|
|||
//gb28181平台对接 |
|||
//刷新设备信息 |
|||
refDevice: function(itemData) { |
|||
console.log("刷新对应设备:" + itemData.deviceId); |
|||
let that = this; |
|||
this.$axios({ |
|||
method: 'post', |
|||
url: '/api/device/query/devices/' + itemData.deviceId + '/sync' |
|||
}).then((res) => { |
|||
console.log("刷新设备结果:"+JSON.stringify(res)); |
|||
if (res.data.code !==0) { |
|||
that.$message({ |
|||
showClose: true, |
|||
message: res.data.msg, |
|||
type: 'error' |
|||
}); |
|||
}else{ |
|||
// that.$message({ |
|||
// showClose: true, |
|||
// message: res.data.msg, |
|||
// type: 'success' |
|||
// }); |
|||
this.$refs.syncChannelProgress.openDialog(itemData.deviceId) |
|||
} |
|||
that.initData() |
|||
}).catch((e) => { |
|||
console.error(e) |
|||
//gb28181平台对接 |
|||
//刷新设备信息 |
|||
refDevice: function (itemData) { |
|||
console.log("刷新对应设备:" + itemData.deviceId); |
|||
let that = this; |
|||
this.$axios({ |
|||
method: 'post', |
|||
url: '/api/device/query/devices/' + itemData.deviceId + '/sync' |
|||
}).then((res) => { |
|||
console.log("刷新设备结果:" + JSON.stringify(res)); |
|||
if (res.data.code !== 0) { |
|||
that.$message({ |
|||
showClose: true, |
|||
message: e, |
|||
message: res.data.msg, |
|||
type: 'error' |
|||
}); |
|||
}); |
|||
} else { |
|||
// that.$message({ |
|||
// showClose: true, |
|||
// message: res.data.msg, |
|||
// type: 'success' |
|||
// }); |
|||
this.$refs.syncChannelProgress.openDialog(itemData.deviceId) |
|||
} |
|||
that.initData() |
|||
}).catch((e) => { |
|||
console.error(e) |
|||
that.$message({ |
|||
showClose: true, |
|||
message: e, |
|||
type: 'error' |
|||
}); |
|||
}); |
|||
|
|||
}, |
|||
}, |
|||
|
|||
getTooltipContent: async function (deviceId){ |
|||
let result = ""; |
|||
await this.$axios({ |
|||
method: 'get', |
|||
async: false, |
|||
url:`/api/device/query/${deviceId}/sync_status/`, |
|||
}).then((res) => { |
|||
if (res.data.code == 0) { |
|||
if (res.data.data.errorMsg !== null) { |
|||
result = res.data.data.errorMsg |
|||
} else if (res.data.msg !== null) { |
|||
result = res.data.msg |
|||
} else { |
|||
result = `同步中...[${res.data.data.current}/${res.data.data.total}]`; |
|||
} |
|||
} |
|||
}) |
|||
return result; |
|||
}, |
|||
//通知设备上传媒体流 |
|||
sendDevicePush: function(itemData) { |
|||
// let deviceId = this.currentDevice.deviceId; |
|||
// let channelId = itemData.channelId; |
|||
// console.log("通知设备推流1:" + deviceId + " : " + channelId); |
|||
// let that = this; |
|||
// this.$axios({ |
|||
// method: 'get', |
|||
// url: '/api/play/' + deviceId + '/' + channelId |
|||
// }).then(function(res) { |
|||
// let ssrc = res.data.ssrc; |
|||
// that.$refs.devicePlayer.play(ssrc,deviceId,channelId); |
|||
// }).catch(function(e) { |
|||
// }); |
|||
}, |
|||
transportChange: function (row) { |
|||
console.log(`修改传输方式为 ${row.streamMode}:${row.deviceId} `); |
|||
let that = this; |
|||
this.$axios({ |
|||
method: 'post', |
|||
url: '/api/device/query/transport/' + row.deviceId + '/' + row.streamMode |
|||
}).then(function(res) { |
|||
getTooltipContent: async function (deviceId) { |
|||
let result = ""; |
|||
await this.$axios({ |
|||
method: 'get', |
|||
async: false, |
|||
url: `/api/device/query/${deviceId}/sync_status/`, |
|||
}).then((res) => { |
|||
if (res.data.code == 0) { |
|||
if (res.data.data.errorMsg !== null) { |
|||
result = res.data.data.errorMsg |
|||
} else if (res.data.msg !== null) { |
|||
result = res.data.msg |
|||
} else { |
|||
result = `同步中...[${res.data.data.current}/${res.data.data.total}]`; |
|||
} |
|||
} |
|||
}) |
|||
return result; |
|||
}, |
|||
//通知设备上传媒体流 |
|||
sendDevicePush: function (itemData) { |
|||
// let deviceId = this.currentDevice.deviceId; |
|||
// let channelId = itemData.channelId; |
|||
// console.log("通知设备推流1:" + deviceId + " : " + channelId); |
|||
// let that = this; |
|||
// this.$axios({ |
|||
// method: 'get', |
|||
// url: '/api/play/' + deviceId + '/' + channelId |
|||
// }).then(function(res) { |
|||
// let ssrc = res.data.ssrc; |
|||
// that.$refs.devicePlayer.play(ssrc,deviceId,channelId); |
|||
// }).catch(function(e) { |
|||
// }); |
|||
}, |
|||
transportChange: function (row) { |
|||
console.log(`修改传输方式为 ${row.streamMode}:${row.deviceId} `); |
|||
let that = this; |
|||
this.$axios({ |
|||
method: 'post', |
|||
url: '/api/device/query/transport/' + row.deviceId + '/' + row.streamMode |
|||
}).then(function (res) { |
|||
|
|||
}).catch(function(e) { |
|||
}).catch(function (e) { |
|||
}); |
|||
}, |
|||
edit: function (row) { |
|||
this.$refs.deviceEdit.openDialog(row, () => { |
|||
this.$refs.deviceEdit.close(); |
|||
this.$message({ |
|||
showClose: true, |
|||
message: "设备修改成功,通道字符集将在下次更新生效", |
|||
type: "success", |
|||
}); |
|||
}, |
|||
edit: function (row) { |
|||
this.$refs.deviceEdit.openDialog(row, ()=>{ |
|||
this.$refs.deviceEdit.close(); |
|||
this.$message({ |
|||
showClose: true, |
|||
message: "设备修改成功,通道字符集将在下次更新生效", |
|||
type: "success", |
|||
}); |
|||
setTimeout(this.getDeviceList, 200) |
|||
setTimeout(this.getDeviceList, 200) |
|||
|
|||
}) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
} |
|||
}; |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style> |
|||
.videoList { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
align-content: flex-start; |
|||
} |
|||
.videoList { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
align-content: flex-start; |
|||
} |
|||
|
|||
.video-item { |
|||
position: relative; |
|||
width: 15rem; |
|||
height: 10rem; |
|||
margin-right: 1rem; |
|||
background-color: #000000; |
|||
} |
|||
.video-item { |
|||
position: relative; |
|||
width: 15rem; |
|||
height: 10rem; |
|||
margin-right: 1rem; |
|||
background-color: #000000; |
|||
} |
|||
|
|||
.video-item-img { |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
.video-item-img { |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.video-item-img:after { |
|||
content: ""; |
|||
display: inline-block; |
|||
position: absolute; |
|||
z-index: 2; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
width: 3rem; |
|||
height: 3rem; |
|||
background-image: url("../assets/loading.png"); |
|||
background-size: cover; |
|||
background-color: #000000; |
|||
} |
|||
.video-item-img:after { |
|||
content: ""; |
|||
display: inline-block; |
|||
position: absolute; |
|||
z-index: 2; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
width: 3rem; |
|||
height: 3rem; |
|||
background-image: url("../assets/loading.png"); |
|||
background-size: cover; |
|||
background-color: #000000; |
|||
} |
|||
|
|||
.video-item-title { |
|||
position: absolute; |
|||
bottom: 0; |
|||
color: #000000; |
|||
background-color: #ffffff; |
|||
line-height: 1.5rem; |
|||
padding: 0.3rem; |
|||
width: 14.4rem; |
|||
} |
|||
.video-item-title { |
|||
position: absolute; |
|||
bottom: 0; |
|||
color: #000000; |
|||
background-color: #ffffff; |
|||
line-height: 1.5rem; |
|||
padding: 0.3rem; |
|||
width: 14.4rem; |
|||
} |
|||
</style> |
|||
|
@ -1,143 +0,0 @@ |
|||
<template> |
|||
<div id="UiHeader"> |
|||
<el-menu router :default-active="activeIndex" menu-trigger="click" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" mode="horizontal"> |
|||
<el-menu-item index="/">控制台</el-menu-item> |
|||
<el-menu-item index="/live">实时监控</el-menu-item> |
|||
<el-menu-item index="/deviceList">国标设备</el-menu-item> |
|||
<el-menu-item index="/devicePosition">电子地图</el-menu-item> |
|||
<el-menu-item index="/pushVideoList">推流列表</el-menu-item> |
|||
<el-menu-item index="/streamProxyList">拉流代理</el-menu-item> |
|||
<el-menu-item index="/cloudRecord">云端录像</el-menu-item> |
|||
<el-menu-item index="/mediaServerManger">节点管理</el-menu-item> |
|||
<el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item> |
|||
<el-menu-item index="/test">设备树</el-menu-item> |
|||
<el-menu-item @click="openDoc">在线文档</el-menu-item> |
|||
<!-- <el-submenu index="/setting">--> |
|||
<!-- <template slot="title">系统设置</template>--> |
|||
<!-- <el-menu-item index="/setting/web">WEB服务</el-menu-item>--> |
|||
<!-- <el-menu-item index="/setting/sip">国标服务</el-menu-item>--> |
|||
<!-- <el-menu-item index="/setting/media">媒体服务</el-menu-item>--> |
|||
<!-- </el-submenu>--> |
|||
<el-switch v-model="alarmNotify" active-text="报警信息推送" style="display: block float: right" @change="alarmNotifyChannge"></el-switch> |
|||
<!-- <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item>--> |
|||
<el-submenu index="" style="float: right;" > |
|||
<template slot="title">欢迎,{{this.$cookies.get("session").username}}</template> |
|||
<el-menu-item @click="changePassword">修改密码</el-menu-item> |
|||
<el-menu-item @click="loginout">注销</el-menu-item> |
|||
</el-submenu> |
|||
</el-menu> |
|||
<changePasswordDialog ref="changePasswordDialog"></changePasswordDialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
|
|||
import changePasswordDialog from './dialog/changePassword.vue' |
|||
export default { |
|||
name: "UiHeader", |
|||
components: { Notification, changePasswordDialog }, |
|||
data() { |
|||
return { |
|||
alarmNotify: false, |
|||
sseSource: null, |
|||
activeIndex: this.$route.path, |
|||
}; |
|||
}, |
|||
created(){ |
|||
if (this.$route.path.startsWith("/channelList")){ |
|||
this.activeIndex = "/deviceList" |
|||
} |
|||
|
|||
}, |
|||
mounted() { |
|||
window.addEventListener('beforeunload', e => this.beforeunloadHandler(e)) |
|||
// window.addEventListener('unload', e => this.unloadHandler(e)) |
|||
this.alarmNotify = this.getAlarmSwitchStatus() === "true"; |
|||
this.sseControl(); |
|||
}, |
|||
methods:{ |
|||
loginout(){ |
|||
this.$axios({ |
|||
method: 'get', |
|||
url:"/api/user/logout" |
|||
}).then((res)=> { |
|||
// 删除cookie,回到登录页面 |
|||
this.$cookies.remove("session"); |
|||
this.$router.push('/login'); |
|||
this.sseSource.close(); |
|||
}).catch((error)=> { |
|||
console.error("登出失败") |
|||
console.error(error) |
|||
}); |
|||
}, |
|||
changePassword(){ |
|||
this.$refs.changePasswordDialog.openDialog() |
|||
}, |
|||
openDoc(){ |
|||
console.log(process.env.BASE_API) |
|||
window.open( !!process.env.BASE_API? process.env.BASE_API + "/doc.html": "/doc.html") |
|||
}, |
|||
beforeunloadHandler() { |
|||
this.sseSource.close(); |
|||
}, |
|||
alarmNotifyChannge(){ |
|||
this.setAlarmSwitchStatus() |
|||
this.sseControl() |
|||
}, |
|||
sseControl() { |
|||
let that = this; |
|||
if (this.alarmNotify) { |
|||
console.log("申请SSE推送API调用,浏览器ID: " + this.$browserId); |
|||
this.sseSource = new EventSource('/api/emit?browserId=' + this.$browserId); |
|||
this.sseSource.addEventListener('message', function(evt) { |
|||
that.$notify({ |
|||
title: '收到报警信息', |
|||
dangerouslyUseHTMLString: true, |
|||
message: evt.data, |
|||
type: 'warning' |
|||
}); |
|||
console.log("收到信息:" + evt.data); |
|||
}); |
|||
this.sseSource.addEventListener('open', function(e) { |
|||
console.log("SSE连接打开."); |
|||
}, false); |
|||
this.sseSource.addEventListener('error', function(e) { |
|||
if (e.target.readyState == EventSource.CLOSED) { |
|||
console.log("SSE连接关闭"); |
|||
} else { |
|||
console.log(e.target.readyState); |
|||
} |
|||
}, false); |
|||
} else { |
|||
if (this.sseSource != null) { |
|||
this.sseSource.removeEventListener('open', null); |
|||
this.sseSource.removeEventListener('message', null); |
|||
this.sseSource.removeEventListener('error', null); |
|||
this.sseSource.close(); |
|||
} |
|||
|
|||
} |
|||
}, |
|||
getAlarmSwitchStatus(){ |
|||
if (localStorage.getItem("alarmSwitchStatus") == null) { |
|||
localStorage.setItem("alarmSwitchStatus", false); |
|||
} |
|||
return localStorage.getItem("alarmSwitchStatus"); |
|||
}, |
|||
setAlarmSwitchStatus(){ |
|||
localStorage.setItem("alarmSwitchStatus", this.alarmNotify); |
|||
} |
|||
}, |
|||
destroyed() { |
|||
window.removeEventListener('beforeunload', e => this.beforeunloadHandler(e)) |
|||
if (this.sseSource != null) { |
|||
this.sseSource.removeEventListener('open', null); |
|||
this.sseSource.removeEventListener('message', null); |
|||
this.sseSource.removeEventListener('error', null); |
|||
this.sseSource.close(); |
|||
} |
|||
}, |
|||
|
|||
} |
|||
|
|||
</script> |
@ -1,393 +1,404 @@ |
|||
<template> |
|||
<div id="channelList"> |
|||
<el-container> |
|||
<el-header> |
|||
<uiHeader></uiHeader> |
|||
</el-header> |
|||
<el-main> |
|||
<div style="background-color: #FFFFFF; position: relative; padding: 1rem 0.5rem 0.5rem 0.5rem; text-align: center;"> |
|||
<span style="font-size: 1rem; font-weight: 500; ">通道列表({{parentChannelId ==0 ? deviceId:parentChannelId}})</span> |
|||
<div id="channelList" style="width: 100%"> |
|||
<div class="page-header"> |
|||
<div class="page-title"> |
|||
<el-button icon="el-icon-arrow-left" size="mini" style="margin-right: 1rem;" type="primary" @click="showDevice"> |
|||
返回 |
|||
</el-button> |
|||
通道列表({{ parentChannelId == 0 ? deviceId : parentChannelId }})</div> |
|||
<div class="page-header-btn"> |
|||
搜索: |
|||
<el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字" |
|||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input> |
|||
|
|||
</div> |
|||
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;"> |
|||
<el-button icon="el-icon-arrow-left" size="mini" style="margin-right: 1rem;" type="primary" @click="showDevice">返回</el-button> |
|||
搜索: <el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字" prefix-icon="el-icon-search" v-model="searchSrt" clearable> </el-input> |
|||
通道类型: |
|||
<el-select size="mini" @change="search" style="margin-right: 1rem;" v-model="channelType" placeholder="请选择" |
|||
default-first-option> |
|||
<el-option label="全部" value=""></el-option> |
|||
<el-option label="设备" value="false"></el-option> |
|||
<el-option label="子目录" value="true"></el-option> |
|||
</el-select> |
|||
在线状态: |
|||
<el-select size="mini" style="margin-right: 1rem;" @change="search" v-model="online" placeholder="请选择" |
|||
default-first-option> |
|||
<el-option label="全部" value=""></el-option> |
|||
<el-option label="在线" value="true"></el-option> |
|||
<el-option label="离线" value="false"></el-option> |
|||
</el-select> |
|||
<el-checkbox size="mini" v-model="autoList" @change="autoListChange"> |
|||
自动刷新 |
|||
</el-checkbox> |
|||
</div> |
|||
</div> |
|||
<devicePlayer ref="devicePlayer" v-loading="isLoging"></devicePlayer> |
|||
<!--设备列表--> |
|||
<el-table ref="channelListTable" :data="deviceChannelList" :height="winHeight" border style="width: 100%"> |
|||
<el-table-column prop="channelId" label="通道编号" width="200"> |
|||
</el-table-column> |
|||
<el-table-column prop="name" label="通道名称"> |
|||
</el-table-column> |
|||
<el-table-column label="快照" width="80" align="center"> |
|||
<template slot-scope="scope"> |
|||
<img style="max-height: 3rem;max-width: 4rem;" |
|||
:id="scope.row.deviceId + '_' + scope.row.channelId" |
|||
:src="getSnap(scope.row)" |
|||
@error="getSnapErrorEvent($event.target.id)" |
|||
alt=""> |
|||
<!-- <el-image--> |
|||
<!-- :id="'snapImg_' + scope.row.deviceId + '_' + scope.row.channelId"--> |
|||
<!-- :src="getSnap(scope.row)"--> |
|||
<!-- @error="getSnapErrorEvent($event, scope.row)"--> |
|||
<!-- :fit="'contain'">--> |
|||
<!-- <div slot="error" class="image-slot">--> |
|||
<!-- <i class="el-icon-picture-outline"></i>--> |
|||
<!-- </div>--> |
|||
<!-- </el-image>--> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="subCount" label="子节点数"> |
|||
</el-table-column> |
|||
<el-table-column prop="manufacture" label="厂家"> |
|||
</el-table-column> |
|||
<el-table-column label="位置信息" align="center"> |
|||
<template slot-scope="scope"> |
|||
<span>{{ scope.row.longitude }},{{ scope.row.latitude }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="ptztypeText" label="云台类型"/> |
|||
<el-table-column label="开启音频" align="center"> |
|||
<template slot-scope="scope"> |
|||
<el-switch @change="updateChannel(scope.row)" v-model="scope.row.hasAudio" active-color="#409EFF"> |
|||
</el-switch> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="状态" width="180" align="center"> |
|||
<template slot-scope="scope"> |
|||
<div slot="reference" class="name-wrapper"> |
|||
<el-tag size="medium" v-if="scope.row.status == 1">开启</el-tag> |
|||
<el-tag size="medium" type="info" v-if="scope.row.status == 0">关闭</el-tag> |
|||
</div> |
|||
</template> |
|||
</el-table-column> |
|||
|
|||
通道类型: <el-select size="mini" @change="search" style="margin-right: 1rem;" v-model="channelType" placeholder="请选择" default-first-option> |
|||
<el-option label="全部" value=""></el-option> |
|||
<el-option label="设备" value="false"></el-option> |
|||
<el-option label="子目录" value="true"></el-option> |
|||
</el-select> |
|||
在线状态: <el-select size="mini" style="margin-right: 1rem;" @change="search" v-model="online" placeholder="请选择" default-first-option> |
|||
<el-option label="全部" value=""></el-option> |
|||
<el-option label="在线" value="true"></el-option> |
|||
<el-option label="离线" value="false"></el-option> |
|||
</el-select> |
|||
<el-checkbox size="mini" style="margin-right: 1rem; float: right;" v-model="autoList" @change="autoListChange">自动刷新</el-checkbox> |
|||
</div> |
|||
<devicePlayer ref="devicePlayer" v-loading="isLoging"></devicePlayer> |
|||
<!--设备列表--> |
|||
<el-table ref="channelListTable" :data="deviceChannelList" :height="winHeight" border style="width: 100%"> |
|||
<el-table-column prop="channelId" label="通道编号" width="200"> |
|||
</el-table-column> |
|||
<el-table-column prop="name" label="通道名称"> |
|||
</el-table-column> |
|||
<el-table-column label="快照" width="80" align="center"> |
|||
<template slot-scope="scope"> |
|||
<img style="max-height: 3rem;max-width: 4rem;" |
|||
:id="scope.row.deviceId + '_' + scope.row.channelId" |
|||
:src="getSnap(scope.row)" |
|||
@error="getSnapErrorEvent($event.target.id)" |
|||
alt=""> |
|||
<!-- <el-image--> |
|||
<!-- :id="'snapImg_' + scope.row.deviceId + '_' + scope.row.channelId"--> |
|||
<!-- :src="getSnap(scope.row)"--> |
|||
<!-- @error="getSnapErrorEvent($event, scope.row)"--> |
|||
<!-- :fit="'contain'">--> |
|||
<!-- <div slot="error" class="image-slot">--> |
|||
<!-- <i class="el-icon-picture-outline"></i>--> |
|||
<!-- </div>--> |
|||
<!-- </el-image>--> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="subCount" label="子节点数"> |
|||
</el-table-column> |
|||
<el-table-column prop="manufacture" label="厂家"> |
|||
</el-table-column> |
|||
<el-table-column label="位置信息" align="center"> |
|||
<template slot-scope="scope"> |
|||
<span>{{scope.row.longitude}},{{scope.row.latitude}}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="ptztypeText" label="云台类型"/> |
|||
<el-table-column label="开启音频" align="center"> |
|||
<template slot-scope="scope"> |
|||
<el-switch @change="updateChannel(scope.row)" v-model="scope.row.hasAudio" active-color="#409EFF"> |
|||
</el-switch> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="状态" width="180" align="center"> |
|||
<template slot-scope="scope"> |
|||
<div slot="reference" class="name-wrapper"> |
|||
<el-tag size="medium" v-if="scope.row.status == 1">开启</el-tag> |
|||
<el-tag size="medium" type="info" v-if="scope.row.status == 0">关闭</el-tag> |
|||
</div> |
|||
</template> |
|||
</el-table-column> |
|||
|
|||
|
|||
<el-table-column label="操作" width="280" align="center" fixed="right"> |
|||
<template slot-scope="scope"> |
|||
<el-button-group> |
|||
<!-- <el-button size="mini" icon="el-icon-video-play" v-if="scope.row.parental == 0" @click="sendDevicePush(scope.row)">播放</el-button> --> |
|||
<el-button size="mini" icon="el-icon-video-play" @click="sendDevicePush(scope.row)">播放</el-button> |
|||
<el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" @click="stopDevicePush(scope.row)">停止</el-button> |
|||
<el-button size="mini" icon="el-icon-s-open" type="primary" v-if="scope.row.subCount > 0" @click="changeSubchannel(scope.row)">查看</el-button> |
|||
<el-button size="mini" icon="el-icon-video-camera" type="primary" @click="queryRecords(scope.row)">设备录象</el-button> |
|||
<!-- <el-button size="mini" @click="sendDevicePush(scope.row)">录像查询</el-button> --> |
|||
</el-button-group> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<el-pagination style="float: right" @size-change="handleSizeChange" @current-change="currentChange" :current-page="currentPage" :page-size="count" :page-sizes="[15, 20, 30, 50]" layout="total, sizes, prev, pager, next" :total="total"> |
|||
</el-pagination> |
|||
|
|||
</el-main> |
|||
</el-container> |
|||
</div> |
|||
<el-table-column label="操作" width="280" align="center" fixed="right"> |
|||
<template slot-scope="scope"> |
|||
<el-button-group> |
|||
<!-- <el-button size="mini" icon="el-icon-video-play" v-if="scope.row.parental == 0" @click="sendDevicePush(scope.row)">播放</el-button> --> |
|||
<el-button size="mini" icon="el-icon-video-play" @click="sendDevicePush(scope.row)">播放</el-button> |
|||
<el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" |
|||
@click="stopDevicePush(scope.row)">停止 |
|||
</el-button> |
|||
<el-button size="mini" icon="el-icon-s-open" type="primary" v-if="scope.row.subCount > 0" |
|||
@click="changeSubchannel(scope.row)">查看 |
|||
</el-button> |
|||
<el-button size="mini" icon="el-icon-video-camera" type="primary" @click="queryRecords(scope.row)">设备录象 |
|||
</el-button> |
|||
<!-- <el-button size="mini" @click="sendDevicePush(scope.row)">录像查询</el-button> --> |
|||
</el-button-group> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<el-pagination style="float: right" @size-change="handleSizeChange" @current-change="currentChange" |
|||
:current-page="currentPage" :page-size="count" :page-sizes="[15, 20, 30, 50]" |
|||
layout="total, sizes, prev, pager, next" :total="total"> |
|||
</el-pagination> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import devicePlayer from './dialog/devicePlayer.vue' |
|||
import uiHeader from './UiHeader.vue' |
|||
import uiHeader from '../layout/UiHeader.vue' |
|||
import moment from "moment"; |
|||
|
|||
export default { |
|||
name: 'channelList', |
|||
components: { |
|||
devicePlayer, |
|||
uiHeader |
|||
}, |
|||
data() { |
|||
return { |
|||
deviceId: this.$route.params.deviceId, |
|||
parentChannelId: this.$route.params.parentChannelId, |
|||
deviceChannelList: [], |
|||
videoComponentList: [], |
|||
currentPlayerInfo: {}, //当前播放对象 |
|||
updateLooper: 0, //数据刷新轮训标志 |
|||
searchSrt: "", |
|||
channelType: "", |
|||
online: "", |
|||
winHeight: window.innerHeight - 250, |
|||
currentPage: parseInt(this.$route.params.page), |
|||
count: parseInt(this.$route.params.count), |
|||
total: 0, |
|||
beforeUrl: "/deviceList", |
|||
isLoging: false, |
|||
autoList: true, |
|||
loadSnap:{} |
|||
}; |
|||
name: 'channelList', |
|||
components: { |
|||
devicePlayer, |
|||
uiHeader |
|||
}, |
|||
data() { |
|||
return { |
|||
deviceId: this.$route.params.deviceId, |
|||
parentChannelId: this.$route.params.parentChannelId, |
|||
deviceChannelList: [], |
|||
videoComponentList: [], |
|||
currentPlayerInfo: {}, //当前播放对象 |
|||
updateLooper: 0, //数据刷新轮训标志 |
|||
searchSrt: "", |
|||
channelType: "", |
|||
online: "", |
|||
winHeight: window.innerHeight - 250, |
|||
currentPage: parseInt(this.$route.params.page), |
|||
count: parseInt(this.$route.params.count), |
|||
total: 0, |
|||
beforeUrl: "/deviceList", |
|||
isLoging: false, |
|||
autoList: true, |
|||
loadSnap: {} |
|||
}; |
|||
}, |
|||
|
|||
mounted() { |
|||
this.initData(); |
|||
if (this.autoList) { |
|||
this.updateLooper = setInterval(this.initData, 5000); |
|||
} |
|||
|
|||
}, |
|||
destroyed() { |
|||
this.$destroy('videojs'); |
|||
clearTimeout(this.updateLooper); |
|||
}, |
|||
methods: { |
|||
initData: function () { |
|||
if (typeof (this.parentChannelId) == "undefined" || this.parentChannelId == 0) { |
|||
this.getDeviceChannelList(); |
|||
} else { |
|||
this.showSubchannels(); |
|||
} |
|||
}, |
|||
initParam: function () { |
|||
this.deviceId = this.$route.params.deviceId; |
|||
this.parentChannelId = this.$route.params.parentChannelId; |
|||
this.currentPage = parseInt(this.$route.params.page); |
|||
this.count = parseInt(this.$route.params.count); |
|||
if (this.parentChannelId == "" || this.parentChannelId == 0) { |
|||
this.beforeUrl = "/deviceList" |
|||
} |
|||
|
|||
mounted() { |
|||
}, |
|||
currentChange: function (val) { |
|||
var url = `/${this.$router.currentRoute.name}/${this.deviceId}/${this.parentChannelId}/${this.count}/${val}` |
|||
this.$router.push(url).then(() => { |
|||
this.initParam(); |
|||
this.initData(); |
|||
if (this.autoList) { |
|||
this.updateLooper = setInterval(this.initData, 5000); |
|||
} |
|||
}) |
|||
}, |
|||
handleSizeChange: function (val) { |
|||
var url = `/${this.$router.currentRoute.name}/${this.$router.params.deviceId}/${this.$router.params.parentChannelId}/${val}/1` |
|||
this.$router.push(url).then(() => { |
|||
this.initParam(); |
|||
this.initData(); |
|||
}) |
|||
|
|||
}, |
|||
destroyed() { |
|||
this.$destroy('videojs'); |
|||
clearTimeout(this.updateLooper); |
|||
getDeviceChannelList: function () { |
|||
let that = this; |
|||
if (typeof (this.$route.params.deviceId) == "undefined") return; |
|||
this.$axios({ |
|||
method: 'get', |
|||
url: `/api/device/query/devices/${this.$route.params.deviceId}/channels`, |
|||
params: { |
|||
page: that.currentPage, |
|||
count: that.count, |
|||
query: that.searchSrt, |
|||
online: that.online, |
|||
channelType: that.channelType |
|||
} |
|||
}).then(function (res) { |
|||
that.total = res.data.total; |
|||
that.deviceChannelList = res.data.list; |
|||
// 防止出现表格错位 |
|||
that.$nextTick(() => { |
|||
that.$refs.channelListTable.doLayout(); |
|||
}) |
|||
}).catch(function (error) { |
|||
console.log(error); |
|||
}); |
|||
}, |
|||
methods: { |
|||
initData: function () { |
|||
if (typeof (this.parentChannelId) == "undefined" || this.parentChannelId == 0) { |
|||
this.getDeviceChannelList(); |
|||
} else { |
|||
this.showSubchannels(); |
|||
} |
|||
}, |
|||
initParam: function () { |
|||
this.deviceId = this.$route.params.deviceId; |
|||
this.parentChannelId = this.$route.params.parentChannelId; |
|||
this.currentPage = parseInt(this.$route.params.page); |
|||
this.count = parseInt(this.$route.params.count); |
|||
if (this.parentChannelId == "" || this.parentChannelId == 0) { |
|||
this.beforeUrl = "/deviceList" |
|||
} |
|||
|
|||
}, |
|||
currentChange: function (val) { |
|||
var url = `/${this.$router.currentRoute.name}/${this.deviceId}/${this.parentChannelId}/${this.count}/${val}` |
|||
this.$router.push(url).then(() => { |
|||
this.initParam(); |
|||
this.initData(); |
|||
}) |
|||
}, |
|||
handleSizeChange: function (val) { |
|||
var url = `/${this.$router.currentRoute.name}/${this.$router.params.deviceId}/${this.$router.params.parentChannelId}/${val}/1` |
|||
this.$router.push(url).then(() => { |
|||
this.initParam(); |
|||
this.initData(); |
|||
}) |
|||
//通知设备上传媒体流 |
|||
sendDevicePush: function (itemData) { |
|||
let deviceId = this.deviceId; |
|||
this.isLoging = true; |
|||
let channelId = itemData.channelId; |
|||
console.log("通知设备推流1:" + deviceId + " : " + channelId); |
|||
let that = this; |
|||
this.$axios({ |
|||
method: 'get', |
|||
url: '/api/play/start/' + deviceId + '/' + channelId |
|||
}).then(function (res) { |
|||
that.isLoging = false; |
|||
if (res.data.code === 0) { |
|||
|
|||
}, |
|||
getDeviceChannelList: function () { |
|||
let that = this; |
|||
if (typeof (this.$route.params.deviceId) == "undefined") return; |
|||
this.$axios({ |
|||
method: 'get', |
|||
url: `/api/device/query/devices/${this.$route.params.deviceId}/channels`, |
|||
params:{ |
|||
page: that.currentPage, |
|||
count: that.count, |
|||
query: that.searchSrt, |
|||
online: that.online, |
|||
channelType: that.channelType |
|||
} |
|||
}).then(function (res) { |
|||
that.total = res.data.total; |
|||
that.deviceChannelList = res.data.list; |
|||
// 防止出现表格错位 |
|||
that.$nextTick(() => { |
|||
that.$refs.channelListTable.doLayout(); |
|||
}) |
|||
}).catch(function (error) { |
|||
console.log(error); |
|||
}); |
|||
}, |
|||
setTimeout(() => { |
|||
|
|||
//通知设备上传媒体流 |
|||
sendDevicePush: function (itemData) { |
|||
let deviceId = this.deviceId; |
|||
this.isLoging = true; |
|||
let channelId = itemData.channelId; |
|||
console.log("通知设备推流1:" + deviceId + " : " + channelId ); |
|||
let that = this; |
|||
this.$axios({ |
|||
method: 'get', |
|||
url: '/api/play/start/' + deviceId + '/' + channelId |
|||
}).then(function (res) { |
|||
that.isLoging = false; |
|||
if (res.data.code === 0) { |
|||
let snapId = deviceId + "_" + channelId; |
|||
that.loadSnap[snapId] = 0; |
|||
that.getSnapErrorEvent(snapId) |
|||
}, 5000) |
|||
that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { |
|||
streamInfo: res.data.data, |
|||
hasAudio: itemData.hasAudio |
|||
}); |
|||
setTimeout(() => { |
|||
that.initData(); |
|||
}, 1000) |
|||
|
|||
setTimeout(()=>{ |
|||
|
|||
let snapId = deviceId + "_" + channelId; |
|||
that.loadSnap[snapId] = 0; |
|||
that.getSnapErrorEvent(snapId) |
|||
},5000) |
|||
that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { |
|||
streamInfo: res.data.data, |
|||
hasAudio: itemData.hasAudio |
|||
}); |
|||
setTimeout(()=>{ |
|||
that.initData(); |
|||
},1000) |
|||
|
|||
}else { |
|||
that.$message.error(res.data.msg); |
|||
} |
|||
}).catch(function (e) {}); |
|||
}, |
|||
queryRecords: function (itemData) { |
|||
var format = moment().format("YYYY-M-D"); |
|||
let deviceId = this.deviceId; |
|||
let channelId = itemData.channelId; |
|||
this.$refs.devicePlayer.openDialog("record", deviceId, channelId, {date: format}) |
|||
}, |
|||
stopDevicePush: function (itemData) { |
|||
var that = this; |
|||
this.$axios({ |
|||
method: 'get', |
|||
url: '/api/play/stop/' + this.deviceId + "/" + itemData.channelId |
|||
}).then(function (res) { |
|||
that.initData(); |
|||
}).catch(function (error) { |
|||
if (error.response.status === 402) { // 已经停止过 |
|||
that.initData(); |
|||
}else { |
|||
console.log(error) |
|||
} |
|||
}); |
|||
}, |
|||
getSnap: function (row){ |
|||
return '/static/snap/' + row.deviceId + '_' + row.channelId + '.jpg' |
|||
}, |
|||
getSnapErrorEvent: function (id){ |
|||
} else { |
|||
that.$message.error(res.data.msg); |
|||
} |
|||
}).catch(function (e) { |
|||
}); |
|||
}, |
|||
queryRecords: function (itemData) { |
|||
var format = moment().format("YYYY-M-D"); |
|||
let deviceId = this.deviceId; |
|||
let channelId = itemData.channelId; |
|||
this.$refs.devicePlayer.openDialog("record", deviceId, channelId, {date: format}) |
|||
}, |
|||
stopDevicePush: function (itemData) { |
|||
var that = this; |
|||
this.$axios({ |
|||
method: 'get', |
|||
url: '/api/play/stop/' + this.deviceId + "/" + itemData.channelId |
|||
}).then(function (res) { |
|||
that.initData(); |
|||
}).catch(function (error) { |
|||
if (error.response.status === 402) { // 已经停止过 |
|||
that.initData(); |
|||
} else { |
|||
console.log(error) |
|||
} |
|||
}); |
|||
}, |
|||
getSnap: function (row) { |
|||
return '/static/snap/' + row.deviceId + '_' + row.channelId + '.jpg' |
|||
}, |
|||
getSnapErrorEvent: function (id) { |
|||
|
|||
if (typeof (this.loadSnap[id]) != "undefined") { |
|||
console.log("下载截图" + this.loadSnap[id]) |
|||
if (this.loadSnap[id] > 5) { |
|||
delete this.loadSnap[id]; |
|||
return; |
|||
} |
|||
setTimeout(()=>{ |
|||
this.loadSnap[id] ++ |
|||
document.getElementById(id).setAttribute("src", '/static/snap/' + id + '.jpg?' + new Date().getTime()) |
|||
},1000) |
|||
if (typeof (this.loadSnap[id]) != "undefined") { |
|||
console.log("下载截图" + this.loadSnap[id]) |
|||
if (this.loadSnap[id] > 5) { |
|||
delete this.loadSnap[id]; |
|||
return; |
|||
} |
|||
setTimeout(() => { |
|||
this.loadSnap[id]++ |
|||
document.getElementById(id).setAttribute("src", '/static/snap/' + id + '.jpg?' + new Date().getTime()) |
|||
}, 1000) |
|||
|
|||
} |
|||
}, |
|||
showDevice: function () { |
|||
this.$router.push(this.beforeUrl).then(() => { |
|||
this.initParam(); |
|||
this.initData(); |
|||
}) |
|||
}, |
|||
changeSubchannel(itemData) { |
|||
this.beforeUrl = this.$router.currentRoute.path; |
|||
} |
|||
}, |
|||
showDevice: function () { |
|||
this.$router.push(this.beforeUrl).then(() => { |
|||
this.initParam(); |
|||
this.initData(); |
|||
}) |
|||
}, |
|||
changeSubchannel(itemData) { |
|||
this.beforeUrl = this.$router.currentRoute.path; |
|||
|
|||
var url = `/${this.$router.currentRoute.name}/${this.$router.currentRoute.params.deviceId}/${itemData.channelId}/${this.$router.currentRoute.params.count}/1` |
|||
this.$router.push(url).then(() => { |
|||
this.searchSrt = ""; |
|||
this.channelType = ""; |
|||
this.online = ""; |
|||
this.initParam(); |
|||
this.initData(); |
|||
}) |
|||
}, |
|||
showSubchannels: function (channelId) { |
|||
let that = this; |
|||
var url = `/${this.$router.currentRoute.name}/${this.$router.currentRoute.params.deviceId}/${itemData.channelId}/${this.$router.currentRoute.params.count}/1` |
|||
this.$router.push(url).then(() => { |
|||
this.searchSrt = ""; |
|||
this.channelType = ""; |
|||
this.online = ""; |
|||
this.initParam(); |
|||
this.initData(); |
|||
}) |
|||
}, |
|||
showSubchannels: function (channelId) { |
|||
let that = this; |
|||
|
|||
this.$axios({ |
|||
method: 'get', |
|||
url:`/api/device/query/sub_channels/${this.deviceId}/${this.parentChannelId}/channels`, |
|||
params: { |
|||
page: that.currentPage, |
|||
count: that.count, |
|||
query: that.searchSrt, |
|||
online: that.online, |
|||
channelType: that.channelType |
|||
} |
|||
}).then(function (res) { |
|||
that.total = res.data.total; |
|||
that.deviceChannelList = res.data.list; |
|||
// 防止出现表格错位 |
|||
that.$nextTick(() => { |
|||
that.$refs.channelListTable.doLayout(); |
|||
}) |
|||
}).catch(function (error) { |
|||
console.log(error); |
|||
}); |
|||
}, |
|||
search: function () { |
|||
this.currentPage = 1; |
|||
this.total = 0; |
|||
this.initData(); |
|||
}, |
|||
updateChannel: function (row) { |
|||
this.$axios({ |
|||
method: 'post', |
|||
url: `/api/device/query/channel/update/${this.deviceId}`, |
|||
params: row |
|||
}).then(function (res) { |
|||
console.log(JSON.stringify(res)); |
|||
}); |
|||
}, |
|||
autoListChange: function () { |
|||
if (this.autoList) { |
|||
this.updateLooper = setInterval(this.initData, 1500); |
|||
}else{ |
|||
window.clearInterval(this.updateLooper); |
|||
} |
|||
this.$axios({ |
|||
method: 'get', |
|||
url: `/api/device/query/sub_channels/${this.deviceId}/${this.parentChannelId}/channels`, |
|||
params: { |
|||
page: that.currentPage, |
|||
count: that.count, |
|||
query: that.searchSrt, |
|||
online: that.online, |
|||
channelType: that.channelType |
|||
} |
|||
|
|||
}).then(function (res) { |
|||
that.total = res.data.total; |
|||
that.deviceChannelList = res.data.list; |
|||
// 防止出现表格错位 |
|||
that.$nextTick(() => { |
|||
that.$refs.channelListTable.doLayout(); |
|||
}) |
|||
}).catch(function (error) { |
|||
console.log(error); |
|||
}); |
|||
}, |
|||
search: function () { |
|||
this.currentPage = 1; |
|||
this.total = 0; |
|||
this.initData(); |
|||
}, |
|||
updateChannel: function (row) { |
|||
this.$axios({ |
|||
method: 'post', |
|||
url: `/api/device/query/channel/update/${this.deviceId}`, |
|||
params: row |
|||
}).then(function (res) { |
|||
console.log(JSON.stringify(res)); |
|||
}); |
|||
}, |
|||
autoListChange: function () { |
|||
if (this.autoList) { |
|||
this.updateLooper = setInterval(this.initData, 1500); |
|||
} else { |
|||
window.clearInterval(this.updateLooper); |
|||
} |
|||
} |
|||
|
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style> |
|||
.videoList { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
align-content: flex-start; |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
align-content: flex-start; |
|||
} |
|||
|
|||
.video-item { |
|||
position: relative; |
|||
width: 15rem; |
|||
height: 10rem; |
|||
margin-right: 1rem; |
|||
background-color: #000000; |
|||
position: relative; |
|||
width: 15rem; |
|||
height: 10rem; |
|||
margin-right: 1rem; |
|||
background-color: #000000; |
|||
} |
|||
|
|||
.video-item-img { |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
width: 100%; |
|||
height: 100%; |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.video-item-img:after { |
|||
content: ""; |
|||
display: inline-block; |
|||
position: absolute; |
|||
z-index: 2; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
width: 3rem; |
|||
height: 3rem; |
|||
background-image: url("../assets/loading.png"); |
|||
background-size: cover; |
|||
background-color: #000000; |
|||
content: ""; |
|||
display: inline-block; |
|||
position: absolute; |
|||
z-index: 2; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
margin: auto; |
|||
width: 3rem; |
|||
height: 3rem; |
|||
background-image: url("../assets/loading.png"); |
|||
background-size: cover; |
|||
background-color: #000000; |
|||
} |
|||
|
|||
.video-item-title { |
|||
position: absolute; |
|||
bottom: 0; |
|||
color: #000000; |
|||
background-color: #ffffff; |
|||
line-height: 1.5rem; |
|||
padding: 0.3rem; |
|||
width: 14.4rem; |
|||
position: absolute; |
|||
bottom: 0; |
|||
color: #000000; |
|||
background-color: #ffffff; |
|||
line-height: 1.5rem; |
|||
padding: 0.3rem; |
|||
width: 14.4rem; |
|||
} |
|||
</style> |
|||
|
File diff suppressed because it is too large
@ -0,0 +1,151 @@ |
|||
<template> |
|||
<div id="UiHeader"> |
|||
<el-menu router :default-active="activeIndex" menu-trigger="click" background-color="#545c64" text-color="#fff" |
|||
active-text-color="#ffd04b" mode="horizontal"> |
|||
<el-menu-item index="/control">控制台</el-menu-item> |
|||
<el-menu-item index="/live">实时监控</el-menu-item> |
|||
<el-menu-item index="/deviceList">国标设备</el-menu-item> |
|||
<el-menu-item index="/pushVideoList">推流列表</el-menu-item> |
|||
<el-menu-item index="/streamProxyList">拉流代理</el-menu-item> |
|||
<el-menu-item index="/cloudRecord">云端录像</el-menu-item> |
|||
<el-menu-item index="/mediaServerManger">节点管理</el-menu-item> |
|||
<el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item> |
|||
<el-menu-item @click="openDoc">在线文档</el-menu-item> |
|||
<!-- <el-submenu index="/setting">--> |
|||
<!-- <template slot="title">系统设置</template>--> |
|||
<!-- <el-menu-item index="/setting/web">WEB服务</el-menu-item>--> |
|||
<!-- <el-menu-item index="/setting/sip">国标服务</el-menu-item>--> |
|||
<!-- <el-menu-item index="/setting/media">媒体服务</el-menu-item>--> |
|||
<!-- </el-submenu>--> |
|||
<el-switch v-model="alarmNotify" active-text="报警信息推送" @change="alarmNotifyChannge"></el-switch> |
|||
<!-- <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item>--> |
|||
<el-submenu index="" style="float: right;"> |
|||
<template slot="title">欢迎,{{ this.$cookies.get("session").username }}</template> |
|||
<el-menu-item @click="changePassword">修改密码</el-menu-item> |
|||
<el-menu-item @click="loginout">注销</el-menu-item> |
|||
</el-submenu> |
|||
</el-menu> |
|||
<changePasswordDialog ref="changePasswordDialog"></changePasswordDialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
|
|||
import changePasswordDialog from '../components/dialog/changePassword.vue' |
|||
|
|||
export default { |
|||
name: "UiHeader", |
|||
components: {Notification, changePasswordDialog}, |
|||
data() { |
|||
return { |
|||
alarmNotify: false, |
|||
sseSource: null, |
|||
activeIndex: this.$route.path, |
|||
}; |
|||
}, |
|||
created() { |
|||
if (this.$route.path.startsWith("/channelList")) { |
|||
this.activeIndex = "/deviceList" |
|||
} |
|||
|
|||
}, |
|||
mounted() { |
|||
window.addEventListener('beforeunload', e => this.beforeunloadHandler(e)) |
|||
// window.addEventListener('unload', e => this.unloadHandler(e)) |
|||
this.alarmNotify = this.getAlarmSwitchStatus() === "true"; |
|||
this.sseControl(); |
|||
}, |
|||
methods: { |
|||
loginout() { |
|||
this.$axios({ |
|||
method: 'get', |
|||
url: "/api/user/logout" |
|||
}).then((res) => { |
|||
// 删除cookie,回到登录页面 |
|||
this.$cookies.remove("session"); |
|||
this.$router.push('/login'); |
|||
this.sseSource.close(); |
|||
}).catch((error) => { |
|||
console.error("登出失败") |
|||
console.error(error) |
|||
}); |
|||
}, |
|||
changePassword() { |
|||
this.$refs.changePasswordDialog.openDialog() |
|||
}, |
|||
openDoc() { |
|||
console.log(process.env.BASE_API) |
|||
window.open(!!process.env.BASE_API ? process.env.BASE_API + "/doc.html" : "/doc.html") |
|||
}, |
|||
beforeunloadHandler() { |
|||
this.sseSource.close(); |
|||
}, |
|||
alarmNotifyChannge() { |
|||
this.setAlarmSwitchStatus() |
|||
this.sseControl() |
|||
}, |
|||
sseControl() { |
|||
let that = this; |
|||
if (this.alarmNotify) { |
|||
console.log("申请SSE推送API调用,浏览器ID: " + this.$browserId); |
|||
this.sseSource = new EventSource('/api/emit?browserId=' + this.$browserId); |
|||
this.sseSource.addEventListener('message', function (evt) { |
|||
that.$notify({ |
|||
title: '收到报警信息', |
|||
dangerouslyUseHTMLString: true, |
|||
message: evt.data, |
|||
type: 'warning' |
|||
}); |
|||
console.log("收到信息:" + evt.data); |
|||
}); |
|||
this.sseSource.addEventListener('open', function (e) { |
|||
console.log("SSE连接打开."); |
|||
}, false); |
|||
this.sseSource.addEventListener('error', function (e) { |
|||
if (e.target.readyState == EventSource.CLOSED) { |
|||
console.log("SSE连接关闭"); |
|||
} else { |
|||
console.log(e.target.readyState); |
|||
} |
|||
}, false); |
|||
} else { |
|||
if (this.sseSource != null) { |
|||
this.sseSource.removeEventListener('open', null); |
|||
this.sseSource.removeEventListener('message', null); |
|||
this.sseSource.removeEventListener('error', null); |
|||
this.sseSource.close(); |
|||
} |
|||
|
|||
} |
|||
}, |
|||
getAlarmSwitchStatus() { |
|||
if (localStorage.getItem("alarmSwitchStatus") == null) { |
|||
localStorage.setItem("alarmSwitchStatus", false); |
|||
} |
|||
return localStorage.getItem("alarmSwitchStatus"); |
|||
}, |
|||
setAlarmSwitchStatus() { |
|||
localStorage.setItem("alarmSwitchStatus", this.alarmNotify); |
|||
} |
|||
}, |
|||
destroyed() { |
|||
window.removeEventListener('beforeunload', e => this.beforeunloadHandler(e)) |
|||
if (this.sseSource != null) { |
|||
this.sseSource.removeEventListener('open', null); |
|||
this.sseSource.removeEventListener('message', null); |
|||
this.sseSource.removeEventListener('error', null); |
|||
this.sseSource.close(); |
|||
} |
|||
}, |
|||
|
|||
} |
|||
|
|||
</script> |
|||
<style> |
|||
#UiHeader .el-switch__label { |
|||
color: white; |
|||
} |
|||
#UiHeader .el-switch__label.is-active{ |
|||
color: #409EFF; |
|||
} |
|||
</style> |
@ -0,0 +1,90 @@ |
|||
<template> |
|||
<el-container style="height: 100%"> |
|||
<el-header> |
|||
<ui-header/> |
|||
</el-header> |
|||
<el-main> |
|||
<el-container> |
|||
<transition name="fade"> |
|||
<router-view></router-view> |
|||
</transition> |
|||
</el-container> |
|||
</el-main> |
|||
</el-container> |
|||
</template> |
|||
|
|||
<script> |
|||
import uiHeader from "./UiHeader.vue"; |
|||
|
|||
export default { |
|||
name: "index", |
|||
components: { |
|||
uiHeader |
|||
}, |
|||
} |
|||
</script> |
|||
<style> |
|||
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/ |
|||
::-webkit-scrollbar { |
|||
width: 8px; |
|||
height: 8px; |
|||
} |
|||
|
|||
/*定义滚动条轨道 内阴影+圆角*/ |
|||
::-webkit-scrollbar-track { |
|||
border-radius: 4px; |
|||
background-color: #F5F5F5; |
|||
} |
|||
|
|||
/*定义滑块 内阴影+圆角*/ |
|||
::-webkit-scrollbar-thumb { |
|||
border-radius: 4px; |
|||
background-color: #c8c8c8; |
|||
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1); |
|||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .1); |
|||
} |
|||
|
|||
/*定义标题栏*/ |
|||
.page-header { |
|||
background-color: #FFFFFF; |
|||
margin-bottom: 1rem; |
|||
padding: 0.5rem; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.page-title { |
|||
font-weight: bold; |
|||
text-align: left; |
|||
} |
|||
|
|||
.page-header-btn { |
|||
text-align: right; |
|||
} |
|||
</style> |
|||
<style scoped> |
|||
.el-main { |
|||
margin: 0; |
|||
} |
|||
|
|||
.fade-enter { |
|||
visibility: hidden; |
|||
opacity: 0; |
|||
} |
|||
|
|||
.fade-leave-to { |
|||
display: none; |
|||
} |
|||
|
|||
.fade-enter-active, |
|||
.fade-leave-active { |
|||
transition: opacity .5s ease; |
|||
} |
|||
|
|||
.fade-enter-to, |
|||
.fade-leave { |
|||
visibility: visible; |
|||
opacity: 1; |
|||
} |
|||
</style> |
Loading…
Reference in new issue