当前位置: 首页 > article >正文

网络管理-期末项目(附源码)

环境:网络管理 主机资源监控系统项目搭建 (保姆级教程 建议点赞 收藏)_搭建网络版信息管理系统-CSDN博客

效果图

 

下面3个文件的项目目录(python3.8.8的虚拟环境)

D:\py_siqintu\myproject5\Scripts\mytest.py

D:\py_siqintu\myproject5\Scripts\templates\main.html

D:\py_siqintu\myproject5\Scripts\static\css\style.css

main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>System Information</title> 
    <script src="{{ url_for('static', filename='js/Bubble.js') }}"></script>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
    <script type="text/javascript" src="https://registry.npmmirror.com/jquery/3.7.1/files/dist/jquery.min.js"></script>
    <script type="text/javascript" src="https://registry.npmmirror.com/echarts/5.5.1/files/dist/echarts.min.js"></script>
</head>

<body>
  <div class="head clearfix">
    <h1 style="text-align: center;">主机资源监控系统</h1>
    </div>
    <div class="mainbox">
    
    <ul class="clearfix nav1">
      <li style="width: 22%">
      <div class="box" style="padding-right: 0;">
        <div class="tit">CPU负载Top5</div>		
        <div id="cpu-monitor" style="width: 340px;height:230px;"></div>
      </div>
      <div class="box">
      <div class="tit">内存占用Top5</div>
      <div id="memory-monitor" style="width: 340px;height:230px;" ></div>
      </div>
      </li>
      <li style="width: 56%">
      <div class="box">
        <div class="boxnav mapc" style="height: 550px; position: relative">
          <div class="mapnav1" style="display: flex;">
            <img style="height: 200px; width: 250px; margin-top: 20px;" src="{{ url_for('static', filename='images/pc.png') }}" alt="PC Image">
            <div style="margin-top: 20px;">
              <div style="font-family: Arial, sans-serif; font-size: 14px; border: 1px solid #ccc; border-radius: 5px; padding: 10px; background-color: #f9f9f9; width: 700px;">
                <div style="display: flex; justify-content: space-between; margin-bottom: 5px; border-bottom: 1px solid #ddd; padding-bottom: 5px;">
                    <p style="font-weight: bold; margin: 0;">系统名字:</p>
                    <p id="SystemNamessr2" style="margin: 0;"></p>
                </div>
                <div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
                    <p style="font-weight: bold; margin: 0;">系统描述:</p>
                    <p id="SystemDescription" style="margin: 0;"></p>
                </div>
                <div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
                    <p style="font-weight: bold; margin: 0;">内存大小:</p>
                    <p id="Memorysize" style="margin: 0;"></p>
                </div>
                <div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
                    <p style="font-weight: bold; margin: 0;">运行时间:</p>
                    <p id="Systemuptime" style="margin: 0;"></p>
                </div>
                <div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
                    <p style="font-weight: bold; margin: 0;">TCP活跃连接数:</p>
                    <p id="tcp_connections" style="margin: 0;"></p>
                </div>
                <div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
                    <p style="font-weight: bold; margin: 0;">当前进程总数:</p>
                    <p id="process_count" style="margin: 0;"></p>
                </div>
                <div style="display: flex; justify-content: space-between; margin-bottom: 5px;">
                    <p style="font-weight: bold; margin: 0;">本机IP:</p>
                    <p id="ip_address" style="margin: 0;"></p>
                </div>
            </div>
           <script>var myurCON = "http://" + window.location.host+"/config/";
            setInterval(()=>{
              fetch(myurCON).then(res=>{
                return res.json()
              }).then((json)=>{
                console.log(json);
                var SystemNamessr2 = document.getElementById('SystemNamessr2');
                SystemNamessr2.innerHTML = json.ssyname;

                var SystemDescription = document.getElementById('SystemDescription');
                SystemDescription.innerHTML =  json.sysDecr;
        
                var Memorysize = document.getElementById('Memorysize');
                let memoryInKiB = json.mem; 
                let memoryReadable =  (memoryInKiB / 1048576).toFixed(2) + " GB"
                Memorysize.innerHTML = memoryReadable;

                var Systemuptime = document.getElementById('Systemuptime');
                let uptimeInHundredths = json.sysUptime; 
                let uptimeInSeconds = uptimeInHundredths * 0.01; 
                let days = Math.floor(uptimeInSeconds / (24 * 3600));
                let hours = Math.floor((uptimeInSeconds % (24 * 3600)) / 3600);
                let minutes = Math.floor((uptimeInSeconds % 3600) / 60);
                let seconds = Math.floor(uptimeInSeconds % 60);
                let uptimeReadable = `${days}天 ${hours}小时 ${minutes}分钟 ${seconds}秒`;
                Systemuptime.innerHTML = uptimeReadable;
              })
            },1000)</script>
          </div>     
        </div>
        <div style="display: flex;">
          <div id="gaugeChart" class="chart" style="width: 350px;height:300px;"></div>	
          <script>
          var gaugeDom = document.getElementById('gaugeChart');
            var gaugeChart = echarts.init(gaugeDom, null, {
              renderer: 'canvas',
              useDirtyRect: false
            });
            var app={}
            var gaugeOption = {
              tooltip: {
                formatter: '{a} <br/>{b} : {c}%'
              },
              series: [
                {
                  name: 'Pressure',
                  type: 'gauge',
                  detail: {
                    formatter: '{value}'
                  },
                  data: [
                    {
                      value: 98,
                      name: 'CPU负载'
                    }
                  ]
                }
              ]
            };
        
            if (gaugeOption && typeof gaugeOption === 'object') {
              gaugeChart.setOption(gaugeOption);
            }
            var myurl3 = "http://" + window.location.host+"/cpu/";
            setInterval(()=>{
              fetch(myurl3).then(res=>{
                return res.json()
              }).then((json)=>{
                gaugeOption.series[0].data[0].value = json.cpu;
                gaugeChart.setOption(gaugeOption);
              })
            },1000)
            </script>
          <div id="disk_usage" style="width: 350px;height:300px;"></div>	
          <script>
            var domdisk_usage = document.getElementById('disk_usage');
var myChartdisk_usage = echarts.init(domdisk_usage, null, {
renderer: 'canvas',
useDirtyRect: false
});
var mydisk_usage = "http://" + window.location.host + "/get_disk/";
var optiondisk_usage = {
tooltip: {
    trigger: 'item',
    formatter: '{a} <br/>{b}: {c}% ({d}%)'
},
legend: {
    top: '5%',
    left: 'center'
},
series: [
    {
        name: 'Disk Usage',
        type: 'pie',
        radius: ['40%', '70%'],
        center: ['50%', '60%'],
        startAngle: 180,
        endAngle: 360,
        data: [
            { name: 'Free', value: 0 },
            { name: 'Used', value: 0 }
        ] 
    }
]
};
myChartdisk_usage.setOption(optiondisk_usage);

