Vue项目中Websocket的使用实例

JavaScript/前端
379
0
0
2023-03-23
标签   websocket
目录
  • 前言
  • 判断浏览器是否支持websocket的方法
  • Vue项目里使用websocket的实例
  • 总结

前言

由于项目需求有要使用长链接,我们普通的http请求如果用轮询的方式与服务端通讯就很消耗资源。我们一起来学习一下在vue项目里如何使用websocket,本文纯属个人观点,如果有不正确的地方请大家批评指正,技术无高低,谦虚学习的心态我认为很重要,天外有天人外有人。

判断浏览器是否支持websocket的方法

比较直观的方式是直接判断全局对象中是否包含WebSocket对象即可:

if( typeof(WebSocket) != "function" ) {
    alert("您的浏览器不支持Websocket通信协议,请更换浏览器为Chrome或者Firefox再次使用!")
  }

但是这种方式不严谨,在 Android 中,即使浏览器不支持 WebSocket ,但是它还是存在这个属性。所以可以使用下面的方法:

if (typeof WebSocket != 'undefined') {
    console.log("您的浏览器支持Websocket通信协议")
}else{
    alert("您的浏览器不支持Websocket通信协议,请使用Chrome或者Firefox浏览器!")
}

或者是这种方法:

if (!!window.WebSocket && window.WebSocket.prototype.send) {
     console.log("您的浏览器支持Websocket通信协议")
}else{
    alert("您的浏览器不支持Websocket通信协议,请使用Chrome或者Firefox浏览器!")
}

Vue项目里使用websocket的实例

请添加图片描述

上面这个页面是我所做项目里的某个页面,由于硬件资源监测和网络性能监测两个板块需要传递给服务端不同的参数来获取数据,传参分别如下:

 { message: "sys_info" }
{ message: "net_info" }

我们需要建立2个不同的长链接。我们项目都是统一在public文件夹下的config.js里统一配置,不管是http请求还是websocket,代码如下:

请添加图片描述

然后在一个js文件里将其封装成一个函数并暴露出去,代码如下:

请添加图片描述

然后在我们要使用到的组件里引入,并在data里定义两个websock实例,然后再在mounted里初始化两个websock实例,最后在destroyed销毁页面时一并销毁两个websock实例,代码如下:

请添加图片描述

然后我们在methods里看看初始化websocket的两个方法怎么写的,代码如下:

请添加图片描述

这里为了考虑各大浏览器是否兼容websocket,所以加了一个判断语句:

 if (typeof WebSocket === "undefined")
        return console.log("您的浏览器不支持websocket");

最后附上完整代码,如有不正确之处望同行前辈批评指正:

<template>
  <div class="homePage">
    <div class="topArea">
      <el-card class="el-card">
        <div slot="header" class="clearfix">
          <div class="headerBox">
            <span class="arrow"
              ><img src="../../assets/homePage/arrow.png"
            /></span>
            <span class="title">硬件资源监测</span>
            <span class="topRight"
              ><img src="../../assets/homePage/topRight.png"
            /></span>
          </div>
        </div>

        <div class="myCont">
          <div class="itemBox">
            <div class="titleBox">
              <span>
                <img src="../../assets/homePage/cpuTitle.png" alt="" />
              </span>
              <span class="title">CPU资源监测</span>
            </div>
            <div class="board">
              <div class="left" id="cpuCharts"></div>
              <div class="right">
                <div class="tipBox">
                  <span>CPU利用率</span>
                  <span>{{ cpu_info.cpu_use }}%</span>
                </div>

                <div class="detailBox">
                  <div>
                    <span></span>
                    <span>CPU颗数</span>
                    <span>{{ cpu_info.cpu_physical_count }}</span>
                  </div>

                  <div>
                    <span></span>
                    <span>CPU核数</span>
                    <span>{{ cpu_info.cpu_kernel_count }}</span>
                  </div>

                  <div>
                    <span></span>
                    <span>CPU负载</span>
                    <span>{{ cpu_info.cpu_average }}</span>
                  </div>
                </div>
              </div>
            </div>
          </div>

          <div class="itemBox">
            <div class="titleBox">
              <span>
                <img src="../../assets/homePage/Memory.png" alt="" />
              </span>
              <span class="title">内存资源监测</span>
            </div>
            <div class="board">
              <div class="left" id="memoryCharts"></div>
              <div class="right">
                <div class="tipBox">
                  <span>内存利用率</span>
                  <span>{{ mem_info.memory_percent }}%</span>
                </div>

                <div class="detailBox">
                  <div>
                    <span style="background: none"></span>
                    <span></span>
                    <span></span>
                  </div>

                  <div>
                    <span style="background: none"></span>
                    <span></span>
                    <span></span>
                  </div>

                  <div>
                    <span></span>
                    <span>内存总量</span>
                    <span>{{
                      mem_info.memory_total | FilterBps(mem_info.memory_total)
                    }}</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="itemBox">
            <div class="titleBox">
              <span>
                <img src="../../assets/homePage/Hard.png" alt="" />
              </span>
              <span class="title">硬盘资源监测</span>
            </div>
            <div class="board">
              <div class="left" id="hardCharts"></div>
              <div class="right">
                <div class="otherBox">
                  <div class="tipBox2">
                    <span>硬盘读速率</span>
                    <span>{{
                      disk_info.read_speed | FilterSpeed(disk_info.read_speed)
                    }}</span>
                    <span>MB/s</span>
                  </div>

                  <div class="tipBox2">
                    <span>硬盘写速率</span>
                    <span>{{
                      disk_info.write_speed | FilterSpeed(disk_info.write_speed)
                    }}</span>
                    <span>MB/s</span>
                  </div>
                </div>

                <div class="detailBox">
                  <div>
                    <span style="background: none"></span>
                    <span></span>
                    <span></span>
                  </div>

                  <div>
                    <span style="background: none"></span>
                    <span></span>
                    <span></span>
                  </div>

                  <div>
                    <span></span>
                    <span>硬盘大小</span>
                    <span
                      >{{
                        disk_info.disk_total
                          | FilterDiskTotal(disk_info.disk_total)
                      }}T</span
                    >
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </el-card>
    </div>

    <div class="topArea bottomArea">
      <el-card class="el-card">
        <div slot="header" class="clearfix">
          <div class="headerBox">
            <span class="arrow"
              ><img src="../../assets/homePage/arrow.png"
            /></span>
            <span class="title">网络性能监测</span>
            <span class="topRight"
              ><img src="../../assets/homePage/topRight.png"
            /></span>
          </div>
        </div>

        <div class="myCont">
          <div class="Throughput">
            <div class="titleBox">
              <span
                ><img src="../../assets/homePage/Throughput.png" alt=""
              /></span>
              <span class="title">通道吞吐量</span>
            </div>

            <div class="lineBox" id="lineCharts"></div>

            <div class="lineTips">
              <span
                ><img src="../../assets/homePage/lineTips.png" alt=""
              /></span>
              <span>吞吐量</span>
              <span>{{ inOutWay }}</span>
              <span>{{ inoutUnit }}</span>
            </div>
          </div>
          <div class="rightArea">
            <div class="Item" v-for="(item, i) in card_info" :key="i">
              <div class="topBox">
                <div class="imgBox">
                  <img src="../../assets/homePage/Frame.png" alt="" />
                </div>

                <div class="portTip">{{ Object.keys(item)[0] }}</div>

                <div class="transferBox transferBoxT">
                  <span>
                    <img src="../../assets/homePage/transferTop.png" alt="" />
                  </span>
                  <span class="Num">{{ WayMethods(item, "incoming") }}</span>
                </div>

                <div class="transferBox transferBoxB">
                  <span>
                    <img
                      src="../../assets/homePage/transferBottom.png"
                      alt=""
                    />
                  </span>
                  <span class="Num">{{ WayMethods(item, "outgoing") }}</span>
                </div>
              </div>
              <div class="bottomBox">
                <div>
                  <span>工作速率:</span>
                  <span>{{ WayMethods(item, "工作速率") }} </span>
                </div>

                <div>
                  <span>双工模式:</span>
                  <span>{{ WayMethods(item, "双工模式") }}</span>
                </div>

                <div>
                  <span>自协商:</span>
                  <span>{{ WayMethods(item, "自协商") }}</span>
                </div>

                <div>
                  <span>接口类型:</span>
                  <span>{{ WayMethods(item, "接口类型") }}</span>
                </div>

                <div>
                  <span>链路状态:</span>
                  <span>{{ WayMethods(item, "链路状态") }}</span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </el-card>
    </div>
  </div>
