增加新版本web页面

This commit is contained in:
lin
2025-04-28 15:04:06 +08:00
parent 3c1c68d327
commit 113743a065
268 changed files with 45419 additions and 3 deletions

View File

@@ -0,0 +1,111 @@
<template>
<div id="consoleCPU" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
<ve-line ref="consoleCPU" :data="chartData" :extend="extend" width="100%" height="100%" :legend-visible="false" />
</div>
</template>
<script>
import moment from 'moment/moment'
import veLine from 'v-charts/lib/line'
export default {
name: 'ConsoleCPU',
components: {
veLine
},
data() {
return {
chartData: {
columns: ['time', 'data'],
rows: []
},
extend: {
title: {
show: true,
text: 'CPU',
left: 'center',
top: 20
},
grid: {
show: true,
right: '30px',
containLabel: true
},
xAxis: {
time: 'time',
max: 'dataMax',
boundaryGap: ['20%', '20%'],
axisLabel: {
formatter: (v) => {
return moment(v).format('HH:mm:ss')
},
showMaxLabel: true
}
},
yAxis: {
type: 'value',
min: 0,
max: 1,
splitNumber: 6,
position: 'left',
silent: true,
axisLabel: {
formatter: (v) => {
return v * 100 + '%'
}
}
},
tooltip: {
trigger: 'axis',
formatter: (data) => {
console.log(data)
return moment(data[0].data[0]).format('HH:mm:ss') + '</br> ' +
data[0].marker + '使用:' + (data[0].data[1] * 100).toFixed(2) + '%'
}
},
series: {
itemStyle: {
color: '#409EFF'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: '#50a3f8' // 0% 处的颜色
}, {
offset: 1, color: '#69b0fa' // 100% 处的颜色
}],
global: false // 缺省为 false
}
}
}
}
}
},
created() {
},
mounted() {
this.$nextTick(_ => {
setTimeout(() => {
this.$refs.consoleCPU.echarts.resize()
}, 100)
})
},
destroyed() {
},
methods: {
setData: function(data) {
this.chartData.rows = data
}
}
}
</script>

View File

@@ -0,0 +1,83 @@
<template>
<div id="ConsoleNet" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
<ve-bar ref="ConsoleNet" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" ></ve-bar>
</div>
</template>
<script>
import veBar from 'v-charts/lib/bar'
export default {
name: 'ConsoleNet',
components: {
veBar
},
data() {
return {
chartData: {
columns: ['path','free','use'],
rows: []
},
chartSettings: {
stack: {
'xxx': ['free', 'use']
},
labelMap: {
'free': '剩余',
'use': '已使用'
},
},
extend: {
title: {
show: true,
text: "磁盘",
left: "center",
top: 20,
},
grid: {
show: true,
right: "30px",
containLabel: true,
},
series: {
barWidth: 30
},
legend: {
left: "center",
bottom: "15px",
},
tooltip: {
trigger: 'axis',
formatter: (data)=>{
console.log(data)
let relVal = "";
for (let i = 0; i < data.length; i++) {
relVal += data[i].marker + data[i].seriesName + ":" + data[i].value.toFixed(2) + "GB"
if (i < data.length - 1) {
relVal += "</br>";
}
}
return relVal;
}
},
}
};
},
mounted() {
this.$nextTick(_ => {
setTimeout(()=>{
this.$refs.ConsoleNet.echarts.resize()
}, 100)
})
},
destroyed() {
},
methods: {
setData: function(data) {
this.chartData.rows = data;
}
}
};
</script>

View File