setInterval(() => {
fetch(mydisk_usage)
    .then(response => response.json())
    .then(data => {
        console.log(data); 
        const free = data.free;
        const used = data.used;
        const total = data.total;
        if (typeof free === 'number' && typeof used === 'number' && typeof total === 'number') {

            const freePercent = (free / total) * 100;
            const usedPercent = (used / total) * 100;

       
            myChartdisk_usage.setOption({
                series: [
                    {
                        data: [
                            { name: 'Free', value: freePercent },
                            { name: 'Used', value: usedPercent }
                        ]
                    }
                ]
            });
        } else {
            console.error('Invalid data format', data);
        }
    })
    .catch(error => {
        console.error('Error fetching disk usage:', error);
    });
}, 1000);



  </script>
          <div id="memory_usage" class="chart" style="height: 300px; width: 350px;"></div>
          </div>
          <script>

var memory_usageDom = document.getElementById('memory_usage');
    var memory_usageChart = echarts.init(memory_usageDom, null, {
      renderer: 'canvas',
      useDirtyRect: false
    });
    var app={}
    var memory_usageOption = {
      tooltip: {
        formatter: '{a} <br/>{b} : {c}%'
      },
      series: [
        {
          name: 'Pressure',
          type: 'gauge',
          detail: {
            formatter: '{value}'
          },
          data: [
            {
              value: 98,
              name: '内存占有率'
            }
          ]
        }
      ]
    };
    if (memory_usageOption && typeof memory_usageOption === 'object') {
      memory_usageChart.setOption(memory_usageOption);
    }
    var myurl99 = "http://" + window.location.host+"/Memoryusage/";
  setInterval(()=>{
    fetch(myurl99).then(res=>{    
          return res.json()
       }).then((json)=>{
        memory_usageOption.series[0].data[0].value = json.memory_usage;
        memory_usageChart.setOption(memory_usageOption);
         })},1000);
          </script>

      </li>
      <li style="width: 22%">
      
      <div class="box">
        <div class="tit">网络接口状态统计</div>
        <div  id="echart3">
        <div id="interface_status" style="height: 230px; width: 350px;"></div>
        <script>


var interfaceDataUrl = "http://" + window.location.host + "/interface_status/";
let interfaceChart = echarts.init(document.getElementById('interface_status'));
let interfaceChartOption = {
    
    tooltip: {
        trigger: 'axis',
        axisPointer: {
            type: 'shadow'
        }
    },
    xAxis: {
        type: 'category',
        data: [], 
        axisLabel: {
            interval: 0,
            rotate: 45
        }
    },
    yAxis: {
        type: 'value',
        name: '',
        minInterval: 1
    },
    series: [
        {
            name: '',
            type: 'bar',
            data: [], 
            itemStyle: {
                color: function (params) {
                    let colorMap = {
                        '运行中': '#4caf50',   
                        '已关闭': '#f44336', 
                        '未启用': '#9e9e9e'  
                    };
                    return colorMap[params.name] || '#000'; 
                }
            }
        }
    ]
};
interfaceChart.setOption(interfaceChartOption);
setInterval(() => {
    fetch(interfaceDataUrl)
        .then(response => response.json())
        .then(data => {
            let statusNames = {
                up: '运行中',
                down: '已关闭',
                notPresent: '未启用'
            };
            let statusCount = {
                '运行中': 0,
                '已关闭': 0,
                '未启用': 0
            };
            data.interfaces.forEach(interface => {
                let status = statusNames[interface.status];
                if (statusCount[status] !== undefined) {
                    statusCount[status]++;
                }
            });
            interfaceChartOption.xAxis.data = Object.keys(statusCount);
            interfaceChartOption.series[0].data = Object.values(statusCount); 

            interfaceChart.setOption(interfaceChartOption);
        })
        .catch(error => {
            console.error("Error fetching interface data:", error);
        });
}, 1000); 

        </script>
        </div>
        </div>
        <div class="box">
        <div class="tit">丢包率和误包率</div>
 
        <div id="error_loss_chart" style="width: 350px;height:200px; margin-top: 20px;"></div>	
        </div>
      
      </li>
      </ul>
      
      <div class="box" style="padding: 20px 0; height: 335px;">
      <ul class="clearfix nav2 ">
      <li style="width:25%;"><div class="tit01">实时流量(MB)</div>
        
        
        <div id="net_s" style="width: 350px;height:240px; margin-top: 20px;"></div>
        <script>

var net_s_Dom = document.getElementById('net_s');
    var myChart_net_s = echarts.init(net_s_Dom, null, {
      renderer: 'canvas',
      useDirtyRect: false
    });
var x_a = new Array();
for(var i =0;i<=200;i++)
{
  x_a.push(i)
}
var app={}
var option_net_s = {
  animation: false,
  title: {
    text: ''
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type:'',
      label: {
        backgroundColor: '#6a7985'
      }
    }
  },
  legend: {
    data: ['入流量', '出流量']
  },
  toolbox: {
    feature: {
      saveAsImage: {}
    }
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '3%',
    containLabel: true
  },  
  xAxis: [
    {
      type: 'category',
      boundaryGap: false,
      data: x_a
    }
  ],
  yAxis: [
    {
      type: 'value'
    }
  ],

series: [
    {
      name: '入流量',
      type: 'line',
      
      emphasis: {
        focus: 'series'
      },
      data: []
    },
    {
      name: '出流量',
      type: 'line',
      
      emphasis: {
        focus: 'series'
      },
      data: [],
      valueAnimation: false
    }
  ]
};
myChart_net_s.setOption(option_net_s);

var mydata_net_in= new Array();
  var mydata_net_out = new Array();
  var net_last_in = 0;
  var net_last_out = 0;
  var myurl4 = "http://" + window.location.host+"/net_m/";
  setInterval(()=>{
    fetch(myurl4).then(res=>{    
          return res.json()
       }).then((json)=>{
          i = (json.in_s - net_last_in);
          o = (json.out_s - net_last_out);
          console.log(i,o);
          
          if(i < 0) 
             i = i + 2**32;
          if(o < 0) 
            o = o + 2**32
          i = i / (1048576)
          o = o / (1048576)
          mydata_net_in.push(i);
          mydata_net_out.push(o);
          net_last_in = json.in_s
          net_last_out = json.out_s
          if (mydata_net_in.length > 200)
          {
             mydata_net_in.shift(json.in_s);
             mydata_net_out.shift(json.out_s);
          }
          option_net_s.series[0].data=mydata_net_in;
          option_net_s.series[1].data=mydata_net_out;
          myChart_net_s.setOption(option_net_s);
         })},1000);

        </script>
        </li>
      <li style="width:25%"><div class="tit01">历史网络流量(5min)</div>
        <div id="net_traffic_chart" style="width: 350px;height:350px;"></div>
       <script>
        var netTrafficContainer = document.getElementById('net_traffic_chart');
