perf: loading更改
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="chart__loading" v-show="showLoading">
|
||||
<i class="el-icon-loading"></i>
|
||||
<img :class="className" :src="path" alt="" :style="innerStyle">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -8,7 +8,12 @@
|
||||
export default {
|
||||
name: 'loading',
|
||||
props: {
|
||||
loading: Boolean
|
||||
loading: Boolean,
|
||||
size: {
|
||||
type: String,
|
||||
default: 'default' // large default small
|
||||
},
|
||||
innerStyle: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -31,6 +36,28 @@ export default {
|
||||
this.showLoading = n
|
||||
}
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
const path = window.location.protocol + '//' + window.location.host + '/images/loading.gif'
|
||||
let className = ''
|
||||
switch (props.size) {
|
||||
case 'large': {
|
||||
className = 'loading-img--large'
|
||||
break
|
||||
}
|
||||
case 'small': {
|
||||
className = 'loading-img--small'
|
||||
break
|
||||
}
|
||||
default: {
|
||||
className = 'loading-img--default'
|
||||
break
|
||||
}
|
||||
}
|
||||
return {
|
||||
path,
|
||||
className
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="show"
|
||||
:top="top"
|
||||
:modal="modal"
|
||||
:custom-class="customClass"
|
||||
:show-close="showClose"
|
||||
:width="width"
|
||||
destroy-on-close
|
||||
>
|
||||
<cn-panel :entity="entity" :is-entity-detail="true"></cn-panel>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Panel from '@/views/charts/Panel'
|
||||
export default {
|
||||
name: 'EntityDetail',
|
||||
components: {
|
||||
'cn-panel': Panel
|
||||
},
|
||||
props: {
|
||||
showDetail: Boolean,
|
||||
top: {
|
||||
type: String,
|
||||
default: '5vh'
|
||||
},
|
||||
modal: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
customClass: {
|
||||
type: String,
|
||||
default: 'entity-detail__dialog'
|
||||
},
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
width: { // 高度需要通过customClass自行定义
|
||||
type: [String, Number],
|
||||
default: '90vw'
|
||||
},
|
||||
entity: Object // 实体,{ type: 'ip|domain|app', name: name, icon: icon-class }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
showDetail (n, o) {
|
||||
this.show = n
|
||||
},
|
||||
show (n, o) {
|
||||
this.$emit('update:show-detail', n)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,367 +0,0 @@
|
||||
<template>
|
||||
<div class="entity-list">
|
||||
<div class="entity__loading" v-show="loading">
|
||||
<i class="el-icon-loading"></i>
|
||||
</div>
|
||||
<div class="entity-list__content">
|
||||
<div class="cn-entity" v-for="(d, i) in entityList" :key="i">
|
||||
<div class="cn-entity__header">
|
||||
<div class="header__content" :title="d.ip||d.domainName||d.appName">
|
||||
<div class="header__icon"><i :class="iconClass"></i></div>
|
||||
<template v-if="from === 'ip'">
|
||||
<div class="content__name" style="top:31px;">
|
||||
{{d.ip || 'Unknown'}}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="from === 'domain'">
|
||||
<div class="content__name" >
|
||||
{{d.domainName || 'Unknown'}}
|
||||
</div>
|
||||
<div class="content__desc" >
|
||||
<span class="desc__label">{{$t('entities.reputationLevel')}}: </span>
|
||||
<span>{{d.reputationLevel || '-'}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="from === 'app'">
|
||||
<div class="content__name" >
|
||||
{{d.appName || 'Unknown'}}
|
||||
</div>
|
||||
<div class="content__desc" >
|
||||
<span class="desc__label">{{$t('entities.risk')}}: </span>
|
||||
<span>{{d.appRisk || '-'}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="header__bottom__line"></div>
|
||||
</div>
|
||||
<div class="cn-entity__body">
|
||||
<template v-if="from === 'ip'">
|
||||
<div class="body__row">
|
||||
<span class="body__row-label"><i class="cn-icon cn-icon-country" ></i>{{$t('overall.country')}}:</span>
|
||||
<div class="body__row-value" :title="d.country">{{d.country || '-'}}</div>
|
||||
</div>
|
||||
<div class="body__row">
|
||||
<span class="body__row-label"><i class="cn-icon cn-icon-position"></i>{{$t('overall.region')}}:</span>
|
||||
<div class="body__row-value" :title="d.region">{{d.region || '-'}}</div>
|
||||
</div>
|
||||
<div class="body__row">
|
||||
<span class="body__row-label"><i class="cn-icon cn-icon-cloud"></i>{{$t('entities.asn')}}:</span>
|
||||
<div class="body__row-value" :title="d.asn">{{d.asn || '-'}}</div>
|
||||
</div>
|
||||
<!-- 曲线-->
|
||||
<div class="body__drawing-box">
|
||||
<div class="body__drawing" :id="`entityListChart${d.id}`"></div>
|
||||
</div>
|
||||
<div class="body__statics">
|
||||
<div class="entity-statics-down"><i class="cn-icon cn-icon-fall entity-statics-icon" style=""></i>{{d.latestReceived || 0}} bps</div>
|
||||
<div class="entity-statics-up" ><i class="cn-icon cn-icon-rise" style=""></i>{{d.latestSent || 0}} bps</div>
|
||||
<div class="body__detail" @click="entityDetail({ip: d.ip, type: 4})">{{$t('overall.detail')}}></div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="from === 'domain'">
|
||||
<div class="body__row">
|
||||
<span class="body__row-label"><i class="cn-icon cn-icon-category"></i>{{$t('entities.group')}}:</span>
|
||||
<div class="body__row-value" :title="d.categoryGroup">{{d.categoryGroup || '-'}}</div>
|
||||
</div>
|
||||
<div class="body__row">
|
||||
<span class="body__row-label"><i class="cn-icon cn-icon-sub-category"></i>{{$t('entities.categoryName')}}:</span>
|
||||
<div class="body__row-value" :title="d.categoryName">{{d.categoryName || '-'}}</div>
|
||||
</div>
|
||||
<div class="body__row">
|
||||
<span class="body__row-label"><i class="cn-icon cn-icon-credit"></i>{{$t('entities.credit')}}:</span>
|
||||
<div class="body__row-value" :title="d.reputationScore">{{d.reputationScore || '-'}}</div>
|
||||
</div>
|
||||
<!-- 曲线-->
|
||||
<div class="body__drawing-box">
|
||||
<div class="body__drawing" :id="`entityListChart${d.id}`"></div>
|
||||
</div>
|
||||
<div class="body__statics">
|
||||
<div class="entity-statics-down" style=" "><i class="cn-icon cn-icon-fall entity-statics-icon" style=""></i>{{d.latestReceived || 0}} bps</div>
|
||||
<div class="entity-statics-up" ><i class="cn-icon cn-icon-rise" style=""></i>{{d.latestSent || 0}} bps</div>
|
||||
<div class="body__detail" @click="entityDetail({domain: d.domainName, type: 5})">{{$t('overall.detail')}}></div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="from === 'app'">
|
||||
<div class="body__row">
|
||||
<span class="body__row-label"><i class="cn-icon cn-icon-id"></i>APP:</span>
|
||||
<div class="body__row-value" :title="d.appId">{{d.appId || '-'}}</div>
|
||||
</div>
|
||||
<div class="body__row">
|
||||
<span class="body__row-label"><i class="cn-icon cn-icon-category"></i>{{$t('entities.category')}}:</span>
|
||||
<div class="body__row-value" :title="d.appCategory">{{d.appCategory || '-'}}</div>
|
||||
</div>
|
||||
<div class="body__row">
|
||||
<span class="body__row-label"><i class="cn-icon cn-icon-sub-category"></i>{{$t('entities.subcategory')}}:</span>
|
||||
<div class="body__row-value" :title="d.appSubategory">{{d.appSubategory || '-'}}</div>
|
||||
</div>
|
||||
<!-- 曲线-->
|
||||
<div class="body__drawing-box">
|
||||
<div class="body__drawing" :id="`entityListChart${d.id}`"></div>
|
||||
</div>
|
||||
<div class="body__statics">
|
||||
<div class="entity-statics-down" style=" "><i class="cn-icon cn-icon-fall entity-statics-icon" style=""></i>{{d.latestReceived || 0}} bps</div>
|
||||
<div class="entity-statics-up" ><i class="cn-icon cn-icon-rise" style=""></i>{{d.latestSent || 0}} bps</div>
|
||||
<div class="body__detail" @click="entityDetail({app: d.appName, type: 6})">{{$t('overall.detail')}}></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="entity-list__pagination">
|
||||
<el-pagination
|
||||
@size-change="size"
|
||||
@prev-click="prev"
|
||||
@next-click="next"
|
||||
@current-change="current"
|
||||
:currentPage="pageObj.pageNo"
|
||||
:page-size="pageObj.pageSize"
|
||||
:total="pageObj.total"
|
||||
layout="total, prev, pager, next"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import * as echarts from 'echarts'
|
||||
import { entityListLineOption } from '@/views/charts/charts/chart-options'
|
||||
import { getChartColor } from '@/views/charts/charts/tools'
|
||||
import { legendMapping } from '@/views/charts/charts/chart-table-title'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { unitTypes } from '@/utils/constants'
|
||||
|
||||
export default {
|
||||
name: 'EntityList',
|
||||
props: {
|
||||
listData: Array,
|
||||
from: String,
|
||||
pageObj: Object,
|
||||
loading: Boolean
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showDetail: false,
|
||||
typeName: '',
|
||||
entityList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
circleColor () {
|
||||
let color
|
||||
switch (this.from) {
|
||||
case ('ip'): {
|
||||
color = '#E8FBF9'
|
||||
break
|
||||
}
|
||||
case ('domain'): {
|
||||
color = '#EEF6FE'
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
color = '#FEF7E7'
|
||||
break
|
||||
}
|
||||
default: break
|
||||
}
|
||||
return color
|
||||
},
|
||||
iconClass () {
|
||||
let className
|
||||
switch (this.from) {
|
||||
case ('ip'): {
|
||||
className = 'cn-icon cn-icon-ip2 ip-green'
|
||||
break
|
||||
}
|
||||
case ('domain'): {
|
||||
className = 'cn-icon cn-icon-domain2 domain-blue'
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
className = 'cn-icon cn-icon-app2 app-orange'
|
||||
break
|
||||
}
|
||||
default: break
|
||||
}
|
||||
return className
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
size (val) {
|
||||
this.$emit('pageSize', val)
|
||||
},
|
||||
// 点击上一页箭头
|
||||
prev () {
|
||||
this.scrollbarToTop()
|
||||
},
|
||||
// 点击下一页箭头
|
||||
next () {
|
||||
this.scrollbarToTop()
|
||||
},
|
||||
// currentPage 改变时会触发
|
||||
current (val) {
|
||||
this.$emit('pageNo', val)
|
||||
this.scrollbarToTop()
|
||||
},
|
||||
scrollbarToTop () {
|
||||
this.$nextTick(() => {
|
||||
const wraps = document.querySelectorAll('.el-table__body-wrapper')
|
||||
wraps.scrollTop = 0
|
||||
})
|
||||
},
|
||||
entityDetail (params) {
|
||||
this.$emit('showDetail', { ...params, icon: this.iconClass })
|
||||
}
|
||||
},
|
||||
setup () {
|
||||
return {
|
||||
chartOption: entityListLineOption
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
listData: {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
handler (n, o) {
|
||||
if (!this.$_.isEmpty(n) && !this.$_.isEqual(n, o)) {
|
||||
this.entityList = []
|
||||
setTimeout(() => {
|
||||
const now = window.$dayJs.tz().valueOf()
|
||||
const queryParams = { startTime: Math.floor(now / 1000 - 3600), endTime: Math.floor(now / 1000) }
|
||||
switch (this.from) {
|
||||
case ('ip'): {
|
||||
n.forEach(data => {
|
||||
const entity = { ...data }
|
||||
let chartOption
|
||||
get(api.ipThroughput, { ...queryParams, ip: entity.ip }).then(response => {
|
||||
if (response.code === 200) {
|
||||
const seriesTemplate = this.chartOption.series[0]
|
||||
const series = response.data.result.filter(r => r.legend !== 'bytes_rate').map((r, i) => {
|
||||
if (r.legend === 'bytes_sent_rate') {
|
||||
entity.latestSent = unitConvert(r.values[r.values.length - 1][1], unitTypes.byte)[0]
|
||||
} else if (r.legend === 'bytes_received_rate') {
|
||||
entity.latestReceived = unitConvert(r.values[r.values.length - 1][1], unitTypes.byte)[0]
|
||||
}
|
||||
return {
|
||||
...seriesTemplate,
|
||||
name: legendMapping[`ip_${r.legend}`],
|
||||
data: r.values.map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.byte]),
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: getChartColor(i),
|
||||
lineStyle: {
|
||||
width: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
chartOption = {
|
||||
...this.chartOption,
|
||||
series
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
this.entityList.push(entity)
|
||||
this.$nextTick(() => {
|
||||
const myChart = echarts.init(document.getElementById(`entityListChart${entity.id}`))
|
||||
myChart.setOption(chartOption)
|
||||
})
|
||||
})
|
||||
})
|
||||
break
|
||||
}
|
||||
case ('domain'): {
|
||||
n.forEach(data => {
|
||||
const entity = { ...data }
|
||||
let chartOption
|
||||
get(api.domainThroughput, { ...queryParams, domain: entity.domainName }).then(response => {
|
||||
if (response.code === 200) {
|
||||
const seriesTemplate = this.chartOption.series[0]
|
||||
const series = response.data.result.filter(r => r.legend !== 'bytes_rate').map((r, i) => {
|
||||
if (r.legend === 'bytes_sent_rate') {
|
||||
entity.latestSent = unitConvert(r.values[r.values.length - 1][1], unitTypes.byte)[0]
|
||||
} else if (r.legend === 'bytes_received_rate') {
|
||||
entity.latestReceived = unitConvert(r.values[r.values.length - 1][1], unitTypes.byte)[0]
|
||||
}
|
||||
return {
|
||||
...seriesTemplate,
|
||||
name: legendMapping[r.legend],
|
||||
data: r.values.map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.byte]),
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: getChartColor(i),
|
||||
lineStyle: {
|
||||
width: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
chartOption = {
|
||||
...this.chartOption,
|
||||
series
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
this.entityList.push(entity)
|
||||
this.$nextTick(() => {
|
||||
const myChart = echarts.init(document.getElementById(`entityListChart${entity.id}`))
|
||||
myChart.setOption(chartOption)
|
||||
})
|
||||
})
|
||||
})
|
||||
break
|
||||
}
|
||||
case ('app'): {
|
||||
n.forEach(data => {
|
||||
const entity = { ...data }
|
||||
let chartOption
|
||||
get(api.appThroughput, { ...queryParams, app: entity.appName }).then(response => {
|
||||
if (response.code === 200) {
|
||||
const seriesTemplate = this.chartOption.series[0]
|
||||
const series = response.data.result.filter(r => r.legend !== 'bytes_rate').map((r, i) => {
|
||||
if (r.legend === 'bytes_sent_rate') {
|
||||
entity.latestSent = unitConvert(r.values[r.values.length - 1][1], unitTypes.byte)[0]
|
||||
} else if (r.legend === 'bytes_received_rate') {
|
||||
entity.latestReceived = unitConvert(r.values[r.values.length - 1][1], unitTypes.byte)[0]
|
||||
}
|
||||
return {
|
||||
...seriesTemplate,
|
||||
name: legendMapping[r.legend],
|
||||
data: r.values.map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.byte]),
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: getChartColor(i),
|
||||
lineStyle: {
|
||||
width: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
chartOption = {
|
||||
...this.chartOption,
|
||||
series
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
this.entityList.push(entity)
|
||||
this.$nextTick(() => {
|
||||
const myChart = echarts.init(document.getElementById(`entityListChart${entity.id}`))
|
||||
myChart.setOption(chartOption)
|
||||
})
|
||||
})
|
||||
})
|
||||
break
|
||||
}
|
||||
default: break
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,113 +0,0 @@
|
||||
<template >
|
||||
<div class="entity-pop-custom" v-ele-click-outside="esc">
|
||||
<div class="pop-title">
|
||||
<div>
|
||||
<i :class="itemData.icon"></i>
|
||||
<span>{{itemData.label}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <button @click="esc" class="el-dialog__headerbtn" type="button"><i class="el-dialog__close el-icon el-icon-close"></i></button>-->
|
||||
<div class="filter-top-box">
|
||||
<div class="filter-top-body">
|
||||
<loading :loading="loading"></loading>
|
||||
<div class="filter-top-type">{{itemData.value}}{{$t('overall.operator')}}{{itemData.label}}</div>
|
||||
<el-table
|
||||
:data="popoverData"
|
||||
:header-cell-style="tableHeaderCellStyle"
|
||||
:header-row-style="tableHeaderRowStyle"
|
||||
:row-style="rowStyle"
|
||||
:cell-style="{'text-align':'left','padding': '1px 0','border':'0px'}"
|
||||
class="customer-no-border-table"
|
||||
style="width: 100%; min-height: 293px;"
|
||||
@row-click="filter"
|
||||
>
|
||||
<el-table-column label="Top10" type="index" :index="indexMethod" width="81"/>
|
||||
<el-table-column prop="name" :label="itemData.label" width="120">
|
||||
<template #default="scope">
|
||||
<div style="overflow: hidden; white-space: nowrap; text-overflow: ellipsis;" :title="scope.row.name">
|
||||
{{valueHandle(scope.row.name, topColumn) || 'unknown'}}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="count" :label="$t('overall.number')" width="79" />
|
||||
<el-table-column prop="percent" :label="$t('overall.percent')" >
|
||||
<template #default="scope">
|
||||
<div class="top-table-percent" >
|
||||
{{(this.totalCount === 0 ? 0 : parseFloat(scope.row.count / this.totalCount) * 100).toFixed(2)}}%
|
||||
<div class="top-table-progress"><el-progress :percentage="(this.totalCount === 0 ? 0 : parseFloat(scope.row.count / this.totalCount) * 100).toFixed(2)" :show-text="false" color="#23BF9A"></el-progress></div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { riskLevelMapping } from '@/utils/constants'
|
||||
import Loading from '@/components/common/Loading'
|
||||
|
||||
export default {
|
||||
components: { Loading },
|
||||
props: {
|
||||
loading: Boolean,
|
||||
popoverData: Array,
|
||||
itemData: Object,
|
||||
totalCount: Number,
|
||||
topColumn: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
custom: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
totalCount2 () {
|
||||
return function (row) {
|
||||
console.info(this.totalCount, row, (this.totalCount === 0 ? 0 : parseFloat(row.count / this.totalCount) * 100).toFixed(2))
|
||||
return (this.totalCount === 0 ? 0 : parseFloat(row.count / this.totalCount) * 100).toFixed(2)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
indexMethod (index) {
|
||||
return index + 1
|
||||
},
|
||||
esc () {
|
||||
this.$emit('close')
|
||||
},
|
||||
filter (row) {
|
||||
this.$emit('filter', row.name, this.itemData)
|
||||
},
|
||||
valueHandle (value, columnName) {
|
||||
if (columnName === 'app_risk') {
|
||||
const m = riskLevelMapping.find(mapping => {
|
||||
return mapping.value === value
|
||||
})
|
||||
return (m && m.name) || value
|
||||
}
|
||||
return value
|
||||
},
|
||||
tableHeaderCellStyle ({ row, column, rowIndex, columnIndex }) {
|
||||
if (rowIndex === 0) {
|
||||
return 'padding-bottom:5px;padding-top:14px;'
|
||||
}
|
||||
},
|
||||
tableHeaderRowStyle ({ row, rowIndex }) {
|
||||
if (rowIndex === 0) {
|
||||
return 'color: #333333;font-weight: 500;font-size: 14px;'
|
||||
}
|
||||
},
|
||||
rowStyle ({ row, rowIndex }) {
|
||||
return 'height:21px;font-size: 14px;color: #666666;font-weight: 400;'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.entity-pop-custom .el-table::before {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,111 +0,0 @@
|
||||
<template>
|
||||
<div class="entity-left-filter">
|
||||
<div class="filter__header">{{$t('entities.filter')}}</div>
|
||||
<div class="filter__body">
|
||||
<el-collapse v-model="active" class="filter__collapse">
|
||||
<el-collapse-item
|
||||
name="0"
|
||||
>
|
||||
<template #title>
|
||||
<div class="collapse-header"><i :class="topFilterData.icon" class="collapse-header__icon"></i><span>{{topFilterData.title}}</span></div>
|
||||
</template>
|
||||
<el-tree
|
||||
:data="topFilterData.data"
|
||||
:props="{ isLeaf: 'leaf' }"
|
||||
:expand-on-click-node="false"
|
||||
:load="loadLevel2"
|
||||
lazy
|
||||
node-key="name"
|
||||
ref="tree-0"
|
||||
highlight-current
|
||||
@node-click="(data, node, component) => nodeClick(data, node, component, 0)"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<div class="filter-item">
|
||||
<div>{{data.name}}</div>
|
||||
<span>{{data.count}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
<div class="filter__more" :class="{'filter__more--disabled': topFilterData.hasnotMore}" @click="showMore(topFilterData)">{{$t('overall.showMore')}}</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item
|
||||
name="1"
|
||||
>
|
||||
<template #title>
|
||||
<div class="collapse-header"><i :class="bottomFilterData.icon" class="collapse-header__icon"></i><span>{{bottomFilterData.title}}</span></div>
|
||||
</template>
|
||||
<el-tree
|
||||
:data="bottomFilterData.data"
|
||||
:props="{ isLeaf: 'leaf' }"
|
||||
:expand-on-click-node="false"
|
||||
node-key="name"
|
||||
ref="tree-1"
|
||||
highlight-current
|
||||
@node-click="(data, node, component) => nodeClick(data, node, component, 1)"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<div class="filter-item">
|
||||
<div>{{data.name}}</div>
|
||||
<span>{{data.count}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
<div class="filter__more" :class="{'filter__more--disabled': bottomFilterData.hasnotMore}" @click="showMore(bottomFilterData)">{{$t('overall.showMore')}}</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'LeftFilter',
|
||||
props: {
|
||||
topFilterData: Object,
|
||||
bottomFilterData: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
active: ['0', '1'],
|
||||
currentDataTop: null,
|
||||
currentDataBottom: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadLevel2 (node, resolve) {
|
||||
resolve(await this.$parent.loadLevel2FilterData(node, this.topFilterData.column))
|
||||
},
|
||||
nodeClick (data, node, component, index) {
|
||||
const currentData = index === 0 ? this.currentDataTop : this.currentDataBottom
|
||||
const column = index === 0 ? this.topFilterData.column : this.bottomFilterData.column
|
||||
if (this.dataEqual(currentData, data)) {
|
||||
node.isCurrent = false
|
||||
}
|
||||
if (index === 0) {
|
||||
this.currentDataTop = this.$_.cloneDeep(data)
|
||||
} else {
|
||||
this.currentDataBottom = this.$_.cloneDeep(data)
|
||||
}
|
||||
this.$emit('select', data, node, index, column)
|
||||
},
|
||||
showMore (filterData) {
|
||||
if (!filterData.hasnotMore) {
|
||||
this.$emit('showMore', filterData.column)
|
||||
}
|
||||
},
|
||||
dataEqual (obj1, obj2) {
|
||||
if (!obj1 || !obj2) {
|
||||
return false
|
||||
}
|
||||
let equal = true
|
||||
this.$_.forIn(obj1, (value, key) => {
|
||||
if (value !== obj2[key]) {
|
||||
equal = false
|
||||
}
|
||||
})
|
||||
return equal
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user