383 lines
14 KiB
Vue
383 lines
14 KiB
Vue
<template>
|
||
<div class="app-container home w100" style="height: calc(100vh - 85px);color: #000;overflow: scroll;">
|
||
<!-- header -->
|
||
<div class="w100" style="height: 17%;min-height: 110px;">
|
||
<div v-for="(item,index) of headerList" class="h100 disInlineBlock" :style="`margin-right:${index + 1 === headerList.length ? 'none' : '1.3%'}`"
|
||
style="width: 24%;padding: 10px 15px;border: 1px solid #d8dce6;border-radius: 10px;vertical-align: bottom;">
|
||
<div style="font-size: 14px;">{{item.title}}</div>
|
||
<div style="margin: 15px 0 10px;">
|
||
<div class="disInlineBlock w50"><span style="font-size: 1.5rem;">{{item.num}}</span><span style="display: inline-block;margin-left: 5px">{{item.unit}}</span></div>
|
||
<img v-if="item && item.type === 'switch'" src="@/assets/images/switch.png" class="fr" width="100" height="35px" alt="">
|
||
<img v-else src="@/assets/images/line.png" class="fr" width="100" alt="">
|
||
</div>
|
||
<div style="font-size: 10px;">{{item.lastVal}} <span>{{item.lastNum}}</span></div>
|
||
</div>
|
||
</div>
|
||
<!-- middle -->
|
||
<div class="w100" style="height: 35%;margin: 1% 0;">
|
||
<div class="disInlineBlock h100" style="width: 24%;border: 1px solid #d8dce6;border-radius: 10px;">
|
||
<EchartsPie :dataList="dataList[0]" class="w100 h100"></EchartsPie>
|
||
</div>
|
||
<div class="disInlineBlock h100" style="width: 49.4%;border: 1px solid #d8dce6;border-radius: 10px;margin: 0 1.3%;">
|
||
<EchartsBar :barData="lineDataParams" :title="`当日业务的在线设备数量统计TOP`+ lineDataParams.data.length" class="w100 h100"></EchartsBar>
|
||
</div>
|
||
<div class="disInlineBlock h100" style="width: 24%;border: 1px solid #d8dce6;border-radius: 10px;">
|
||
<EchartsPie :dataList="dataList[1]" class="w100 h100"></EchartsPie>
|
||
</div>
|
||
</div>
|
||
<!-- footer -->
|
||
<div class="w100" style="height: 44%;margin: 1% 0 0;">
|
||
<div class="disInlineBlock h100 p10" style="width: 49.5%;border: 1px solid #d8dce6;border-radius: 10px;margin-right: 1%;vertical-align: middle;">
|
||
<div style="font-size: 14px;height: 7%">
|
||
<span>服务器带宽收益</span>
|
||
<span @click="routerLine(1)" style="float: right;font-size: 12px; color: #0d52d9;cursor: pointer;">更多 >></span>
|
||
</div>
|
||
<div style="height: 93%;overflow: scroll;" class="newSty w100">
|
||
<TableList style="height: 95%" class="w100" :config="{colHiddenCheck: true, colTopHiddenIcon: true}" :columns="serverColumns" :queryParams="serQueryParams" :tableList="serTableList" @fnRenderList="serverTableList"></TableList>
|
||
</div>
|
||
</div>
|
||
<div class="disInlineBlock h100 p10" style="width: 49.5%;border: 1px solid #d8dce6;border-radius: 10px;vertical-align: middle;">
|
||
<div style="font-size: 14px;height: 7%">
|
||
<span>资源监控</span>
|
||
<span @click="routerLine(2)" style="float: right;font-size: 12px; color: #0d52d9;cursor: pointer;">更多 >></span>
|
||
</div>
|
||
<div style="height: 93%;overflow: scroll;" class="newSty w100">
|
||
<TableList style="height: 95%" class="w100" :config="{colHiddenCheck: true, colTopHiddenIcon: true}" :columns="resMonitorColumns" :queryParams="resQueryParams" :tableList="resTableList" @fnRenderList="resMonitorTableList"></TableList>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- <div v-if="echartList && echartList.length > 0" class="w100" style="height: 30%;margin: 1% 0 0">-->
|
||
<!-- <!– 拖拽容器 –>-->
|
||
<!-- <draggable-->
|
||
<!-- class="w100 h100"-->
|
||
<!-- v-model="echartList"-->
|
||
<!-- :animation="150"-->
|
||
<!-- :handle="'.el-collapse-item__header'"-->
|
||
<!-- :ghost-class="'ghost-item'"-->
|
||
<!-- :chosen-class="'chosen-item'"-->
|
||
<!-- @start="onDragStart"-->
|
||
<!-- @end="onDragEnd">-->
|
||
<!-- <template v-for="(val,index) of echartList">-->
|
||
<!-- <el-collapse v-model="activeNames" class="w100 h100">-->
|
||
<!-- <el-collapse-item :title="val.title" name="1" class="w100 h100">-->
|
||
<!-- <EchartsLine class="w100 h100" :sideIcon="{iconName: [{name: '从首页删除',type: 'del'}]}" :lineData="val.dataVal" :chartData="(valData) => chartDataEvent(valData, val)"></EchartsLine>-->
|
||
<!-- </el-collapse-item>-->
|
||
<!-- </el-collapse>-->
|
||
<!-- </template>-->
|
||
<!-- </draggable>-->
|
||
<!-- </div>-->
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import draggable from 'vuedraggable'
|
||
import EchartsPie from "@/components/echartsList/pie.vue"
|
||
import EchartsLine from "@/components/echartsList/line.vue"
|
||
import EchartsBar from "@/components/echartsList/bar.vue"
|
||
import TableList from "@/components/table/index.vue";
|
||
import {listBandWidth} from "@/api/disRevenue/earnManage"
|
||
import {listTopology} from "@/api/disRevenue/resource"
|
||
import {countBusiness, sumTrafficByServer, sumTrafficBySwitch, countSwitchNum, serverOnlineRate, countDeviceNumTop5} from "@/api/homeIndex";
|
||
export default {
|
||
name: "Index",
|
||
components: {draggable, EchartsPie, EchartsLine, EchartsBar, TableList},
|
||
data() {
|
||
return {
|
||
// 版本号
|
||
version: "3.6.6",
|
||
headerList: [
|
||
{title: '当前在线服务器的流量相关的业务数', num: '0', unit: '个'},
|
||
{title: '当前在线服务器发送带宽总流量', type: 'switch', num: '0', unit: 'Mbps'},
|
||
{title: '当前在线交换机接收带宽总流量', type: 'switch', num: '0', unit: 'Mbps'},
|
||
{title: '交换机在线数量', num: '0', unit: '个', lastVal: '交换机注册总数', lastNum: '0'},
|
||
],
|
||
lineDataParams: {
|
||
titleVal: {x: '1%', y: '3%',fontSize: 14, textAlign: 'left'},
|
||
gridTop: '15%',
|
||
seriesLabel: true,
|
||
hiddenTime: true,
|
||
yAxis: true,
|
||
hidAxisLabel: true,
|
||
hidSplitLine: true,
|
||
name: ' ',
|
||
lineXData: [],
|
||
data: []
|
||
},
|
||
dataList: [{
|
||
titleVal: {title: '服务器在线率', show: true, x: '1%', y: '3%', textAlign: 'left'},
|
||
centerVal: '0%',
|
||
lastVal: '在线率',
|
||
color: ['#0d52d9', '#bbc4d2'],
|
||
radius: ['60%', '70%'],
|
||
data: [
|
||
{ value: 0, name: '在线' },
|
||
{ value: 0, name: '总数' }
|
||
]
|
||
},{
|
||
titleVal: {title: '资源告警处理情况', show: true, x: '1%', y: '3%', textAlign: 'left'},
|
||
centerVal: '82%',
|
||
lastVal: '告警处理率',
|
||
radius: ['60%', '70%'],
|
||
color: ['#0d52d9', '#bbc4d2'],
|
||
data: [
|
||
{ value: 82, name: '已处理告警数' },
|
||
{ value: 28, name: '总告警数' }
|
||
]
|
||
}],
|
||
// 列显隐信息
|
||
serverColumns: {
|
||
id: {label: `ID`},
|
||
nodeName: {label: `节点名称`, visible: true},
|
||
businessName: {label: `业务名称`, visible: true},
|
||
effectiveBandwidth95Daily: {label: `有效95带宽值Mbps/日`, width: '160px', visible: true},
|
||
avgMonthlyBandwidth95: {label: `月均日95值Mbps`, width: '130px', visible: true}
|
||
},
|
||
serTableList:[],
|
||
serQueryParams: {
|
||
pageNum: 1,
|
||
pageSize: 5,
|
||
total: 0,
|
||
layout: 'pager'
|
||
},
|
||
// 列显隐信息
|
||
resMonitorColumns: {
|
||
id: { label: `ID`, visible: false },
|
||
switchName: { label: `资源名称`, visible: true },
|
||
interfaceName: { label: `ip地址`, visible: true },
|
||
serverSn: { label: `CPU使用率%`,visible: true},
|
||
serverPort: { label: `内存使用率%`, visible: true }
|
||
},
|
||
resTableList: [],
|
||
resQueryParams: {
|
||
pageNum: 1,
|
||
pageSize: 6,
|
||
total: 0,
|
||
layout: 'pager'
|
||
},
|
||
// 拖拽列
|
||
activeNames: ['1'],
|
||
dragStatus: '',
|
||
echartList: [{
|
||
title: '设备CPU使用率(%)',
|
||
dataVal: {
|
||
titleVal: {textAlign: 'left', left: '1%'},
|
||
gridTop: '30%',
|
||
legend: {top: '5%', left: '10%'},
|
||
lineXData: ['2025-9-1', '2025-9-2', '2025-9-3', '2025-9-4', '2025-9-5', '2025-9-6', '2025-9-7'],
|
||
dataList: [{
|
||
name: '设备CPU使用率',
|
||
data: [120, 132, 101, 134, 90, 230, 210],
|
||
}]
|
||
}
|
||
},{
|
||
title: '设备内存使用率(%)',
|
||
dataVal: {
|
||
titleVal: {textAlign: 'left', left: '1%'},
|
||
gridTop: '30%',
|
||
legend: {top: '5%', left: '10%'},
|
||
lineXData: ['2025-9-1', '2025-9-2', '2025-9-3', '2025-9-4', '2025-9-5', '2025-9-6', '2025-9-7'],
|
||
dataList: [{
|
||
name: '设备内存使用率',
|
||
data: [120, 132, 101, 134, 90, 230, 210],
|
||
},{
|
||
name: 'CPU运行用户进程所花费的时间',
|
||
data: [220, 182, 191, 234, 290, 330, 310]
|
||
}]
|
||
}
|
||
}],
|
||
}
|
||
},
|
||
created() {
|
||
this.serverTableList();
|
||
this.resMonitorTableList();
|
||
this.getCountBusiness();
|
||
this.getSumTrafficByServer();
|
||
this.getSumTrafficBySwitch();
|
||
this.getCountSwitchNum();
|
||
this.getServerOnlineRate();
|
||
this.getCountDeviceNumTop5();
|
||
},
|
||
methods: {
|
||
getCountBusiness(){
|
||
countBusiness().then(res => {
|
||
this.headerList[0].num = res && res.data;
|
||
});
|
||
},
|
||
getSumTrafficByServer(){
|
||
sumTrafficByServer().then(res => {
|
||
this.headerList[1].num = res && res.data;
|
||
});
|
||
},
|
||
getSumTrafficBySwitch(){
|
||
sumTrafficBySwitch().then(res => {
|
||
this.headerList[2].num = res && res.data;
|
||
});
|
||
},
|
||
getCountSwitchNum(){
|
||
countSwitchNum().then(res => {
|
||
this.headerList[3].num = res && res.onlineCount;
|
||
this.headerList[3].lastNum = res && res.total;
|
||
});
|
||
},
|
||
getServerOnlineRate(){
|
||
serverOnlineRate().then(res => {
|
||
if (res) {
|
||
let newParams = {
|
||
centerVal: res.onlineRate + '%',
|
||
data: [
|
||
{value: res && res.onlineCount, name: '在线'},
|
||
{value: res && res.offlineCount, name: '总数'}
|
||
]
|
||
};
|
||
this.dataList[0] = Object.assign({}, this.dataList[0], newParams);
|
||
}
|
||
});
|
||
},
|
||
getCountDeviceNumTop5(){
|
||
countDeviceNumTop5().then(res => {
|
||
let lineXData = [];
|
||
let dataList = [];
|
||
if (res && res.data) {
|
||
let newArr = res.data;
|
||
if (res.data && res.data.length < 5) {
|
||
newArr = this.sortedNum(res.data);
|
||
}
|
||
newArr.forEach(item => {
|
||
lineXData.push(item.businessName);
|
||
dataList.push(item.total);
|
||
});
|
||
this.lineDataParams['lineXData'] = lineXData;
|
||
this.lineDataParams['data'] = dataList;
|
||
}
|
||
});
|
||
},
|
||
sortedNum(data){
|
||
// 提取value并转换为数字,同时保存name映射
|
||
const valueMap = new Map(); // 存储 {value: name}
|
||
const values = [];
|
||
|
||
for (const item of data) {
|
||
const value = parseInt(item.total, 10);
|
||
// 校验value有效性
|
||
if (isNaN(value) || value <= 0) {
|
||
return "错误:所有value必须是大于0的数字";
|
||
}
|
||
// 校验重复value
|
||
if (valueMap.has(value)) {
|
||
return "错误:输入数组不能包含重复的value";
|
||
}
|
||
valueMap.set(value, item.businessName);
|
||
values.push(value);
|
||
}
|
||
|
||
// 对输入value排序(降序)
|
||
const sortedInputs = [...values].sort((a, b) => b - a);
|
||
|
||
// 生成目标value序列(包含所有输入值的5个递减正数)
|
||
let targetValues = [];
|
||
let start = sortedInputs[0];
|
||
while (true) {
|
||
const candidate = new Set();
|
||
// 先加入所有输入值
|
||
sortedInputs.forEach(v => candidate.add(v));
|
||
// 从start开始向下补充,直到有5个值
|
||
let current = start;
|
||
while (candidate.size < 5) {
|
||
if (current <= 0) break;
|
||
candidate.add(current);
|
||
current--;
|
||
}
|
||
// 转换为数组并排序(降序)
|
||
const arr = [...candidate].sort((a, b) => b - a);
|
||
if (arr.length === 5 && arr.every(v => v > 0)) {
|
||
targetValues = arr;
|
||
break;
|
||
}
|
||
start++; // 若当前start无法生成有效序列,增大start重试
|
||
}
|
||
|
||
// 生成每个value对应的name
|
||
const result = [];
|
||
for (const val of targetValues) {
|
||
if (valueMap.has(val)) {
|
||
// 已有value,使用原name
|
||
result.push({ businessName: valueMap.get(val), total: val.toString() });
|
||
} else {
|
||
// 补充的value,寻找对应的name前缀
|
||
// 找到小于当前val的最大输入value
|
||
const closestSmaller = sortedInputs.find(v => v < val);
|
||
if (closestSmaller !== undefined) {
|
||
const prefix = valueMap.get(closestSmaller);
|
||
result.push({ businessName: `${prefix}${val}`, total: val.toString() });
|
||
} else {
|
||
// 若所有输入值都大于当前val(极端情况),用最大输入值的name
|
||
const maxInput = sortedInputs[0];
|
||
const prefix = valueMap.get(maxInput);
|
||
result.push({ businessName: `${prefix}${val}`, total: val.toString() });
|
||
}
|
||
}
|
||
}
|
||
return result;
|
||
},
|
||
serverTableList() {
|
||
listBandWidth(this.serQueryParams).then(response => {
|
||
this.serTableList = response.rows;
|
||
this.serQueryParams.total = response.total;
|
||
})
|
||
},
|
||
resMonitorTableList() {
|
||
listTopology(this.resQueryParams).then(response => {
|
||
this.resTableList = response.rows;
|
||
this.resQueryParams.total = response.total;
|
||
})
|
||
},
|
||
// 跳转页面
|
||
routerLine(num) {
|
||
if (num === 1) {
|
||
this.$router.push({path:'/earnManage/server'});
|
||
}
|
||
if (num === 2) {
|
||
this.$router.push({path:'/resource/resMonitor'});
|
||
}
|
||
},
|
||
// 拖拽开始
|
||
onDragStart(evt){
|
||
this.dragStatus = `开始拖拽:从位置 ${evt.oldIndex + 1}`;
|
||
},
|
||
// 拖拽结束(获取最新顺序)
|
||
onDragEnd (evt) {
|
||
this.dragStatus = `拖拽结束:从位置 ${evt.oldIndex + 1} → 位置 ${evt.newIndex + 1}`;
|
||
// 此时 items 已自动更新顺序,可直接使用
|
||
console.log('更新后的列表:', this.items);
|
||
},
|
||
chartDataEvent(val, itemVal) {
|
||
console.log('val===',val);
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
::-webkit-scrollbar {
|
||
width: 0px!important;
|
||
height: 0px!important;
|
||
}
|
||
/*::v-deep .newSty .el-table {*/
|
||
/* height: 190px;*/
|
||
/* overflow-y: scroll;*/
|
||
/*}*/
|
||
::v-deep .el-collapse-item__header {
|
||
background-color: #d4e3fc!important;
|
||
/*color: #fff!important;*/
|
||
padding-left: 20px;
|
||
font-size: 1rem;
|
||
}
|
||
::v-deep .el-collapse-item__wrap {
|
||
height: 85%;
|
||
}
|
||
::v-deep .el-collapse-item__content {
|
||
height: 100%;
|
||
}
|
||
</style>
|
||
|