var netTrafficChart = echarts.init(netTrafficContainer, null, {
  renderer: 'canvas',
  useDirtyRect: false
});
var netTrafficOption = {
  tooltip: { trigger: 'axis' },
  legend: { data: ['入流量', '出流量'] },
  xAxis: { type: 'category', boundaryGap: true, data: [] },
  yAxis: { type: 'value', name: 'Traffic (MB)' },
  series: [
    { name: 'Incoming Traffic', type: 'line', data: [] },
    { name: 'Outgoing Traffic', type: 'line', data: [] }
  ],
  animationDuration: 0,
  animationDurationUpdate: 3000,
  animationEasing: 'linear',
  animationEasingUpdate: 'linear'
};

netTrafficChart.setOption(netTrafficOption);
var trafficDataUrl = "http://" + window.location.host + "/net_h/";
setInterval(() => {
  fetch(trafficDataUrl)
    .then(response => response.json())
    .then(data => {
      var newTimeStamps = data.timestamps || [];
      var newIncomingTraffic = data.net_in || [];
      var newOutgoingTraffic = data.net_out || [];
      netTrafficOption.xAxis.data = newTimeStamps.slice(-30);
      netTrafficOption.series[0].data = newIncomingTraffic.slice(-30);
      netTrafficOption.series[1].data = newOutgoingTraffic.slice(-30);
      netTrafficChart.setOption(netTrafficOption);
    })
    .catch(error => console.error('Error fetching traffic data:', error));
}, 3000);
window.addEventListener('resize', netTrafficChart.resize);
       </script>
        <div class="ftechart" id="echart4"></div>
        </li>
      <li style="width:25%">
        <div class="tit01">网络波动</div>
        						<div id="network_volatility" style="width: 300px; height: 300px;"></div>

                    <script>

var networkVolatilityDom = document.getElementById('network_volatility');
var networkVolatilityChart = echarts.init(networkVolatilityDom, null, {
    renderer: 'canvas',
    useDirtyRect: false
});

var networkVolatilityOption = {
    tooltip: {
        trigger: 'axis'
    },
    xAxis: {
        type: 'category',
        data: [] 
    },
    yAxis: {
        type: 'value',
        axisLabel: {
            formatter: '{value} bytes'
        }
    },
    series: [
        {
            name: '波动字节',
            type: 'line',
            smooth: true,
            data: []  
        }
    ]
};

if (networkVolatilityOption && typeof networkVolatilityOption === 'object') {
    networkVolatilityChart.setOption(networkVolatilityOption);
}
var myurlNetworkVolatility = "http://" + window.location.host + "/volatility/";

setInterval(() => {
    fetch(myurlNetworkVolatility)  
        .then(res => res.json())
        .then((json) => {
            const currentTimestamp = new Date().toISOString(); 
            if (json.volatility !== undefined) {
                networkVolatilityOption.xAxis.data.push(currentTimestamp);  
                networkVolatilityOption.series[0].data.push(json.volatility);  
            }
            if (networkVolatilityOption.xAxis.data.length > 10) {
                networkVolatilityOption.xAxis.data.shift();
                networkVolatilityOption.series[0].data.shift();
            }

            networkVolatilityChart.setOption(networkVolatilityOption);
        })
        .catch((error) => console.error("获取网络波动字节数据失败", error));
}, 1000);

                    </script>
        </li>
      <li style="width:25%"><div class="tit01">TCP&UDP</div>
        <div id="tcp_udp_chart" style="width: 350px;height:240px; margin-top: 20px;"></div>

        <script>

var tcp_udp_Dom = document.getElementById('tcp_udp_chart');
var tcp_udp_chart = echarts.init(tcp_udp_Dom, null, {
    renderer: 'canvas',
    useDirtyRect: false
});
var tcp_udp_option = {
    title: {
        text: ''
    },
    tooltip: {
        trigger: 'axis'
    },
    legend: {
        data: ['TCP In', 'TCP Out', 'UDP In', 'UDP Out']
    },
    grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
    },
    xAxis: {
        type: 'category',
        boundaryGap: false,
        data: []  
    },
    yAxis: [
        {
            type: 'value',
            name: 'TCP Packets',
            min: 0,
            max: 800000, 
            position: 'left',
            axisLine: {
                lineStyle: {
                    color: '#5470C6' 
                }
            }
        },
        {
            type: 'value',
            name: 'UDP Packets',
            min: 0,
            max: 800000, 
            position: 'right',
            axisLine: {
                lineStyle: {
                    color: '#91CC75' 
                }
            }
        }
    ],
    series: [
        {
            name: 'TCP In',
            type: 'line',
            yAxisIndex: 0, 
            data: []  
        },
        {
            name: 'TCP Out',
            type: 'line',
            yAxisIndex: 0, 
            data: []  
        },
        {
            name: 'UDP In',
            type: 'line',
            yAxisIndex: 1, 
            data: []  
        },
        {
            name: 'UDP Out',
            type: 'line',
            yAxisIndex: 1,
            data: [] 
        }
    ]
};

tcp_udp_chart.setOption(tcp_udp_option);
var myurl2 = "http://" + window.location.host + "/tcp_udp_status/";

setInterval(() => {
    fetch(myurl2)
        .then(res => res.json())
        .then(json => {
            var now = new Date().toLocaleTimeString(); 
            tcp_udp_option.xAxis.data.push(now);
            if (tcp_udp_option.xAxis.data.length > 50) {
                tcp_udp_option.xAxis.data.shift();
            }
            tcp_udp_option.series[0].data.push(json.tcp_in); 
            tcp_udp_option.series[1].data.push(json.tcp_out);
            tcp_udp_option.series[2].data.push(json.udp_in);         
            tcp_udp_option.series[3].data.push(json.udp_out);         
            if (tcp_udp_option.series[0].data.length > 50) {
                tcp_udp_option.series[0].data.shift();
                tcp_udp_option.series[1].data.shift();
                tcp_udp_option.series[2].data.shift();
                tcp_udp_option.series[3].data.shift();
            }
            tcp_udp_chart.setOption(tcp_udp_option);
        })
        .catch(error => console.error('Error fetching TCP/UDP data:', error));
}, 1000);
        </script>
        <div class="" id="">
        <div style="float: left; width: 50%; height: 200px" id="fb03"></div>
        <div style="float: left; width: 50%; height: 200px"  id="fb04"></div>
          
        </div>
        
        </li>
      </ul>
      </div>
     
    </div>




       
   

    <script>


    var myur50 = "http://" + window.location.host+"/ip_addresses/";
    setInterval(()=>{
      fetch(myur50).then(res=>{
        return res.json()
      }).then((json)=>{
        console.log(json)
        var SystemDescription = document.getElementById('ip_address');
        SystemDescription.innerHTML =  json.ip_addresses.ip_addresses;
      })
    },1000)
   
    




    


    var errorLossChartDom = document.getElementById('error_loss_chart');
