vue2 + less 实现通信图组件

在这里插入图片描述

下面是用到的组件和数据格式

Flow.vue

<template lang="pug">
.flow
  .header
    div(v-for="(item, index) in ipArr" :key="index")
      ip-flow(:data="item")
  //- 图表
  .common-content
    div.end-data
      div.flow-content(:style="{width: getStyleWidth(true, ipArrIndex)}" v-for="(ipArrData, ipArrIndex) in endData" :key="ipArrIndex")
        div.common-content-a(:style="{width: getStyleWidth(ipArrIndex === 0 ? false : true, ipArrIndex)}" v-if="item.show" v-for="(item, index) in ipArrData.tableData" :key="index" @click="showDetails(item)")
          div(:class="item.leftShow ? (getLeftPosition(item, ipArrIndex) ? 'left' : 'left-2') : (getLeftPosition(item, ipArrIndex) ? 'left-m' : 'left-m-2') ")
            span.port {{ item.srcPort }}
          div(:class="ipArr.length < 3 ? 'content' : (getEndData(ipArrIndex) ? 'content-m bdrborder' : 'content-m-nowidth')" :style="{width: getStyleWidth((ipArrIndex === 0) ? false : true)}")
            div(:class="getPosition(item) ? 'method-text-left' : 'method-text-right'") {{ item.method }}
            div(:title="item.ruriUserText" :class="getPosition(item) ? 'ruri-user-text-left' : 'ruri-user-text-right'" :style="{width: getEndData(ipArrIndex) ? '' : getStyleWidth(ipArrIndex === 0 ? false : true)}") {{ item.ruriUserText }}
            Arrow(:arrowDirection="getPosition(item) ? 'left' : 'right'" :width="getEndData(ipArrIndex) ? '' : getStyleWidth(ipArrIndex === 0 ? false : true)")
            div(:class="getPosition(item) ? 'c-r' : ''")
              span.id-type-time [{{ item.id }}]&nbsp;[{{ item.communicationMethod }}]&nbsp;{{ item.createDateText }}
              br
              span.id-type-time +{{ item.diffTime }}
          div(:class="ipArr.length < 3 ? (!getPosition(item) ? 'right' : 'right-2') : (!getPosition(item) ? 'right-m' : 'right-m-2')")
            span.d-p {{ item.dstPort }}
        div.common-content-b(v-else)
          .left(v-if="item.leftShow")
          div(:class="getEndData(ipArrIndex) ? 'content-m bdrborder' : 'content-m-nowidth'" :style="{width: getStyleWidth(ipArrIndex === 0 ? false : true)}")
          .right-m
