648540858
3 years ago
committed by
GitHub
18 changed files with 2379 additions and 2192 deletions
@ -1,349 +1,350 @@ |
|||||
<template> |
<template> |
||||
<div id="app"> |
<div id="app" style="width: 100%"> |
||||
<el-container> |
<div class="page-header"> |
||||
<el-header> |
<div class="page-title">设备列表</div> |
||||
<uiHeader></uiHeader> |
<div class="page-header-btn"> |
||||
</el-header> |
<el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading" |
||||
<el-main> |
@click="getDeviceList()"></el-button> |
||||
<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> |
</div> |
||||
<span style="font-size: 1rem; font-weight: bold;">设备列表</span> |
</div> |
||||
<div style="position: absolute; right: 1rem; top: 0.3rem;"> |
<!-- <devicePlayer ref="devicePlayer"></devicePlayer> --> |
||||
<el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading" @click="getDeviceList()"></el-button> |
<!--设备列表--> |
||||
</div> |
<el-table :data="deviceList" border style="width: 100%;font-size: 12px;" :height="winHeight"> |
||||
</div> |
<el-table-column prop="name" label="名称" align="center"> |
||||
<!-- <devicePlayer ref="devicePlayer"></devicePlayer> --> |
</el-table-column> |
||||
<!--设备列表--> |
<el-table-column prop="deviceId" label="设备编号" width="180" align="center"> |
||||
<el-table :data="deviceList" border style="width: 100%;font-size: 12px;" :height="winHeight"> |
</el-table-column> |
||||
<el-table-column prop="name" label="名称" align="center"> |
<el-table-column label="地址" width="180" align="center"> |
||||
</el-table-column> |
<template slot-scope="scope"> |
||||
<el-table-column prop="deviceId" label="设备编号" width="180" align="center"> |
<div slot="reference" class="name-wrapper"> |
||||
</el-table-column> |
<el-tag size="medium">{{ scope.row.hostAddress }}</el-tag> |
||||
<el-table-column label="地址" width="180" align="center"> |
</div> |
||||
<template slot-scope="scope"> |
</template> |
||||
<div slot="reference" class="name-wrapper"> |
</el-table-column> |
||||
<el-tag size="medium">{{ scope.row.hostAddress }}</el-tag> |
<el-table-column prop="manufacturer" label="厂家" align="center"> |
||||
</div> |
</el-table-column> |
||||
</template> |
<el-table-column label="流传输模式" align="center" width="120"> |
||||
</el-table-column> |
<template slot-scope="scope"> |
||||
<el-table-column prop="manufacturer" label="厂家" align="center"> |
<el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择"> |
||||
</el-table-column> |
<el-option key="UDP" label="UDP" value="UDP"></el-option> |
||||
<el-table-column label="流传输模式" align="center" width="120"> |
<el-option key="TCP-ACTIVE" label="TCP主动模式" :disabled="true" value="TCP-ACTIVE"></el-option> |
||||
<template slot-scope="scope"> |
<el-option key="TCP-PASSIVE" label="TCP被动模式" value="TCP-PASSIVE"></el-option> |
||||
<el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择"> |
</el-select> |
||||
<el-option key="UDP" label="UDP" value="UDP"></el-option> |
</template> |
||||
<el-option key="TCP-ACTIVE" label="TCP主动模式" :disabled="true" value="TCP-ACTIVE"></el-option> |
</el-table-column> |
||||
<el-option key="TCP-PASSIVE" label="TCP被动模式" value="TCP-PASSIVE"></el-option> |
<el-table-column prop="channelCount" label="通道数" align="center"> |
||||
</el-select> |
</el-table-column> |
||||
</template> |
<el-table-column label="状态" width="120" align="center"> |
||||
</el-table-column> |
<template slot-scope="scope"> |
||||
<el-table-column prop="channelCount" label="通道数" align="center"> |
<div slot="reference" class="name-wrapper"> |
||||
</el-table-column> |
<el-tag size="medium" v-if="scope.row.online == 1">在线</el-tag> |
||||
<el-table-column label="状态" width="120" align="center"> |
<el-tag size="medium" type="info" v-if="scope.row.online == 0">离线</el-tag> |
||||
<template slot-scope="scope"> |
</div> |
||||
<div slot="reference" class="name-wrapper"> |
</template> |
||||
<el-tag size="medium" v-if="scope.row.online == 1">在线</el-tag> |
</el-table-column> |
||||
<el-tag size="medium" type="info" v-if="scope.row.online == 0">离线</el-tag> |
<el-table-column prop="keepaliveTime" label="最近心跳" align="center" width="140"> |
||||
</div> |
</el-table-column> |
||||
</template> |
<el-table-column prop="registerTime" label="最近注册" align="center" width="140"> |
||||
</el-table-column> |
</el-table-column> |
||||
<el-table-column prop="keepaliveTime" label="最近心跳" align="center" width="140"> |
<el-table-column prop="updateTime" label="更新时间" align="center" width="140"> |
||||
</el-table-column> |
</el-table-column> |
||||
<el-table-column prop="registerTime" label="最近注册" align="center" width="140"> |
<el-table-column prop="createTime" label="创建时间" align="center" width="140"> |
||||
</el-table-column> |
</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"> |
<el-table-column label="操作" width="450" align="center" fixed="right"> |
||||
<template slot-scope="scope"> |
<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 size="mini" v-if="scope.row.online!=0" icon="el-icon-refresh" @click="refDevice(scope.row)" |
||||
<el-button-group> |
@mouseover="getTooltipContent(scope.row.deviceId)">刷新 |
||||
<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> |
||||
<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-group> |
||||
<el-button size="mini" icon="el-icon-edit" type="primary" @click="edit(scope.row)">编辑</el-button> |
<el-button size="mini" icon="el-icon-video-camera-solid" v-bind:disabled="scope.row.online==0" |
||||
<el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteDevice(scope.row)">删除</el-button> |
type="primary" @click="showChannelList(scope.row)">通道 |
||||
</el-button-group> |
</el-button> |
||||
</template> |
<el-button size="mini" icon="el-icon-location" v-bind:disabled="scope.row.online==0" type="primary" |
||||
</el-table-column> |
@click="showDevicePosition(scope.row)">定位 |
||||
</el-table> |
</el-button> |
||||
<el-pagination |
<el-button size="mini" icon="el-icon-edit" type="primary" @click="edit(scope.row)">编辑</el-button> |
||||
style="float: right" |
<el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteDevice(scope.row)">删除</el-button> |
||||
@size-change="handleSizeChange" |
</el-button-group> |
||||
@current-change="currentChange" |
</template> |
||||
:current-page="currentPage" |
</el-table-column> |
||||
:page-size="count" |
</el-table> |
||||
:page-sizes="[15, 25, 35, 50]" |
<el-pagination |
||||
layout="total, sizes, prev, pager, next" |
style="float: right" |
||||
:total="total"> |
@size-change="handleSizeChange" |
||||
</el-pagination> |
@current-change="currentChange" |
||||
<deviceEdit ref="deviceEdit" ></deviceEdit> |
:current-page="currentPage" |
||||
<syncChannelProgress ref="syncChannelProgress" ></syncChannelProgress> |
:page-size="count" |
||||
</el-main> |
:page-sizes="[15, 25, 35, 50]" |
||||
</el-container> |
layout="total, sizes, prev, pager, next" |
||||
</div> |
:total="total"> |
||||
|
</el-pagination> |
||||
|
<deviceEdit ref="deviceEdit"></deviceEdit> |
||||
|
<syncChannelProgress ref="syncChannelProgress"></syncChannelProgress> |
||||
|
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
import uiHeader from './UiHeader.vue' |
import uiHeader from '../layout/UiHeader.vue' |
||||
import deviceEdit from './dialog/deviceEdit.vue' |
import deviceEdit from './dialog/deviceEdit.vue' |
||||
import syncChannelProgress from './dialog/SyncChannelProgress.vue' |
import syncChannelProgress from './dialog/SyncChannelProgress.vue' |
||||
export default { |
|
||||
name: 'app', |
|
||||
components: { |
|
||||
uiHeader, |
|
||||
deviceEdit, |
|
||||
syncChannelProgress, |
|
||||
}, |
|
||||
data() { |
|
||||
return { |
|
||||
deviceList: [], //设备列表 |
|
||||
currentDevice: {}, //当前操作设备对象 |
|
||||
|
|
||||
videoComponentList: [], |
export default { |
||||
updateLooper: 0, //数据刷新轮训标志 |
name: 'app', |
||||
currentDeviceChannelsLenth:0, |
components: { |
||||
winHeight: window.innerHeight - 200, |
uiHeader, |
||||
currentPage:1, |
deviceEdit, |
||||
count:15, |
syncChannelProgress, |
||||
total:0, |
}, |
||||
getDeviceListLoading: false, |
data() { |
||||
}; |
return { |
||||
}, |
deviceList: [], //设备列表 |
||||
computed: { |
currentDevice: {}, //当前操作设备对象 |
||||
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; |
|
||||
}); |
|
||||
|
|
||||
}, |
videoComponentList: [], |
||||
deleteDevice: function(row) { |
updateLooper: 0, //数据刷新轮训标志 |
||||
let msg = "确定删除此设备?" |
currentDeviceChannelsLenth: 0, |
||||
if (row.online !== 0) { |
winHeight: window.innerHeight - 200, |
||||
msg = "在线设备删除后仍可通过注册再次上线。<br/>如需彻底删除请先将设备离线。<br/><strong>确定删除此设备?</strong>" |
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, '提示', { |
}).then(function (res) { |
||||
dangerouslyUseHTMLString : true, |
that.total = res.data.total; |
||||
confirmButtonText: '确定', |
that.deviceList = res.data.list; |
||||
cancelButtonText: '取消', |
that.getDeviceListLoading = false; |
||||
center: true, |
}).catch(function (error) { |
||||
type: 'warning' |
console.error(error); |
||||
}).then(() => { |
that.getDeviceListLoading = false; |
||||
this.$axios({ |
}); |
||||
method: 'delete', |
|
||||
url:`/api/device/query/devices/${row.deviceId}/delete` |
|
||||
}).then((res)=>{ |
|
||||
this.getDeviceList(); |
|
||||
}).catch((error) =>{ |
|
||||
console.error(error); |
|
||||
}); |
|
||||
}).catch(() => { |
|
||||
|
|
||||
|
}, |
||||
|
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) { |
showChannelList: function (row) { |
||||
this.$router.push(`/channelList/${row.deviceId}/0/15/1`); |
this.$router.push(`/channelList/${row.deviceId}/0/15/1`); |
||||
}, |
}, |
||||
showDevicePosition: function(row) { |
showDevicePosition: function (row) { |
||||
this.$router.push(`/devicePosition/${row.deviceId}/0/15/1`); |
this.$router.push(`/devicePosition/${row.deviceId}/0/15/1`); |
||||
}, |
}, |
||||
|
|
||||
//gb28181平台对接 |
//gb28181平台对接 |
||||
//刷新设备信息 |
//刷新设备信息 |
||||
refDevice: function(itemData) { |
refDevice: function (itemData) { |
||||
console.log("刷新对应设备:" + itemData.deviceId); |
console.log("刷新对应设备:" + itemData.deviceId); |
||||
let that = this; |
let that = this; |
||||
this.$axios({ |
this.$axios({ |
||||
method: 'post', |
method: 'post', |
||||
url: '/api/device/query/devices/' + itemData.deviceId + '/sync' |
url: '/api/device/query/devices/' + itemData.deviceId + '/sync' |
||||
}).then((res) => { |
}).then((res) => { |
||||
console.log("刷新设备结果:"+JSON.stringify(res)); |
console.log("刷新设备结果:" + JSON.stringify(res)); |
||||
if (res.data.code !==0) { |
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) |
|
||||
that.$message({ |
that.$message({ |
||||
showClose: true, |
showClose: true, |
||||
message: e, |
message: res.data.msg, |
||||
type: 'error' |
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){ |
getTooltipContent: async function (deviceId) { |
||||
let result = ""; |
let result = ""; |
||||
await this.$axios({ |
await this.$axios({ |
||||
method: 'get', |
method: 'get', |
||||
async: false, |
async: false, |
||||
url:`/api/device/query/${deviceId}/sync_status/`, |
url: `/api/device/query/${deviceId}/sync_status/`, |
||||
}).then((res) => { |
}).then((res) => { |
||||
if (res.data.code == 0) { |
if (res.data.code == 0) { |
||||
if (res.data.data.errorMsg !== null) { |
if (res.data.data.errorMsg !== null) { |
||||
result = res.data.data.errorMsg |
result = res.data.data.errorMsg |
||||
} else if (res.data.msg !== null) { |
} else if (res.data.msg !== null) { |
||||
result = res.data.msg |
result = res.data.msg |
||||
} else { |
} else { |
||||
result = `同步中...[${res.data.data.current}/${res.data.data.total}]`; |
result = `同步中...[${res.data.data.current}/${res.data.data.total}]`; |
||||
} |
} |
||||
} |
} |
||||
}) |
}) |
||||
return result; |
return result; |
||||
}, |
}, |
||||
//通知设备上传媒体流 |
//通知设备上传媒体流 |
||||
sendDevicePush: function(itemData) { |
sendDevicePush: function (itemData) { |
||||
// let deviceId = this.currentDevice.deviceId; |
// let deviceId = this.currentDevice.deviceId; |
||||
// let channelId = itemData.channelId; |
// let channelId = itemData.channelId; |
||||
// console.log("通知设备推流1:" + deviceId + " : " + channelId); |
// console.log("通知设备推流1:" + deviceId + " : " + channelId); |
||||
// let that = this; |
// let that = this; |
||||
// this.$axios({ |
// this.$axios({ |
||||
// method: 'get', |
// method: 'get', |
||||
// url: '/api/play/' + deviceId + '/' + channelId |
// url: '/api/play/' + deviceId + '/' + channelId |
||||
// }).then(function(res) { |
// }).then(function(res) { |
||||
// let ssrc = res.data.ssrc; |
// let ssrc = res.data.ssrc; |
||||
// that.$refs.devicePlayer.play(ssrc,deviceId,channelId); |
// that.$refs.devicePlayer.play(ssrc,deviceId,channelId); |
||||
// }).catch(function(e) { |
// }).catch(function(e) { |
||||
// }); |
// }); |
||||
}, |
}, |
||||
transportChange: function (row) { |
transportChange: function (row) { |
||||
console.log(`修改传输方式为 ${row.streamMode}:${row.deviceId} `); |
console.log(`修改传输方式为 ${row.streamMode}:${row.deviceId} `); |
||||
let that = this; |
let that = this; |
||||
this.$axios({ |
this.$axios({ |
||||
method: 'post', |
method: 'post', |
||||
url: '/api/device/query/transport/' + row.deviceId + '/' + row.streamMode |
url: '/api/device/query/transport/' + row.deviceId + '/' + row.streamMode |
||||
}).then(function(res) { |
}).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", |
||||
}); |
}); |
||||
}, |
setTimeout(this.getDeviceList, 200) |
||||
edit: function (row) { |
|
||||
this.$refs.deviceEdit.openDialog(row, ()=>{ |
|
||||
this.$refs.deviceEdit.close(); |
|
||||
this.$message({ |
|
||||
showClose: true, |
|
||||
message: "设备修改成功,通道字符集将在下次更新生效", |
|
||||
type: "success", |
|
||||
}); |
|
||||
setTimeout(this.getDeviceList, 200) |
|
||||
|
|
||||
}) |
}) |
||||
} |
} |
||||
|
|
||||
} |
} |
||||
}; |
}; |
||||
</script> |
</script> |
||||
|
|
||||
<style> |
<style> |
||||
.videoList { |
.videoList { |
||||
display: flex; |
display: flex; |
||||
flex-wrap: wrap; |
flex-wrap: wrap; |
||||
align-content: flex-start; |
align-content: flex-start; |
||||
} |
} |
||||
|
|
||||
.video-item { |
.video-item { |
||||
position: relative; |
position: relative; |
||||
width: 15rem; |
width: 15rem; |
||||
height: 10rem; |
height: 10rem; |
||||
margin-right: 1rem; |
margin-right: 1rem; |
||||
background-color: #000000; |
background-color: #000000; |
||||
} |
} |
||||
|
|
||||
.video-item-img { |
.video-item-img { |
||||
position: absolute; |
position: absolute; |
||||
top: 0; |
top: 0; |
||||
bottom: 0; |
bottom: 0; |
||||
left: 0; |
left: 0; |
||||
right: 0; |
right: 0; |
||||
margin: auto; |
margin: auto; |
||||
width: 100%; |
width: 100%; |
||||
height: 100%; |
height: 100%; |
||||
} |
} |
||||
|
|
||||
.video-item-img:after { |
.video-item-img:after { |
||||
content: ""; |
content: ""; |
||||
display: inline-block; |
display: inline-block; |
||||
position: absolute; |
position: absolute; |
||||
z-index: 2; |
z-index: 2; |
||||
top: 0; |
top: 0; |
||||
bottom: 0; |
bottom: 0; |
||||
left: 0; |
left: 0; |
||||
right: 0; |
right: 0; |
||||
margin: auto; |
margin: auto; |
||||
width: 3rem; |
width: 3rem; |
||||
height: 3rem; |
height: 3rem; |
||||
background-image: url("../assets/loading.png"); |
background-image: url("../assets/loading.png"); |
||||
background-size: cover; |
background-size: cover; |
||||
background-color: #000000; |
background-color: #000000; |
||||
} |
} |
||||
|
|
||||
.video-item-title { |
.video-item-title { |
||||
position: absolute; |
position: absolute; |
||||
bottom: 0; |
bottom: 0; |
||||
color: #000000; |
color: #000000; |
||||
background-color: #ffffff; |
background-color: #ffffff; |
||||
line-height: 1.5rem; |
line-height: 1.5rem; |
||||
padding: 0.3rem; |
padding: 0.3rem; |
||||
width: 14.4rem; |
width: 14.4rem; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
@ -1,141 +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="/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="报警信息推送" 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> |
<template> |
||||
<div id="channelList"> |
<div id="channelList" style="width: 100%"> |
||||
<el-container> |
<div class="page-header"> |
||||
<el-header> |
<div class="page-title"> |
||||
<uiHeader></uiHeader> |
<el-button icon="el-icon-arrow-left" size="mini" style="margin-right: 1rem;" type="primary" @click="showDevice"> |
||||
</el-header> |
返回 |
||||
<el-main> |
</el-button> |
||||
<div style="background-color: #FFFFFF; position: relative; padding: 1rem 0.5rem 0.5rem 0.5rem; text-align: center;"> |
通道列表({{ parentChannelId == 0 ? deviceId : parentChannelId }})</div> |
||||
<span style="font-size: 1rem; font-weight: 500; ">通道列表({{parentChannelId ==0 ? deviceId:parentChannelId}})</span> |
<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-select size="mini" @change="search" style="margin-right: 1rem;" v-model="channelType" placeholder="请选择" |
||||
<el-button icon="el-icon-arrow-left" size="mini" style="margin-right: 1rem;" type="primary" @click="showDevice">返回</el-button> |
default-first-option> |
||||
搜索: <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-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"> |
||||
<el-table-column label="操作" width="280" align="center" fixed="right"> |
<template slot-scope="scope"> |
||||
<template slot-scope="scope"> |
<el-button-group> |
||||
<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" 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-video-play" @click="sendDevicePush(scope.row)">播放</el-button> |
<el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" |
||||
<el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" @click="stopDevicePush(scope.row)">停止</el-button> |
@click="stopDevicePush(scope.row)">停止 |
||||
<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> |
||||
<el-button size="mini" icon="el-icon-video-camera" type="primary" @click="queryRecords(scope.row)">设备录象</el-button> |
<el-button size="mini" icon="el-icon-s-open" type="primary" v-if="scope.row.subCount > 0" |
||||
<!-- <el-button size="mini" @click="sendDevicePush(scope.row)">录像查询</el-button> --> |
@click="changeSubchannel(scope.row)">查看 |
||||
</el-button-group> |
</el-button> |
||||
</template> |
<el-button size="mini" icon="el-icon-video-camera" type="primary" @click="queryRecords(scope.row)">设备录象 |
||||
</el-table-column> |
</el-button> |
||||
</el-table> |
<!-- <el-button size="mini" @click="sendDevicePush(scope.row)">录像查询</el-button> --> |
||||
<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-button-group> |
||||
</el-pagination> |
</template> |
||||
|
</el-table-column> |
||||
</el-main> |
</el-table> |
||||
</el-container> |
<el-pagination style="float: right" @size-change="handleSizeChange" @current-change="currentChange" |
||||
</div> |
:current-page="currentPage" :page-size="count" :page-sizes="[15, 20, 30, 50]" |
||||
|
layout="total, sizes, prev, pager, next" :total="total"> |
||||
|
</el-pagination> |
||||
|
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
import devicePlayer from './dialog/devicePlayer.vue' |
import devicePlayer from './dialog/devicePlayer.vue' |
||||
import uiHeader from './UiHeader.vue' |
import uiHeader from '../layout/UiHeader.vue' |
||||
import moment from "moment"; |
import moment from "moment"; |
||||
|
|
||||
export default { |
export default { |
||||
name: 'channelList', |
name: 'channelList', |
||||
components: { |
components: { |
||||
devicePlayer, |
devicePlayer, |
||||
uiHeader |
uiHeader |
||||
}, |
}, |
||||
data() { |
data() { |
||||
return { |
return { |
||||
deviceId: this.$route.params.deviceId, |
deviceId: this.$route.params.deviceId, |
||||
parentChannelId: this.$route.params.parentChannelId, |
parentChannelId: this.$route.params.parentChannelId, |
||||
deviceChannelList: [], |
deviceChannelList: [], |
||||
videoComponentList: [], |
videoComponentList: [], |
||||
currentPlayerInfo: {}, //当前播放对象 |
currentPlayerInfo: {}, //当前播放对象 |
||||
updateLooper: 0, //数据刷新轮训标志 |
updateLooper: 0, //数据刷新轮训标志 |
||||
searchSrt: "", |
searchSrt: "", |
||||
channelType: "", |
channelType: "", |
||||
online: "", |
online: "", |
||||
winHeight: window.innerHeight - 250, |
winHeight: window.innerHeight - 250, |
||||
currentPage: parseInt(this.$route.params.page), |
currentPage: parseInt(this.$route.params.page), |
||||
count: parseInt(this.$route.params.count), |
count: parseInt(this.$route.params.count), |
||||
total: 0, |
total: 0, |
||||
beforeUrl: "/deviceList", |
beforeUrl: "/deviceList", |
||||
isLoging: false, |
isLoging: false, |
||||
autoList: true, |
autoList: true, |
||||
loadSnap:{} |
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(); |
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() { |
getDeviceChannelList: function () { |
||||
this.$destroy('videojs'); |
let that = this; |
||||
clearTimeout(this.updateLooper); |
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) { |
sendDevicePush: function (itemData) { |
||||
var url = `/${this.$router.currentRoute.name}/${this.deviceId}/${this.parentChannelId}/${this.count}/${val}` |
let deviceId = this.deviceId; |
||||
this.$router.push(url).then(() => { |
this.isLoging = true; |
||||
this.initParam(); |
let channelId = itemData.channelId; |
||||
this.initData(); |
console.log("通知设备推流1:" + deviceId + " : " + channelId); |
||||
}) |
let that = this; |
||||
}, |
this.$axios({ |
||||
handleSizeChange: function (val) { |
method: 'get', |
||||
var url = `/${this.$router.currentRoute.name}/${this.$router.params.deviceId}/${this.$router.params.parentChannelId}/${val}/1` |
url: '/api/play/start/' + deviceId + '/' + channelId |
||||
this.$router.push(url).then(() => { |
}).then(function (res) { |
||||
this.initParam(); |
that.isLoging = false; |
||||
this.initData(); |
if (res.data.code === 0) { |
||||
}) |
|
||||
|
|
||||
}, |
setTimeout(() => { |
||||
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); |
|
||||
}); |
|
||||
}, |
|
||||
|
|
||||
//通知设备上传媒体流 |
let snapId = deviceId + "_" + channelId; |
||||
sendDevicePush: function (itemData) { |
that.loadSnap[snapId] = 0; |
||||
let deviceId = this.deviceId; |
that.getSnapErrorEvent(snapId) |
||||
this.isLoging = true; |
}, 5000) |
||||
let channelId = itemData.channelId; |
that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { |
||||
console.log("通知设备推流1:" + deviceId + " : " + channelId ); |
streamInfo: res.data.data, |
||||
let that = this; |
hasAudio: itemData.hasAudio |
||||
this.$axios({ |
}); |
||||
method: 'get', |
setTimeout(() => { |
||||
url: '/api/play/start/' + deviceId + '/' + channelId |
that.initData(); |
||||
}).then(function (res) { |
}, 1000) |
||||
that.isLoging = false; |
|
||||
if (res.data.code === 0) { |
|
||||
|
|
||||
setTimeout(()=>{ |
} else { |
||||
|
that.$message.error(res.data.msg); |
||||
let snapId = deviceId + "_" + channelId; |
} |
||||
that.loadSnap[snapId] = 0; |
}).catch(function (e) { |
||||
that.getSnapErrorEvent(snapId) |
}); |
||||
},5000) |
}, |
||||
that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { |
queryRecords: function (itemData) { |
||||
streamInfo: res.data.data, |
var format = moment().format("YYYY-M-D"); |
||||
hasAudio: itemData.hasAudio |
let deviceId = this.deviceId; |
||||
}); |
let channelId = itemData.channelId; |
||||
setTimeout(()=>{ |
this.$refs.devicePlayer.openDialog("record", deviceId, channelId, {date: format}) |
||||
that.initData(); |
}, |
||||
},1000) |
stopDevicePush: function (itemData) { |
||||
|
var that = this; |
||||
}else { |
this.$axios({ |
||||
that.$message.error(res.data.msg); |
method: 'get', |
||||
} |
url: '/api/play/stop/' + this.deviceId + "/" + itemData.channelId |
||||
}).catch(function (e) {}); |
}).then(function (res) { |
||||
}, |
that.initData(); |
||||
queryRecords: function (itemData) { |
}).catch(function (error) { |
||||
var format = moment().format("YYYY-M-D"); |
if (error.response.status === 402) { // 已经停止过 |
||||
let deviceId = this.deviceId; |
that.initData(); |
||||
let channelId = itemData.channelId; |
} else { |
||||
this.$refs.devicePlayer.openDialog("record", deviceId, channelId, {date: format}) |
console.log(error) |
||||
}, |
} |
||||
stopDevicePush: function (itemData) { |
}); |
||||
var that = this; |
}, |
||||
this.$axios({ |
getSnap: function (row) { |
||||
method: 'get', |
return '/static/snap/' + row.deviceId + '_' + row.channelId + '.jpg' |
||||
url: '/api/play/stop/' + this.deviceId + "/" + itemData.channelId |
}, |
||||
}).then(function (res) { |
getSnapErrorEvent: function (id) { |
||||
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") { |
if (typeof (this.loadSnap[id]) != "undefined") { |
||||
console.log("下载截图" + this.loadSnap[id]) |
console.log("下载截图" + this.loadSnap[id]) |
||||
if (this.loadSnap[id] > 5) { |
if (this.loadSnap[id] > 5) { |
||||
delete this.loadSnap[id]; |
delete this.loadSnap[id]; |
||||
return; |
return; |
||||
} |
} |
||||
setTimeout(()=>{ |
setTimeout(() => { |
||||
this.loadSnap[id] ++ |
this.loadSnap[id]++ |
||||
document.getElementById(id).setAttribute("src", '/static/snap/' + id + '.jpg?' + new Date().getTime()) |
document.getElementById(id).setAttribute("src", '/static/snap/' + id + '.jpg?' + new Date().getTime()) |
||||
},1000) |
}, 1000) |
||||
|
|
||||
} |
} |
||||
}, |
}, |
||||
showDevice: function () { |
showDevice: function () { |
||||
this.$router.push(this.beforeUrl).then(() => { |
this.$router.push(this.beforeUrl).then(() => { |
||||
this.initParam(); |
this.initParam(); |
||||
this.initData(); |
this.initData(); |
||||
}) |
}) |
||||
}, |
}, |
||||
changeSubchannel(itemData) { |
changeSubchannel(itemData) { |
||||
this.beforeUrl = this.$router.currentRoute.path; |
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` |
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.$router.push(url).then(() => { |
||||
this.searchSrt = ""; |
this.searchSrt = ""; |
||||
this.channelType = ""; |
this.channelType = ""; |
||||
this.online = ""; |
this.online = ""; |
||||
this.initParam(); |
this.initParam(); |
||||
this.initData(); |
this.initData(); |
||||
}) |
}) |
||||
}, |
}, |
||||
showSubchannels: function (channelId) { |
showSubchannels: function (channelId) { |
||||
let that = this; |
let that = this; |
||||
|
|
||||
this.$axios({ |
this.$axios({ |
||||
method: 'get', |
method: 'get', |
||||
url:`/api/device/query/sub_channels/${this.deviceId}/${this.parentChannelId}/channels`, |
url: `/api/device/query/sub_channels/${this.deviceId}/${this.parentChannelId}/channels`, |
||||
params: { |
params: { |
||||
page: that.currentPage, |
page: that.currentPage, |
||||
count: that.count, |
count: that.count, |
||||
query: that.searchSrt, |
query: that.searchSrt, |
||||
online: that.online, |
online: that.online, |
||||
channelType: that.channelType |
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); |
|
||||
} |
|
||||
} |
} |
||||
|
}).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> |
</script> |
||||
|
|
||||
<style> |
<style> |
||||
.videoList { |
.videoList { |
||||
display: flex; |
display: flex; |
||||
flex-wrap: wrap; |
flex-wrap: wrap; |
||||
align-content: flex-start; |
align-content: flex-start; |
||||
} |
} |
||||
|
|
||||
.video-item { |
.video-item { |
||||
position: relative; |
position: relative; |
||||
width: 15rem; |
width: 15rem; |
||||
height: 10rem; |
height: 10rem; |
||||
margin-right: 1rem; |
margin-right: 1rem; |
||||
background-color: #000000; |
background-color: #000000; |
||||
} |
} |
||||
|
|
||||
.video-item-img { |
.video-item-img { |
||||
position: absolute; |
position: absolute; |
||||
top: 0; |
top: 0; |
||||
bottom: 0; |
bottom: 0; |
||||
left: 0; |
left: 0; |
||||
right: 0; |
right: 0; |
||||
margin: auto; |
margin: auto; |
||||
width: 100%; |
width: 100%; |
||||
height: 100%; |
height: 100%; |
||||
} |
} |
||||
|
|
||||
.video-item-img:after { |
.video-item-img:after { |
||||
content: ""; |
content: ""; |
||||
display: inline-block; |
display: inline-block; |
||||
position: absolute; |
position: absolute; |
||||
z-index: 2; |
z-index: 2; |
||||
top: 0; |
top: 0; |
||||
bottom: 0; |
bottom: 0; |
||||
left: 0; |
left: 0; |
||||
right: 0; |
right: 0; |
||||
margin: auto; |
margin: auto; |
||||
width: 3rem; |
width: 3rem; |
||||
height: 3rem; |
height: 3rem; |
||||
background-image: url("../assets/loading.png"); |
background-image: url("../assets/loading.png"); |
||||
background-size: cover; |
background-size: cover; |
||||
background-color: #000000; |
background-color: #000000; |
||||
} |
} |
||||
|
|
||||
.video-item-title { |
.video-item-title { |
||||
position: absolute; |
position: absolute; |
||||
bottom: 0; |
bottom: 0; |
||||
color: #000000; |
color: #000000; |
||||
background-color: #ffffff; |
background-color: #ffffff; |
||||
line-height: 1.5rem; |
line-height: 1.5rem; |
||||
padding: 0.3rem; |
padding: 0.3rem; |
||||
width: 14.4rem; |
width: 14.4rem; |
||||
} |
} |
||||
</style> |
</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