var errorLossChart = echarts.init(errorLossChartDom, null, {
    renderer: 'canvas',
    useDirtyRect: false
});
var errorLossChartOptions = {
    title: {
        text: ''
    },
    tooltip: {
        trigger: 'axis'
    },
    legend: {
        data: [
            'In Packet Loss Rate', 
            'Out Packet Loss Rate', 
            'In Error Rate', 
            'Out Error Rate'
        ]
    },
    grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
    },
    xAxis: {
        type: 'category',
        boundaryGap: false,
        data: []  
    },
    yAxis: {
        type: 'value',
        name: 'Rate (%)',
        min: 0,
        max: 100,
        position: 'left',
        axisLine: {
            lineStyle: {
                color: '#5470C6' 
            }
        }
    },
    series: [
        {
            name: 'In Packet Loss Rate',
            type: 'line',
            data: [], 
            lineStyle: {
                color: '#EE6666'
            }
        },
        {
            name: 'Out Packet Loss Rate',
            type: 'line',
            data: [], 
            lineStyle: {
                color: '#5470C6'
            }
        },
        {
            name: 'In Error Rate',
            type: 'line',
            data: [],  
            lineStyle: {
                color: '#91CC75'
            }
        },
        {
            name: 'Out Error Rate',
            type: 'line',
            data: [],  
            lineStyle: {
                color: '#FAC858'
            }
        }
    ]
};

errorLossChart.setOption(errorLossChartOptions);
var errorLossDataUrl = "http://" + window.location.host + "/packet_loss_rate/";
setInterval(() => {
    fetch(errorLossDataUrl)
        .then(res => res.json())
        .then(json => {
            var now = new Date().toLocaleTimeString(); 
            errorLossChartOptions.xAxis.data.push(now);
            if (errorLossChartOptions.xAxis.data.length > 50) {
                errorLossChartOptions.xAxis.data.shift();
            }
            errorLossChartOptions.series[0].data.push(json.in_packet_loss_rate);
            errorLossChartOptions.series[1].data.push(json.out_packet_loss_rate);
            errorLossChartOptions.series[2].data.push(json.in_error_rate);
            errorLossChartOptions.series[3].data.push(json.out_error_rate);
            if (errorLossChartOptions.series[0].data.length > 50) {
                errorLossChartOptions.series[0].data.shift();
                errorLossChartOptions.series[1].data.shift();
                errorLossChartOptions.series[2].data.shift();
                errorLossChartOptions.series[3].data.shift();
            }
            errorLossChart.setOption(errorLossChartOptions);
        })
        .catch(error => console.error('Error fetching Packet Loss & Error Rate data:', error));
}, 1000);

var cpuMonitorContainer = document.getElementById('cpu-monitor');
    var cpuChart = echarts.init(cpuMonitorContainer, null, {
      renderer: 'canvas',
      useDirtyRect: false
    });


    var cpuChartOption = {
      grid: {
    left: '20%', 
    right: '10%',
    top: '10%',
    bottom: '10%'
  },
      xAxis: {
        type: 'value',
        max: 'dataMax',
        name: 'CPU %',
        nameLocation: 'middle',
        nameGap: 30
      },
      yAxis: {
        type: 'category',
        data: [], 
        inverse: true,
        name: '',
        nameLocation: 'middle',
        nameGap: 50,
        nameTextStyle: {
    fontSize: 16, 
    fontWeight: 'bold',
    color: '#333' 
  }
      },
      series: [
        {
          name: 'CPU Usage',
          type: 'bar',
          data: [], 
          label: {
            show: true,
            position: 'right',
            formatter: '{c}%', 
            valueAnimation: true
          }
        }
      ],
      tooltip: {
        trigger: 'item',
        formatter: '{b}: {c}%' 
      },
      legend: {
        show: true,
        data: ['CPU Usage']
      },
      animationDuration: 0,
      animationDurationUpdate: 3000,
      animationEasing: 'linear',
      animationEasingUpdate: 'linear'
    };


    const processNames = []; 
    const processCpuUsage = []; 

    
    cpuChart.setOption(cpuChartOption);

    
    window.addEventListener('resize', cpuChart.resize);
    errorLossChart.setOption(errorLossChartOptions);
    var cpuDataUrl = "http://" + window.location.host + "/top_processes/";
setInterval(() => {
    fetch(cpuDataUrl)
        .then(res => res.json())
        .then(data => {
            var processNames = [];
            var processCpuUsage = [];
            
          
            data.top_cpu_processes.forEach(process => {
                processNames.push(process.name || `PID ${process.pid}`);
                processCpuUsage.push(process.cpu_percent);
            });

            
            cpuChartOption.yAxis.data = processNames;
            cpuChartOption.series[0].data = processCpuUsage;
            
         
            cpuChart.setOption(cpuChartOption);
        })
        .catch(error => console.error('Error fetching CPU data:', error));
}, 1000);
var memoryMonitorContainer = document.getElementById('memory-monitor');
var memoryChart = echarts.init(memoryMonitorContainer, null, {
  renderer: 'canvas',
  useDirtyRect: false
});


var memoryChartOption = {
  grid: {
    left: '20%', 
    right: '10%',
    top: '10%',
    bottom: '10%'
  },
  xAxis: {
    type: 'value',
    max: 'dataMax',
    name: 'Memory %',
    nameLocation: 'middle',
    nameGap: 30
  },
  yAxis: {
    type: 'category',
    data: [], 
    inverse: true,
    name: '',
    nameLocation: 'middle',
    nameGap: 50,
    nameTextStyle: {
    fontSize: 16, 
    fontWeight: 'bold', 
    color: '#333' 
  }
  },
  series: [
    {
      name: 'Memory Usage',
      type: 'bar',
      data: [], 
      label: {
        show: true,
        position: 'right',
        formatter: '{c}%', 
        valueAnimation: true
      }
    }
  ],
  tooltip: {
    trigger: 'item',
    formatter: '{b}: {c}%' 
  },
  legend: {
    show: true,
    data: ['Memory Usage']
  },
  animationDuration: 0,
  animationDurationUpdate: 3000,
  animationEasing: 'linear',
  animationEasingUpdate: 'linear'
};


