Compare commits

...

21 Commits

Author SHA1 Message Date
chenjinsong
82035a20f5 fix: 调整link测试用例 2024-01-02 19:57:49 +08:00
chenjinsong
a121857093 fix: 适配演示,修改链路网格图逻辑 2023-11-01 18:00:28 +08:00
chenjinsong
0152c46d05 fix: 修复知识库更新记录的时间丢失时区的问题 2023-10-31 19:39:54 +08:00
chenjinsong
64f376e22a CN-1445 fix: 修复切换不同知识库的更新页面后,psiphon3的柱状图不能显示的问题 2023-10-31 18:46:02 +08:00
chenjinsong
5b89fca77c CN-1404 fix: 去掉其他知识库的update按钮 2023-10-31 18:05:36 +08:00
陈劲松
d1f5997b88 Merge branch 'cherry-pick-f151415d' into 'dev-23.10'
fix: detection--policy的trigger去除秒时间选项

See merge request cyber-narrator/cn-ui!54
2023-10-31 09:25:41 +00:00
刘洪洪
88002a8fc4 fix: detection--policy的trigger去除秒时间选项
(cherry picked from commit f151415de6)
2023-10-31 09:25:33 +00:00
陈劲松
556a9b03b4 Merge branch 'cherry-pick-bd1f7556' into 'dev-23.10'
CN-1425 fix: 修复dashboard下钻后切换顶部最后一级面包屑时会回到下钻前页面的问题

See merge request cyber-narrator/cn-ui!53
2023-10-30 08:38:35 +00:00
chenjinsong
ca5c81d8be CN-1425 fix: 修复dashboard下钻后切换顶部最后一级面包屑时会回到下钻前页面的问题
(cherry picked from commit bd1f755612)
2023-10-30 08:38:28 +00:00
陈劲松
02779c26d1 Merge branch 'cherry-pick-dd4f5e1f' into 'dev-23.10'
fix: eventType取消国际化转换

See merge request cyber-narrator/cn-ui!52
2023-10-30 08:37:51 +00:00
刘洪洪
20692705e9 fix: eventType取消国际化转换
(cherry picked from commit dd4f5e1fba)
2023-10-30 08:37:42 +00:00
陈劲松
bc3bc7eaf3 Merge branch 'cherry-pick-ed1d994d' into 'dev-23.10'
fix: eventType取消国际化转换

See merge request cyber-narrator/cn-ui!51
2023-10-30 08:37:21 +00:00
刘洪洪
d05ae06af6 fix: eventType取消国际化转换
(cherry picked from commit ed1d994d5e)
2023-10-30 08:37:15 +00:00
陈劲松
ca3d8766ba Merge branch 'cherry-pick-815af776' into 'dev-23.10'
fix: 修复policy新建时点击save按钮不生效的问题

See merge request cyber-narrator/cn-ui!50
2023-10-30 08:35:12 +00:00
刘洪洪
00e73adadb fix: 修复policy新建时点击save按钮不生效的问题
(cherry picked from commit 815af776aa)
2023-10-30 08:35:01 +00:00
陈劲松
4ede5768e4 Merge branch 'cherry-pick-a4da1dbf' into 'dev-23.10'
fix: 去掉部分控制台打印

See merge request cyber-narrator/cn-ui!49
2023-10-30 08:34:06 +00:00
chenjinsong
541692f50f fix: 去掉部分控制台打印
(cherry picked from commit a4da1dbfac)
2023-10-30 08:33:59 +00:00
陈劲松
89294c98e1 Merge branch 'cherry-pick-7b8ca904' into 'dev-23.10'
fix: 修复policy新建时form的时间提示被盖住,以及限制输入框内容长度的问题

See merge request cyber-narrator/cn-ui!48
2023-10-30 08:33:22 +00:00
刘洪洪
8fd283c1e7 fix: 修复policy新建时form的时间提示被盖住,以及限制输入框内容长度的问题
(cherry picked from commit 7b8ca90436)
2023-10-30 08:33:16 +00:00
陈劲松
90b90fdd3c Merge branch 'cherry-pick-90827fd7' into 'dev-23.10'
fix: policy新建时添加小时不得超过24等时间限制

See merge request cyber-narrator/cn-ui!47
2023-10-30 07:19:38 +00:00
刘洪洪
72ee214877 fix: policy新建时添加小时不得超过24等时间限制
(cherry picked from commit 90827fd706)
2023-10-30 07:19:27 +00:00
16 changed files with 392 additions and 113 deletions

View File

