CN-403 fix: performance详情域名截取二级域名
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -49,6 +49,10 @@ const routes = [
|
|||||||
{
|
{
|
||||||
path: '/chart',
|
path: '/chart',
|
||||||
component: () => import('@/views/settings/Chart')
|
component: () => import('@/views/settings/Chart')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/temp',
|
||||||
|
component: () => import('@/views/Temp')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const panel = {
|
|||||||
x: 0,
|
x: 0,
|
||||||
y: 0
|
y: 0
|
||||||
},
|
},
|
||||||
chartList:[]
|
chartList: []
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
setShowRightBox (state, flag) {
|
setShowRightBox (state, flag) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -461,68 +461,68 @@ export function humpToLine (name) {
|
|||||||
}
|
}
|
||||||
return name.replace(/([A-Z])/g, '_$1').toLowerCase()
|
return name.replace(/([A-Z])/g, '_$1').toLowerCase()
|
||||||
}
|
}
|
||||||
//排序功能:从大到小,降序排列
|
// 排序功能:从大到小,降序排列
|
||||||
export function reverseSortBy (i) {
|
export function reverseSortBy (i) {
|
||||||
return function (a, b) {
|
return function (a, b) {
|
||||||
return b[i] - a[i]
|
return b[i] - a[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//排序功能:从小到大,升序排列
|
// 排序功能:从小到大,升序排列
|
||||||
export function sortBy (i) {
|
export function sortBy (i) {
|
||||||
return function (a, b) {
|
return function (a, b) {
|
||||||
return a[i] - b[i]
|
return a[i] - b[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//echart图标,y轴鼠标悬浮时,显示标签所有内容
|
// echart图标,y轴鼠标悬浮时,显示标签所有内容
|
||||||
export function extensionEchartY(chart){
|
export function extensionEchartY (chart) {
|
||||||
//判断是否创建过div框,如果创建过就不再创建了
|
// 判断是否创建过div框,如果创建过就不再创建了
|
||||||
//该div用来盛放文本显示内容的,方便对其悬浮位置进行处理
|
// 该div用来盛放文本显示内容的,方便对其悬浮位置进行处理
|
||||||
let id = document.getElementById("extension")
|
const id = document.getElementById('extension')
|
||||||
if(!id) {
|
if (!id) {
|
||||||
let div = "<div id = 'extension' style=\"display:block\"></div>"
|
const div = "<div id = 'extension' style=\"display:block\"></div>"
|
||||||
let contentDiv = document.createElement("div")
|
const contentDiv = document.createElement('div')
|
||||||
contentDiv.setAttribute('id','extension')
|
contentDiv.setAttribute('id', 'extension')
|
||||||
contentDiv.setAttribute('style','display:block')
|
contentDiv.setAttribute('style', 'display:block')
|
||||||
document.documentElement.append(contentDiv)
|
document.documentElement.append(contentDiv)
|
||||||
}
|
}
|
||||||
chart.on('mouseover', function(params) {
|
chart.on('mouseover', function (params) {
|
||||||
//注意这里,我是以Y轴显示内容过长为例,如果是x轴的话,需要改为xAxis
|
// 注意这里,我是以Y轴显示内容过长为例,如果是x轴的话,需要改为xAxis
|
||||||
if(params.componentType === "yAxis") {
|
if (params.componentType === 'yAxis') {
|
||||||
//设置悬浮文本的位置以及样式
|
// 设置悬浮文本的位置以及样式
|
||||||
let extEle = document.getElementById("extension")
|
const extEle = document.getElementById('extension')
|
||||||
extEle.style.cssText = "display:inline;position:absolute;" +
|
extEle.style.cssText = 'display:inline;position:absolute;' +
|
||||||
" padding: 12px;" +
|
' padding: 12px;' +
|
||||||
" max-width: 400px !important;" +
|
' max-width: 400px !important;' +
|
||||||
" color: #666;" +
|
' color: #666;' +
|
||||||
" background-color: rgb(255, 255, 255);" +
|
' background-color: rgb(255, 255, 255);' +
|
||||||
" font-size: 14px;" +
|
' font-size: 14px;' +
|
||||||
" line-height: 20px;" +
|
' line-height: 20px;' +
|
||||||
" font-weight:400; " +
|
' font-weight:400; ' +
|
||||||
" font-family: \"Microsoft YaHei\"" +
|
' font-family: "Microsoft YaHei"' +
|
||||||
" border-style: solid;" +
|
' border-style: solid;' +
|
||||||
" border-width: 1px;" +
|
' border-width: 1px;' +
|
||||||
" border-radius: 4px;" +
|
' border-radius: 4px;' +
|
||||||
" border-color: transparent !important;" +
|
' border-color: transparent !important;' +
|
||||||
" box-shadow: rgb(0 0 0 / 30%) 0px 0px 3px;" +
|
' box-shadow: rgb(0 0 0 / 30%) 0px 0px 3px;' +
|
||||||
" white-space: nowrap;" +
|
' white-space: nowrap;' +
|
||||||
" z-index: 99999999;"
|
' z-index: 99999999;'
|
||||||
|
|
||||||
extEle.innerHTML = params.value;
|
extEle.innerHTML = params.value
|
||||||
document.documentElement.onmousemove = function(event) {
|
document.documentElement.onmousemove = function (event) {
|
||||||
let extEle = document.getElementById("extension")
|
const extEle = document.getElementById('extension')
|
||||||
let xx = event.pageX - extEle.offsetWidth - 20
|
const xx = event.pageX - extEle.offsetWidth - 20
|
||||||
let yy = event.pageY + 20
|
const yy = event.pageY + 20
|
||||||
extEle.style.cssText = extEle.style.cssText+"top:"+yy+"px;left:"+xx+"px;"
|
extEle.style.cssText = extEle.style.cssText + 'top:' + yy + 'px;left:' + xx + 'px;'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
chart.on('mouseout', function(params) {
|
chart.on('mouseout', function (params) {
|
||||||
//注意这里,我是以Y轴显示内容过长为例,如果是x轴的话,需要改为xAxis
|
// 注意这里,我是以Y轴显示内容过长为例,如果是x轴的话,需要改为xAxis
|
||||||
if(params.componentType == "yAxis") {
|
if (params.componentType == 'yAxis') {
|
||||||
let extEle = document.getElementById("extension")
|
const extEle = document.getElementById('extension')
|
||||||
extEle.style.cssText = "display:none;"
|
extEle.style.cssText = 'display:none;'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -352,9 +352,9 @@ export default {
|
|||||||
ChartAlarmInfo,
|
ChartAlarmInfo,
|
||||||
ChartDomainRecursiveResolve
|
ChartDomainRecursiveResolve
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
tabHandleClickType: '',
|
tabHandleClickType: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
@@ -374,7 +374,7 @@ export default {
|
|||||||
tabHandleClickType: String
|
tabHandleClickType: String
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isNoData() {
|
isNoData () {
|
||||||
return (
|
return (
|
||||||
!this.loading &&
|
!this.loading &&
|
||||||
(_.isEmpty(this.chartData) || this.isError) &&
|
(_.isEmpty(this.chartData) || this.isError) &&
|
||||||
@@ -389,47 +389,47 @@ export default {
|
|||||||
!this.isAlarmInfo
|
!this.isAlarmInfo
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
chartOption() {
|
chartOption () {
|
||||||
if (this.customChartOption) {
|
if (this.customChartOption) {
|
||||||
return _.cloneDeep(this.customChartOption)
|
return _.cloneDeep(this.customChartOption)
|
||||||
} else {
|
} else {
|
||||||
return getOption(this.chartInfo.type)
|
return getOption(this.chartInfo.type)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
resize() {
|
resize () {
|
||||||
this.$refs['chart' + this.chartInfo.id] &&
|
this.$refs['chart' + this.chartInfo.id] &&
|
||||||
this.$refs['chart' + this.chartInfo.id].resize()
|
this.$refs['chart' + this.chartInfo.id].resize()
|
||||||
},
|
},
|
||||||
showLoading(show) {
|
showLoading (show) {
|
||||||
this.$emit('showLoading', show)
|
this.$emit('showLoading', show)
|
||||||
},
|
},
|
||||||
getAlarmInfo(url, extraParams, isRefresh, timeFilter) {
|
getAlarmInfo (url, extraParams, isRefresh, timeFilter) {
|
||||||
this.$emit('getChartData', url, extraParams, isRefresh, timeFilter)
|
this.$emit('getChartData', url, extraParams, isRefresh, timeFilter)
|
||||||
},
|
},
|
||||||
getChartData(url, extraParams) {
|
getChartData (url, extraParams) {
|
||||||
this.$emit('getChartData', url, extraParams)
|
this.$emit('getChartData', url, extraParams)
|
||||||
},
|
},
|
||||||
initEchartsWithTable() {
|
initEchartsWithTable () {
|
||||||
this.$refs['chart' + this.chartInfo.id] &&
|
this.$refs['chart' + this.chartInfo.id] &&
|
||||||
this.$refs['chart' + this.chartInfo.id].initEchartsWithTable(
|
this.$refs['chart' + this.chartInfo.id].initEchartsWithTable(
|
||||||
`chart${this.chartInfo.id}`,
|
`chart${this.chartInfo.id}`
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
query(params) {
|
query (params) {
|
||||||
this.$emit('query', params)
|
this.$emit('query', params)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
tabHandleClickType: {
|
tabHandleClickType: {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler(n) {
|
handler (n) {
|
||||||
this.tabHandleClickType = n
|
this.tabHandleClickType = n
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup (props) {
|
||||||
return {
|
return {
|
||||||
isEcharts: isEcharts(props.chartInfo.type),
|
isEcharts: isEcharts(props.chartInfo.type),
|
||||||
isEchartsLine: isEchartsLine(props.chartInfo.type),
|
isEchartsLine: isEchartsLine(props.chartInfo.type),
|
||||||
@@ -442,7 +442,7 @@ export default {
|
|||||||
isSingleValue: isSingleValue(props.chartInfo.type),
|
isSingleValue: isSingleValue(props.chartInfo.type),
|
||||||
isSingleValueWithEcharts: isSingleValueWithEcharts(props.chartInfo.type),
|
isSingleValueWithEcharts: isSingleValueWithEcharts(props.chartInfo.type),
|
||||||
isSingleValueWithEchartsTemp: isSingleValueWithEchartsTemp(
|
isSingleValueWithEchartsTemp: isSingleValueWithEchartsTemp(
|
||||||
props.chartInfo.type,
|
props.chartInfo.type
|
||||||
),
|
),
|
||||||
isRelationShip: isRelationShip(props.chartInfo.type),
|
isRelationShip: isRelationShip(props.chartInfo.type),
|
||||||
isTable: isTable(props.chartInfo.type),
|
isTable: isTable(props.chartInfo.type),
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ import {
|
|||||||
isBasicTable,
|
isBasicTable,
|
||||||
isGroup,
|
isGroup,
|
||||||
isEchartsWithTable,
|
isEchartsWithTable,
|
||||||
isAlarmInfo,
|
isAlarmInfo
|
||||||
} from './charts/tools'
|
} from './charts/tools'
|
||||||
import ChartError from '@/views/charts/ChartError'
|
import ChartError from '@/views/charts/ChartError'
|
||||||
import { getNowTime } from '@/utils/date-util'
|
import { getNowTime } from '@/utils/date-util'
|
||||||
@@ -246,7 +246,7 @@ import {
|
|||||||
chartActiveIpTableOrderOptions,
|
chartActiveIpTableOrderOptions,
|
||||||
chartPieTableTopOptions,
|
chartPieTableTopOptions,
|
||||||
eventSeverity,
|
eventSeverity,
|
||||||
chartTableColumnMapping,
|
chartTableColumnMapping
|
||||||
} from '@/utils/constants'
|
} from '@/utils/constants'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -255,19 +255,19 @@ export default {
|
|||||||
chartInfo: Object,
|
chartInfo: Object,
|
||||||
errorInfo: {
|
errorInfo: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: ''
|
||||||
},
|
},
|
||||||
isError: {
|
isError: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false
|
||||||
},
|
},
|
||||||
table: Object,
|
table: Object,
|
||||||
orderPieTable: Object,
|
orderPieTable: Object
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
ChartError,
|
ChartError
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
chartTableColumnMapping,
|
chartTableColumnMapping,
|
||||||
dropdownMenuShow: false,
|
dropdownMenuShow: false,
|
||||||
@@ -280,37 +280,37 @@ export default {
|
|||||||
tableData: [
|
tableData: [
|
||||||
{
|
{
|
||||||
name: '192.168.20.21',
|
name: '192.168.20.21',
|
||||||
num: 111,
|
num: 111
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '192.168.20.22',
|
name: '192.168.20.22',
|
||||||
num: 345,
|
num: 345
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '192.168.20.23',
|
name: '192.168.20.23',
|
||||||
num: 111,
|
num: 111
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '192.168.20.24',
|
name: '192.168.20.24',
|
||||||
num: 345,
|
num: 345
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '192.168.20.25',
|
name: '192.168.20.25',
|
||||||
num: 111,
|
num: 111
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '192.168.20.26',
|
name: '192.168.20.26',
|
||||||
num: 345,
|
num: 345
|
||||||
},
|
}
|
||||||
], // table的所有数据
|
] // table的所有数据
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
refresh() {
|
refresh () {
|
||||||
this.$emit('refresh')
|
this.$emit('refresh')
|
||||||
},
|
},
|
||||||
timeRefreshChange() {
|
timeRefreshChange () {
|
||||||
// 不是自选时间
|
// 不是自选时间
|
||||||
if (!this.$refs.dateTimeRange.isCustom) {
|
if (!this.$refs.dateTimeRange.isCustom) {
|
||||||
const value = this.chartTimeFilter.dateRangeValue
|
const value = this.chartTimeFilter.dateRangeValue
|
||||||
@@ -319,26 +319,26 @@ export default {
|
|||||||
this.$emit('refresh', this.chartTimeFilter)
|
this.$emit('refresh', this.chartTimeFilter)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
reload(s, e, v) {
|
reload (s, e, v) {
|
||||||
this.dateTimeRangeChange(s, e, v)
|
this.dateTimeRangeChange(s, e, v)
|
||||||
},
|
},
|
||||||
groupShow() {
|
groupShow () {
|
||||||
this.$emit('groupShow', this.chartInfo)
|
this.$emit('groupShow', this.chartInfo)
|
||||||
},
|
},
|
||||||
dateTimeRangeChange(s, e, v) {
|
dateTimeRangeChange (s, e, v) {
|
||||||
this.chartTimeFilter = { startTime: s, endTime: e, dateRangeValue: v }
|
this.chartTimeFilter = { startTime: s, endTime: e, dateRangeValue: v }
|
||||||
this.$emit('refresh', this.chartTimeFilter)
|
this.$emit('refresh', this.chartTimeFilter)
|
||||||
},
|
},
|
||||||
tableLimitChange() {
|
tableLimitChange () {
|
||||||
this.$emit('tableChange')
|
this.$emit('tableChange')
|
||||||
},
|
},
|
||||||
activeIpTableLimitChange() {
|
activeIpTableLimitChange () {
|
||||||
this.$emit('tableChange')
|
this.$emit('tableChange')
|
||||||
},
|
},
|
||||||
orderPieTableChange() {
|
orderPieTableChange () {
|
||||||
this.$emit('orderPieTableChange', this.orderPieTable)
|
this.$emit('orderPieTableChange', this.orderPieTable)
|
||||||
},
|
},
|
||||||
tabHandleClick(item) {
|
tabHandleClick (item) {
|
||||||
this.isFocus = item
|
this.isFocus = item
|
||||||
if (item === 'All') {
|
if (item === 'All') {
|
||||||
this.isFocusAll = true
|
this.isFocusAll = true
|
||||||
@@ -346,24 +346,24 @@ export default {
|
|||||||
this.isFocusAll = false
|
this.isFocusAll = false
|
||||||
}
|
}
|
||||||
this.$emit('tabHandleClick', item)
|
this.$emit('tabHandleClick', item)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
isFocus: {
|
isFocus: {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler(n) {},
|
handler (n) {}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showRefreshButton() {
|
showRefreshButton () {
|
||||||
// 自己是group且父元素是block时,不显示刷新按钮
|
// 自己是group且父元素是block时,不显示刷新按钮
|
||||||
// TODO 父元素是block,且只有自己一个子元素时,不显示刷新按钮
|
// TODO 父元素是block,且只有自己一个子元素时,不显示刷新按钮
|
||||||
const isGroupAndParentIsBlock =
|
const isGroupAndParentIsBlock =
|
||||||
this.$_.get(this.chartInfo.parent, 'type') === 95 && this.isGroup
|
this.$_.get(this.chartInfo.parent, 'type') === 95 && this.isGroup
|
||||||
return !isGroupAndParentIsBlock
|
return !isGroupAndParentIsBlock
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup (props) {
|
||||||
const dateRangeValue = 60
|
const dateRangeValue = 60
|
||||||
const { startTime, endTime } = getNowTime(dateRangeValue)
|
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||||
// entity详情内的chart时间工具不是公共的,需要单独定义
|
// entity详情内的chart时间工具不是公共的,需要单独定义
|
||||||
@@ -382,8 +382,8 @@ export default {
|
|||||||
isActiveIpTable: isActiveIpTable(props.chartInfo.type),
|
isActiveIpTable: isActiveIpTable(props.chartInfo.type),
|
||||||
isEchartsWithTable: isEchartsWithTable(props.chartInfo.type),
|
isEchartsWithTable: isEchartsWithTable(props.chartInfo.type),
|
||||||
isGroup: isGroup(props.chartInfo.type),
|
isGroup: isGroup(props.chartInfo.type),
|
||||||
isAlarmInfo: isAlarmInfo(props.chartInfo.type),
|
isAlarmInfo: isAlarmInfo(props.chartInfo.type)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -181,10 +181,10 @@ export default {
|
|||||||
this.queryTimeRange = { startTime: getSecond(this.chartTimeFilter.startTime), endTime: getSecond(this.chartTimeFilter.endTime) }
|
this.queryTimeRange = { startTime: getSecond(this.chartTimeFilter.startTime), endTime: getSecond(this.chartTimeFilter.endTime) }
|
||||||
}
|
}
|
||||||
const chartParams = this.chartInfo.params
|
const chartParams = this.chartInfo.params
|
||||||
if(isAlarmInfo && JSON.stringify(extraParams) === '{}'){
|
if (isAlarmInfo && JSON.stringify(extraParams) === '{}') {
|
||||||
extraParams = {
|
extraParams = {
|
||||||
pageNo : 1,
|
pageNo: 1,
|
||||||
pageSize : 9
|
pageSize: 9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 接口查询参数
|
// 接口查询参数
|
||||||
@@ -426,7 +426,7 @@ export default {
|
|||||||
isCryptocurrencyEventList: isCryptocurrencyEventList(props.chartInfo.type),
|
isCryptocurrencyEventList: isCryptocurrencyEventList(props.chartInfo.type),
|
||||||
isAppBasicInfo: isAppBasicInfo(props.chartInfo.type),
|
isAppBasicInfo: isAppBasicInfo(props.chartInfo.type),
|
||||||
isAppRelatedDomain: isAppRelatedDomain(props.chartInfo.type),
|
isAppRelatedDomain: isAppRelatedDomain(props.chartInfo.type),
|
||||||
isAlarmInfo:isAlarmInfo(props.chartInfo.type)
|
isAlarmInfo: isAlarmInfo(props.chartInfo.type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,16 +119,16 @@ export default {
|
|||||||
chartInfo: Object,
|
chartInfo: Object,
|
||||||
chartData: [Array, Object],
|
chartData: [Array, Object],
|
||||||
tabHandleClickType: String,
|
tabHandleClickType: String,
|
||||||
queryParams: Object,
|
queryParams: Object
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
pageSizeForAlarm: 9,
|
pageSizeForAlarm: 9,
|
||||||
eventSeverityColor: eventSeverityColor,
|
eventSeverityColor: eventSeverityColor,
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
alarmInfoCount: {},
|
alarmInfoCount: {},
|
||||||
fromChartData: '',
|
fromChartData: '',
|
||||||
isNoData:false
|
isNoData: false
|
||||||
// result: [
|
// result: [
|
||||||
// {
|
// {
|
||||||
// entityType: 'ip',
|
// entityType: 'ip',
|
||||||
@@ -145,52 +145,52 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isNoData() {
|
isNoData () {
|
||||||
let isNoData = true
|
let isNoData = true
|
||||||
if (!this.$_.isEmpty(this.chartData)) {
|
if (!this.$_.isEmpty(this.chartData)) {
|
||||||
isNoData = false
|
isNoData = false
|
||||||
}
|
}
|
||||||
return isNoData
|
return isNoData
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
tabHandleClickType: {
|
tabHandleClickType: {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler(n) {
|
handler (n) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.getData(1, n)
|
this.getData(1, n)
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
alarmInfoCount: {
|
alarmInfoCount: {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler(n) {},
|
handler (n) {}
|
||||||
},
|
},
|
||||||
queryParams: {
|
queryParams: {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler(n) {
|
handler (n) {
|
||||||
if (n.startTime && n.endTime) {
|
if (n.startTime && n.endTime) {
|
||||||
this.getCount(1)
|
this.getCount(1)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
ChartTablePagination,
|
ChartTablePagination
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
unitConvert,
|
unitConvert,
|
||||||
getMillisecond,
|
getMillisecond,
|
||||||
getCount() {
|
getCount () {
|
||||||
let countQuery = {
|
const countQuery = {
|
||||||
startTime: this.queryParams.startTime,
|
startTime: this.queryParams.startTime,
|
||||||
endTime: this.queryParams.endTime,
|
endTime: this.queryParams.endTime,
|
||||||
eventSeverity:
|
eventSeverity:
|
||||||
this.tabHandleClickType === 'All' ? '' : this.tabHandleClickType,
|
this.tabHandleClickType === 'All' ? '' : this.tabHandleClickType
|
||||||
}
|
}
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
get('/interface/dns/alarmInfoCount', {
|
get('/interface/dns/alarmInfoCount', {
|
||||||
...countQuery,
|
...countQuery
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
this.alarmInfoCount = response.data
|
this.alarmInfoCount = response.data
|
||||||
@@ -198,7 +198,7 @@ export default {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getData(val, n) {
|
getData (val, n) {
|
||||||
this.pageNo = val
|
this.pageNo = val
|
||||||
const extraParams = {
|
const extraParams = {
|
||||||
pageNo: val,
|
pageNo: val,
|
||||||
@@ -208,30 +208,30 @@ export default {
|
|||||||
? ''
|
? ''
|
||||||
: n
|
: n
|
||||||
: this.tabHandleClickType === 'All'
|
: this.tabHandleClickType === 'All'
|
||||||
? ''
|
? ''
|
||||||
: this.tabHandleClickType,
|
: this.tabHandleClickType
|
||||||
}
|
}
|
||||||
const query = {
|
const query = {
|
||||||
startTime: this.queryParams.startTime,
|
startTime: this.queryParams.startTime,
|
||||||
endTime: this.queryParams.endTime,
|
endTime: this.queryParams.endTime,
|
||||||
eventSeverity:
|
eventSeverity:
|
||||||
this.tabHandleClickType === 'All' ? '' : this.tabHandleClickType,
|
this.tabHandleClickType === 'All' ? '' : this.tabHandleClickType
|
||||||
}
|
}
|
||||||
this.$emit('getAlarmInfo', null, extraParams, false, {
|
this.$emit('getAlarmInfo', null, extraParams, false, {
|
||||||
startTime: query.startTime,
|
startTime: query.startTime,
|
||||||
endTime: query.endTime,
|
endTime: query.endTime
|
||||||
})
|
})
|
||||||
get('/interface/dns/alarmInfoCount', {
|
get('/interface/dns/alarmInfoCount', {
|
||||||
...query,
|
...query
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
this.alarmInfoCount = response.data
|
this.alarmInfoCount = response.data
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
pageJump(val) {
|
pageJump (val) {
|
||||||
this.getData(val)
|
this.getData(val)
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
<div style="display: flex; justify-content: space-between; width: 100%;">
|
<div style="display: flex; justify-content: space-between; width: 100%;">
|
||||||
<el-descriptions :column="1" style="padding: 20px 30px;">
|
<el-descriptions :column="1" style="padding: 20px 30px;">
|
||||||
<el-descriptions-item :label="$t('overall.appName') + ':'">{{$_.get(chartData, "name") || '-'}}</el-descriptions-item>
|
<el-descriptions-item :label="$t('overall.appName') + ':'">{{$_.get(chartData, "name") || '-'}}</el-descriptions-item>
|
||||||
<el-descriptions-item :label="$t('overall.appFullName') + ':'">{{$_.get(chartData, "allName") || '-'}}</el-descriptions-item>
|
<el-descriptions-item :label="$t('overall.appFullName') + ':'">{{$_.get(chartData, "appLongname") || '-'}}</el-descriptions-item>
|
||||||
<el-descriptions-item :label="$t('overall.technology') + ':'">{{$_.get(chartData, "tech") || '-'}}</el-descriptions-item>
|
<el-descriptions-item :label="$t('overall.technology') + ':'">{{$_.get(chartData, "appTechnology") || '-'}}</el-descriptions-item>
|
||||||
<el-descriptions-item :label="$t('overall.remark') + ':'">{{$_.get(chartData, "description") || '-'}}</el-descriptions-item>
|
<el-descriptions-item :label="$t('overall.remark') + ':'">{{$_.get(chartData, "appDescription") || '-'}}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<div class="cn-chart__body-single">
|
<div class="cn-chart__body-single">
|
||||||
<div class="cn-chart__body-single-table">
|
<div class="cn-chart__body-single-table">
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ export default {
|
|||||||
this.handleYaxis()
|
this.handleYaxis()
|
||||||
|
|
||||||
if (this.isEchartsPie) {
|
if (this.isEchartsPie) {
|
||||||
if(chartParams.size && chartParams.size === 'small'){
|
if (chartParams.size && chartParams.size === 'small') {
|
||||||
this.chartOption.series[0] = {
|
this.chartOption.series[0] = {
|
||||||
...this.chartOption.series[0],
|
...this.chartOption.series[0],
|
||||||
radius : ['30%', '45%'],
|
radius: ['30%', '45%'],
|
||||||
label: {
|
label: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
@@ -50,18 +50,18 @@ export default {
|
|||||||
}
|
}
|
||||||
this.chartOption.legend = {
|
this.chartOption.legend = {
|
||||||
...this.chartOption.legend,
|
...this.chartOption.legend,
|
||||||
left :'60%',
|
left: '60%',
|
||||||
itemGap:5,
|
itemGap: 5,
|
||||||
itemWidth:8,
|
itemWidth: 8,
|
||||||
itemHeight:8,
|
itemHeight: 8,
|
||||||
formatter: function (name) {
|
formatter: function (name) {
|
||||||
return name.length > 9 ? name.substr(0, 9) + '...' : name
|
return name.length > 9 ? name.substr(0, 9) + '...' : name
|
||||||
//return echarts.format.truncateText(name, 6, '…');
|
// return echarts.format.truncateText(name, 6, '…');
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: true
|
show: true
|
||||||
},
|
},
|
||||||
textStyle: { //图例文字的样式
|
textStyle: { // 图例文字的样式
|
||||||
color: '#666666',
|
color: '#666666',
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: 400
|
fontWeight: 400
|
||||||
@@ -71,23 +71,23 @@ export default {
|
|||||||
let otherData = []
|
let otherData = []
|
||||||
this.chartData.sort(reverseSortBy('num'))
|
this.chartData.sort(reverseSortBy('num'))
|
||||||
|
|
||||||
if(this.chartData.length>5){
|
if (this.chartData.length > 5) {
|
||||||
chartDataTmp = this.chartData.slice(0, 5)
|
chartDataTmp = this.chartData.slice(0, 5)
|
||||||
chartDataTmp.forEach(data=>{
|
chartDataTmp.forEach(data => {
|
||||||
if(data.name===''){
|
if (data.name === '') {
|
||||||
data.name = ' '
|
data.name = ' '
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let otherSum = 0
|
let otherSum = 0
|
||||||
otherData = this.chartData.slice(5)
|
otherData = this.chartData.slice(5)
|
||||||
otherData.forEach(data=>{
|
otherData.forEach(data => {
|
||||||
otherSum = otherSum+data.num
|
otherSum = otherSum + data.num
|
||||||
})
|
})
|
||||||
chartDataTmp.push({'num':otherSum,'name':'other'})
|
chartDataTmp.push({ num: otherSum, name: 'other' })
|
||||||
} else if(this.chartData.length<=5){
|
} else if (this.chartData.length <= 5) {
|
||||||
chartDataTmp = this.chartData.slice(0, this.chartData.length)
|
chartDataTmp = this.chartData.slice(0, this.chartData.length)
|
||||||
chartDataTmp.forEach(data=>{
|
chartDataTmp.forEach(data => {
|
||||||
if(data.name===''){
|
if (data.name === '') {
|
||||||
data.name = ' '
|
data.name = ' '
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -101,7 +101,7 @@ export default {
|
|||||||
unitType: chartParams.unitType ? chartParams.unitType : 'number'
|
unitType: chartParams.unitType ? chartParams.unitType : 'number'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}else {
|
} else {
|
||||||
this.chartOption.series[0].data = this.chartData.map(d => {
|
this.chartOption.series[0].data = this.chartData.map(d => {
|
||||||
return {
|
return {
|
||||||
name: lineToSpace(d.name),
|
name: lineToSpace(d.name),
|
||||||
|
|||||||
@@ -139,30 +139,30 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
chartInfo: Object,
|
chartInfo: Object,
|
||||||
chartData: [Array, Object],
|
chartData: [Array, Object],
|
||||||
queryParams: Object,
|
queryParams: Object
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
icon: '',
|
icon: '',
|
||||||
color: '',
|
color: '',
|
||||||
type: 0,
|
type: 0,
|
||||||
chartOption: null,
|
chartOption: null,
|
||||||
timer: null,
|
timer: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
chartInfo: {
|
chartInfo: {
|
||||||
deep: true,
|
deep: true,
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(n) {
|
handler (n) {
|
||||||
this.icon = n.params.icon
|
this.icon = n.params.icon
|
||||||
this.color = n.params.color
|
this.color = n.params.color
|
||||||
this.type = n.type
|
this.type = n.type
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
handleSingleValue() {
|
handleSingleValue () {
|
||||||
const value =
|
const value =
|
||||||
this.$_.isEmpty(this.chartData) || this.$_.get(this, 'chartData')
|
this.$_.isEmpty(this.chartData) || this.$_.get(this, 'chartData')
|
||||||
? this.chartData
|
? this.chartData
|
||||||
@@ -185,7 +185,7 @@ export default {
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
singleValueClass() {
|
singleValueClass () {
|
||||||
return function (type) {
|
return function (type) {
|
||||||
let c
|
let c
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -214,10 +214,10 @@ export default {
|
|||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
chartSingleValueTotal() {
|
chartSingleValueTotal () {
|
||||||
const chartParams = this.$_.get(this.chartInfo, 'params') || {}
|
const chartParams = this.$_.get(this.chartInfo, 'params') || {}
|
||||||
if (this.type === 52) {
|
if (this.type === 52) {
|
||||||
const dom = document.getElementById(`chart${this.chartInfo.id}`)
|
const dom = document.getElementById(`chart${this.chartInfo.id}`)
|
||||||
@@ -234,29 +234,29 @@ export default {
|
|||||||
data: r.values.map((v) => [
|
data: r.values.map((v) => [
|
||||||
Number(v[0]) * 1000,
|
Number(v[0]) * 1000,
|
||||||
Number(v[1]),
|
Number(v[1]),
|
||||||
chartParams.unitType,
|
chartParams.unitType
|
||||||
]),
|
]),
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: getChartColor[i],
|
color: getChartColor[i]
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
myChart.setOption(this.chartOption)
|
myChart.setOption(this.chartOption)
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted () {
|
||||||
this.$nextTick(
|
this.$nextTick(
|
||||||
() =>
|
() =>
|
||||||
(this.timer = setTimeout(() => {
|
(this.timer = setTimeout(() => {
|
||||||
this.chartSingleValueTotal()
|
this.chartSingleValueTotal()
|
||||||
}, 200)),
|
}, 200))
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
deactivated() {
|
deactivated () {
|
||||||
clearTimeout(this.timer)
|
clearTimeout(this.timer)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch:{
|
watch: {
|
||||||
pageSizeForAlarm:{
|
pageSizeForAlarm: {
|
||||||
deep:true,
|
deep: true
|
||||||
},
|
},
|
||||||
total:{
|
total: {
|
||||||
deep:true,
|
deep: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ export default {
|
|||||||
result: {
|
result: {
|
||||||
doh: {
|
doh: {
|
||||||
count: 111,
|
count: 111,
|
||||||
percent: 0.85,
|
percent: 0.85
|
||||||
},
|
},
|
||||||
dot: {
|
dot: {
|
||||||
count: 111,
|
count: 111,
|
||||||
percent: 80.85,
|
percent: 80.85
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,14 +84,14 @@ export default {
|
|||||||
this.myChart2.setOption(this.chartOption)
|
this.myChart2.setOption(this.chartOption)
|
||||||
this.$store.commit('setChartList', this.$_.cloneDeep(this.myChart2))
|
this.$store.commit('setChartList', this.$_.cloneDeep(this.myChart2))
|
||||||
}
|
}
|
||||||
let _this = this
|
const _this = this
|
||||||
window.addEventListener("resize", function(){
|
window.addEventListener('resize', function () {
|
||||||
_this.$store.getters.getChartList.forEach(chart =>{
|
_this.$store.getters.getChartList.forEach(chart => {
|
||||||
if(chart){
|
if (chart) {
|
||||||
chart.resize()
|
chart.resize()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
} finally {
|
} finally {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.$emit('showLoading', false)
|
this.$emit('showLoading', false)
|
||||||
|
|||||||
@@ -223,16 +223,16 @@ export function getLayout (type) {
|
|||||||
|
|
||||||
export function getGroupHeight (arr) {
|
export function getGroupHeight (arr) {
|
||||||
if (arr.length) {
|
if (arr.length) {
|
||||||
let minYArr = [...arr]
|
const minYArr = [...arr]
|
||||||
minYArr.sort((a, b) => {
|
minYArr.sort((a, b) => {
|
||||||
return a.y - b.y
|
return a.y - b.y
|
||||||
})
|
})
|
||||||
let maxYArr = [...arr]
|
const maxYArr = [...arr]
|
||||||
maxYArr.sort((a, b) => {
|
maxYArr.sort((a, b) => {
|
||||||
return (b.y + b.h) - (a.y + a.h)
|
return (b.y + b.h) - (a.y + a.h)
|
||||||
})
|
})
|
||||||
return maxYArr[0].y + maxYArr[0].h - minYArr[0].y
|
return maxYArr[0].y + maxYArr[0].h - minYArr[0].y
|
||||||
/*let lastItem = []
|
/* let lastItem = []
|
||||||
let maxY = arr[0].y
|
let maxY = arr[0].y
|
||||||
arr.forEach((children, index) => {
|
arr.forEach((children, index) => {
|
||||||
if (maxY === children.y) {
|
if (maxY === children.y) {
|
||||||
@@ -251,7 +251,7 @@ export function getGroupHeight (arr) {
|
|||||||
if (maxY < 0) {
|
if (maxY < 0) {
|
||||||
maxY = 0
|
maxY = 0
|
||||||
}
|
}
|
||||||
return maxHeight + maxY*/
|
return maxHeight + maxY */
|
||||||
} else {
|
} else {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ import { ref } from 'vue'
|
|||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import { multipleBarOption, pieForSeverity, activeAttackBar, getAttackColor, getSeverityColor, getSeriesIndex } from '@/views/detections/options/detectionOptions'
|
import { multipleBarOption, pieForSeverity, activeAttackBar, getAttackColor, getSeverityColor, getSeriesIndex } from '@/views/detections/options/detectionOptions'
|
||||||
import { api, getData } from '@/utils/api'
|
import { api, getData } from '@/utils/api'
|
||||||
import { reverseSortBy ,sortBy ,extensionEchartY} from '@/utils/tools'
|
import { reverseSortBy, sortBy, extensionEchartY } from '@/utils/tools'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import DetectionNoData from '@/views/detections/DetectionNoData'
|
import DetectionNoData from '@/views/detections/DetectionNoData'
|
||||||
|
|
||||||
@@ -237,7 +237,7 @@ export default {
|
|||||||
initEventSeverityTrendData (params) {
|
initEventSeverityTrendData (params) {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
getData(api.detection[this.pageType].eventSeverityTrend, params).then(data => {
|
getData(api.detection[this.pageType].eventSeverityTrend, params).then(data => {
|
||||||
/*data = [
|
/* data = [
|
||||||
{
|
{
|
||||||
"statTime": "2022-01-01T10:07:03.008Z",
|
"statTime": "2022-01-01T10:07:03.008Z",
|
||||||
"eventSeverity": "critical",
|
"eventSeverity": "critical",
|
||||||
@@ -329,7 +329,7 @@ export default {
|
|||||||
"eventSeverity": "info",
|
"eventSeverity": "info",
|
||||||
"count": 27
|
"count": 27
|
||||||
},
|
},
|
||||||
]*/
|
] */
|
||||||
this.eventSeverityData = data
|
this.eventSeverityData = data
|
||||||
if (!this.$_.isEmpty(data)) {
|
if (!this.$_.isEmpty(data)) {
|
||||||
const dataMap = new Map()
|
const dataMap = new Map()
|
||||||
@@ -347,36 +347,36 @@ export default {
|
|||||||
const chartDom = document.getElementById(`eventSeverityTrendBar${this.pageType}`)
|
const chartDom = document.getElementById(`eventSeverityTrendBar${this.pageType}`)
|
||||||
const eventSeverityTrendOption = this.$_.cloneDeep(multipleBarOption)
|
const eventSeverityTrendOption = this.$_.cloneDeep(multipleBarOption)
|
||||||
|
|
||||||
let xData = []
|
const xData = []
|
||||||
dataMap.forEach(function (value, key) {
|
dataMap.forEach(function (value, key) {
|
||||||
//eventSeverityTrendOption.series[Number(getSeriesIndex(key))].data = value.map(v => Number(v[1]))
|
// eventSeverityTrendOption.series[Number(getSeriesIndex(key))].data = value.map(v => Number(v[1]))
|
||||||
value.forEach(item => {
|
value.forEach(item => {
|
||||||
if(xData.indexOf(item[0]) < 0){
|
if (xData.indexOf(item[0]) < 0) {
|
||||||
xData.push(item[0])
|
xData.push(item[0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
eventSeverityTrendOption.series.forEach(serie => {
|
eventSeverityTrendOption.series.forEach(serie => {
|
||||||
let seriesData = []
|
const seriesData = []
|
||||||
xData.forEach(item => {
|
xData.forEach(item => {
|
||||||
if(dataMap.has(serie.name)){
|
if (dataMap.has(serie.name)) {
|
||||||
let hasX = dataMap.get(serie.name).some(function(v) {
|
const hasX = dataMap.get(serie.name).some(function (v) {
|
||||||
if (item == v[0]) {
|
if (item == v[0]) {
|
||||||
seriesData.push(Number(v[1]))
|
seriesData.push(Number(v[1]))
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if(!hasX){
|
if (!hasX) {
|
||||||
seriesData.push(0)
|
seriesData.push(0)
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
seriesData.push(0)
|
seriesData.push(0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
serie.data = seriesData
|
serie.data = seriesData
|
||||||
})
|
})
|
||||||
|
|
||||||
//eventSeverityTrendOption.xAxis.data = dataMap.get('info').map(v => rTime(v[0]))
|
// eventSeverityTrendOption.xAxis.data = dataMap.get('info').map(v => rTime(v[0]))
|
||||||
eventSeverityTrendOption.xAxis.data = xData
|
eventSeverityTrendOption.xAxis.data = xData
|
||||||
const detectionChart = echarts.init(chartDom)
|
const detectionChart = echarts.init(chartDom)
|
||||||
detectionChart.setOption(eventSeverityTrendOption)
|
detectionChart.setOption(eventSeverityTrendOption)
|
||||||
@@ -709,7 +709,7 @@ export default {
|
|||||||
return [d.count, d.name]
|
return [d.count, d.name]
|
||||||
}).reverse()
|
}).reverse()
|
||||||
detectionChart.setOption(option)
|
detectionChart.setOption(option)
|
||||||
extensionEchartY(detectionChart)//y轴标签过长时,鼠标悬浮,显示所有内容
|
extensionEchartY(detectionChart)// y轴标签过长时,鼠标悬浮,显示所有内容
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export const multipleBarOption = {
|
|||||||
{
|
{
|
||||||
name: 'critical',
|
name: 'critical',
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
stack:'eventSeverityTrend',
|
stack: 'eventSeverityTrend',
|
||||||
emphasis: {
|
emphasis: {
|
||||||
focus: 'series'
|
focus: 'series'
|
||||||
},
|
},
|
||||||
@@ -117,7 +117,7 @@ export const multipleBarOption = {
|
|||||||
{
|
{
|
||||||
name: 'high',
|
name: 'high',
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
stack:'eventSeverityTrend',
|
stack: 'eventSeverityTrend',
|
||||||
emphasis: {
|
emphasis: {
|
||||||
focus: 'series'
|
focus: 'series'
|
||||||
},
|
},
|
||||||
@@ -130,7 +130,7 @@ export const multipleBarOption = {
|
|||||||
{
|
{
|
||||||
name: 'medium',
|
name: 'medium',
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
stack:'eventSeverityTrend',
|
stack: 'eventSeverityTrend',
|
||||||
emphasis: {
|
emphasis: {
|
||||||
focus: 'series'
|
focus: 'series'
|
||||||
},
|
},
|
||||||
@@ -143,7 +143,7 @@ export const multipleBarOption = {
|
|||||||
{
|
{
|
||||||
name: 'low',
|
name: 'low',
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
stack:'eventSeverityTrend',
|
stack: 'eventSeverityTrend',
|
||||||
emphasis: {
|
emphasis: {
|
||||||
focus: 'series'
|
focus: 'series'
|
||||||
},
|
},
|
||||||
@@ -156,7 +156,7 @@ export const multipleBarOption = {
|
|||||||
{
|
{
|
||||||
name: 'info',
|
name: 'info',
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
stack:'eventSeverityTrend',
|
stack: 'eventSeverityTrend',
|
||||||
emphasis: {
|
emphasis: {
|
||||||
focus: 'series'
|
focus: 'series'
|
||||||
},
|
},
|
||||||
@@ -253,14 +253,14 @@ export const activeAttackBar = {
|
|||||||
axisLine: { show: false },
|
axisLine: { show: false },
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
show: true,
|
show: true,
|
||||||
width:95,
|
width: 95,
|
||||||
overflow:'truncate',
|
overflow: 'truncate'
|
||||||
|
|
||||||
},
|
},
|
||||||
splitLine: {
|
splitLine: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
triggerEvent: true,
|
triggerEvent: true
|
||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
barWidth: 5,
|
barWidth: 5,
|
||||||
|
|||||||
@@ -45,7 +45,12 @@
|
|||||||
<div class="overview__right">
|
<div class="overview__right">
|
||||||
<div class="overview__title">{{$t('detections.goToEntity')}}</div>
|
<div class="overview__title">{{$t('detections.goToEntity')}}</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__content row__content--link">{{$t('detections.viewDetailOf', {ip: detection.appName})}}</div>
|
<div class="row__content">
|
||||||
|
<span>{{ $t('detections.viewDetailOf') }}</span>
|
||||||
|
<span
|
||||||
|
class="row__content--link"
|
||||||
|
@click="goDetail('app', detection.appName)">{{detection.appName}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__title">{{$t('detections.goToHunt')}}</div>
|
<div class="overview__title">{{$t('detections.goToHunt')}}</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
@@ -111,16 +116,16 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
goDetail(type, name) {
|
goDetail (type, name) {
|
||||||
const { href } = this.$router.resolve({
|
const { href } = this.$router.resolve({
|
||||||
path: '/entityDetail',
|
path: '/entityDetail',
|
||||||
query: {
|
query: {
|
||||||
entityType: type,
|
entityType: type,
|
||||||
name: name,
|
name: name
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
window.open(href, '_blank')
|
window.open(href, '_blank')
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.query()
|
this.query()
|
||||||
|
|||||||
@@ -49,7 +49,12 @@
|
|||||||
<div class="overview__right">
|
<div class="overview__right">
|
||||||
<div class="overview__title">{{$t('detections.goToEntity')}}</div>
|
<div class="overview__title">{{$t('detections.goToEntity')}}</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__content row__content--link">{{$t('detections.viewDetailOf', {ip: detection.domain})}}</div>
|
<div class="row__content">
|
||||||
|
<span>{{ $t('detections.viewDetailOf') }}</span>
|
||||||
|
<span
|
||||||
|
class="row__content--link"
|
||||||
|
@click="goDetail('domain', computeSecondaryDomain(detection.domain))">{{computeSecondaryDomain(detection.domain)}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__title">{{$t('detections.goToHunt')}}</div>
|
<div class="overview__title">{{$t('detections.goToHunt')}}</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
@@ -61,7 +66,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { api, getData } from '@/utils/api'
|
import { api, getData } from '@/utils/api'
|
||||||
import { eventSeverityColor } from '@/utils/constants'
|
import { eventSeverityColor, topDomain } from '@/utils/constants'
|
||||||
export default {
|
export default {
|
||||||
name: 'DetectionPerformanceEventDomainOverview',
|
name: 'DetectionPerformanceEventDomainOverview',
|
||||||
props: {
|
props: {
|
||||||
@@ -94,6 +99,32 @@ export default {
|
|||||||
}
|
}
|
||||||
return result || '-'
|
return result || '-'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
computeSecondaryDomain () {
|
||||||
|
return function (name) {
|
||||||
|
// 命中的顶级域名
|
||||||
|
let hitTopDomain = ''
|
||||||
|
// 同顶级域名比对
|
||||||
|
const hits = []
|
||||||
|
topDomain.forEach(td => {
|
||||||
|
const hitIndex = name.lastIndexOf(td)
|
||||||
|
if (hitIndex > -1 && hitIndex + td.length === name.length) {
|
||||||
|
hits.push(td)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (hits.length > 0) {
|
||||||
|
hits.sort((a, b) => {
|
||||||
|
return b.split('.').length - a.split('.').length
|
||||||
|
})
|
||||||
|
hitTopDomain = hits[0]
|
||||||
|
} else {
|
||||||
|
const arr = name.split('.')
|
||||||
|
hitTopDomain = arr[arr.length - 1]
|
||||||
|
}
|
||||||
|
const index = name.lastIndexOf(hitTopDomain)
|
||||||
|
const preArr = name.substring(0, index).split('.')
|
||||||
|
return [preArr[preArr.length - 2], hitTopDomain].join('.')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -115,16 +146,16 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
goDetail(type, name) {
|
goDetail (type, name) {
|
||||||
const { href } = this.$router.resolve({
|
const { href } = this.$router.resolve({
|
||||||
path: '/entityDetail',
|
path: '/entityDetail',
|
||||||
query: {
|
query: {
|
||||||
entityType: type,
|
entityType: type,
|
||||||
name: name,
|
name: name
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
window.open(href, '_blank')
|
window.open(href, '_blank')
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.query()
|
this.query()
|
||||||
|
|||||||
@@ -39,7 +39,12 @@
|
|||||||
<div class="overview__right">
|
<div class="overview__right">
|
||||||
<div class="overview__title">{{$t('detections.goToEntity')}}</div>
|
<div class="overview__title">{{$t('detections.goToEntity')}}</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__content row__content--link">{{$t('detections.viewDetailOf', {ip: detection.serverIp})}}</div>
|
<div class="row__content">
|
||||||
|
<span>{{ $t('detections.viewDetailOf') }}</span>
|
||||||
|
<span
|
||||||
|
class="row__content--link"
|
||||||
|
@click="goDetail('ip', detection.serverIp)">{{detection.serverIp}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__title">{{$t('detections.goToHunt')}}</div>
|
<div class="overview__title">{{$t('detections.goToHunt')}}</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
@@ -103,16 +108,16 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
goDetail(type, name) {
|
goDetail (type, name) {
|
||||||
const { href } = this.$router.resolve({
|
const { href } = this.$router.resolve({
|
||||||
path: '/entityDetail',
|
path: '/entityDetail',
|
||||||
query: {
|
query: {
|
||||||
entityType: type,
|
entityType: type,
|
||||||
name: name,
|
name: name
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
window.open(href, '_blank')
|
window.open(href, '_blank')
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.query()
|
this.query()
|
||||||
|
|||||||
@@ -173,9 +173,7 @@
|
|||||||
<span>{{ $t('detections.viewDetailOf') }}</span>
|
<span>{{ $t('detections.viewDetailOf') }}</span>
|
||||||
<span
|
<span
|
||||||
class="row__content--link"
|
class="row__content--link"
|
||||||
@click="goDetail('ip', basicInfo.victimIp)"
|
@click="goDetail('ip', basicInfo.victimIp)"></span>
|
||||||
>{{ basicInfo.victimIp }}</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__title">{{ $t('detections.goToOffender') }}</div>
|
<div class="overview__title">{{ $t('detections.goToOffender') }}</div>
|
||||||
@@ -287,18 +285,18 @@ import _ from 'lodash'
|
|||||||
export default {
|
export default {
|
||||||
name: 'DetectionOverview',
|
name: 'DetectionOverview',
|
||||||
props: {
|
props: {
|
||||||
detection: Object,
|
detection: Object
|
||||||
},
|
},
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
eventSeverityColor,
|
eventSeverityColor,
|
||||||
basicInfo: {},
|
basicInfo: {},
|
||||||
events: [],
|
events: [],
|
||||||
reference: 'https://attack.mitre.org',
|
reference: 'https://attack.mitre.org'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
formatT0() {
|
formatT0 () {
|
||||||
const vm = this
|
const vm = this
|
||||||
return function (event) {
|
return function (event) {
|
||||||
const diffSeconds = event.diffSeconds
|
const diffSeconds = event.diffSeconds
|
||||||
@@ -318,7 +316,7 @@ export default {
|
|||||||
unitTypes.time,
|
unitTypes.time,
|
||||||
's',
|
's',
|
||||||
null,
|
null,
|
||||||
0,
|
0
|
||||||
).join('')
|
).join('')
|
||||||
if (eventStartTime > entityStartTime) {
|
if (eventStartTime > entityStartTime) {
|
||||||
return `T0+${suffix}`
|
return `T0+${suffix}`
|
||||||
@@ -328,26 +326,26 @@ export default {
|
|||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getMillisecond,
|
getMillisecond,
|
||||||
query() {
|
query () {
|
||||||
Promise.all([this.queryBasic(), this.queryEvent()]).then((responses) => {
|
Promise.all([this.queryBasic(), this.queryEvent()]).then((responses) => {
|
||||||
responses[0] && (this.basicInfo = responses[0])
|
responses[0] && (this.basicInfo = responses[0])
|
||||||
responses[1] &&
|
responses[1] &&
|
||||||
(this.events = responses[1].sort(
|
(this.events = responses[1].sort(
|
||||||
(e1, e2) => e1.startTime - e2.startTime,
|
(e1, e2) => e1.startTime - e2.startTime
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
queryBasic() {
|
queryBasic () {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
get(api.detection.securityEvent.overviewBasic, {
|
get(api.detection.securityEvent.overviewBasic, {
|
||||||
eventId: this.detection.eventId,
|
eventId: this.detection.eventId,
|
||||||
startTime: this.detection.startTime,
|
startTime: this.detection.startTime,
|
||||||
endTime: this.detection.endTime,
|
endTime: this.detection.endTime
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
resolve(response.data.result[0])
|
resolve(response.data.result[0])
|
||||||
@@ -360,13 +358,13 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
queryEvent() {
|
queryEvent () {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
get(api.detection.securityEvent.overviewEvent, {
|
get(api.detection.securityEvent.overviewEvent, {
|
||||||
startTime: this.detection.startTime,
|
startTime: this.detection.startTime,
|
||||||
offenderIp: this.detection.offenderIp,
|
offenderIp: this.detection.offenderIp,
|
||||||
victimIp: this.detection.victimIp,
|
victimIp: this.detection.victimIp
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
resolve(response.data.result)
|
resolve(response.data.result)
|
||||||
@@ -379,19 +377,19 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
goDetail(type, name) {
|
goDetail (type, name) {
|
||||||
const { href } = this.$router.resolve({
|
const { href } = this.$router.resolve({
|
||||||
path: '/entityDetail',
|
path: '/entityDetail',
|
||||||
query: {
|
query: {
|
||||||
entityType: type,
|
entityType: type,
|
||||||
name: name,
|
name: name
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
window.open(href, '_blank')
|
window.open(href, '_blank')
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted () {
|
||||||
this.query()
|
this.query()
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -200,21 +200,21 @@ export default {
|
|||||||
name: 'Row',
|
name: 'Row',
|
||||||
props: {
|
props: {
|
||||||
index: Number,
|
index: Number,
|
||||||
timeFilter: Object,
|
timeFilter: Object
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
DetailOverview,
|
DetailOverview
|
||||||
},
|
},
|
||||||
mixins: [entityListMixin, entityDetailMixin, relatedServer],
|
mixins: [entityListMixin, entityDetailMixin, relatedServer],
|
||||||
data() {
|
data () {
|
||||||
return {
|
return {
|
||||||
isCollapse: true, // 是否是折叠状态
|
isCollapse: true, // 是否是折叠状态
|
||||||
trafficUrl: '',
|
trafficUrl: '',
|
||||||
entityType: '',
|
entityType: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
ipLocationRegion() {
|
ipLocationRegion () {
|
||||||
return function (entityData) {
|
return function (entityData) {
|
||||||
const hasProvinceAndCity =
|
const hasProvinceAndCity =
|
||||||
entityData.ipLocationProvince &&
|
entityData.ipLocationProvince &&
|
||||||
@@ -237,7 +237,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
entityType() {
|
entityType () {
|
||||||
let type
|
let type
|
||||||
switch (this.entityData.entityType) {
|
switch (this.entityData.entityType) {
|
||||||
case 'ip': {
|
case 'ip': {
|
||||||
@@ -257,12 +257,12 @@ export default {
|
|||||||
}
|
}
|
||||||
this.entityType = type
|
this.entityType = type
|
||||||
return type
|
return type
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
entityData: {
|
entityData: {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler(n) {
|
handler (n) {
|
||||||
if (n.entityType) {
|
if (n.entityType) {
|
||||||
switch (n.entityType) {
|
switch (n.entityType) {
|
||||||
case 'ip': {
|
case 'ip': {
|
||||||
@@ -281,35 +281,35 @@ export default {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
setup() {
|
setup () {
|
||||||
return {
|
return {
|
||||||
unitConvert,
|
unitConvert,
|
||||||
unitTypes,
|
unitTypes
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* 切换折叠状态 */
|
/* 切换折叠状态 */
|
||||||
switchCollapse() {
|
switchCollapse () {
|
||||||
this.isCollapse = !this.isCollapse
|
this.isCollapse = !this.isCollapse
|
||||||
this.$emit('switchCollapse', this.isCollapse, this.index)
|
this.$emit('switchCollapse', this.isCollapse, this.index)
|
||||||
},
|
},
|
||||||
/* 设为折叠状态 */
|
/* 设为折叠状态 */
|
||||||
collapse() {
|
collapse () {
|
||||||
this.isCollapse = true
|
this.isCollapse = true
|
||||||
},
|
},
|
||||||
getQueryParams() {
|
getQueryParams () {
|
||||||
const queryParams = {
|
const queryParams = {
|
||||||
startTime: parseInt(this.timeFilter.startTime / 1000),
|
startTime: parseInt(this.timeFilter.startTime / 1000),
|
||||||
endTime: parseInt(this.timeFilter.endTime / 1000),
|
endTime: parseInt(this.timeFilter.endTime / 1000),
|
||||||
appName: this.entityType,
|
appName: this.entityType,
|
||||||
domain:this.entityType,
|
domain: this.entityType,
|
||||||
ip:this.entityType
|
ip: this.entityType
|
||||||
}
|
}
|
||||||
return queryParams
|
return queryParams
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -4,19 +4,23 @@
|
|||||||
<div class="overview__content">
|
<div class="overview__content">
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label row__label--width130">APP ID</div>
|
<div class="row__label row__label--width130">APP ID</div>
|
||||||
<div class="row__content">{{entityData.appId|| '-'}}</div>
|
<div class="row__content">{{entity.appId|| '-'}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label row__label--width130">{{$t('entities.category')}}</div>
|
<div class="row__label row__label--width130">{{$t('entities.category')}}</div>
|
||||||
<div class="row__content">{{entityData.appCategory|| '-'}}</div>
|
<div class="row__content">{{entity.appCategory|| '-'}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label row__label--width130">{{$t('entities.subcategory')}}</div>
|
<div class="row__label row__label--width130">{{$t('entities.subcategory')}}</div>
|
||||||
<div class="row__content">{{entityData.appSubcategory || '-'}}</div>
|
<div class="row__content">{{entity.appSubcategory || '-'}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label row__label--width130">{{$t('entities.riskLevel')}}</div>
|
<div class="row__label row__label--width130">{{$t('entities.riskLevel')}}</div>
|
||||||
<div class="row__content">{{appRisk(entityData.appRisk) || '-'}}</div>
|
<div class="row__content">{{appRisk(entity.appRisk) || '-'}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label row__label--width130">{{$t('overall.remark')}}</div>
|
||||||
|
<div class="row__content">{{entity.appDescription || '-'}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export default {
|
|||||||
this.entityData.max = t.aggregation.max
|
this.entityData.max = t.aggregation.max
|
||||||
this.entityData.avg = t.aggregation.avg
|
this.entityData.avg = t.aggregation.avg
|
||||||
} else if (t.legend === 'bytesSentRate') {
|
} else if (t.legend === 'bytesSentRate') {
|
||||||
this.entityData.bytesSentRate = _.nth(t.values,-3)[1]
|
this.entityData.bytesSentRate = _.nth(t.values, -3)[1]
|
||||||
this.chartOptionSent = {
|
this.chartOptionSent = {
|
||||||
...this.chartOption,
|
...this.chartOption,
|
||||||
series: [
|
series: [
|
||||||
@@ -88,7 +88,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
color: '#69b072',
|
color: '#69b072',
|
||||||
data: _.dropRight(t.values,2).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.byte]),
|
data: _.dropRight(t.values, 2).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.byte]),
|
||||||
showSymbol: false
|
showSymbol: false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user