@@ -0,0 +1,106 @@
<template>
<div id="ConsoleMEM" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
<ve-line ref="ConsoleMEM" :data="chartData" :extend="extend" width="100%" height="100%" :legend-visible="false" />
</div>
</template>
<script>
import veLine from 'v-charts/lib/line'
import moment from 'moment/moment'
export default {
name: 'ConsoleMEM',
components: {
veLine
},
data() {
return {
chartData: {
columns: ['time', 'data'],
rows: []
},
extend: {
title: {
show: true,
text: '内存',
left: 'center',
top: 20
},
grid: {
show: true,
right: '30px',
containLabel: true
},
xAxis: {
time: 'time',
max: 'dataMax',
boundaryGap: ['20%', '20%'],
axisLabel: {
formatter: (v) => {
return moment(v).format('HH:mm:ss')
},
showMaxLabel: true
}
},
yAxis: {
type: 'value',
min: 0,
max: 1,
splitNumber: 6,
position: 'left',
silent: true,
axisLabel: {
formatter: (v) => {
return v * 100 + '%'
}
}
},
tooltip: {
trigger: 'axis',
formatter: (data) => {
console.log(data)
return moment(data[0].data[0]).format('HH:mm:ss') + '</br>' + data[0].marker + ' 使用:' + (data[0].data[1] * 100).toFixed(2) + '%'
}
},
series: {
itemStyle: {
color: '#409EFF'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: '#50a3f8' // 0% 处的颜色
}, {
offset: 1, color: '#69b0fa' // 100% 处的颜色
}],
global: false // 缺省为 false
}
}
}
}
}
},
mounted() {
this.$nextTick(_ => {
setTimeout(() => {
this.$refs.ConsoleMEM.echarts.resize()
}, 100)
})
},
destroyed() {
},
methods: {
setData: function(data) {
this.chartData.rows = data
}
}
}
</script>

View File

@@ -0,0 +1,88 @@
<template>
<div id="ConsoleMediaServer" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
<ve-histogram ref="ConsoleMEM" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" />
</div>
</template>
<script>
import veHistogram from 'v-charts/lib/histogram'
import moment from 'moment/moment'
export default {
name: 'ConsoleMediaServer',
components: {
veHistogram
},
data() {
return {
chartData: {
columns: ['time', 'in', 'out'],
rows: [
]
},
chartSettings: {
area: true,
labelMap: {
'in': '下载',
'out': '上传'
}
},
extend: {
title: {
show: true,
text: '网络',
left: 'center',
top: 20
},
grid: {
show: true,
right: '30px',
containLabel: true
},
xAxis: {
time: 'time',
max: 'dataMax',
boundaryGap: ['20%', '20%'],
axisLabel: {
formatter: (v) => {
return moment(v).format('HH:mm:ss')
},
showMaxLabel: true
}
},
tooltip: {
trigger: 'axis',
formatter: (data) => {
console.log(parseFloat(data[0].data[1]).toFixed(2))
console.log(parseFloat(data[1].data[1]).toFixed(2))
console.log('############')
return '下载:' + parseFloat(data[0].data[1]).toFixed(2) + 'Mbps' + '</br> 上传:' + parseFloat(data[1].data[1]).toFixed(2) + 'Mbps'
}
},
legend: {
left: 'center',
bottom: '15px'
}
}
}
},
mounted() {
this.$nextTick(_ => {
setTimeout(() => {
this.$refs.ConsoleMEM.echarts.resize()
}, 100)
})
},
destroyed() {
},
methods: {
setData: function(data) {
console.log(data)
this.chartData.rows = data
}
}
}
</script>

View File