@@ -101,6 +101,12 @@
justify-content: flex-start; justify-content: flex-start;
height: 24px; height: 24px;
line-height: 24px; line-height: 24px;
.policy-form-item {
.el-form-item__error {
width: 260px;
}
}
} }
.el-input--mini .el-input__inner { .el-input--mini .el-input__inner {

View File

@@ -1905,6 +1905,9 @@
&.update-dialog__table--psiphon3 { &.update-dialog__table--psiphon3 {
height: calc(90vh - 190px - 200px - 50px - 10px); height: calc(90vh - 190px - 200px - 50px - 10px);
} }
&.update-dialog__table--system-user {
height: calc(100% - 139px);
}
} }
.update-knowledge-form { .update-knowledge-form {
.el-upload { .el-upload {

View File

@@ -791,10 +791,10 @@ export default {
}) })
return return
} }
/* if (route === this.route) { if (route === this.route) {
this.refresh() this.refresh()
return return
} */ }
if (route) { if (route) {
this.$router.push({ this.$router.push({
path: route, path: route,

View File

@@ -59,7 +59,7 @@
<el-option <el-option
v-for="item in eventTypeList" v-for="item in eventTypeList"
:key="item.value" :key="item.value"
:label="$t(item.label)" :label="item.label"
:value="item.value" :value="item.value"
/> />
</el-select> </el-select>

View File

@@ -66,7 +66,9 @@
<div class="center-dialog"> <div class="center-dialog">
<el-dialog v-model="showUpdateDialog" <el-dialog v-model="showUpdateDialog"
:destroy-on-close="true"
:custom-class="showAddUpdateDialog ? 'update-knowledge update-knowledge--upload' : 'update-knowledge'" :custom-class="showAddUpdateDialog ? 'update-knowledge update-knowledge--upload' : 'update-knowledge'"
:before-close="beforeClose"
:after-close="handleClose"> :after-close="handleClose">
<div class="knowledge-update__top" > <div class="knowledge-update__top" >
<div class="update-left__icon"> <div class="update-left__icon">
@@ -83,6 +85,7 @@
:active-value="1" :active-value="1"
:inactive-value="0" :inactive-value="0"
:before-change="(knowledgeId) => confirmSwitchLearning(updateKnowledge.knowledgeId)" :before-change="(knowledgeId) => confirmSwitchLearning(updateKnowledge.knowledgeId)"
v-if="updateKnowledge.source === 'cn_psiphon3_ip'"
> >
</el-switch> </el-switch>
</div> </div>
@@ -126,7 +129,7 @@
</button> </button>
</div> </div>
</div> </div>
<div :style="{height: updateKnowledge.source === 'cn_psiphon3_ip' ? 'calc(90vh - 190px - 200px - 50px - 42px)' : 'calc(100% - 242px)', marginTop: '42px', position: 'absolute', width: 'calc(100% - 60px)'}"> <div :style="{height: updateKnowledge.source === 'cn_psiphon3_ip' && activeTab === 'intelligenceLearning' ? 'calc(90vh - 190px - 200px - 50px - 42px)' : 'calc(100% - 242px)', marginTop: '42px', position: 'absolute', width: 'calc(100% - 60px)'}">
<loading :loading="updateLogLoading"></loading> <loading :loading="updateLogLoading"></loading>
</div> </div>
<el-table ref="updateDataTable" <el-table ref="updateDataTable"
@@ -134,11 +137,19 @@
:data="updateHistoryList" :data="updateHistoryList"
@selection-change="secondSelectionChange" @selection-change="secondSelectionChange"
width="100%" width="100%"
:class="updateKnowledge.source === 'cn_psiphon3_ip' ? 'update-dialog__table update-dialog__table--psiphon3' : 'update-dialog__table'" class="update-dialog__table"
:class="{
'update-dialog__table--psiphon3': updateKnowledge.source === 'cn_psiphon3_ip' && activeTab === 'intelligenceLearning',
'update-dialog__table--system-user': updateKnowledge.source === 'cn_psiphon3_ip' && activeTab !== 'intelligenceLearning'
}"
:header-cell-style="{background:'#f5f7fa',color:'#353636',fontWeight: '400',fontSize: '12px',borderRight: 'none',borderBottom: 'none'}" :header-cell-style="{background:'#f5f7fa',color:'#353636',fontWeight: '400',fontSize: '12px',borderRight: 'none',borderBottom: 'none'}"
cell-style="padding:6px 0px;font-size: 12px;color: #353636;font-weight: 400;line-height: 20px;border-right:none;" cell-style="padding:6px 0px;font-size: 12px;color: #353636;font-weight: 400;line-height: 20px;border-right:none;"
header-cell-style="padding:8px 0px;font-size: 12px;color: #353636;font-weight: 500;border-right:none;"> header-cell-style="padding:8px 0px;font-size: 12px;color: #353636;font-weight: 500;border-right:none;">
<el-table-column prop="opTime" :label="$t('entities.tab.informationAggregation.updateTime')" width="150" ></el-table-column> <el-table-column prop="opTime" :label="$t('entities.tab.informationAggregation.updateTime')" width="150" >
<template #default="scope" :column="item">
<span>{{scope.row.opTime ? dateFormatByAppearance(scope.row.opTime) : '-'}}</span>
</template>
</el-table-column>
<el-table-column prop="user" :label="$t('knowledgeBase.operator')" width="150" v-if="activeTab === 'updateRecord'"> <el-table-column prop="user" :label="$t('knowledgeBase.operator')" width="150" v-if="activeTab === 'updateRecord'">
<template #default="scope" :column="item"> <template #default="scope" :column="item">
<span>{{$_.get(scope.row, 'user.name', '-')}}</span> <span>{{$_.get(scope.row, 'user.name', '-')}}</span>
@@ -154,7 +165,7 @@
</template> </template>
</el-table> </el-table>
<div class="psiphon3" v-if="updateKnowledge.source === 'cn_psiphon3_ip'"> <div class="psiphon3" v-if="updateKnowledge.source === 'cn_psiphon3_ip' && activeTab === 'intelligenceLearning'">
<div class="psiphon3-title">{{$t('knowledgeBase.psiphon3IpCount')}}</div> <div class="psiphon3-title">{{$t('knowledgeBase.psiphon3IpCount')}}</div>
<div class="psiphon3-bar"> <div class="psiphon3-bar">
<chart-error v-if="showErrorForPsiphon3" :content="errorMsgForPsiphon3"/> <chart-error v-if="showErrorForPsiphon3" :content="errorMsgForPsiphon3"/>
@@ -525,7 +536,9 @@ export default {
timeChange () { timeChange () {
this.timeFilter.endTime = window.$dayJs.tz().valueOf() this.timeFilter.endTime = window.$dayJs.tz().valueOf()
this.timeFilter.startTime = this.timeFilter.endTime - this.selectTime * 60 * 1000 this.timeFilter.startTime = this.timeFilter.endTime - this.selectTime * 60 * 1000
this.init() if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
this.init()
}
this.$nextTick(() => { this.$nextTick(() => {
this.handleActiveBar() this.handleActiveBar()
}) })
@@ -535,7 +548,9 @@ export default {
this.tabType = item.class this.tabType = item.class
} }
this.legendSelectChange(item) this.legendSelectChange(item)
this.init() if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
this.init()
}
}, },
mouseenterTab (item) { mouseenterTab (item) {
if (this.isNoDataForPsiphon3) return if (this.isNoDataForPsiphon3) return
@@ -577,7 +592,9 @@ export default {
this.$message.success(this.$t('tip.success')) this.$message.success(this.$t('tip.success'))
this.showAddUpdateDialog = false this.showAddUpdateDialog = false
this.getCurTabData() this.getCurTabData()
this.init() if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
this.init()
}
/* } else { /* } else {
this.$message.error(this.$t('tip.uploadFailed', { msg: response.message })) this.$message.error(this.$t('tip.uploadFailed', { msg: response.message }))
} */ } */
@@ -612,6 +629,13 @@ export default {
data.isSelected = val data.isSelected = val
this.$emit('checkboxStatusChange', val, data) this.$emit('checkboxStatusChange', val, data)
}, },
beforeClose (done) {
if (this.myChart) {
this.myChart.dispose()
this.myChart = null
}
done()
},
handleClose () { handleClose () {
this.showUpdateDialog = false this.showUpdateDialog = false
this.showAddUpdateDialog = false this.showAddUpdateDialog = false
@@ -631,7 +655,9 @@ export default {
this.updateKnowledge = data this.updateKnowledge = data
this.showEnable = showEnable this.showEnable = showEnable
await this.getCurTabData() await this.getCurTabData()
await this.init() if (data.source === 'cn_psiphon3_ip') {
await this.init()
}
this.showUpdate() this.showUpdate()
this.$nextTick(() => { this.$nextTick(() => {
this.handleActiveBar() this.handleActiveBar()
@@ -676,6 +702,9 @@ export default {
// 切换tab // 切换tab
handleClick (tab) { handleClick (tab) {
this.getCurTabData() this.getCurTabData()
if (tab.index === '1') {
this.init()
}
}, },
clearSelect () { clearSelect () {
this.$nextTick(() => { this.$nextTick(() => {
@@ -742,7 +771,9 @@ export default {
}, },
timeFilter: { timeFilter: {
handler () { handler () {
this.init() if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
this.init()
}
this.$nextTick(() => { this.$nextTick(() => {
this.handleActiveBar() this.handleActiveBar()
}) })
@@ -750,7 +781,6 @@ export default {
}, },
tableData: { tableData: {
handler (n) { handler (n) {
console.info(n)
if (this.tableData && this.tableData.length > 0) { if (this.tableData && this.tableData.length > 0) {
this.aiTaggingList = [] this.aiTaggingList = []
this.websketchList = [] this.websketchList = []
@@ -772,6 +802,14 @@ export default {
} }
} }
}, },
activeTab (n) {
if (n === 'updateRecord') {
if (this.myChart) {
this.myChart.dispose()
this.myChart = null
}
}
},
showAddUpdateDialog: { showAddUpdateDialog: {
handler (n) { handler (n) {
if (!n) { if (!n) {
@@ -780,8 +818,10 @@ export default {
this.init() this.init()
} }
} else { } else {
this.myChart && this.myChart.dispose() if (this.myChart) {
this.myChart = null this.myChart.dispose()
this.myChart = null
}
} }
} }
} }

File diff suppressed because one or more lines are too long

View File

@@ -13,11 +13,17 @@ export function getMillisecond (time) {
ms = window.$dayJs.tz(new Date(time)).valueOf() ms = window.$dayJs.tz(new Date(time)).valueOf()
} else if (_.isNumber(time)) { } else if (_.isNumber(time)) {
const timeStr = _.toString(time) const timeStr = _.toString(time)
const difference = timeStr.length - 13 /* const difference = timeStr.length - 13
if (difference >= 0) { if (difference >= 0) {
ms = window.$dayJs.tz(new Date(Number(timeStr.slice(0, 13)))).valueOf() ms = window.$dayJs.tz(new Date(Number(timeStr.slice(0, 13)))).valueOf()
} else { } else {
ms = window.$dayJs.tz(new Date(Math.floor(time * (10 ** (0 - difference))))).valueOf() ms = window.$dayJs.tz(new Date(Math.floor(time * (10 ** (0 - difference))))).valueOf()
} */
// 判断9位和10位数为秒12位和13位为毫秒。其他位数不做处理
if (timeStr.length === 9 || timeStr.length === 10) {
ms = window.$dayJs.tz(new Date(Number(time * 1000))).valueOf()
} else {
ms = window.$dayJs.tz(new Date(Number(time))).valueOf()
} }
} else if (_.isString(time)) { } else if (_.isString(time)) {
try { try {
@@ -121,8 +127,6 @@ export function xAxisTimeFormatter (value) {
':' + ':' +
(date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes()) (date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes())
// 如果是一天的开始 // 如果是一天的开始
console.info(date.getTime(), dayStart.getTime(), hourStart.getTime(), date.getTime() === dayStart.getTime(), date.getTime() === hourStart.getTime())
console.info(getSecond(date.getTime()), getSecond(dayStart.getTime()), getSecond(hourStart.getTime()))
if (getSecond(date.getTime()) === getSecond(dayStart.getTime())) { if (getSecond(date.getTime()) === getSecond(dayStart.getTime())) {
return '{day|' + dateFormat(date, 'YYYY-MM-DD') + '}' return '{day|' + dateFormat(date, 'YYYY-MM-DD') + '}'
} else if (getSecond(date.getTime()) === getSecond(hourStart.getTime())) { } else if (getSecond(date.getTime()) === getSecond(hourStart.getTime())) {

View File

@@ -125,7 +125,6 @@ export default {
const openPort = axios.get(url, { params: params }) const openPort = axios.get(url, { params: params })
// const security = axios.get(`${api.entity.security}/${this.entity.entityType}`, { params: params }) // const security = axios.get(`${api.entity.security}/${this.entity.entityType}`, { params: params })
// const performance = axios.get(`${api.entity.performance}/${this.entityType}`, { params: params }) // const performance = axios.get(`${api.entity.performance}/${this.entityType}`, { params: params })
Promise.all([informationAggregation, openPort]).then(response => { Promise.all([informationAggregation, openPort]).then(response => {
if (response[0].status === 200) { if (response[0].status === 200) {
const list = [] const list = []
@@ -166,6 +165,10 @@ export default {
// } // }
this.initSetTag(entityDetailTabsName.securityEvent, 0) this.initSetTag(entityDetailTabsName.securityEvent, 0)
this.initSetTag(entityDetailTabsName.performanceEvent, 0) this.initSetTag(entityDetailTabsName.performanceEvent, 0)
if (this.entity.entityName === 'hqzc.wssp.hainan.gov.cn' || this.entity.entityName === '218.77.183.150') {
this.initSetTag(entityDetailTabsName.securityEvent, 3)
this.initSetTag(entityDetailTabsName.performanceEvent, 1)
}
}) })
// 域名解析 // 域名解析

View File

@@ -11,7 +11,7 @@
<div class="cn-detection__case entity-detail-performance"> <div class="cn-detection__case entity-detail-performance">
<div class="cn-detection__icon" :style="`background-color: ${eventSeverityColor[item.eventSecurity]}`"></div> <div class="cn-detection__icon" :style="`background-color: ${eventSeverityColor[item.eventSecurity]}`"></div>
<div class="cn-detection__row"> <div class="cn-detection__row">
<div class="cn-detection__header"> <div class="cn-detection__header" style="padding-bottom: 0">
<span <span
:test-id="`severity-color-block${index}`" :test-id="`severity-color-block${index}`"
class="detection-event-severity-color-block" class="detection-event-severity-color-block"
@@ -38,6 +38,11 @@
<span>{{ $t('overall.duration') }}&nbsp;:&nbsp;&nbsp;&nbsp;</span> <span>{{ $t('overall.duration') }}&nbsp;:&nbsp;&nbsp;&nbsp;</span>
<span :test-id="`duration-time${index}`">{{ unitConvert(item.durationMs, 'time', null, null, 0).join(' ') || '-' }}</span> <span :test-id="`duration-time${index}`">{{ unitConvert(item.durationMs, 'time', null, null, 0).join(' ') || '-' }}</span>
</div> </div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-traffic-overview"></i>
<span>{{ $t('entity.detail.anomaly') }}&nbsp;:&nbsp;&nbsp;&nbsp;</span>
<div id="anomalyChart" style="height: 20px; width: 100px;"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -51,15 +56,19 @@
<script> <script>
import { dateFormatByAppearance } from '@/utils/date-util' import { dateFormatByAppearance } from '@/utils/date-util'
import { eventSeverityColor, entityDetailTabsName } from '@/utils/constants' import { eventSeverityColor, entityDetailTabsName, unitTypes } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert' import unitConvert from '@/utils/unit-convert'
import axios from 'axios' import axios from 'axios'
import { api } from '@/utils/api' import { api } from '@/utils/api'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import chartMixin from '@/views/charts2/chart-mixin' import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error' import ChartError from '@/components/common/Error'
import { toUpperCaseByString } from '@/utils/tools' import { reverseSortBy, sortBy, toUpperCaseByString } from '@/utils/tools'
import ChartNoData from '@/views/charts/charts/ChartNoData' import ChartNoData from '@/views/charts/charts/ChartNoData'
import { markRaw } from 'vue'
import { metricOption } from '@/views/detections/options/detectionOptions'
import * as echarts from 'echarts'
import _ from 'lodash'
export default { export default {
name: 'PerformanceEvent', name: 'PerformanceEvent',
@@ -80,18 +89,19 @@ export default {
return { return {
entityType, entityType,
entityName entityName,
chartOption: metricOption
} }
}, },
mounted () { mounted () {
// this.initData() this.initData()
this.isNoData = true /*this.isNoData = true
this.$emit('checkTag', entityDetailTabsName.performanceEvent, 0) this.$emit('checkTag', entityDetailTabsName.performanceEvent, 0)
this.toggleLoading(true) this.toggleLoading(true)
const timer = setTimeout(() => { const timer = setTimeout(() => {
this.toggleLoading(false) this.toggleLoading(false)
clearInterval(timer) clearInterval(timer)
}, 200) }, 200)*/
}, },
methods: { methods: {
unitConvert, unitConvert,
@@ -105,31 +115,88 @@ export default {
} }
this.toggleLoading(true) this.toggleLoading(true)
axios.get(`${api.entity.performance}/${this.entityType}`, { params: params }).then(response => {
const res = response.data
if (response.status === 200) { if (this.entityName === 'hqzc.wssp.hainan.gov.cn' || this.entityName === '218.77.183.150') {
this.isNoData = res.data.result.length === 0 setTimeout(() => {
this.$emit('checkTag', entityDetailTabsName.performanceEvent, res.data.result.length) this.toggleLoading(false)
this.showError = false this.isNoData = false
if (!this.isNoData) { this.eventList = [
this.eventList = res.data.result {
"serverIp": "1.1.1.1",
"domain": "www.baidu.com",
"appName": "ab",
"eventSeverity": "critical",
"eventType": "Http error",
"durationMs": 840000,
"startTime": new Date().getTime() - 1957 * 1000,
"endTime": 2222222222
}
]
this.metricList = [
[new Date().getTime() / 1000 - 2677, 2],
[new Date().getTime() / 1000 - 2557, 3],
[new Date().getTime() / 1000 - 2437, 2],
[new Date().getTime() / 1000 - 2317, 7],
[new Date().getTime() / 1000 - 2197, 8],
[new Date().getTime() / 1000 - 2077, 38],
[new Date().getTime() / 1000 - 1857, 12],
[new Date().getTime() / 1000 - 1637, 8],
[new Date().getTime() / 1000 - 1517, 7],
[new Date().getTime() / 1000 - 1277, 3],
[new Date().getTime() / 1000 - 1157, 1],
[new Date().getTime() / 1000 - 1037, 2]
]
this.$emit('checkTag', entityDetailTabsName.performanceEvent, 1)
this.$nextTick(() => {
this.initChart()
})
}, 200)
} else {
setTimeout(() => {
this.isNoData = true
this.toggleLoading(false)
this.eventList = []
this.$emit('checkTag', entityDetailTabsName.performanceEvent, 0)
}, 200)
/*axios.get(`${api.entity.performance}/${this.entityType}`, {params: params}).then(response => {
const res = response.data
if (response.status === 200) {
this.isNoData = res.data.result.length === 0
this.$emit('checkTag', entityDetailTabsName.performanceEvent, res.data.result.length)
this.showError = false
if (!this.isNoData) {
this.eventList = res.data.result
}
} else {
this.httpError(res)
} }
} else { }).catch(e => {
this.httpError(res) console.error(e)
} this.httpError(e)
}).catch(e => { }).finally(() => {
console.error(e) this.toggleLoading(false)
this.httpError(e) })*/
}).finally(() => { }
this.toggleLoading(false)
})
}, },
httpError (e) { httpError (e) {
this.isNoData = false this.isNoData = false
this.showError = true this.showError = true
this.errorMsg = this.errorMsgHandler(e) this.errorMsg = this.errorMsgHandler(e)
this.$emit('checkTag', entityDetailTabsName.performanceEvent, 0) this.$emit('checkTag', entityDetailTabsName.performanceEvent, 0)
},
initChart () {
this.metricChart = markRaw(echarts.init(document.getElementById('anomalyChart')))
this.chartOptionMetric = _.cloneDeep(this.chartOption)
this.chartOptionMetric.series[0].data = this.metricList.slice(0, 4).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
this.chartOptionMetric.series[1].data = this.metricList.slice(3, 9).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
this.chartOptionMetric.series[2].data = this.metricList.slice(8, 11).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
this.chartOptionMetric.series.forEach(item => {
item.name = 'Http error'
})
this.chartOptionMetric && this.metricChart.setOption(this.chartOptionMetric)
} }
} }
} }

View File

@@ -17,7 +17,7 @@
class="detection-event-severity-color-block" class="detection-event-severity-color-block"
:style="`background-color: ${eventSeverityColor[item.eventSeverity]}`"> :style="`background-color: ${eventSeverityColor[item.eventSeverity]}`">
</span> </span>
<span class="detection-event-severity-block">{{ toUpperCaseByString(item.securityType) || '-' }}</span> <span class="detection-event-severity-block">{{ item.eventName || '-' }}</span>
<i class="cn-icon cn-icon-attacker"></i> <i class="cn-icon cn-icon-attacker"></i>
<span :test-id="`offender-ip${index}`">{{ item.offenderIp || '-' }}</span> <span :test-id="`offender-ip${index}`">{{ item.offenderIp || '-' }}</span>
<div class="domain">{{ item.offenderDomain }}</div> <div class="domain">{{ item.offenderDomain }}</div>
@@ -25,7 +25,7 @@
<span class="circle"></span> <span class="circle"></span>
<i class="cn-icon cn-icon-attacked"></i> <i class="cn-icon cn-icon-attacked"></i>
<span :test-id="`victim-ip${index}`">{{ item.victimIp || '-' }}</span> <span :test-id="`victim-ip${index}`">{{ item.victimIp || '-' }}</span>
<div class="domain">{{ item.victimDomain }}</div> <div class="domain">{{ item.domain }}</div>
</div> </div>
<div class="cn-detection__body"> <div class="cn-detection__body">
<div class="body__basic-info"> <div class="body__basic-info">
@@ -58,7 +58,7 @@
<div class="basic-info__item"> <div class="basic-info__item">
<i class="cn-icon cn-icon-time2"></i> <i class="cn-icon cn-icon-time2"></i>
<span>{{ $t('detection.list.startTime') }}&nbsp;:&nbsp;&nbsp;</span> <span>{{ $t('detection.list.startTime') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ dateFormatByAppearance(item.startTime) || '-' }}</span> <span>{{ dateFormatByAppearance(parseFloat(item.startTime)) || '-' }}</span>
</div> </div>
<div class="basic-info__item"> <div class="basic-info__item">
<i class="cn-icon cn-icon-duration"></i> <i class="cn-icon cn-icon-duration"></i>
@@ -109,14 +109,14 @@ export default {
} }
}, },
mounted () { mounted () {
// this.initData() this.initData()
this.isNoData = true /*this.isNoData = true
this.$emit('checkTag', entityDetailTabsName.securityEvent, 0) this.$emit('checkTag', entityDetailTabsName.securityEvent, 0)
this.toggleLoading(true) this.toggleLoading(true)
const timer = setTimeout(() => { const timer = setTimeout(() => {
this.toggleLoading(false) this.toggleLoading(false)
clearInterval(timer) clearInterval(timer)
}, 200) }, 200)*/
}, },
methods: { methods: {
unitConvert, unitConvert,
@@ -130,25 +130,101 @@ export default {
} }
this.toggleLoading(true) this.toggleLoading(true)
axios.get(`${api.entity.security}/${this.entityType}`, { params: params }).then(response => { if (this.entityName === 'hqzc.wssp.hainan.gov.cn' || this.entityName === '218.77.183.150') {
const res = response.data setTimeout(() => {
this.toggleLoading(false)
this.isNoData = false
this.eventList = [
{
eventId: '1717034000326447105',
eventType: 'Command and Control',
eventName: 'Mirai',
eventKey: '5,26.26.26.1,192.168.38.73',
ruleId: '5',
ruleType: 'indicator_match',
isBuiltin: '1',
eventSeverity: 'critical',
offenderIp: '119.102.149.177',
victimIp: '218.77.183.150',
domain: 'hqzc.wssp.hainan.gov.cn',
app: '',
startTime: new Date().getTime() - 3600 * 1000,
endTime: '1698207720',
durationMs: 1613000,
matchTimes: '1',
status: '1',
eventInfo: '{\"knowledge_id\":\"8\",\"name\":\"built_in_ioc_darkweb\",\"ioc_type\":\"ip\",\"ioc_value\":\"26.26.26.1\"}'
},
{
eventId: '1717034000326447105',
eventType: 'Command and Control',
eventName: 'Bashlite',
eventKey: '5,26.26.26.1,192.168.38.73',
ruleId: '5',
ruleType: 'indicator_match',
isBuiltin: '1',
eventSeverity: 'critical',
offenderIp: '142.4.196.195',
victimIp: '218.77.183.150',
domain: 'hqzc.wssp.hainan.gov.cn',
app: '',
startTime: new Date().getTime() - 1600 * 1000,
endTime: '1698207720',
durationMs: 1285000,
matchTimes: '1',
status: '1',
eventInfo: '{\"knowledge_id\":\"8\",\"name\":\"built_in_ioc_darkweb\",\"ioc_type\":\"ip\",\"ioc_value\":\"26.26.26.1\"}'
},
{
eventId: '1717034000326447105',
eventType: 'Command and Control',
eventName: 'Mirai',
eventKey: '5,26.26.26.1,192.168.38.73',
ruleId: '5',
ruleType: 'indicator_match',
isBuiltin: '1',
eventSeverity: 'critical',
offenderIp: '103.119.112.54',
victimIp: '218.77.183.150',
domain: 'hqzc.wssp.hainan.gov.cn',
app: '',
startTime: new Date().getTime() - 2600 * 1000,
endTime: '1698207720',
durationMs: 2280000,
matchTimes: '1',
status: '1',
eventInfo: '{\"knowledge_id\":\"8\",\"name\":\"built_in_ioc_darkweb\",\"ioc_type\":\"ip\",\"ioc_value\":\"26.26.26.1\"}'
}
]
this.$emit('checkTag', entityDetailTabsName.securityEvent, 3)
}, 200)
} else {
setTimeout(() => {
this.isNoData = true
this.toggleLoading(false)
this.eventList = []
this.$emit('checkTag', entityDetailTabsName.securityEvent, 0)
}, 200)
/*axios.get(`${api.entity.security}/${this.entityType}`, { params: params }).then(response => {
const res = response.data
if (response.status === 200) { if (response.status === 200) {
this.isNoData = res.data.result.length === 0 this.isNoData = res.data.result.length === 0
this.$emit('checkTag', entityDetailTabsName.securityEvent, res.data.result.length) this.$emit('checkTag', entityDetailTabsName.securityEvent, res.data.result.length)
this.showError = false this.showError = false
if (!this.isNoData) { if (!this.isNoData) {
this.eventList = res.data.result this.eventList = res.data.result
}
} else {
this.httpError(res)
} }
} else { }).catch(e => {
this.httpError(res) console.error(e)
} this.httpError(e)
}).catch(e => { }).finally(() => {
console.error(e) this.toggleLoading(false)
this.httpError(e) })*/
}).finally(() => { }
this.toggleLoading(false)
})
}, },
httpError (e) { httpError (e) {
this.$emit('checkTag', entityDetailTabsName.securityEvent, 0) this.$emit('checkTag', entityDetailTabsName.securityEvent, 0)

View File

@@ -188,9 +188,9 @@ export default {
// 链路下一跳数据 // 链路下一跳数据
let nextGridData = [] let nextGridData = []
const nextGridTemplate = [ const nextGridTemplate = [
{ linkId: 'Hundredgige2', nextHop: '太原', out: [] }, { linkId: 'Hundredgige2', nextHop: 'City2', out: [] },
{ linkId: 'Hundredgige1', nextHop: '西安', out: [] }, { linkId: 'Hundredgige1', nextHop: 'City1', out: [] },
{ linkId: 'Hundredgige4', nextHop: '西宁', out: [] } { linkId: 'Hundredgige4', nextHop: 'City3', out: [] }
] ]
nextGridData = JSON.parse(JSON.stringify(nextGridTemplate)) nextGridData = JSON.parse(JSON.stringify(nextGridTemplate))
nextGridData.forEach(link => { nextGridData.forEach(link => {

View File

@@ -31,7 +31,7 @@
<div class="new-filter-content-content"> <div class="new-filter-content-content">
<el-checkbox-group v-model="checkEventType" @change="onChangeCategory" style="display: flex;flex-direction: column"> <el-checkbox-group v-model="checkEventType" @change="onChangeCategory" style="display: flex;flex-direction: column">
<el-checkbox v-for="item in eventTypeList" :key="item.name" class="new-filter-content-checkbox" :label="item.name"> <el-checkbox v-for="item in eventTypeList" :key="item.name" class="new-filter-content-checkbox" :label="item.name">
{{ item.label }} {{ item.name }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
@@ -94,13 +94,7 @@ export default {
} }
if (data.eventTypeList) { if (data.eventTypeList) {
this.eventTypeList = [] this.eventTypeList = data.eventTypeList
data.eventTypeList.forEach(item => {
const obj = detectionUnitList.eventTypeList.find(d => d.value === item.name)
if (obj) {
this.eventTypeList.push({ ...item, label: this.$t(obj.label) })
}
})
} else { } else {
this.eventTypeList = [] this.eventTypeList = []
} }

View File

@@ -57,12 +57,12 @@
<div class="trigger-block-item margin-b-10"> <div class="trigger-block-item margin-b-10">
<div>At least</div> <div>At least</div>
<el-form-item prop="atLeast"> <el-form-item prop="atLeast">
<el-input size="mini" v-model="triggerObj.atLeast" oninput="value=value.replace(/[^\d]/g,'')"></el-input> <el-input size="mini" maxlength="5" v-model="triggerObj.atLeast" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
</el-form-item> </el-form-item>
<div>times within</div> <div>times within</div>
<el-form-item prop="interval"> <el-form-item prop="interval" class="policy-form-item">
<el-input size="mini" v-model="triggerObj.interval" oninput="value=value.replace(/[^\d]/g,'')"></el-input> <el-input size="mini" maxlength="5" v-model="triggerObj.interval" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
</el-form-item> </el-form-item>
<el-form-item prop="intervalVal"> <el-form-item prop="intervalVal">
@@ -79,8 +79,8 @@
<div class="trigger-block-item"> <div class="trigger-block-item">
<div>With the counter resetting after no activity for</div> <div>With the counter resetting after no activity for</div>
<el-form-item prop="resetInterval"> <el-form-item prop="resetInterval" class="policy-form-item">
<el-input size="mini" v-model="triggerObj.resetInterval" oninput="value=value.replace(/[^\d]/g,'')"></el-input> <el-input size="mini" maxlength="5" v-model="triggerObj.resetInterval" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
</el-form-item> </el-form-item>
<el-form-item prop="resetIntervalVal"> <el-form-item prop="resetIntervalVal">
<el-select v-model="triggerObj.resetIntervalVal" class="form-trigger__select" placeholder=" " size="mini"> <el-select v-model="triggerObj.resetIntervalVal" class="form-trigger__select" placeholder=" " size="mini">
@@ -98,7 +98,7 @@
<div class="trigger-block-item margin-b-10"> <div class="trigger-block-item margin-b-10">
<el-form-item prop="interval"> <el-form-item prop="interval">
<el-input size="mini" v-model="triggerObj.interval" oninput="value=value.replace(/[^\d]/g,'')"></el-input> <el-input size="mini" maxlength="5" v-model="triggerObj.interval" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
</el-form-item> </el-form-item>
<el-form-item prop="intervalVal"> <el-form-item prop="intervalVal">
@@ -113,7 +113,7 @@
</el-form-item> </el-form-item>
内至少发生 内至少发生
<el-form-item prop="atLeast"> <el-form-item prop="atLeast">
<el-input size="mini" v-model="triggerObj.atLeast" oninput="value=value.replace(/[^\d]/g,'')"></el-input> <el-input size="mini" maxlength="5" v-model="triggerObj.atLeast" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
</el-form-item> </el-form-item>
</div> </div>
@@ -121,7 +121,7 @@
<div class="trigger-block-item"> <div class="trigger-block-item">
若连续 若连续
<el-form-item prop="resetInterval"> <el-form-item prop="resetInterval">
<el-input size="mini" v-model="triggerObj.resetInterval" oninput="value=value.replace(/[^\d]/g,'')"></el-input> <el-input size="mini" maxlength="5" v-model="triggerObj.resetInterval" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
</el-form-item> </el-form-item>
<el-form-item prop="resetIntervalVal"> <el-form-item prop="resetIntervalVal">
<el-select v-model="triggerObj.resetIntervalVal" class="form-trigger__select" placeholder=" " size="mini"> <el-select v-model="triggerObj.resetIntervalVal" class="form-trigger__select" placeholder=" " size="mini">
@@ -165,6 +165,40 @@ import { storageKey, detectionUnitList } from '@/utils/constants'
export default { export default {
name: 'DetectionForm', name: 'DetectionForm',
data () { data () {
const intervalValidator = (rule, value, callback) => {
const obj = this.handleIntervalByDateType(rule, value, this.triggerObj.intervalVal)
if (!obj.flag && obj.msg) {
callback(new Error(obj.msg))
} else {
callback()
}
}
const intervalValValidator = (rule, value, callback) => {
const obj = this.handleIntervalByDateType(rule, this.triggerObj.intervalVal, value)
if (!obj.flag && obj.msg) {
this.$refs.form3.validateField('interval')
callback()
} else {
callback()
}
}
const resetIntervalValidator = (rule, value, callback) => {
const obj = this.handleIntervalByDateType(rule, value, this.triggerObj.resetIntervalVal)
if (!obj.flag && obj.msg) {
callback(new Error(obj.msg))
} else {
callback()
}
}
const resetIntervalValValidator = (rule, value, callback) => {
const obj = this.handleIntervalByDateType(rule, this.triggerObj.resetIntervalVal, value)
if (!obj.flag && obj.msg) {
this.$refs.form3.validateField('resetInterval')
callback()
} else {
callback()
}
}
return { return {
activeNames: ['1'], activeNames: ['1'],
rules: { rules: {
@@ -180,6 +214,10 @@ export default {
required: true, required: true,
message: this.$t('validate.required'), message: this.$t('validate.required'),
trigger: 'blur' trigger: 'blur'
},
{
validator: intervalValidator,
trigger: 'blur'
} }
], ],
intervalVal: [ intervalVal: [
@@ -187,6 +225,10 @@ export default {
required: true, required: true,
message: this.$t('validate.required'), message: this.$t('validate.required'),
trigger: 'change' trigger: 'change'
},
{
validator: intervalValValidator,
trigger: 'change'
} }
], ],
resetInterval: [ resetInterval: [
@@ -194,6 +236,10 @@ export default {
required: true, required: true,
message: this.$t('validate.required'), message: this.$t('validate.required'),
trigger: 'blur' trigger: 'blur'
},
{
validator: resetIntervalValidator,
trigger: 'blur'
} }
], ],
resetIntervalVal: [ resetIntervalVal: [
@@ -201,6 +247,10 @@ export default {
required: true, required: true,
message: this.$t('validate.required'), message: this.$t('validate.required'),
trigger: 'change' trigger: 'change'
},
{
validator: resetIntervalValValidator,
trigger: 'change'
} }
] ]
}, },
@@ -368,6 +418,7 @@ export default {
this.myLoading = false this.myLoading = false
}) })
} else { } else {
console.log('进来')
this.myLoading = true this.myLoading = true
axios.put(api.detection.create.create, formObj).then(response => { axios.put(api.detection.create.create, formObj).then(response => {
if (response.status === 200) { if (response.status === 200) {
@@ -417,6 +468,29 @@ export default {
}) })
} }
this.$message.error(this.$t('detection.create.informationFilled')) this.$message.error(this.$t('detection.create.informationFilled'))
},
handleIntervalByDateType (rule, value, type) {
if (value && (type === 'hours' || type === '小时')) {
if (parseInt(value) <= 24) {
return { flag: true }
} else {
return { flag: false, msg: this.$t('policy.dateTimeRangeHours') }
}
}
if (value && (type === 'minutes' || type === '分钟')) {
if (parseInt(value) <= 1440) {
return { flag: true }
} else {
return { flag: false, msg: this.$t('policy.dateTimeRangeMinutes') }
}
}
if (value && (type === 'seconds' || type === '秒')) {
if (parseInt(value) <= 86400) {
return { flag: true }
} else {
return { flag: false, msg: this.$t('policy.dateTimeRangeSeconds') }
}
}
} }
} }
} }

View File

@@ -56,9 +56,6 @@
<template v-else-if="item.prop === 'category'"> <template v-else-if="item.prop === 'category'">
{{ changeCategory(scope.row[item.prop]) }} {{ changeCategory(scope.row[item.prop]) }}
</template> </template>
<template v-else-if="item.prop === 'eventType'">
{{ changeEventType(scope.row[item.prop]) }}
</template>
<template v-else-if="item.prop === 'description'"> <template v-else-if="item.prop === 'description'">
<div style="padding-right: 20px">{{ scope.row[item.prop] }}</div> <div style="padding-right: 20px">{{ scope.row[item.prop] }}</div>
</template> </template>
@@ -181,16 +178,6 @@ export default {
} }
return label return label
} }
},
changeEventType (value) {
if (value) {
const obj = detectionUnitList.eventTypeList.find(d => d.value === value)
let label = value
if (obj) {
label = this.$t(obj.label)
}
return label
}
} }
} }
} }

View File

@@ -308,6 +308,10 @@ export const metricOption = {
str += `<span class="cn-chart-tooltip-value"> str += `<span class="cn-chart-tooltip-value">
${unitConvert(item.data[1], unitTypes.time).join(' ')} ${unitConvert(item.data[1], unitTypes.time).join(' ')}
</span>` </span>`
} else if (item.seriesName === 'Http error') {
str += `<span class="cn-chart-tooltip-value">
${unitConvert(item.data[1], unitTypes.number, '', '', 0).join(' ')}
</span>`
} else { } else {
str += `<span class="cn-chart-tooltip-value"> str += `<span class="cn-chart-tooltip-value">
${unitConvert(item.data[1], unitTypes.percent, '', '', 0).join(' ')} ${unitConvert(item.data[1], unitTypes.percent, '', '', 0).join(' ')}

View File

@@ -71,7 +71,8 @@
<div class="right-label">{{ $t('network.total') }}</div> <div class="right-label">{{ $t('network.total') }}</div>
<div class="right-label-loading"> <div class="right-label-loading">
<loading :loading="loadingApp" size="small"></loading> <loading :loading="loadingApp" size="small"></loading>
<div class="right-value">{{ numberWithCommas(entityAppTotal) }}</div> <!-- <div class="right-value">{{ numberWithCommas(entityAppTotal) }}</div>-->
<div class="right-value">837</div>
</div> </div>
</div> </div>
@@ -101,7 +102,8 @@
<div class="right-label">{{ $t('network.total') }}</div> <div class="right-label">{{ $t('network.total') }}</div>
<div class="right-label-loading"> <div class="right-label-loading">
<loading :loading="loadingDomain" size="small"></loading> <loading :loading="loadingDomain" size="small"></loading>
<div class="right-value">{{ numberWithCommas(entityDomainTotal) }}</div> <!-- <div class="right-value">{{ numberWithCommas(entityDomainTotal) }}</div>-->
<div class="right-value">1,032,544</div>
</div> </div>
</div> </div>
@@ -131,7 +133,8 @@
<div class="right-label">{{ $t('network.total') }}</div> <div class="right-label">{{ $t('network.total') }}</div>
<div class="right-label-loading"> <div class="right-label-loading">
<loading :loading="loadingIp" size="small"></loading> <loading :loading="loadingIp" size="small"></loading>
<div class="right-value">{{ numberWithCommas(entityIpTotal) }}</div> <!-- <div class="right-value">{{ numberWithCommas(entityIpTotal) }}</div>-->
<div class="right-value">1,900,804</div>
</div> </div>
</div> </div>