const processNames2 = []; 
const processMemoryUsage = []; 


memoryChart.setOption(memoryChartOption);


window.addEventListener('resize', memoryChart.resize);


var memoryDataUrl = "http://" + window.location.host + "/top_processes/";

setInterval(() => {
  fetch(memoryDataUrl)
    .then(res => res.json())
    .then(data => {
      var processNames2 = [];
      var processMemoryUsage = [];
      
     
      data.top_memory_processes.forEach(process => {
        processNames2.push(process.name || `PID ${process.pid}`);
        processMemoryUsage.push((process.memory_percent).toFixed(2)); 
      });

      
      memoryChartOption.yAxis.data = processNames2;
      memoryChartOption.series[0].data = processMemoryUsage;
      
     
      memoryChart.setOption(memoryChartOption);
    })
    .catch(error => console.error('Error fetching memory data:', error));
}, 1000);


var myur15 = "http://" + window.location.host+"/tcp_connections/";
    setInterval(()=>{
      fetch(myur15).then(res=>{
        return res.json()
      }).then((json)=>{
        var tcp_connections2 = document.getElementById('tcp_connections');
        tcp_connections2.innerHTML =  json.tcp_active_connections;
      })
    },1000)
    var myur16 = "http://" + window.location.host+"/process_count/";
    setInterval(()=>{
      fetch(myur16).then(res=>{
        return res.json()
      }).then((json)=>{
        var process_count = document.getElementById('process_count');
        process_count.innerHTML =  json.process_count;
      })
    },1000)






    </script>
</body>
</html>

mytest.py

import random
from pysnmp.hlapi import *
from flask import Flask,render_template
app = Flask(__name__)

myhost='localhost'
myport=161
mycommunity ='public'
myifindex ='.10'

myOIDs={
      'os_version': '1.3.6.1.2.1.1.1.0',
    'hostname': '1.3.6.1.2.1.1.5.0',
    'cpu_count': '1.3.6.1.4.1.2021.11.50.0',
    'disk_total': '1.3.6.1.4.1.2021.9.1.6.1',
    'disk_used': '1.3.6.1.4.1.2021.9.1.8.1',
    'disk_free': '1.3.6.1.4.1.2021.9.1.7.1',
    'process_count': '1.3.6.1.2.1.25.1.6.0',
    'tcp_active_connections': '1.3.6.1.2.1.6.9.0',
    'interface_status': '1.3.6.1.2.1.2.2.1.8',
  'sysDecr' : ".1.3.6.1.2.1.1.1.0",
  'sysUptime' : ".1.3.6.1.2.1.1.3.0",
    'sysName':".1.3.6.1.2.1.1.5.0",
    'wlan_if_in':'1.3.6.1.2.1.2.2.1.10',
    'wlan_if_out':'1.3.6.1.2.1.2.2.1.16',
  'if_in'     : ".1.3.6.1.2.1.2.2.1.10",
  'if_out'    : ".1.3.6.1.2.1.2.2.1.16",
  'if_inpkt'  : ".1.3.6.1.2.1.2.2.1.11",
  'if_outpkt' : ".1.3.6.1.2.1.2.2.1.17",
  'if_inbpkt' : ".1.3.6.1.2.1.2.2.1.12",
  'if_outbpkt': ".1.3.6.1.2.1.2.2.1.18",
  'if_speed'  : ".1.3.6.1.2.1.2.2.1.5",
  'mem_total' : ".1.3.6.1.2.1.25.2.2.0",
  'cpu_loads' : ". 1.3.6.1.2.1.25.3.3.1.2",
    'hrStorageSize':'1.3.6.1.2.1.25.2.3.1.5.4',
'hrStorageUsed':"1.3.6.1.2.1.25.2.3.1.6.4" ,
'if_in_discards': "1.3.6.1.2.1.2.2.1.13",
'if_out_discards': "1.3.6.1.2.1.2.2.1.19"  ,
'if_in_errors': "1.3.6.1.2.1.2.2.1.14",
'if_out_errors': "1.3.6.1.2.1.2.2.1.20",
'ipAddrTable_oid' :'1.3.6.1.2.1.4.20.1.1',
  }

