Files
profitManage1.1/src/views/index.vue
2025-10-16 19:08:32 +08:00

383 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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">-->
<!-- &lt;!&ndash; 拖拽容器 &ndash;&gt;-->
<!-- <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>