@@ -0,0 +1,135 @@
<template>
<div id="ConsoleNet" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
<ve-line ref="ConsoleNet" :data="chartData" :extend="extend" :settings="chartSettings" :events="chartEvents" width="100%" height="100%" />
</div>
</template>
<script>
import veLine from 'v-charts/lib/line'
import moment from 'moment/moment'
export default {
name: 'ConsoleNet',
components: {
veLine
},
data() {
return {
chartData: {
columns: ['time', 'out', 'in'],
rows: []
},
chartSettings: {
area: true,
labelMap: {
'in': '下载',
'out': '上传'
}
},
extend: {
title: {
show: true,
text: '网络',
left: 'center',
top: 20
},
grid: {
show: true,
right: '30px',
containLabel: true
},
xAxis: {
time: 'time',
max: 'dataMax',
boundaryGap: ['20%', '20%'],
axisLabel: {
formatter: (v) => {
return moment(v).format('HH:mm:ss')
},
showMaxLabel: true
}
},
yAxis: {
type: 'value',
min: 0,
max: 1000,
splitNumber: 6,
position: 'left',
silent: true
},
tooltip: {
trigger: 'axis',
formatter: (data) => {
let in_sel = true
let out_sel = true
for (const key in this.extend.legend.selected) {
if (key == '上传') {
out_sel = this.extend.legend.selected[key]
}
if (key == '下载') {
in_sel = this.extend.legend.selected[key]
}
}
if (out_sel && in_sel) {
return (
data[1].marker +
'下载:' +
parseFloat(data[1].data[1]).toFixed(2) +
'Mbps' +
'</br> ' +
data[0].marker +
'上传:' +
parseFloat(data[0].data[1]).toFixed(2) +
'Mbps'
)
} else if (out_sel) {
return (
data[0].marker +
'上传:' +
parseFloat(data[0].data[1]).toFixed(2) +
'Mbps'
)
} else if (in_sel) {
return (
data[0].marker +
'下载:' +
parseFloat(data[0].data[1]).toFixed(2) +
'Mbps'
)
}
return ''
}
},
legend: {
left: 'center',
bottom: '15px',
selected: {}
}
},
chartEvents: {
legendselectchanged: (item) => {
this.extend.legend.selected = item.selected
}
}
}
},
mounted() {
this.$nextTick(_ => {
setTimeout(() => {
this.$refs.ConsoleNet.echarts.resize()
}, 100)
})
},
destroyed() {
},
methods: {
setData: function(data, total) {
this.chartData.rows = data
this.extend.yAxis.max = total
}
}
}
</script>

View File

@@ -0,0 +1,65 @@
<template>
<div id="ConsoleNodeLoad" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
<ve-histogram ref="consoleNodeLoad" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" :legend-visible="true" />
</div>
</template>
<script>
import veHistogram from 'v-charts/lib/histogram'
export default {
name: 'ConsoleNodeLoad',
components: {
veHistogram
},
data() {
return {
chartData: {
columns: ['id', 'push', 'proxy', 'gbReceive', 'gbSend'],
rows: []
},
chartSettings: {
labelMap: {
'push': '直播推流',
'proxy': '拉流代理',
'gbReceive': '国标收流',
'gbSend': '国标推流'
}
},
extend: {
title: {
show: true,
text: '节点负载',
left: 'center',
top: 20
},
legend: {
left: 'center',
bottom: '15px'
},
label: {
show: true,
position: 'top'
}
}
}
},
mounted() {
this.$nextTick(_ => {
setTimeout(() => {
this.$refs.consoleNodeLoad.echarts.resize()
}, 100)
})
},
destroyed() {
},
methods: {
setData: function(data) {
this.chartData.rows = data
}
}
}
</script>

View File

@@ -0,0 +1,89 @@
<template>
<div id="consoleResource" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
<div style="width: 50%;height: 50%; float:left; ">
<el-progress v-if="deviceInfo.total > 0" :width="100" :stroke-width="8" type="circle" :percentage="Math.floor(deviceInfo.online/deviceInfo.total*100)" style="margin-top: 20px; font-size: 18px" />
<el-progress v-if="deviceInfo.total === 0" :width="100" :stroke-width="8" type="circle" :percentage="0" style="margin-top: 20px; font-size: 18px" />
<div class="resourceInfo">
设备总数:{{ deviceInfo.total }}<br>
在线数:{{ deviceInfo.online }}
</div>
</div>
<div style="width: 50%;height: 50%; float:left; ">
<el-progress v-if="channelInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(channelInfo.online/channelInfo.total*100)" style="margin-top: 20px" />
<el-progress v-if="channelInfo.total === 0" :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px" />
<div class="resourceInfo">
通道总数:{{ channelInfo.total }}<br>
在线数:{{ channelInfo.online }}
</div>
</div>
<div style="width: 50%;height: 50%; float:left; ">
<el-progress v-if="pushInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(pushInfo.online/pushInfo.total*100)" style="margin-top: 20px" />
<el-progress v-if="pushInfo.total === 0" :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px" />
<div class="resourceInfo">
推流总数:{{ pushInfo.total }}<br>
在线数:{{ pushInfo.online }}
</div>
</div>
<div style="width: 50%;height: 50%; float:left; ">
<el-progress v-if="proxyInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(proxyInfo.online/proxyInfo.total*100)" style="margin-top: 20px" />
<el-progress v-if="proxyInfo.total === 0" :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px" />
<div class="resourceInfo">
拉流代理总数:{{ proxyInfo.total }}<br>
在线数:{{ proxyInfo.online }}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ConsoleResource',
data() {
return {
deviceInfo: {
total: 0,
online: 0
},
channelInfo: {
total: 0,
online: 0
},
pushInfo: {
total: 0,
online: 0
},
proxyInfo: {
total: 0,
online: 0
}
}
},
created() {
},
mounted() {
},
destroyed() {
},
methods: {
setData: function(data) {
this.deviceInfo = data.device
this.channelInfo = data.channel
this.pushInfo = data.push
this.proxyInfo = data.proxy
}
}
}
</script>
<style>
.resourceInfo{
width: 100%;
text-align: center;
font-size: 12px
}
.el-progress__text {
font-size: 18px !important;
}
</style>