</template>
<script>
import Arrow from './Arrow.vue'
import IpFlow from './IpFlow.vue'
export default {
  name: 'Flow',
  components: {
    Arrow,
    IpFlow
  },
  props: {
    data: {
      type: Object,
      default: () => {
        return null
      }
    }
  },
  data () {
    return {
      // 图表相关属性
      tableData: [],
      ipArr: [],
      endData: [],
      flowContentWidth: ''
    }
  },
  watch: {
    data: {
      handler: function (val, oldVal) {
        if (val && val !== oldVal) {
          this.init(val)
        }
      }
    }
  },
  mounted () {
    window.onresize = () => {
      this.getWidth()
    }
  },
  methods: {
    init (data) {
      this.tableData = data.list || []
      this.ipArr = data.ipArr || {}
      this.ipArr = this.getIpArr(JSON.parse(JSON.stringify(this.ipArr)))
      const newIpArr = []
      this.ipArr.forEach((item, index) => {
        if (this.ipArr[index + 1]) {
          const newIp = item.ip + '-' + this.ipArr[index + 1].ip
          newIpArr.push(newIp)
        }
      })
      this.endData = []
      newIpArr.forEach((ele, eleIndex) => {
        const data = {
          ipArea: ele,
          tableData: []
        }
        this.tableData.forEach((e, i) => {
          const item = JSON.parse(JSON.stringify(e))
          const flag = this.getAreaContent(item, ele)
          if (eleIndex === 0) {
            item.leftShow = true
          } else {
            item.leftShow = false
          }
          if (flag) {
            item.show = true
          } else {
            item.show = false
          }
          data.tableData.push(item)
        })
        this.endData.push(data)
      })
      this.getWidth()
    },
    getWidth () {
      this.$nextTick(() => {
        const clientWidth = document.querySelectorAll('.end-data')[0].clientWidth
        if (this.endData.length >= 2) {
          this.flowContentWidth = ((clientWidth - 100) / this.endData.length).toFixed(0)
        } else {
          this.flowContentWidth = (clientWidth / this.endData.length).toFixed(0)
        }
      })
    },
    getIpArr (ipData) {
      const tempArr = []
      const arr = Object.keys(ipData)
      if (arr && arr.length > 0) {
        arr.forEach((e) => {
          const data = ipData[e]
          const ip = data['host'][0].split(':')[0]
          data.ip = ip
          tempArr.push(data)
        })
      }
      if (tempArr.length > 0) {
        return tempArr.sort(this.sortBy('position'))
      }
      return tempArr
    },
    sortBy (field) {
      // 根据传过来的字段进行排序
      return (x, y) => {
        return x[field] - y[field]
      }
    },
    getCreateDate (date) {
      return this.moment(date).format('YYYY-MM-DD HH:mm:ss.SSS')
    },
    getPosition (item) {
      if (item.arrowDirection === 'right') {
        return false
      } else {
        return true
      }
    },
    getLeftPosition (item, index) {
      if (item.arrowDirection === 'left') {
        return false
      } else {
        return true
      }
    },
    getAreaContent (data, area) {
      const ipArr = area.split('-')
      if ((data.srcIp === ipArr[0] && data.dstIp === ipArr[1]) || (data.srcIp === ipArr[1] && data.dstIp === ipArr[0])) {
        return true
      } else {
        return false
      }
    },
    getAreaContentFlag (data, index) {
      if (index === 0) {
        if (!this.endData[index]) return false
        const ipArr = this.endData[index].ipArea.split('-')
        if ((data.srcIp === ipArr[0] && data.dstIp === ipArr[1]) || (data.srcIp === ipArr[1] && data.dstIp === ipArr[0])) {
          return false
        } else {
          return true
        }
      } else {
        if (!this.endData[index + 1]) return false
        const ipArr = this.endData[index].ipArea.split('-')
        if ((data.srcIp === ipArr[0] && data.dstIp === ipArr[1]) || (data.srcIp === ipArr[1] && data.dstIp === ipArr[0])) {
          return false
        } else {
          return true
        }
      }
    },
    getEndData (index) {
      if (index === (this.endData.length - 1)) {
        return true
      } else {
        return false
      }
    },
    getStyleWidth (flag, index) {
      if (index === 0 || index === (this.endData.length - 1)) {
        if (this.endData.length >= 2) {
          return '100%'
        } else {
          return '100%'
        }
      }
      return this.flowContentWidth + 'px'
    },
    // 详情
    showDetails (data) {
      this.$emit('showDetails', data)
    }
  }
}
</script>
<style lang="less" scoped>
@color: rgb(102, 214, 92);
@bgColor: #EFFAEE;
@borderColor: #e9eaec;
@lineHeight: 91px;
@lineHeight2: 91px;
.method-text() {
  font-size: 14px;
  font-weight: 600;
  margin-left: 3px;
}
.ruri-user-text() {
  position: relative;
  top: 5px;
}
.no-line () {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hover-content() {
  background-color: #a4a4a447;
  cursor: pointer;
}
.common-center() {
  .method-text-right {
    .method-text();
  }
  .method-text-left {
    .method-text();
    text-align: end;
    color: @color;
    margin-right: 3px;
  }
  .ruri-user-text-left {
    .ruri-user-text();
    .no-line ();
    text-align: end;
    margin-right: 3px;
    right: 2px;
  }
  .ruri-user-text-right {
    .ruri-user-text();
    .no-line ();
    left: 3px;
  }
  .id-type-time {
    position: relative;
    top: -5px;
    left: 3px;
  }
}
.flow {
  .header {
    display: flex;
    justify-content: space-between;
  }
  .common-content {
    display: flex;
    flex-wrap: wrap;
    .common-content-a {
      height: 100px;
      display: flex;
      .content-m-nowidth:hover {
        .hover-content();
      }
      .content-m:hover {
        .hover-content();
      }
      .content:hover {
        .hover-content();
      }
    }
    .common-content-b {
      width: 100%;
      height: 100px;
      display: flex;
      .left {
        text-align: right;
        line-height: @lineHeight;
      }
      .content-m {
      }
    }
    .end-data {
      width: 100%;
      display: flex;
    }
  }
  .flow-content {
    background-color: @bgColor;
    width: 100%;
    .left {
      width: 50px;
      text-align: right;
      line-height: @lineHeight;
      padding-right: 5px;
    }
    .left-2 {
      width: 50px;
      text-align: right;
      line-height: @lineHeight2;
      padding-right: 5px;
    }
    .left-m {
      width: 0;
      text-align: right;
      line-height: @lineHeight;
      position: relative;
      .port {
        display: block;
        position: relative;
        left: -31px;
      }
    }
    .left-m-2 {
      width: 0;
      text-align: right;
      line-height: @lineHeight2;
      position: relative;
      .port {
        display: block;
        position: relative;
        left: -31px;
      }
    }
    .content {
      .common-center();
      width: calc(100% - 100px);
      border-left: 1px solid @borderColor;
      border-right: 1px solid @borderColor;
    }
    .content-m {
      .common-center();
      width: calc(100% - 50px);
      height: 100px;
      border-left: 1px solid @borderColor;
    }
    .content-m-nowidth {
      .common-center();
      height: 100px;
      border-left: 1px solid @borderColor;
    }
    .right {
      width: 50px;
      text-align: left;
      line-height: @lineHeight;
      padding-left: 5px;
    }
    .right-2 {
      width: 50px;
      text-align: left;
      line-height: @lineHeight2;
      padding-left: 5px;
    }
    .right-m {
      width: 0;
      text-align: left;
      line-height: @lineHeight;
      padding-left: 0;
      position: relative;
      .d-p {
        margin-left: 5px;
      }
    }
    .right-m-2 {
      width: 0;
      text-align: left;
      line-height: @lineHeight2;
      padding-left: 0;
      position: relative;
      .d-p {
        margin-left: 5px;
      }
    }
  }
  .c-r {
    text-align: end;
    margin-right: 6px;
  }

  .bdrborder {
    border-right: 1px solid @borderColor;
  }
}
</style>

IpFlow.vue

<template lang="pug">
.arrow
  div.arrow-content
    div.content
      .left-arrow
      .horizontal-line-left
    div.content
      .horizontal-line-right
      .right-arrow
  .bottom
    span {{ data.ip }}
</template>
<script>
export default {
  name: 'IpFlow',
  props: {
    data: {
      type: Object,
      default: () => {
        return {}
      }
    }
  },
  data () {
    return {
    }
  },
  methods: {
  }
}
</script>
<style lang="less" scoped>
@color: #A3A3A3;
@borderWidth: 10px;
@borderColor: #e1e1e1;
.arrow-common() {
  border: 5px solid transparent;
  width: 0;
  height: 0px;
}
.horizontal-line () {
  border-top: 3px solid @color;
  width: 14px;
  position: relative;
  top: 3px;
}

.arrow {
  width: 100px;
  border-radius: 5px;
  background-color: #f9f9f9;
  border: 1px dashed @borderColor;
  margin: 0 0 1px 0;
  .arrow-content {
    padding: 16px;
    .content {
      display: flex;
      justify-content: center;
      padding: 1px 0;
    }
  }
  .bottom {
    text-align: center;
    font-size: 12px;
    border-top: 1px solid @borderColor;
    padding: 3px;
  }
  .left-arrow {
    .arrow-common();
    border-right: @borderWidth solid @color;
    position: relative;
    left: -6px;
  }
  .horizontal-line-left {
    .horizontal-line ();
    left: -6px;
  }
  .right-arrow {
    .arrow-common();
    border-left: @borderWidth solid @color;
  }
  .horizontal-line-right {
    .horizontal-line ();
  }
}
</style>

Arrow.vue

<template lang="pug">
.arrow(:style="{width: width}")
  div.left-arrow(v-if="arrowDirection === 'left'" :style="{borderRight: `10px solid ${color}`}")
  div.horizontal-line(:style="{borderTop: `2px solid ${color}`}")
  div.right-arrow(v-if="arrowDirection === 'right'" :style="{borderLeft: `10px solid ${color}`}")
</template>
<script>
export default {
  name: 'Arrow',
  props: {
    arrowDirection: {
      type: String,
      default: 'right'
    },
    color: {
      type: String,
      default: 'rgb(102, 214, 92)'
    },
    width: {
      type: String,
      default: '100%'
    }
  },
  data () {
    return {
    }
  },
  mounted () {
    this.init()
  },
  methods: {
    init () {
    }
  }
}
</script>
<style lang="less" scoped>
@color: rgb(102, 214, 92);
@borderWidth: 14px;
.arrow-common() {
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  position: relative;
  top: -2px;
  width: 0;
  height: 0;
}

.arrow {
  display: flex;
  .horizontal-line {
    width: 100%;
    position: relative;
    top: 5px;
  }
  .left-arrow {
    .arrow-common();
  }
  .right-arrow {
    .arrow-common();
  }
}
</style>

Flow.vue中data的数据格式

{
	"ipArr": {
		"21.151.96.161:7100": {
			"host": [
				"21.151.96.161:7100"
			],
			"position": 0
		},
		"10.0.8.14:7100": {
			"host": [
				"10.0.8.14:7100"
			],
			"position": 1
		}
	},
	"list": [{
			"id": 275231,
			"sid": "903997704",
			"createDate": "2023-06-01 09:20:02",
			"raw": "MESSAGE sip:21140000002000000001@10.0.8.14:7100 SIP/2.0\r\nVia: SIP/2.0/UDP 21.151.96.161:7100;rport;branch=z9hG4bK1567269288\r\nFrom: <sip:21140000002000000022@21.151.96.161:7100>;tag=3670656861\r\nTo: <sip:21140000002000000001@10.0.8.14:7100>\r\nCall-ID: 903997704\r\nCSeq: 20 MESSAGE\r\nContent-Type: Application/MANSCDP+xml\r\nMax-Forwards: 70\r\nUser-Agent: NCG V2.3.9.205749\r\nContent-Length:   154\r\n\r\n<?xml version=\"1.0\"?>\n<Notify>\r\n<CmdType>Keepalive</CmdType>\r\n<SN>222170</SN>\r\n<DeviceID>21140000002000000022</DeviceID>\r\n<Status>OK</Status>\r\n</Notify>\r\n",
			"dstIp": "10.0.8.14",
			"srcIp": "21.151.96.161",
			"dstPort": 7100,
			"srcPort": 7100,
			"protocol": 17,
			"captureId": "2002",
			"payloadType": 1,
			"timeSeconds": 1685582402,
			"timeUseconds": 746522,
			"correlation_id": "903997704",
			"protocolFamily": 2,
			"cseq": "20 MESSAGE",
			"callid": "903997704",
			"method": "MESSAGE",
			"to_user": "21140000002000000001",
			"from_tag": "3670656861",
			"from_user": "21140000002000000022",
			"ruri_user": "21140000002000000001",
			"user_agent": "NCG V2.3.9.205749",
			"ruri_domain": "10.0.8.14",
			"createDateText": "2023-06-01 09:20:02.746",
			"diffTime": "0ms",
			"arrowDirection": "right",
			"ruriUserText": "21140000002000000001,MESSAGE sip:21140000002000000001@10.0.8.14:7100 SIP/2.0",
			"communicationMethod": "UDP"
		},
		{
			"id": 275236,
			"sid": "903997704",
			"createDate": "2023-06-01 09:20:02",
			"raw": "SIP/2.0 200 OK\r\nVia: SIP/2.0/UDP 21.151.96.161:7100;rport=7100;branch=z9hG4bK1567269288\r\nFrom: <sip:21140000002000000022@21.151.96.161:7100>;tag=3670656861\r\nTo: <sip:21140000002000000001@10.0.8.14:7100>;tag=3511899241\r\nCall-ID: 903997704\r\nCSeq: 20 MESSAGE\r\nUser-Agent: NcgV2.3.6\r\nContent-Length: 0\r\n\r\n",
			"dstIp": "21.151.96.161",
			"srcIp": "10.0.8.14",
			"dstPort": 7100,
			"srcPort": 7100,
			"protocol": 17,
			"captureId": "2002",
			"payloadType": 1,
			"timeSeconds": 1685582402,
			"timeUseconds": 751882,
			"correlation_id": "903997704",
			"protocolFamily": 2,
			"cseq": "20 MESSAGE",
			"callid": "903997704",
			"method": "200",
			"to_user": "21140000002000000001",
			"from_tag": "3670656861",
			"from_user": "21140000002000000022",
			"ruri_user": "",
			"user_agent": "NcgV2.3.6",
			"ruri_domain": "",
			"createDateText": "2023-06-01 09:20:02.751",
			"diffTime": "5ms",
			"arrowDirection": "left",
			"ruriUserText": "SIP/2.0 200 OK\r\nVia: SIP/2.0/UDP 21.151.96.161:7100;",
			"communicationMethod": "UDP"
		}
	]
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值