def getTableRows(oids):
    iterator = nextCmd(
        SnmpEngine(),
        CommunityData(mycommunity, mpModel=0),
        UdpTransportTarget((myhost, myport)),
        ContextData(),
        *oids,
    lexicographicMode = False)
    ret = []
    for errorIndication, errorStatus, errorIndex, varBinds in iterator:
        count = ()
        if errorIndication:
            print(errorIndication)
            break
        elif errorStatus:
            print('%s at %s' % (errorStatus.prettyPrint(),
                                errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
            break
        else:
            for varBind in varBinds:
                count = count + (varBind[1]._value,)
            ret.append(count)
    return ret
def getObjs(oids):
  iterator = getCmd(
      SnmpEngine(),
      CommunityData(mycommunity, mpModel=0),
      UdpTransportTarget((myhost, myport)),
      ContextData(),
      *oids)
  ret = []
  errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
  if errorIndication:
        print(errorIndication)
        return 0
  elif errorStatus:
        print('%s at %s' % (errorStatus.prettyPrint(),
                            errorIndex and varBinds[int(errorIndex)-1][0] or '?'))
        return 0
  else:
        for varBind in varBinds:
            ret.append(varBind[1]._value)
  return ret
def get_memory_usage():
    total_memory = getObjs([ObjectType(ObjectIdentity(myOIDs['hrStorageSize']))])
    used_memory = getObjs([ObjectType(ObjectIdentity(myOIDs['hrStorageUsed']))])
    if total_memory and used_memory and total_memory[0] > 0:
        memory_usage = (used_memory[0] / total_memory[0]) * 100
        return round(memory_usage, 2)
    else:
        return None
@app.route('/')
def index():
    return render_template('main.html')

@app.route('/cpu/')
def cpu_used():
    cpuoid=ObjectType(ObjectIdentity(myOIDs['cpu_loads']))
    ret = getTableRows((cpuoid,))
    cpuload=0
    for i in ret:
        cpuload += i[0]
    print(cpuload)
    return {'cpu':cpuload}
@app.route('/net_m/')
def net_used():
    getoids=(ObjectType(ObjectIdentity(myOIDs['if_in']+'.41')),
             ObjectType(ObjectIdentity(myOIDs['if_out']+'.41')))
    in_out = getObjs(getoids)
    return {'in_s':in_out[0],'out_s':in_out[1]}
@app.route('/config/')
def m_config():
    getoids=(ObjectType(ObjectIdentity(myOIDs['sysDecr'])),
             ObjectType(ObjectIdentity(myOIDs['sysUptime'])),
             ObjectType(ObjectIdentity(myOIDs['mem_total'])),
             ObjectType(ObjectIdentity(myOIDs['sysName'])),
    )

    configs = getObjs(getoids)
    return {'sysDecr':configs[0].decode(),
            'sysUptime':configs[1],
            'mem':configs[2],
            'ssyname': configs[3].decode(),
           }
@app.route('/Memoryusage/')
def Memoryusage():
    memory_usage = get_memory_usage()
    return {
            'memory_usage': memory_usage
           }
@app.route('/tcp_udp_status/')
def tcp_udp_status():
    tcp_in_oid = ObjectType(ObjectIdentity('1.3.6.1.2.1.6.10.0'))
    tcp_out_oid = ObjectType(ObjectIdentity('1.3.6.1.2.1.6.11.0'))
    udp_in_oid = ObjectType(ObjectIdentity('1.3.6.1.2.1.7.1.0'))
    udp_out_oid = ObjectType(ObjectIdentity('1.3.6.1.2.1.7.4.0'))
    tcp_udp_data = getObjs([tcp_in_oid,tcp_out_oid, udp_in_oid, udp_out_oid])
    if tcp_udp_data:
        return {
            'tcp_in': tcp_udp_data[0],
            'tcp_out': tcp_udp_data[1],
            'udp_in': tcp_udp_data[2],
            'udp_out': tcp_udp_data[3]
        }
    else:
        return {'error': 'Failed to retrieve TCP/UDP statistics'}, 500
def get_packet_loss_rate():
    getoids = (
        ObjectType(ObjectIdentity(myOIDs['if_in_discards'] + '.41')),
        ObjectType(ObjectIdentity(myOIDs['if_out_discards'] + '.41')),
        ObjectType(ObjectIdentity(myOIDs['if_inpkt'] + '.41')),
        ObjectType(ObjectIdentity(myOIDs['if_outpkt'] + '.41'))
    )
    results = getObjs(getoids)
    in_discards = results[0]
    out_discards = results[1]
    in_pkts = results[2]
    out_pkts = results[3]
    in_packet_loss_rate = (in_discards / in_pkts) * 100 if in_pkts > 0 else 0
    out_packet_loss_rate = (out_discards / out_pkts) * 100 if out_pkts > 0 else 0
    return round(in_packet_loss_rate, 2), round(out_packet_loss_rate, 2)

def get_error_rate():
    getoids = (
        ObjectType(ObjectIdentity(myOIDs['if_in_errors'] + '.41')),
        ObjectType(ObjectIdentity(myOIDs['if_out_errors'] + '.41')),
        ObjectType(ObjectIdentity(myOIDs['if_inpkt'] + '.41')),
        ObjectType(ObjectIdentity(myOIDs['if_outpkt'] + '.41'))
    )
    results = getObjs(getoids)
    in_errors = results[0]
    out_errors = results[1]
    in_pkts = results[2]
    out_pkts = results[3]
    in_error_rate = (in_errors / in_pkts) * 100 if in_pkts > 0 else 0
    out_error_rate = (out_errors / out_pkts) * 100 if out_pkts > 0 else 0
    return round(in_error_rate, 2), round(out_error_rate, 2)

@app.route('/packet_loss_rate/')
def packet_loss_rate():
    in_loss_rate, out_loss_rate = get_packet_loss_rate()
    in_error_rate, out_error_rate = get_error_rate()
    if None not in (in_loss_rate, out_loss_rate, in_error_rate, out_error_rate):
        return {
            'in_packet_loss_rate': in_loss_rate,
            'out_packet_loss_rate': out_loss_rate,
            'in_error_rate': in_error_rate,
            'out_error_rate': out_error_rate
        }
    else:
        return {'error': 'Failed to retrieve packet loss or error rate'}, 500

import ipaddress
import struct

def parse_ip_from_binary(binary_data):
    try:
        ip_address = ipaddress.ip_address(binary_data)
        return str(ip_address)
    except ValueError:
        print(f"Invalid binary data: {binary_data}")
        return None

def get_ip_addresses():
    ip_addresses = []
    ip_entries = getTableRows([ObjectType(ObjectIdentity(myOIDs['ipAddrTable_oid']))])
    if ip_entries:
        for entry in ip_entries:
            ip_address = entry[0]
            if isinstance(ip_address, bytes):
                ip_address = parse_ip_from_binary(ip_address)
                if ip_address:
                    ip_addresses.append(ip_address)
            else:
                print(f"Unexpected format: {ip_address}")

        if ip_addresses:
            return {"ip_addresses": ip_addresses}
        else:
            return {"error": "No valid IP addresses found"}
    else:
        return {"error": "Failed to retrieve IP addresses"}


import psutil  

@app.route('/top_processes/')
def top_processes():
    processes = []
    for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent']):
        try:
            proc_info = proc.info
            processes.append(proc_info)
        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
            pass
    top_cpu_processes = sorted(processes, key=lambda x: x['cpu_percent'], reverse=True)[1:6]
    top_memory_processes = sorted(processes, key=lambda x: x['memory_percent'], reverse=True)[:5]

    return {
        'top_cpu_processes': top_cpu_processes,
        'top_memory_processes': top_memory_processes
    }
@app.route('/interface_status/')
def interface_status():
    interfaces = getTableRows([ObjectType(ObjectIdentity(myOIDs['interface_status']))])
    status_map = {1: 'up', 2: 'down', 3: 'testing', 4: 'unknown', 5: 'dormant', 6: 'notPresent', 7: 'lowerLayerDown'}
    interface_status = [{'interface_index': idx+1, 'status': status_map.get(status, 'unknown')} for idx, (status,) in enumerate(interfaces)]
    return {'interfaces': interface_status}

@app.route('/tcp_connections/')
def tcp_connections():
    tcp_active_connections = getObjs([ObjectType(ObjectIdentity(myOIDs['tcp_active_connections']))])
    if tcp_active_connections:
        return {'tcp_active_connections': tcp_active_connections[0]}
    else:
        return {'error': 'Failed to retrieve TCP connections'}, 500
@app.route('/process_count/')
def process_count():
    process_count = getObjs([ObjectType(ObjectIdentity(myOIDs['process_count']))])
    if process_count:
        return {'process_count': process_count[0]}
    else:
        return {'error': 'Failed to retrieve process count'}, 500
#     ip
@app.route('/ip_addresses/')
def ip_addresses():
    ip_list = get_ip_addresses()
    if ip_list:
        return {'ip_addresses': ip_list}
    else:
        return {'error': 'Failed to retrieve IP addresses'}, 500


from collections import deque
import threading
import time
from datetime import datetime, timedelta

net_history_data = deque(maxlen=30)
def update_net_history():
    while True:
        getoids = (
            ObjectType(ObjectIdentity(myOIDs['if_in'] + '.41')),
            ObjectType(ObjectIdentity(myOIDs['if_out'] + '.41'))
        )
        in_out = getObjs(getoids)
        if in_out:
            timestamp = datetime.now()
            net_history_data.append({
                "timestamp": timestamp,
                "net_in": in_out[0],
                "net_out": in_out[1]
            })
        else:
            print("Failed to retrieve network data")
        time.sleep(10)
threading.Thread(target=update_net_history, daemon=True).start()
@app.route('/net_h/')
def net_history():
    net_in = [round(entry["net_in"] / (1024 * 1024), 2) for entry in net_history_data]
    net_out = [round(entry["net_out"] / (1024 * 1024), 2) for entry in net_history_data]
    timestamps = [entry["timestamp"].strftime('%Y-%m-%d %H:%M:%S') for entry in net_history_data]
    return {"net_in": net_in, "net_out": net_out, "timestamps": timestamps}
@app.route('/get_disk/')
def get_disk_usage():
    getoids = (
        ObjectType(ObjectIdentity('1.3.6.1.2.1.25.2.3.1.5.2')),
        ObjectType(ObjectIdentity('1.3.6.1.2.1.25.2.3.1.5.1')),
        ObjectType(ObjectIdentity('1.3.6.1.2.1.25.2.3.1.6.1')),
        ObjectType(ObjectIdentity('1.3.6.1.2.1.25.2.3.1.6.2'))
    )
    results = getObjs(getoids)
    total_part1 = results[0]
    total_part2 = results[1]
    used_part1 = results[2]
    used_part2 = results[3]
    if None not in [total_part1, total_part2, used_part1, used_part2]:
        total = (total_part1 + total_part2) * 4096
        used = (used_part1 + used_part2) * 4096
        free = total - used
        return {
            'total': round(total / (1024 ** 3), 2),
            'used': round(used / (1024 ** 3), 2),
            'free': round(free / (1024 ** 3), 2)
        }
    else:
        return None

def get_network_traffic():
    in_bytes = getObjs([ObjectType(ObjectIdentity(myOIDs['if_in']+'.41'))])
    return in_bytes[0] if in_bytes else 0
last_in_bytes = 0
@app.route('/volatility/')
def network_traffic_volatility():
    global last_in_bytes
    in_bytes= get_network_traffic()
    volatility = in_bytes - last_in_bytes
    last_in_bytes = in_bytes
    return {'volatility': volatility}
if __name__ == '__main__':
    app.run()

style.css

@charset "utf-8";
/* CSS Document */
*{
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box}
*,body{padding:0px;	margin:0px;font-family: "微软雅黑";}
body{color:#2c3e50;font-size: 16px; background: #fff;}
html,body{height: 100%;}
li{ list-style-type:none;}
i{ margin:0px; padding:0px; text-indent:0px;}
img{ border:none; max-width: 100%;}
a{ text-decoration:none; color:#34495e;}
a.active,a:focus{ outline:none!important; text-decoration:none;}
ol,ul,p,h1,h2,h3,h4,h5,h6{ padding:0; margin:0}
a:hover{ color:#3498db; text-decoration: none!important}
.clearfix:after, .clearfix:before {display: table;content: " "}
.clearfix:after {clear: both}
.pulll_left{float:left;}
.pulll_right{float:right;}
i{font-style: normal;}
.text-w{color: #f1c40f}
.text-d{color: #e67e22}
.text-s{color: #2ecc71}
.text-b{color: #3498db}

.head{position: relative; height: 90px; margin: 0 15px; padding-right: 60px;}
.head h1{  font-size: 30px; letter-spacing: -2px; text-align: center; line-height: 90px; padding-right: 55px; color: #3498db;}
.head .menu ul{ font-size: 0;}

.head .menu li{ display: inline-block; position: relative;margin: 25px 15px;;}
.head .menu li a{ display: block; font-size: 18px; color: #34495e; line-height: 40px; padding: 0 15px; }
.head .time{position: absolute; right: 0; line-height: 90px;}

.menu li:before,
.menu li:after{ position:absolute; width:10px; height:5px;opacity: .4; content: "";  border-top: 2px solid #3498db; top: -1px;border-radius: 2px;}
.menu li:before,.menu li a:before{border-left: 2px solid #3498db;left: -1px;}
.menu li:after,.menu li a:after{border-right: 2px solid #3498db; right: -1px;}
.menu li a{ position:relative;}
.menu li a:before,
.menu li a:after{ position:absolute; width:10px; height:5px; opacity: .4;  content: "";border-bottom: 2px solid #3498db; bottom:-1px;border-radius: 2px;}

.head .menu li a:hover{ color: #3498db;}
.menu li a:hover:before,
.menu li a:hover:after,
.menu li:hover:before,
.menu li:hover:after{border-color: #3498db; opacity: 1;}

.mainbox{padding: 0px 10px;}
.nav1{margin-left: -6px; margin-right:-6px;}
.nav1>li{padding:0 6px; float: left;}

.box{ border:1px solid rgba(52,152,219,.5); box-shadow:inset 0 0 10px rgba(52,152,219,.4); margin-bottom: 12px; position: relative;}
.tit{ padding: 10px 10px 10px 25px;border-bottom:1px solid rgba(52,152,219,.7);font-size: 16px; font-weight: 500; position: relative;}
.tit:before,.tit01:before{position: absolute; content: ""; width: 6px; height: 6px; background: rgba(52,152,219,.9);box-shadow: 0 0 5px rgba(52,152,219,.9); border-radius: 10px; left: 10px; top: 18px;}

.tit:after,.box:before{ width: 100%; height: 1px; content: ""; position: absolute; left: 0; bottom:-1px; background:linear-gradient(to right,#3498db,#2980b9,#3498db); box-shadow: 0 0 5px rgba(52,152,219,1); opacity: .6}
.box:before{top: -1px;}

.boxnav{padding: 10px;}
.nav2>li:first-child{border:none;}
.nav2>li{float: left;border-left:1px solid rgba(52,152,219,.2); height:240px; padding: 0 10px 10px 10px;}
.tit01{font-size: 16px; font-weight: 500; position: relative; padding-left: 15px;}
.tit01:before{ left: 3px; top: 8px;}

.ftechart{height: 200px;}

.table1 th{ border-bottom: 1px solid #3498db; font-size: 14px; text-align: center; padding: 6px 0; color: rgba(44,62,80,.9)}
.table1 td{ border-bottom: 1px dotted #3498db;font-size: 12px; padding:6px 0;text-align: center; color: rgba(44,62,80,.7)}
.table1 tr:last-child td{border: none;}
.mapc{background: url(../images/bg3.png) no-repeat center center; background-size: 100% 100%}
.map{position: relative; height: 100%; padding-left: 10%;}

.mapnav{position: absolute;z-index: 10;}
.mapnav div{ background: url(../images/bg1.png) no-repeat; background-size:100% auto;  width: 110px;text-align: center; padding: 20px 0; line-height: 120%;}
.mapnav div span{font-size: 14px; opacity: .6}
.mapnav div p{font-size: 20px; font-weight: bold; padding-top: 5px;}
.mapnav li{float: left; margin-right: 6px;}

.leidanav{margin-top: -5px;}
.leidanav li{float: left; width: 20%; text-align: center; border-left: 1px solid rgba(52,152,219,.1)}
.leidanav2 li{ width: 33.3333%}
.leidanav3 li{ width: 25%}
.leidanav li:first-child{border-left: none;}
.leidanav span{font-size: 12px; opacity: .6}

.leidanav p{font-size: 18px; color: #3498db }
.mapnav2{ position: absolute; left: 10px; bottom:0px; width: 40%; z-index: 10;}
.ybp{width: 100%}
.ybp li{float: left; width: 50%; height: 120px; }
.duibi li{float: left; width: 25%; height: 200px; padding: 0; border: none;}

.btn{ position: absolute;  border-radius:2px; padding:4px 20px; opacity: .8;}
.btn1{border: 1px solid rgba(52,152,219,.5); background: #27ae60; left:35%; top: 30%;}
.btn2{ border: 1px solid rgba(52,152,219,.5); background: #2980b9;right:32%; top: 60%;}
.btn:hover{color: #fff; opacity:1;}
.btn1:before,.btn2:before{position: absolute; content: ''; width: 50px; height: 1px; background: #2c3e50;}
.btn1:before{ transform: rotate(30deg); right: -65%; top: 100%}
.btn2:before{ transform: rotate(30deg); left: -65%; top: -10%}
.tit02{font-size: 14px; padding: 10px 0;}
.water-container {
  position: relative;
  text-align: center;
}

.circle {
  position: relative;
  width: 150px;
  height: 150px;
  border-radius: 50%;
  overflow: hidden;
  background: #f0f0f0;
  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.1);
}

.water {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 100%;
  background: #4da6ff;
  animation: wave 2s infinite linear;
  transform: translateY(70%);
}

.text {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 20px;
  font-weight: bold;
  color: #333;
}

.label {
  margin-top: 10px;
  font-size: 16px;
  color: #888;
}

/* 波浪动画 */
@keyframes wave {
  from {
      transform: translateY(70%);
  }
  to {
      transform: translateY(65%);
  }
}

.tagcloud { 
  width:100%; 
  height:90%!important; 
  overflow: hidden;
  position: relative;
}
.tagcloud a {
  display: block;
  border-radius: 50%;
  color: #2c3e50;
  font-weight: bold;
  font-size: 14px;
  text-decoration: none;
  text-align: center;
  display: flex; 
  align-items: center; 
  justify-content: center;
}

.b01{ width: 50px; height: 50px; }
.b02{ width: 80px; height: 80px; }
.b03{ width: 60px; height: 60px; }
.b04{ width: 70px; height: 70px; }

.co01{ border: 2px solid rgba(52,152,219,1); box-shadow: inset 0 0 20px rgba(52,152,219,1);}
.co02{ border: 2px solid rgba(241,196,15,1); box-shadow: inset 0 0 20px rgba(241,196,15,1);}
.co03{ border: 2px solid rgba(41,128,185,1); box-shadow: inset 0 0 20px rgba(41,128,185,1);}
.co04{ border: 2px solid rgba(46,204,113,1); box-shadow: inset 0 0 20px rgba(46,204,113,1);}
.co05{ border: 2px solid rgba(230,126,34,1); box-shadow: inset 0 0 20px rgba(230,126,34,1);}

.huati{ padding-top: 20px;}
.huati li{ font-size: 12px; line-height: 230%;}

.wancheng{display: flex; align-items: center; justify-content: center;}
.wancheng span{font-size: 14px; color: #2c3e50;}
.wancheng h3{font-size: 20px; color:#3498db;}
.wancheng h3 i{font-size: 12px; color:#2c3e50;}
.yuan{padding:5px;border-radius: 100%; margin-left: 10px; border: 2px solid rgba(52,152,219,.8);}
.yuan span{width: 60px; height: 60px; border-radius: 100%; background: rgba(52,152,219,.8); display: flex; align-items: center; justify-content: center; font-size: 20px;}


http://www.kler.cn/a/452301.html

相关文章:

  • Python数据处理——re库与pydantic的使用总结与实战,处理采集到的思科ASA防火墙设备信息
  • PyQt5 学习方法之悟道
  • Docker怎么关闭容器开机自启,批量好几个容器一起操作?
  • 互联网视频云平台EasyDSS无人机推流直播技术如何助力野生动植物保护工作?
  • 【R语言遥感技术】“R+遥感”的水环境综合评价方法
  • 1.系统学习-线性回归
  • PySide6如何实现点击TableWidget列表头在该列右侧显示列表选择框筛选列数据
  • 数据仓库是什么?数据仓库简介
  • 设计一个自己的AI Agent
  • .NET 9 中的 多级缓存 HybridCache
  • Android绘图Path基于LinearGradient线性动画渐变,Kotlin(2)
  • HarmonyOS NEXT 实战之元服务:静态案例效果---电台推荐
  • 【1224】数据结构(sizeof/数组的长度定义/读取字符串函数/线性表长度/左值右值/静态变量/指针与引用)
  • WPF自定义窗口 输入验证不生效
  • SpringBoot3-第四篇(基础特性)
  • Mybatisplus如何使用selectPage
  • 接口测试Day03-postman断言关联
  • HuaWei、NVIDIA 数据中心 AI 算力对比
  • 谈谈JSON
  • DigitalOcean Droplet 云服务器:新增自动扩展池功能
  • npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
  • openwrt 负载均衡方法 openwrt负载均衡本地源接口
  • 08 Django - Django媒体文件静态文件文件上传
  • Ubuntu存储硬盘扩容-无脑ChatGPT方法
  • 嵌入式学习-QT-Day06
  • 网站使用站群服务器都有哪些好处?