CN-1592 fix: tag下拉增加时间选择框、修复不能删除的bug

This commit is contained in:
chenjinsong
2024-04-15 22:25:39 +08:00
parent 3faea70349
commit 397b254ec5
8 changed files with 153 additions and 113 deletions

View File

@@ -22,5 +22,8 @@ const DEFAULT_TIME_FILTER_RANGE = {
behaviorPattern: 60 * 24 * 7 // 实体详情--IP--行为模式 behaviorPattern: 60 * 24 * 7 // 实体详情--IP--行为模式
}, },
detection: 60, // 事件日志列表 detection: 60, // 事件日志列表
tag:60//标签列表 tag: { // 标签列表
activeEntity: 60, // 标签table下拉--活跃实体
totalEntity: 7 * 24 * 60 // 标签table下拉--全部实体
}
} }

View File

@@ -1,5 +1,6 @@
@use 'element-plus/theme-chalk/src/select.scss' as *; @use 'element-plus/theme-chalk/src/select.scss' as *;
.date-range-box { .date-range-box {
position: relative;
font-size: 14px; font-size: 14px;
border-radius: var(--el-border-radius-base); border-radius: var(--el-border-radius-base);
display: flex; display: flex;

View File

@@ -14,6 +14,8 @@
height: calc(100% - 62px) !important; height: calc(100% - 62px) !important;
.el-table__expanded-cell { .el-table__expanded-cell {
z-index: 2;
.down { .down {
margin-left: 32px; margin-left: 32px;
height: 100%; height: 100%;
@@ -47,25 +49,16 @@
} }
.block.drop-down-time { .block.drop-down-time {
margin: 15px 0 14px 0; margin: 15px 0 14px 0;
display: flex;
.el-date-editor { position: relative;
justify-content: center;
.el-range-separator {
width: 24px;
}
.el-input__icon.el-range__close-icon {
display: none;
}
}
.tag-dropdown{ .tag-dropdown{
align-items: center; align-items: center;
width: 100%;
height: 24px; height: 24px;
justify-content: center; justify-content: center;
line-height: 24px; line-height: 24px;
padding: 0 6px; padding: 0 6px;
margin-right: 20px;
span { span {
margin-right: 6px; margin-right: 6px;
@@ -83,6 +76,24 @@
font-size: 12px; font-size: 12px;
} }
} }
.expand-observed-entities {
font-size: 12px;
color: var(--el-color-primary);
cursor: pointer;
line-height: 24px;
&.expand-observed-entities--disabled {
color: var(--el-text-color-regular);
cursor: default;
}
i {
top: 1px;
}
}
.date-range-box {
position: absolute;
right: 20px;
}
} }
.expand { .expand {
min-height: 150px; min-height: 150px;
@@ -104,7 +115,7 @@
.expand-left { .expand-left {
//background: #F9F9F9; //background: #F9F9F9;
//border-radius: 2px; //border-radius: 2px;
width:calc(100% - 200px); width: 100%;
height: 150px; height: 150px;
position: relative; position: relative;
.chart-drawing { .chart-drawing {
@@ -130,20 +141,6 @@
padding: 2px 3px 0 0; padding: 2px 3px 0 0;
} }
} }
.expand-observed-entities {
font-size: 12px;
color: var(--el-color-primary);
margin-bottom: 4px;
cursor: pointer;
&.expand-observed-entities--disabled {
color: var(--el-text-color-regular);
cursor: default;
}
i {
top: 1px;
}
}
.expand-icon { .expand-icon {
display: flex; display: flex;
justify-content: space-evenly; justify-content: space-evenly;

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-ele-click-outside="changeDropdown" style="position: relative;" class="date-range-box"> <div v-ele-click-outside="changeDropdown" class="date-range-box">
<div @click="showDropdown" tabindex="1" class="date-range-text" :class="myClass" :style="style"> <div @click="showDropdown" tabindex="1" class="date-range-text" :class="myClass" :style="style">
<div class="calendar-popover-text"><i class="cn-icon cn-icon-Data"></i></div> <div class="calendar-popover-text"><i class="cn-icon cn-icon-Data"></i></div>
<div class="calendar-popover-text" style="display: flex" v-if="isCustom" :title="`${dateFormatByAppearance(getMillisecond(startTime))} -${dateFormatByAppearance(getMillisecond(endTime))}`"> <div class="calendar-popover-text" style="display: flex" v-if="isCustom" :title="`${dateFormatByAppearance(getMillisecond(startTime))} -${dateFormatByAppearance(getMillisecond(endTime))}`">
@@ -219,6 +219,9 @@ export default {
returnValue() returnValue()
} }
}) })
watch(() => props.startTime, (newVal) => {
console.info(newVal)
})
/** /**
* 监测下拉框,一旦隐藏,则设置其位置靠最左边 * 监测下拉框,一旦隐藏,则设置其位置靠最左边

View File

@@ -17,7 +17,7 @@
<el-table-column type="expand" width="30"> <el-table-column type="expand" width="30">
<template #default="props"> <template #default="props">
<div class="down"> <div class="down">
<div class="block drop-down-time" style="border:0px yellow solid;"> <div class="block drop-down-time">
<el-popover placement="bottom-start" <el-popover placement="bottom-start"
:ref="`tagPopover${props.row.id}`" :ref="`tagPopover${props.row.id}`"
:key="`tagPopover${props.row.id}`" :key="`tagPopover${props.row.id}`"
@@ -43,6 +43,15 @@
</ul> </ul>
</el-row> </el-row>
</el-popover> </el-popover>
<span class="expand-observed-entities" :class="{'expand-observed-entities--disabled': disableToEntity}" @click="toEntityList(props.row)">{{countDesc}}&nbsp;<el-icon v-if="!disableToEntity"><Right /></el-icon></span>
<date-time-range
class="date-time-range"
:start-time="timeFilter.startTime"
:end-time="timeFilter.endTime"
:date-range="timeFilter.dateRangeValue"
ref="dateTimeRange"
@change="reload"
/>
</div> </div>
<div class="expand"> <div class="expand">
<loading :loading="loadingDown"></loading> <loading :loading="loadingDown"></loading>
@@ -51,12 +60,6 @@
<div class="expand-left"> <div class="expand-left">
<div class="chart-drawing" :id="`chart${props.row.id}`"></div> <div class="chart-drawing" :id="`chart${props.row.id}`"></div>
</div> </div>
<div class="expand-right">
<div class="expand-count">{{observedCount}}</div>
<div class="expand-observed-entities" :class="{'expand-observed-entities--disabled': disableToEntity}" @click="toEntityList(props.row)">
Observed IPs&nbsp;<el-icon v-if="!disableToEntity"><Right /></el-icon>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -146,28 +149,28 @@ export default {
label: this.$t('overall.name'), label: this.$t('overall.name'),
prop: 'name', prop: 'name',
show: true, show: true,
minWidth: 50, width: 300,
sortable: 'custom' sortable: 'custom'
}, { }, {
label: this.$t('tag.category'), label: this.$t('tag.category'),
prop: 'category', prop: 'category',
show: true, show: true,
minWidth: 50 width: 100
}, { }, {
label: this.$t('tag.entityType'), label: this.$t('tag.entityType'),
prop: 'indicatorType', prop: 'indicatorType',
show: true, show: true,
minWidth: 50 width: 120
}, { }, {
label: this.$t('tag.intention'), label: this.$t('tag.intention'),
prop: 'intent', prop: 'intent',
show: true, show: true,
minWidth: 30 width: 100
}, { }, {
label: this.$t('tag.source'), label: this.$t('tag.source'),
prop: 'isBuiltIn', prop: 'isBuiltIn',
show: true, show: true,
minWidth: 30 width: 120
}, { }, {
label: this.$t('overall.remark'), label: this.$t('overall.remark'),
prop: 'description', prop: 'description',
@@ -192,7 +195,9 @@ export default {
selectIds: [], // 单行选中的id列表 selectIds: [], // 单行选中的id列表
initExpandFlag: false, // 初始化时单行展开标志false是未展开true展开, initExpandFlag: false, // 初始化时单行展开标志false是未展开true展开,
myChartArray: [], myChartArray: [],
observedCount: 0, observedIpCount: 0,
observedDomainCount: 0,
countDesc: '', // tag下拉中实体数量描述信息
disableToEntity: false, disableToEntity: false,
tagIntent tagIntent
} }
@@ -201,10 +206,31 @@ export default {
* 添加vue3的setup目的是添加/获取地址栏的参数 * 添加vue3的setup目的是添加/获取地址栏的参数
*/ */
setup () { setup () {
const { startTime, endTime } = getNowTime(60 * 24 * 30)
const timeRange = ref([startTime, endTime])
const { query } = useRoute() const { query } = useRoute()
/*// 获取url携带的range、startTime、endTime
const rangeParam = query.range
const startTimeParam = query.startTime
const endTimeParam = query.endTime
const dateRangeValue = rangeParam ? parseInt(rangeParam) : (DEFAULT_TIME_FILTER_RANGE.tag.activeEntity || 60)
const timeFilter = ref({ dateRangeValue })
if (!startTimeParam || !endTimeParam) {
const { startTime, endTime } = getNowTime(dateRangeValue)
timeFilter.value.startTime = getSecond(startTime)
timeFilter.value.endTime = getSecond(endTime)
// 如果没有时间参数就将参数写入url
const newUrl = urlParamsHandler(window.location.href, useRoute().query, { startTime: timeFilter.value.startTime, endTime: timeFilter.value.endTime, range: dateRangeValue })
overwriteUrl(newUrl)
} else {
timeFilter.value.startTime = parseInt(startTimeParam)
timeFilter.value.endTime = parseInt(endTimeParam)
}*/
const dateRangeValue = DEFAULT_TIME_FILTER_RANGE.tag.activeEntity || 60
const timeFilter = ref({ dateRangeValue })
const { startTime, endTime } = getNowTime(dateRangeValue)
timeFilter.value.startTime = getSecond(startTime)
timeFilter.value.endTime = getSecond(endTime)
// 展开行的id列表只展开一行 // 展开行的id列表只展开一行
const expandedId = [] const expandedId = []
@@ -232,7 +258,7 @@ export default {
const pageObj = ref(tempPageObj) const pageObj = ref(tempPageObj)
const myChart = shallowRef(null) const myChart = shallowRef(null)
return { return {
timeRange, timeFilter,
expandedIds, expandedIds,
pageObj, pageObj,
myChart myChart
@@ -257,12 +283,6 @@ export default {
} }
this.reloadUrl(expandPage) this.reloadUrl(expandPage)
} }
const dateParam = {
startTime: dateFormatToUTC(this.timeRange[0]),
endTime: dateFormatToUTC(this.timeRange[1])
}
this.reloadUrl(dateParam)
} else { } else {
// 删除地址栏参数,然后删除缓存 // 删除地址栏参数,然后删除缓存
const newQuery = this.$route.query // 深拷贝路由数据 const newQuery = this.$route.query // 深拷贝路由数据
@@ -273,13 +293,15 @@ export default {
this.reloadUrl(newQuery, 'cleanOldParams') this.reloadUrl(newQuery, 'cleanOldParams')
} }
}, },
timeRange (newVal, oldVal) { timeFilter (n) {
if (newVal) { const id = this.expandedIds[0] || null
const dateParam = { if (id) {
startTime: dateFormatToUTC(newVal[0]), const item = this.tableData.find(item => item.id === id)
endTime: dateFormatToUTC(newVal[1]) if (this.disableToEntity) {
this.init(item, api.tagIndicatorTrend, api.tagIndicatorStatistics)
} else {
this.init(item, api.tagTrafficEntityTrend, api.tagTrafficEntityStatistics)
} }
this.reloadUrl(dateParam)
} }
} }
}, },
@@ -297,6 +319,9 @@ export default {
const t = vm.tagIntent.find(t => t.value === intent) const t = vm.tagIntent.find(t => t.value === intent)
return t ? t.name + '-list' : vm.tagIntent[0].name + '-list' return t ? t.name + '-list' : vm.tagIntent[0].name + '-list'
} }
},
observedCount () {
return this.observedIpCount + this.observedDomainCount
} }
}, },
mounted () { mounted () {
@@ -330,8 +355,9 @@ export default {
this.myChart = echarts.init(dom) this.myChart = echarts.init(dom)
// } // }
this.chartOption = tagLineChartOption this.chartOption = tagLineChartOption
this.chartOption.series = [ const series = []
{ if (item.indicatorType && item.indicatorType.indexOf('IP') > -1) {
series.push({
type: 'line', type: 'line',
symbol: 'circle', symbol: 'circle',
smooth: true, smooth: true,
@@ -355,8 +381,10 @@ export default {
color: '#35ADDA' color: '#35ADDA'
}, },
data: data.map(t => { return [Number(t.statTime) * 1000, Number(t.ipIndicatorCount)] }) data: data.map(t => { return [Number(t.statTime) * 1000, Number(t.ipIndicatorCount)] })
}, })
{ }
if (item.indicatorType && item.indicatorType.indexOf('Domain') > -1) {
series.push({
type: 'line', type: 'line',
symbol: 'circle', symbol: 'circle',
smooth: true, smooth: true,
@@ -366,7 +394,7 @@ export default {
borderWidth: 2 borderWidth: 2
} }
}, },
name: 'Domain Name', name: this.$t('overall.domain'),
stack: 'Total', stack: 'Total',
lineStyle: { lineStyle: {
color: '#E48F3E', color: '#E48F3E',
@@ -380,8 +408,9 @@ export default {
color: '#E48F3E' color: '#E48F3E'
}, },
data: data.map(t => { return [Number(t.statTime) * 1000, Number(t.domainIndicatorCount)] }) data: data.map(t => { return [Number(t.statTime) * 1000, Number(t.domainIndicatorCount)] })
} })
] }
this.chartOption.series = series
this.chartOption.yAxis[0].axisLabel.formatter = (value) => { this.chartOption.yAxis[0].axisLabel.formatter = (value) => {
return unitConvert(value, 'number').join('') return unitConvert(value, 'number').join('')
@@ -398,6 +427,27 @@ export default {
t.resize() t.resize()
}) })
}, },
handleCountDesc () {
let desc = this.observedCount
// 全部实体
if (this.disableToEntity) {
if (this.observedCount < 2) {
desc += ` ${this.$t('tag.activeEntity2')}`
} else {
desc += ` ${this.$t('tag.activeEntities2')}`
}
} else { // 活跃实体
if (this.observedCount < 2) {
desc += ` ${this.$t('overall.entity2')}`
} else {
desc += ` ${this.$t('overall.entities2')}`
}
}
if (this.observedCount > 0) {
desc += `, IP ${this.observedIpCount}, ${this.$t('overall.domain')} ${this.observedDomainCount}`
}
return desc
},
uniqueEntityObserved (item) { uniqueEntityObserved (item) {
this.curExpendDataType = this.$t('tag.uniqueEntityObserved') this.curExpendDataType = this.$t('tag.uniqueEntityObserved')
this.curExpendDataTypeVal = 'uniqueEntityObserved' this.curExpendDataTypeVal = 'uniqueEntityObserved'
@@ -409,7 +459,10 @@ export default {
totalIndicatorsDom.style.cssText = '' totalIndicatorsDom.style.cssText = ''
document.getElementById('tagDropdown' + item.id).click() document.getElementById('tagDropdown' + item.id).click()
}) })
this.init(item, api.tagTrafficEntityTrend, api.tagTrafficEntityStatistics) // 重置时间条件
this.$refs.dateTimeRange.quickChange(DEFAULT_TIME_FILTER_RANGE.tag.activeEntity || 60)
// this.init(item, api.tagTrafficEntityTrend, api.tagTrafficEntityStatistics)
}, },
totalIndicators (item) { totalIndicators (item) {
this.curExpendDataType = this.$t('tag.totalIndicators') this.curExpendDataType = this.$t('tag.totalIndicators')
@@ -422,7 +475,12 @@ export default {
totalIndicatorsDom.style.cssText = 'color:var(--el-color-primary);font-weight: bold;' totalIndicatorsDom.style.cssText = 'color:var(--el-color-primary);font-weight: bold;'
document.getElementById('tagDropdown' + item.id).click() document.getElementById('tagDropdown' + item.id).click()
}) })
this.init(item, api.tagIndicatorTrend, api.tagIndicatorStatistics) // 重置时间条件
const dateRangeValue = DEFAULT_TIME_FILTER_RANGE.tag.totalEntity || 7 * 24 * 60
const { startTime, endTime } = getNowTime(dateRangeValue)
this.$refs.dateTimeRange.timeArrChange([startTime, endTime])
// this.init(item, api.tagIndicatorTrend, api.tagIndicatorStatistics)
}, },
/** /**
* 进入页面判断是否需要展开表格 * 进入页面判断是否需要展开表格
@@ -531,12 +589,23 @@ export default {
} }
overwriteUrl(newUrl) overwriteUrl(newUrl)
}, },
reload (startTime, endTime, dateRangeValue) {
this.timeFilter = { startTime: getSecond(startTime), endTime: getSecond(endTime), dateRangeValue: dateRangeValue }
const { query } = this.$route
this.$store.commit('setTimeRangeArray', [this.timeFilter.startTime, this.timeFilter.endTime])
this.$store.commit('setTimeRangeFlag', dateRangeValue.value)
const newUrl = urlParamsHandler(window.location.href, query, {
startTime: this.timeFilter.startTime,
endTime: this.timeFilter.endTime,
range: dateRangeValue.value
})
overwriteUrl(newUrl)
},
initLine (item, lineUrl) { initLine (item, lineUrl) {
const dateRangeValue = DEFAULT_TIME_FILTER_RANGE.dashboard || 60
const { startTime, endTime } = getNowTime(dateRangeValue)
const params = { const params = {
startTime: getSecond(startTime), startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(endTime) endTime: getSecond(this.timeFilter.endTime)
} }
lineUrl = lineUrl || api.tagTrafficEntityTrend lineUrl = lineUrl || api.tagTrafficEntityTrend
lineUrl = lineUrl.replace('{{name}}', item.name) lineUrl = lineUrl.replace('{{name}}', item.name)
@@ -562,22 +631,16 @@ export default {
}) })
}, },
initStatistics (item, statisticsUrl) { initStatistics (item, statisticsUrl) {
const dateRangeValue = DEFAULT_TIME_FILTER_RANGE.dashboard || 60
const { startTime, endTime } = getNowTime(dateRangeValue)
const params = {
startTime: getSecond(startTime),
endTime: getSecond(endTime)
}
statisticsUrl = statisticsUrl || api.tagTrafficEntityStatistics statisticsUrl = statisticsUrl || api.tagTrafficEntityStatistics
statisticsUrl = statisticsUrl.replace('{{name}}', item.name) statisticsUrl = statisticsUrl.replace('{{name}}', item.name)
let observedCount = 0 axios.get(statisticsUrl, { params: { startTime: 1, endTime: 9999999999 } }).then(response => { // TODO 计数统计暂时不限制时间
axios.get(statisticsUrl, { params: params }).then(response => {
const res = response.data const res = response.data
if (response.status === 200) { if (response.status === 200) {
res.data.result.forEach(item => { const ipFind = res.data.result.find(item => item.type === 'IP')
observedCount = observedCount + item.count this.observedIpCount = ipFind ? ipFind.count : 0
}) const domainFind = res.data.result.find(item => item.type === 'Domain')
this.observedCount = observedCount this.observedDomainCount = domainFind ? domainFind.count : 0
this.countDesc = this.handleCountDesc()
} else { } else {
this.errorMsg = this.errorMsgHandler(res) this.errorMsg = this.errorMsgHandler(res)
} }

View File

@@ -808,8 +808,7 @@ export const tagLineChartOption = {
x: 'center', x: 'center',
y: 'bottom', y: 'bottom',
icon: 'circle', icon: 'circle',
itemGap: 50, itemGap: 50
data: ['IP', 'Domain Name']
}, },
grid: { grid: {
top: '12%', top: '12%',

View File

@@ -191,7 +191,7 @@ export default {
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
this.toggleLoading(true) this.toggleLoading(true)
axios.delete(api.tag + ids).then(response => { axios.delete(api.tag + '?id=' + ids).then(response => {
if (response.status === 200) { if (response.status === 200) {
this.delFlag = true this.delFlag = true
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') }) this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') })

View File

@@ -229,20 +229,6 @@
</transition> </transition>
</template> </template>
</el-collapse-item> </el-collapse-item>
<el-collapse-item name="3" class="enable-form__mt">
<template #title>
<div class="form-sub-title">{{ $t('tag.enable') }}</div>
</template>
<el-switch class="card-enable"
v-model="editObject.status"
active-color="#38ACD2"
inactive-color="#C0CEDB"
:active-value="1"
:inactive-value="0"
>
</el-switch>
</el-collapse-item>
</el-collapse> </el-collapse>
</div> </div>
<div class="edit-tag__footer"> <div class="edit-tag__footer">
@@ -1451,7 +1437,7 @@ export default {
third: itemListHeight.noData third: itemListHeight.noData
} }
const stepHeights = ref([stepHeightConstant.first, stepHeightConstant.second, stepHeightConstant.third, stepHeightConstant.collapse]) const stepHeights = ref([stepHeightConstant.first, stepHeightConstant.second, stepHeightConstant.third])
// 没上传过文件的提示 // 没上传过文件的提示
const uploadErrorTip = ref('') const uploadErrorTip = ref('')
@@ -1512,18 +1498,6 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
.el-overlay-message-box, .el-message-box {
padding: 0 !important;
}
.el-overlay-message-box {
text-align: center !important;
}
.is-message-box .el-overlay-message-box {
display: flex;
justify-content: center;
align-items: center;
}
.del-model { .del-model {
&.el-message-box { &.el-message-box {
max-width: 480px !important; max-width: 480px !important;