134
web/src/views/dashboard/index.vue Executable file
View File

@@ -0,0 +1,134 @@
<template>
<div id="app" class="app-container" style="height: calc(100vh - 118px); background-color: rgba(242,242,242,0.50)">
<el-row style="width: 100%;height: 100%;">
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }">
<div id="ThreadsLoad" class="control-cell">
<div style="width:100%; height:100%; ">
<consoleCPU ref="consoleCPU" />
</div>
</div>
</el-col>
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }">
<div id="WorkThreadsLoad" class="control-cell">
<div style="width:100%; height:100%; ">
<consoleResource ref="consoleResource" />
</div>
</div>
</el-col>
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }">
<div id="WorkThreadsLoad" class="control-cell">
<div style="width:100%; height:100%; ">
<consoleNet ref="consoleNet" />
</div>
</div>
</el-col>
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }">
<div id="WorkThreadsLoad" class="control-cell">
<div style="width:100%; height:100%; ">
<consoleMem ref="consoleMem" />
</div>
</div>
</el-col>
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }">
<div id="WorkThreadsLoad" class="control-cell">
<div style="width:100%; height:100%; ">
<consoleNodeLoad ref="consoleNodeLoad" />
</div>
</div>
</el-col>
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }">
<div id="WorkThreadsLoad" class="control-cell">
<div style="width:100%; height:100%; ">
<consoleDisk ref="consoleDisk" />
</div>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import consoleCPU from './console/ConsoleCPU.vue'
import consoleMem from './console/ConsoleMEM.vue'
import consoleNet from './console/ConsoleNet.vue'
import consoleNodeLoad from './console/ConsoleNodeLoad.vue'
import consoleDisk from './console/ConsoleDisk.vue'
import consoleResource from './console/ConsoleResource.vue'
export default {
name: 'Dashboard',
components: {
consoleCPU,
consoleMem,
consoleNet,
consoleNodeLoad,
consoleDisk,
consoleResource
},
data() {
return {
timer: null
}
},
created() {
this.getSystemInfo()
this.getLoad()
this.getResourceInfo()
this.loopForSystemInfo()
},
destroyed() {
window.clearImmediate(this.timer)
},
methods: {
loopForSystemInfo: function() {
if (this.timer != null) {
window.clearTimeout(this.timer)
}
this.timer = setTimeout(() => {
console.log(this.$route.name)
if (this.$route.name === '控制台') {
this.getSystemInfo()
this.getLoad()
this.timer = null
this.loopForSystemInfo()
this.getResourceInfo()
}
}, 2000)
},
getSystemInfo: function() {
this.$store.dispatch('server/getSystemInfo')
.then(data => {
this.$refs.consoleCPU.setData(data.cpu)
this.$refs.consoleMem.setData(data.mem)
this.$refs.consoleNet.setData(data.net, data.netTotal)
this.$refs.consoleDisk.setData(data.disk)
})
},
getLoad: function() {
this.$store.dispatch('server/getMediaServerLoad')
.then(data => {
this.$refs.consoleNodeLoad.setData(data)
})
},
getResourceInfo: function() {
this.$store.dispatch('server/getResourceInfo')
.then(data => {
this.$refs.consoleResource.setData(data)
})
}
}
}
</script>
<style>
#app {
height: 100%;
}
.control-cell {
padding-top: 10px;
padding-left: 5px;
padding-right: 10px;
height: 360px;
}
</style>