</template>

<script>
import { homeWsUrl } from "@/api/websocket.js";
export default {
  data() {
    return {
      wsUrl: homeWsUrl(),
      websock: null, //ws实例
      websockNet: null, //ws实例
      cpu_info: {
        cpu_use: 0,
      },
      mem_info: {
        memory_percent: 0,
      },
      disk_info: {
        disk_percent: 0,
      },
      inoutArr: [], //吞吐量集合

      card_info: [],
      in_out_total: 0, //吞吐量
      inoutUnit: "",
    };
  },
  filters: {
    FilterBps(bps) {
      if (bps) {
        let Grate = 1024 * 1024 * 1024;
        return (Number(bps) / Grate).toFixed(2) + "G";
      }
    },

    FilterSpeed(bps) {
      if (bps) {
        let Grate = 1024 * 1024;
        return (Number(bps) / Grate).toFixed(2);
      } else {
        return 0;
      }
    },

    FilterDiskTotal(bps) {
      if (bps) {
        let Grate = 1024 * 1024 * 1024 * 1024;
        return (Number(bps) / Grate).toFixed(2);
      }
    },
  },

  mounted() {
    this.cpuCharts();
    this.memoryCharts();
    this.hardCharts();
    this.lineCharts();

    //初始化websocket,此页面建立了2个长链接
    this.initWebSocket();
    this.initWebSocketNet();
  },
  destroyed() {
    //离开路由之后断开websocket连接
    this.websock.close();
    this.websockNet.close();
  },
  computed: {
    inOutWay() {
      // console.log("inOutWay", this.in_out_total);
      if (this.in_out_total <= 1000) {
        return (
          (this.inoutUnit = "bit/s"),
          (this.in_out_total = Number(this.in_out_total))
        );
      } else if (this.in_out_total > 1000 && this.in_out_total <= 1000 * 1000) {
        return (
          (this.inoutUnit = "Kb/s"),
          (this.in_out_total = (Number(this.in_out_total) / 1000).toFixed(2))
        );
      } else if (
        this.in_out_total > 1000 * 1000 &&
        this.in_out_total <= 1000 * 1000 * 1000
      ) {
        return (
          (this.inoutUnit = "Mb/s"),
          (this.in_out_total = (
            Number(this.in_out_total) /
            (1000 * 1000)
          ).toFixed(2))
        );
      } else if (this.in_out_total > 1000 * 1000 * 1000) {
        return (
          (this.inoutUnit = "Gb/s"),
          (this.in_out_total = (
            Number(this.in_out_total) /
            (1000 * 1000 * 1000)
          ).toFixed(2))
        );
      }
    },
  },
  methods: {
    cpuCharts() {
      let chartDom = document.getElementById("cpuCharts");
      let myChart = this.$echarts.init(chartDom);
      let option = {
        // tooltip: {
        //   formatter: "{a} <br/>{b} : {c}%",
        // },
        series: [
          {
            name: "Pressure",
            title: {
              show: false,
            },
            type: "gauge",
            progress: {
              show: true,
            },
            radius: "100%",
            detail: {
              valueAnimation: true,
              formatter: "{value}%",
              fontSize: 14,
            },
            data: [
              {
                value: this.cpu_info.cpu_use,
                name: "SCORE",
              },
            ],
          },
        ],
      };

      option && myChart.setOption(option);
    },
    memoryCharts() {
      let chartDom = document.getElementById("memoryCharts");
      let myChart = this.$echarts.init(chartDom);
      let option = {
        // tooltip: {
        //   formatter: "{a} <br/>{b} : {c}%",
        // },
        series: [
          {
            name: "Pressure",
            title: {
              show: false,
            },
            type: "gauge",
            progress: {
              show: true,
            },
            radius: "100%",
            detail: {
              valueAnimation: true,
              formatter: "{value}%",
              fontSize: 14,
            },
            data: [
              {
                value: this.mem_info.memory_percent,
                name: "SCORE",
              },
            ],
          },
        ],
      };

      option && myChart.setOption(option);
    },
    hardCharts() {
      let chartDom = document.getElementById("hardCharts");
      let myChart = this.$echarts.init(chartDom);
      let option = {
        // tooltip: {
        //   formatter: "{a} <br/>{b} : {c}%",
        // },
        series: [
          {
            name: "Pressure",
            title: {
              show: false,
            },
            type: "gauge",
            progress: {
              show: true,
            },
            radius: "100%",
            detail: {
              valueAnimation: true,
              formatter: "{value}%",
              fontSize: 14,
            },
            data: [
              {
                value: this.disk_info.disk_percent,
                name: "SCORE",
              },
            ],
          },
        ],
      };

      option && myChart.setOption(option);
    },
    lineCharts() {
      let chartDom = document.getElementById("lineCharts");
      let myChart = this.$echarts.init(chartDom);
      let option;

      // prettier-ignore
      // const data = [["2000-06-05", 1160], ["2000-06-06", 1209], ["2000-06-07", 1035], ["2000-06-08", 86], ["2000-06-09", 703],
      //   ["2000-06-10", 805], ["2000-06-11", 73], ["2000-06-12", 68], ["2000-06-13", 92], ["2000-06-14", 130], ["2000-06-15", 245],
      // ];
      // const dateList = data.map(function (item) {
      //   return item[0];
      // });
      // const valueList = data.map(function (item) {
      //   return item[1];
      // });

      // console.log("this.inoutArr",this.inoutArr)
      const data = this.inoutArr;
      const dateList = this.inoutArr;
      const valueList = this.inoutArr;
      option = {
        // Make gradient line here
        visualMap: [
          {
            show: false,
            type: "continuous",
            seriesIndex: 0,
            min: 0,
          },
          {
            show: false,
            type: "continuous",
            seriesIndex: 1,
            dimension: 0,
            min: 0,
          },
        ],
        title: [
          {
            left: "left",
            text: `吞吐量Gb/s`,
            textStyle: {
              fontSize: 12,
              color: "#7C818D",
            },
          },
        ],
        // tooltip: {
        //   trigger: "axis",
        // },
        xAxis:
          // {
          //   data: dateList,
          // },
          {
            show: false,
            data: dateList,
            gridIndex: 1,
          },

        yAxis: {
          gridIndex: 1,
          min: 0, //取0为最小刻度
          // max: 1000000, //取100000为最大刻度
        },

        grid: [
          {
            bottom: "0%",
          },
          {
            top: "20%",
          },
        ],
        series: [
          {
            type: "line",
            showSymbol: false,
            data: valueList,
          },
        ],
      };

      option && myChart.setOption(option);
    },
    //初始化Websocket--sys_info
    initWebSocket() {
      if (typeof WebSocket === "undefined")
        return console.log("您的浏览器不支持websocket");
      this.websock = new WebSocket(this.wsUrl);
      this.websock.onmessage = this.websocketonmessage;
      this.websock.onopen = this.websocketonopen;
      this.websock.onerror = this.websocketonerror;
      this.websock.onclose = this.websocketclose;
    },
    websocketonopen() {
      // console.log("链接建立之后执行send方法发送数据");
      let action = { message: "sys_info" };
      this.websocketsend(JSON.stringify(action));
    },
    websocketonerror() {
      //链接建立失败重连
      this.initWebSocket();
    },
    websocketonmessage(e) {
      //数据接收
      const redata = JSON.parse(e.data);
      // console.log("接收的数据", redata);
      this.cpu_info = redata.cpu_info;

      this.cpuCharts();
      this.mem_info = redata.mem_info;
      this.memoryCharts();
      this.disk_info = redata.disk_info;
      this.hardCharts();
    },
    websocketsend(Data) {
      //数据发送
      // console.log("数据发送", Data);
      this.websock.send(Data);
    },
    websocketclose(e) {
      //关闭
      // console.log("断开链接", e);
    },

    //初始化Websocket--net_info
    initWebSocketNet() {
      if (typeof WebSocket === "undefined")
        return console.log("您的浏览器不支持websocket");
      this.websockNet = new WebSocket(this.wsUrl);
      this.websockNet.onmessage = this.websocketonmessageNet;
      this.websockNet.onopen = this.websocketonopenNet;
      this.websockNet.onerror = this.websocketonerrorNet;
      this.websockNet.onclose = this.websocketcloseNet;
    },

    websocketonopenNet() {
      // console.log("链接建立之后执行send方法发送数据");
      let action = { message: "net_info" };
      this.websocketsendNet(JSON.stringify(action));
    },
    websocketonerrorNet() {
      //链接建立失败重连
      this.initWebSocketNet();
    },
    websocketonmessageNet(e) {
      //数据接收
      const redata = JSON.parse(e.data);
      // console.log("net_info接收的数据", redata);
      this.in_out_total = redata.in_out_total;

      let allRate = 1000 * 1000 * 1000;
      this.inoutArr = this.inoutArr.concat(
        (redata.in_out_total / allRate).toFixed(2)
      );

      this.card_info = redata.card_info;

      this.lineCharts();
    },
    websocketsendNet(Data) {
      //数据发送
      // console.log("数据发送", Data);
      this.websockNet.send(Data);
    },
    websocketcloseNet(e) {
      //关闭
      // console.log("断开链接", e);
    },

    WayMethods(item, type) {
      let arr = Object.keys(item);
      // console.log("arr", item, arr);

      if (type == "incoming") {
        if (item[arr[0]].incoming <= 1000) {
          return item[arr[0]].incoming + "bit/s";
        } else if (
          item[arr[0]].incoming > 1000 &&
          item[arr[0]].incoming <= 1000 * 1000
        ) {
          return (item[arr[0]].incoming / 1000).toFixed(2) + "Kb/s";
        } else if (
          item[arr[0]].incoming > 1000 * 1000 &&
          item[arr[0]].incoming <= 1000 * 1000 * 1000
        ) {
          return (item[arr[0]].incoming / (1000 * 1000)).toFixed(2) + "Mb/s";
        } else if (item[arr[0]].incoming > 1000 * 1000 * 1000) {
          return (
            (item[arr[0]].incoming / (1000 * 1000 * 1000)).toFixed(2) + "Gb/s"
          );
        }
      } else if (type == "outgoing") {
        if (item[arr[0]].outgoing <= 1000) {
          return item[arr[0]].outgoing + "bit/s";
        } else if (
          item[arr[0]].outgoing > 1000 &&
          item[arr[0]].outgoing <= 1000 * 1000
        ) {
          return (item[arr[0]].outgoing / 1000).toFixed(2) + "Kb/s";
        } else if (
          item[arr[0]].outgoing > 1000 * 1000 &&
          item[arr[0]].outgoing <= 1000 * 1000 * 1000
        ) {
          return (item[arr[0]].outgoing / (1000 * 1000)).toFixed(2) + "Mb/s";
        } else if (item[arr[0]].outgoing > 1000 * 1000 * 1000) {
          return (
            (item[arr[0]].outgoing / (1000 * 1000 * 1000)).toFixed(2) + "Gb/s"
          );
        }
      } else {
        return item[arr[0]][type];
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.homePage {
  display: flex;
  flex-direction: column;

  .topArea {
    display: flex;
    justify-content: space-between;

    .el-card {
      width: 100%;
      background: #fbfdff;

      ::v-deep .el-card__header {
        padding: 0 !important;
        z-index: 9;
        position: relative;
      }

      ::v-deep .el-card__body {
        padding: 0 !important;
      }

      .headerBox {
        position: relative;
        width: 100%;
        height: 39px;
        z-index: 9;
        background: #fff !important;

        .arrow {
          position: absolute;
          top: 0.6875rem;
          left: 0.5rem;

          img {
            width: 1rem;
            height: 1rem;
          }
        }

        .title {
          position: absolute;
          top: 0.687rem;
          left: 1.625rem;

          font-weight: bolder;
          color: #2d3d59;
          font-size: 1rem;
          font-family: SourceHanSansCN;
        }

        .topRight {
          position: absolute;
          bottom: -0.3rem;
          right: 0;

          img {
            width: 2.1875rem;
            height: 0.3125rem;
          }
        }
      }

      .myCont {
        // border: 1px solid blue;
        width: 100%;

        display: flex;

        background: #fbfdff;

        margin-top: 1rem;
        margin-bottom: 1rem;

        .itemBox {
          width: 32.5625rem;
          height: 21.75rem;
          //   border: 1px solid red;
          display: flex;
          flex-direction: column;

          .titleBox {
            height: 2rem;
            display: flex;

            span img {
              margin-top: 0.125rem;
              width: 1rem;
              height: 1rem;
            }

            .title {
              margin-left: 0.625rem;
              font-size: 1rem;
              font-family: SourceHanSansCN;
              font-weight: bolder;
              color: #2d3d59;
            }
          }

          .board {
            width: 29.5625rem;
            height: 18.75rem;
            background: #f3f7ff;
            box-shadow: inset 0px 0.25rem 0.25rem 0px rgba(92, 127, 252, 0.12);
            border-radius: 0.25rem;
            opacity: 1;
            display: flex;

            .left {
              width: 15rem;
              height: 12.5rem;

              margin-top: 3.125rem;
              margin-left: 0.875rem;
            }

            .right {
              width: 15.1875rem;
              //   border: 1px solid blue;
              margin-top: 3.125rem;
              position: relative;

              .tipBox {
                width: 11.9375rem;
                height: 4.875rem;
                display: flex;
                justify-content: space-between;
                // border: 1px solid red;

                position: absolute;
                top: 1.125rem;
                left: 1.375rem;

                span {
                  &:nth-child(1) {
                    font-size: 0.875rem;
                    font-family: SourceHanSansCN;
                    font-weight: bold;
                    color: #413f3f;
                  }

                  &:nth-child(2) {
                    font-size: 1.5rem;
                    font-family: D-DIN-DIN-Bold, D-DIN-DIN;
                    font-weight: bold;
                    color: #0082fa;
                    margin-top: -0.5rem;
                  }
                }
              }

              .detailBox {
                position: absolute;
                top: 5rem;
                left: 1.375rem;
                display: flex;
                flex-direction: column;
                // border: 1px solid salmon;
                width: 11.9375rem;

                div {
                  height: 1.75rem;
                  display: flex;
                  position: relative;

                  span {
                    // border: 1px solid red;

                    &:nth-child(1) {
                      width: 0.375rem;
                      height: 0.375rem;
                      border-radius: 0.1875rem;
                      background: #00b42a;
                      opacity: 1;

                      position: absolute;
                      top: 0.5rem;
                      left: 0;
                    }

                    &:nth-child(2) {
                      font-size: 0.8125rem;
                      font-family: SourceHanSansCN;
                      font-weight: 400;
                      color: #413f3f;
                      position: absolute;
                      top: 0.25rem;
                      left: 0.625rem;
                    }

                    &:nth-child(3) {
                      font-size: 0.8125rem;
                      font-family: SourceHanSansCN;
                      font-weight: 400;
                      color: #413f3f;
                      position: absolute;
                      top: 0.25rem;
                      right: 0rem;
                    }
                  }
                }
              }

              .otherBox {
                display: flex;
                flex-direction: column;
                position: absolute;
                top: 0;
                left: 1.375rem;
                height: 4.875rem;
                width: 100%;
                // border: 1px solid blue;
                .tipBox2 {
                  width: 11.9375rem;
                  height: 2.4375rem;
                  display: flex;
                  justify-content: space-between;
                  // border: 1px solid red;

                  span {
                    &:nth-child(1) {
                      font-size: 0.875rem;
                      font-family: SourceHanSansCN;
                      font-weight: bold;
                      color: #413f3f;
                      display: block;
                    }

                    &:nth-child(2) {
                      font-size: 1.5rem;
                      font-family: D-DIN-DIN-Bold, D-DIN-DIN;
                      font-weight: bold;
                      color: #0082fa;
                      margin-top: -0.35rem;
                    }

                    &:nth-child(3) {
                      font-size: 1rem;
                      font-family: D-DIN-DIN-Bold, D-DIN-DIN;
                      font-weight: bold;
                      color: #0082fa;
                      margin-top: -0.05rem;
                    }
                  }
                }
              }
            }
          }

          &:nth-child(1) {
            margin-left: 1.6875rem;
          }

          &:nth-child(2) {
            margin-left: 2.625rem;
          }

          &:nth-child(3) {
            margin-left: 2.625rem;
          }
        }
      }
    }
  }

  .bottomArea {
    margin-top: 1rem;
    .el-card {
      .myCont {
        height: 19rem;
        display: flex;

        .Throughput {
          width: 36.875rem;
          display: flex;
          flex-direction: column;

          .titleBox {
            margin-top: 2.5rem;
            margin-left: 1.5rem;
            position: relative;

            height: 2rem;
            span {
              position: absolute;
              top: 0;
              left: 0;
              img {
                width: 1rem;
                height: 1rem;
              }
            }

            .title {
              position: absolute;
              top: 0;
              left: 1.5rem;
              font-size: 0.875rem;
              font-family: SourceHanSansCN;
              font-weight: 400;
              color: #2d3d59;
            }
          }

          .lineBox {
            width: 31.25rem;
            height: 12.5rem;
            margin-left: 1.6875rem;
            // border: 1px solid red;
            background: #fefbff;
          }

          .lineTips {
            margin-left: 1.6875rem;
            background: #fefbff;
            width: 31.25rem;
            span {
              img {
                width: 1rem;
                height: 1rem;
              }
              &:nth-child(1) {
                margin-top: 0.25rem;
              }

              &:nth-child(2) {
                font-size: 0.875rem;
                font-family: SourceHanSansCN;
                font-weight: 400;
                color: #413f3f;
                margin: 0rem 0.5rem;
              }

              &:nth-child(3) {
                font-size: 1rem;
                font-family: D-DIN-DIN-Bold, D-DIN-DIN;
                font-weight: bold;
                color: #413f3f;
              }

              &:nth-child(4) {
                font-size: 1rem;
                font-family: D-DIN-DIN-Bold, D-DIN-DIN;
                font-weight: bold;
                color: #413f3f;
              }
            }
          }
        }

        .rightArea {
          //   border: 1px solid blue;
          width: 64.8125rem;
          display: flex;
          .Item {
            width: 14rem;
            height: 16.125rem;
            margin-top: 2.5rem;
            margin-right: 3rem;
            // border: 1px solid red;
            opacity: 1;
            display: flex;
            flex-direction: column;

            &:nth-child(4) {
              margin-right: 0rem;
            }

            .topBox {
              position: relative;
              background: #f2f3fb !important;
              height: 5.875rem;
              z-index: 9;
              border-radius: 0.25rem;
              .imgBox {
                position: absolute;
                top: 0.875rem;
                left: 1rem;
                img {
                  width: 4.125rem;
                  height: 4.125rem;
                }
              }

              .portTip {
                position: absolute;
                top: 0.75rem;
                left: 5.875rem;
                font-size: 1rem;
                font-family: SourceHanSansCN;
                font-weight: 500;
                color: #413f3f;
              }

              .transferBox {
                span {
                  img {
                    width: 1rem;
                    height: 1rem;
                  }
                }

                .Num {
                  font-size: 0.875rem;
                  font-family: SourceHanSansCN;
                  font-weight: 500;
                  color: #7c818d;
                }
              }

              .transferBoxT {
                position: absolute;
                top: 2.5rem;
                left: 5.875rem;
              }

              .transferBoxB {
                position: absolute;
                top: 3.8125rem;
                left: 5.875rem;
              }
            }

            .bottomBox {
              background: #fefbff;
              //   border: 1px solid orange;
              margin-top: 1.5rem;
              display: flex;
              flex-direction: column;
              div {
                display: flex;
                font-size: 0.875rem;
                font-family: SourceHanSansCN;
                font-weight: 400;
                color: #413f3f;
                line-height: 1.75rem;

                span {
                  &:nth-child(1) {
                    margin-right: 0.5rem;
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
</style>