Compare commits

..

21 Commits

Author SHA1 Message Date
刘洪洪
374c66fcff fix: 还原之前版本 2024-01-02 11:05:01 +08:00
刘洪洪
705572b245 fix: 修复实体、检测界面因路由路径问题不能打开,以及实体详情界面部分问题 2024-01-02 10:42:54 +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
108 changed files with 1348 additions and 2702 deletions

View File

@@ -3,18 +3,3 @@ const BASE_CONFIG = {
version: '23.10',
apiVersion: 'v1'
}
// 默认时间过滤条件,单位分钟. 0表示请求接口时不传时间参数
const DEFAULT_TIME_FILTER_RANGE = {
dashboard: 60,
entity: {
list: 60,
trafficLine: 60,
informationAggregation: 0,
relatedEntity: 60 * 24 * 7,
openPort: 60 * 24 * 7,
securityEvent: 60 * 24 * 7,
performanceEvent: 60 * 24 * 7,
behaviorPattern: 60 * 24 * 7
},
detection: 60
}

View File

@@ -54,8 +54,7 @@ export default {
return {
loading: false,
username: '',
pin: '',
language: ''
pin: ''
}
},
methods: {
@@ -76,9 +75,6 @@ export default {
if (!_.isEmpty(res.data.data.user.lang)) {
localStorage.setItem(storageKey.language, res.data.data.user.lang)
}
if (!localStorage.getItem(storageKey.language)) {
localStorage.setItem(storageKey.language, this.language)
}
if (!_.isEmpty(res.data.data.user.theme)) {
localStorage.setItem(storageKey.theme, res.data.data.user.theme)
}
@@ -111,7 +107,6 @@ export default {
})
},
appearanceOut (data) {
this.language = data.lang || defaultLang
if (_.isEmpty(localStorage.getItem(storageKey.language))) {
localStorage.setItem(storageKey.language, data.lang || defaultLang)
}

View File

@@ -3,92 +3,84 @@
height: 100%;
.search__suffixes {
height: 38px;
&.entity-explorer-home {
margin-right: 1px;
color: #3976CB;
&.search__suffixes--text-mode, &.search__suffixes--tag-mode {
.search__suffix:last-of-type {
width: unset;
height: unset;
margin-right: 12px;
background-color: transparent;
.el-icon-search {
color: #3976CB;
}
}
}
}
&.search__suffixes--text-mode, &.search__suffixes--tag-mode {
position: absolute;
display: flex;
align-items: center;
top: 1px;
right: 0;
top: 10px;
right: 10px;
.search__suffix {
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
border-radius: 0 2px 2px 0;
// margin-left: 8px;
.cn-icon-search-advance, .cn-icon-search-normal, .cn-icon-filter {
color: #A6AAAE;
font-size: 18px;
}
.el-icon-search {
color: #3976CB;
font-size: 22px;
}
&:hover {
cursor: pointer;
}
&:last-of-type {
margin-right: 0;
width: 41px;
height: 38px;
line-height: 39px;
background: #38ACD2;
.el-icon-search {
font-size: 22px;
color: #fff;
}
}
}
.search__suffix-close {
height: 40px;
line-height: 40px;
margin-top: -9px;
.el-icon-error {
font-size: 17px;
color: #C4C4C4;
margin-right: 12px;
cursor: pointer;
}
}
.entity-explorer-search {
color: #3976CB;
margin-top: -2px;
}
.margin-r-12 {
margin-right: 12px;
}
.new-search__suffix {
width: 41px;
height: 41px;
line-height: 41px;
background: #38ACD2;
text-align: center;
margin-top: -10px;
margin-right: -10px;
.el-icon-search {
color: #fff !important;
margin-top: 9px !important;
}
}
.my-popper-class .el-popper__arrow {
display: none;
}
}
&.search__suffixes--tag-mode__block {
background: #fff;
}
}
/*.search-tip--error {
font-size: 14px;
color: #F56C6C;
}*/
}
.detections {
.tag-search, .CodeMirror {
border: 1px solid #E2E5EC;
}
.advanced-search--show-list .CodeMirror, .advanced-search--show-list .tag-search {
border: none;
}
.tag-search {
display: flex;
align-items: center;
height: 40px;
overflow: auto hidden;
border: 1px solid #CECECE;
border-radius: 2px;
padding-left: 10px;
padding-right: 80px;
background-color: white;
border: 1px solid #DEDEDE;
&::-webkit-scrollbar {
width: 8px;
@@ -112,7 +104,6 @@
border-radius: 1px;
cursor: pointer;
transition: all linear .1s;
margin-right: 30px;
&:hover {
background-color: white;
@@ -176,9 +167,6 @@
}
}
}
.entity__search .tag-search {
padding-left: 65px;
}
.el-popover.my-popper-class {
width: auto !important;

View File

@@ -13,16 +13,11 @@
color: #ccc;
}
}
.entity__search {
.CodeMirror {
padding-left: 60px;
}
}
/* PADDING */
.CodeMirror-lines {
padding: 9px 5px; /* Vertical padding around content */
padding: 11px 5px; /* Vertical padding around content */
}
.CodeMirror pre.CodeMirror-line,
.CodeMirror pre.CodeMirror-line-like {

View File

@@ -5,7 +5,6 @@
&>div {
height: 100%;
}
overflow-y: auto;
}
.cn-header {

View File

@@ -15,7 +15,8 @@
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
margin-top: 20px;
padding: 0 20px 20px;
.panel__title {
font-size: 24px;

View File

@@ -194,13 +194,12 @@
}
}
.form-setting__btn, .form-setting__btn1, .policy-form__footer__btn {
.form-setting__btn, .form-setting__btn1 {
width: 100%;
display: flex;
justify-content: flex-end;
.el-button {
width: 80px !important;
height: 30px !important;
min-height: 30px !important;
line-height: 30px !important;
@@ -223,15 +222,8 @@
}
}
}
.policy-form__footer__btn {
justify-content: center;
margin-top: 8px;
.btn1 {
margin-right: 16px;
}
}
.form-setting__btn1, .policy-form__footer__btn {
.form-setting__btn1 {
.el-button {
padding: 0 11px !important;
}

View File

@@ -10,9 +10,9 @@
}
.detection-form-content {
height: calc(100% - 92px);
height: 100%;
overflow: scroll;
padding-bottom: 20px;
padding-bottom: 40px;
.detection-form-collapse {
margin-top: 20px;
@@ -130,12 +130,6 @@
}
}
}
.policy-form-trigger {
.el-collapse-item__content {
padding-bottom: 0 !important;
}
}
}
.el-input--mini, .el-input--mini .el-input__inner {
@@ -149,13 +143,4 @@
padding-bottom: 20px;
}
.policy-form__footer {
width: calc(100% + 40px);
height: 60px;
margin-left: -20px;
box-shadow: 0 -1px 4px 0 rgba(0,0,0,0.10);
display: flex;
align-items: center;
justify-content: center;
}
}

View File

@@ -34,15 +34,6 @@
.drawer-basic-id {
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
i {
font-size: 14px;
font-weight: 400;
cursor: pointer;
}
}
}
}

View File

@@ -2,124 +2,98 @@
display: flex;
flex-direction: column;
width: 280px;
margin-right: 12px;
padding: 10px;
margin-right: 10px;
background-color: white;
overflow: auto;
z-index: 1;
border: 1px solid rgba(226, 229, 236, 1) !important;
border-radius: 4px !important;
.filter-case__header {
padding-left: 8px;
height: 36px;
line-height: 36px;
color: #666;
font-size: 14px;
background: #F7F7F7;
box-shadow: 0 1px 0 0 rgba(226,229,236,1);
border-radius: 4px 4px 0 0;
}
.detection-filter {
display: flex;
flex-direction: column;
margin-bottom: 10px;
.filter__header {
height: 46px;
line-height: 46px;
margin: 0 20px;
font-size: 14px;
color: #353636;
font-weight: 500;
}
.filter__body {
width: calc(100% - 30px);
margin: 0 10px 0 20px;
max-height: 265px;
overflow-y: scroll;
overflow-x: hidden;
.filter__body-item {
height: 26px;
line-height: 26px;
.filter__header {
display: flex;
flex: 0 0 32px;
align-items: center;
justify-content: space-between;
padding-left: 10px;
color: #666;
//background-color: #F3F7FA;
cursor: pointer;
.filter__body-item-left {
display: flex;
align-items: center;
span {
font-size: 14px;
padding-left: 6px;
}
i {
font-size: 12px;
transition: all linear .1s;
transform: rotate(0) translate(0, 2px);
}
i.arrow-rotate {
transform: rotate(90deg) translate(2px, 3px);
}
.new-detection-filter-header-title {
font-size: 14px;
color: #353636;
font-weight: 400;
font-weight: 600;
}
.new-detection-filter-icon {
margin-left: 8px;
margin-bottom: 2px;
font-weight: bold !important;
}
}
.filter__body-item-left-index {
width: 16px;
height: 16px;
text-align: center;
background: #EFF2F5;
border-radius: 2px;
margin-right: 6px;
font-family: NotoSansHans-Black;
font-size: 9px;
color: #96A2B0;
font-weight: 900;
.filter__body {
padding: 5px 0 0 15px;
.el-checkbox-group {
display: flex;
flex-direction: column;
.el-checkbox {
display: flex;
align-items: center;
justify-content: center;
}
padding: 5px 0;
margin-right: 5px;
.el-checkbox__label {
width: 100%;
}
.filter__body-item-left-label {
max-width: 180px;
font-family: NotoSansSChineseRegular;
font-size: 14px;
color: #353636;
font-weight: 400;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.filter__checkbox-label {
display: flex;
justify-content: space-between;
align-items: center;
.filter__body-item-right {
flex-shrink: 0;
font-family: NotoSansSChineseRegular;
font-size: 12px;
color: #717171;
font-weight: 400;
margin-right: 10px;
.severity-color-block {
width: 4px;
height: 15px;
border-radius: 2px;
}
}
&:last-of-type {
padding-bottom: 0;
}
}
}
}
}
.new-detection-filter-title {
display: flex;
flex: 0 0 32px;
align-items: center;
padding-left: 27px;
background-color: #EFF2F5;
cursor: pointer;
font-size: 14px;
color: #353636;
font-weight: 600;
margin: -10px;
margin-bottom: 10px;
}
}
.filter-country-flag {
width: 18px;
height: 12px;
margin-right: 6px;
border: 1px solid #E8E8E8;
}
.filter-show-more, .filter-no-show-more {
cursor: pointer;
height: 26px;
line-height: 26px;
margin-left: 20px;
color: #046ECA;
user-select: none; // 禁止文本选中
font-size: 12px;
}
.filter-no-show-more {
cursor: not-allowed;
color: rgba(16, 16, 16, 0.3);
}
.filter-hr {
width: calc(100% - 40px);
margin-left: 20px;
margin-top: 6px;
height: 1px;
background: #EFF2F5;
//background: #000;
}
.new-detection-filter-title {
height: 32px;
line-height: 32px;

View File

@@ -149,7 +149,7 @@
flex-direction: row;
flex-wrap: wrap;
.basic-info__item, .basic-info__item1 {
.basic-info__item {
padding-right: 30px;
display: flex;
align-items: center;
@@ -172,11 +172,6 @@
color: #666;
}
}
.basic-info__item1 {
span: {
color: #666;
}
}
}
.show-detail {

View File

@@ -203,7 +203,6 @@
color: #046ECA;
margin-bottom: 10px;
font-weight: 500;
height: 36px;
}
.timeline__start-time {
font-size: 12px;

View File

@@ -26,7 +26,7 @@
justify-content: flex-start;
}
.explorer-top-tools, .explorer-detection-top-tools, .explorer-entity-top-tools {
.explorer-top-tools, .explorer-detection-top-tools {
display: flex;
justify-content: flex-end;
align-items: center;
@@ -46,10 +46,7 @@
}
}
}
.explorer-entity-top-tools {
width: 100%;
}
.explorer-detection-top-tools, .explorer-entity-top-tools {
.explorer-detection-top-tools {
display: flex;
justify-content: space-between;
}
@@ -90,13 +87,6 @@
font-size: 14px;
color: #353636;
font-weight: 400;
.entity-hide-entity {
margin-left: 20px;
.el-checkbox__label {
padding-left: 6px;
}
}
}
.explorer-container, .explorer-container-new {
display: flex;

View File

@@ -2,7 +2,7 @@
display: flex;
flex-direction: column;
width: 320px;
margin-right: 12px;
margin-right: 20px;
overflow: auto;
z-index: 1;
border: 1px solid rgba(226, 229, 236, 1) !important;

View File

@@ -351,7 +351,6 @@
}
.score-dot {
display: inline-block;
margin-bottom: 2px;
width: 6px;
height: 6px;
border-radius: 50%;

View File

@@ -79,20 +79,9 @@
.cn-entity__header-title {
margin-right: 10px;
}
.entity-related-entity {
font-size: 12px;
color: #717171;
cursor: pointer;
margin-right: 6px;
}
}
.cn-entity__header-tag {
.entity-row-tag {
display: flex;
margin-left: 6px;
margin-top: 1px;
flex-wrap: wrap;
margin-bottom: -10px;
}
}
.cn-entity__body {
@@ -109,7 +98,7 @@
flex-direction: row;
flex-wrap: wrap;
.basic-info__item, .basic-info__item1 {
.basic-info__item {
padding-right: 30px;
.item__box {
@@ -172,17 +161,6 @@
color: #666;
}
}
.basic-info__item1 {
span: {
color: #666;
}
span:first-of-type {
color: #666;
}
.row-item-label {
color: #999 !important;
}
}
.row-item-label {
font-family: NotoSansSChineseRegular;
@@ -199,7 +177,6 @@
.score-dot {
display: inline-block;
margin-bottom: 2px;
width: 6px;
height: 6px;
border-radius: 50%;

View File

@@ -26,8 +26,7 @@
padding: 0 20px;
&.explorer-search__input-case--question-mark-in-line {
//flex-direction: row;
flex-direction: column;
flex-direction: row;
padding: 0;
.explorer-search__input {
@@ -35,8 +34,9 @@
max-width: unset;
}
.explorer-search__input--border .CodeMirror {
border: 1px solid #DEDEDE;
.explorer-search__input__border {
border: 1px #DEDEDE solid;
height: 43px;
}
}
.search-symbol-inline {
@@ -53,14 +53,14 @@
max-width: 1000px;
height: 40px;
}
.explorer-search__foot,.explorer-search__foot-list {
.explorer-search__foot {
display: flex;
padding-top: 9px;
padding-top: 18px;
width: 100%;
max-width: 1000px;
position: relative;
justify-content: flex-start;
//font-weight: bold;
justify-content: space-between;
font-weight: bold;
.foot__item {
display: flex;
@@ -87,15 +87,14 @@
.search__history {
position: absolute;
top: 6px;
display: flex;
padding: 10px 0 0 0;
flex-direction: column;
width: 100%;
max-width: 1000px;
z-index: 2;
//top: 47px;
border: 1px solid rgba(226,229,236,1);
top: 47px;
border: 1px solid rgba(206,206,206,0.20);
border-radius: 2px;
background-color: white;
@@ -138,32 +137,8 @@
color: #66b1ff;
}
}
.history__items-new {
max-height: 300px;
overflow: auto;
.el-table th,.el-table td {
padding: 6px 0;
border: none !important;
}
.el-table {
font-family: NotoSansSChineseRegular;
font-size: 14px;
color: #575757;
font-weight: 400;
thead {
font-family: NotoSansHans-Medium;
font-size: 14px;
color: #353636;
font-weight: 500;
}
.cell {
padding-left: 18px;
}
}
}
.clear-all {
padding-left: 18px;
padding-left: 30px;
font-weight: normal;
font-size: 14px;
height: 35px;
@@ -177,71 +152,6 @@
}
}
}
.explorer-search__foot-list {
max-width: 756px;
position: absolute;
left: 196px;
top: 44px;
.search__history {
top: 6px;
max-width: 756px;
margin-left: -196px;
.history__items-new {
max-height: 300px;
overflow: auto;
.el-table th,.el-table td {
padding: 4px 0;
border: none !important;
}
.el-table {
font-size: 12px;
thead {
font-size: 12px;
}
}
.el-table--scrollable-x .el-table__body-wrapper {
overflow-x: hidden;
}
}
}
}
}
}
.highlight__text {
background: #FEECC2;
padding: 0 3px;
}
.highlight__block {
background: #FEECC2;
}
.explorer-search__foot-list .explorer-search__block {
margin-left: -196px;
top: -44px;
}
.explorer-search__foot .explorer-search__block {
margin-left: 0;
top: -40px;
}
.explorer-search__block {
position: absolute;
padding-left: 15px;
height: 39px;
display: flex;
align-items: center;
cursor: pointer;
z-index: 1;
i {
font-size: 20px;
color: #999;
}
.search-dividing-line {
width: 1px;
height: 26px;
background: #DEDEDE;
margin-left: 15px;
margin-top: 2px;
}
}

View File

@@ -1798,12 +1798,6 @@
margin-right:5px;
}
}
.top-tool-btn--update:disabled {
cursor: not-allowed;
opacity: 0.66;
i {
}
}
.top-tool-btn--update:hover {
background-color: #57B8D9 !important;
border-color: #2E88A6 !important;
@@ -1852,12 +1846,6 @@
margin-right:5px;
}
}
.top-tool-btn--update:disabled {
cursor: not-allowed;
opacity: 0.66;
i {
}
}
.top-tool-btn--update:hover {
background-color: #57B8D9 !important;
border-color: #2E88A6 !important;

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "cn-icon"; /* Project id 2614877 */
src: url('iconfont.woff2?t=1699411209748') format('woff2'),
url('iconfont.woff?t=1699411209748') format('woff'),
url('iconfont.ttf?t=1699411209748') format('truetype');
src: url('iconfont.woff2?t=1698229141457') format('woff2'),
url('iconfont.woff?t=1698229141457') format('woff'),
url('iconfont.ttf?t=1698229141457') format('truetype');
}
.cn-icon {
@@ -13,10 +13,6 @@
-moz-osx-font-smoothing: grayscale;
}
.cn-icon-related:before {
content: "\e640";
}
.cn-icon-indicator-match:before {
content: "\e80c";
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -17,7 +17,7 @@
size="mini"
v-model="meta.column.label"
ref="columnSelect"
:placeholder="meta.column.label || ' '"
:placeholder="meta.column.label || ''"
@blur="columnBlur(meta, index)"
@change="(value) => selectColumn(value, meta)"
>
@@ -90,8 +90,8 @@
</template>
</div>
<div class="tag-search__add" @click="addCondition">{{$t('entities.advancedSearch.add')}}</div>
<div class="search__suffixes search__suffixes--tag-mode search__suffixes--tag-mode__block" :class="showList ? '' : 'entity-explorer-home'">
<span class="search__suffix">
<div class="search__suffixes search__suffixes--tag-mode">
<div class="search__suffix" style="margin-right: 12px">
<el-popover
popper-class="my-popper-class"
placement="top"
@@ -102,13 +102,13 @@
<i class="cn-icon cn-icon-search-normal" @click="changeMode"></i>
</template>
</el-popover>
</span>
<span v-show="metaList.length>0" class="search__suffix search__suffix-close" @click="cleanMetaList">
</div>
<div v-show="metaList.length>0" class="search__suffix-close" @click="cleanMetaList">
<i class="el-icon-error"></i>
</span>
<span class="search__suffix" @click="search">
</div>
<div class="search__suffix" :class="showList ? 'new-search__suffix' : 'entity-explorer-search'" @click="search">
<i class="el-icon-search"></i>
</span>
</div>
</div>
</div>
</template>
@@ -202,7 +202,6 @@ export default {
if (this.isCustomized(value)) {
meta.column.type = columnType.fullText
meta.column.label = value
meta.column.isFullText = true
meta.resetOperator()
meta.resetValue()
} else {
@@ -249,7 +248,6 @@ export default {
if (meta.column && meta.column.type === 'fullText') {
meta.operator.value = '='
meta.column.show = false
meta.column.isFullText = true
meta.operator.show = false
const label = JSON.parse(JSON.stringify(meta.column.label))
meta.column.label = parser.getEntityTypeByValue(meta.column.label)
@@ -463,21 +461,13 @@ export default {
if (this.metaList.length > 0) {
const parser = new Parser(this.columnList)
const errorList = parser.validateMeta(this.metaList)
const keywordList = []
this.metaList.forEach(item => {
if (item.column && item.column.isFullText) {
keywordList.push({ type: 'fullText', value: item.value.value })
} else if (item.column && !item.column.isFullText) {
keywordList.push({ type: item.column.type, value: item.value.value })
}
})
if (_.isEmpty(errorList)) {
const strObj = parser.handleMetaListToStr(this.metaList)
const str = strObj.str ? strObj.str : strObj
const str2 = strObj.str2 ? strObj.str2 : strObj
// str为将metaList转成字符串的值str2为地址栏展示的值
const key = parser.handleEntityTypeByStr(str)
this.$emit('search', { ...parser.parseStr(key), str: str2, keywordList: keywordList })
this.$emit('search', { ...parser.parseStr(key), str: str2 })
} else {
this.$message.error(handleErrorTip(errorList[0]))
}
@@ -565,17 +555,14 @@ export default {
const column = this.columnList.find(c => {
return c.label === param.column
})
const obj = this.metaList.find(d => d.column && d.column.label === param.column && d.value && (d.value.value === `'${param.value[0]}'` || d.value.value === param.value[0]))
if (obj) {
const metaIndex = this.metaList.findIndex(m => m.column && m.column.label === param.column && m.operator.value === param.operator && m.value.value === this.handleValue(param.value, column, param.operator))
// 不是在首位则删除时顺带删除前一个indexand或or否则顺带删除后一个index
if (metaIndex > 0) {
this.metaList.splice(metaIndex - 1, 2)
} else if (this.metaList.length === 1) {
this.metaList.splice(metaIndex, 1)
} else {
this.metaList.splice(metaIndex, 2)
}
const metaIndex = this.metaList.findIndex(m => m.column && m.column.label === param.column && m.operator.value === param.operator && m.value.value === this.handleValue(param.value, column, param.operator))
// 不是在首位则删除时顺带删除前一个indexand或or否则顺带删除后一个index
if (metaIndex > 0) {
this.metaList.splice(metaIndex - 1, 2)
} else if (this.metaList.length === 1) {
this.metaList.splice(metaIndex, 1)
} else {
this.metaList.splice(metaIndex, 2)
}
})
},
@@ -635,9 +622,6 @@ export default {
let { q } = this.$route.query
if (q && !this.convertMetaList) {
const parser = new Parser(this.columnList)
if (q.indexOf('+') > -1) {
q = q.replace('+', '')
}
if (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1) {
q = decodeURI(q)
} else {
@@ -666,7 +650,6 @@ export default {
if (item.column && item.column.type === 'fullText') {
item.operator.value = '='
item.column.show = false
item.column.isFullText = true
item.operator.show = false
const label = JSON.parse(JSON.stringify(item.column.label))
item.column.label = parser.getEntityTypeByValue(item.column.label)

View File

@@ -1,11 +1,9 @@
<template>
<textarea
style="text-indent: 65px;"
cols="40"
ref="textSearch"
></textarea>
<div class="search__suffixes search__suffixes--text-mode" :class="showList ? '' : 'entity-explorer-home'" style="padding-left: 1px">
<span class="search__suffix">
<div class="search__suffixes search__suffixes--text-mode">
<div class="search__suffix">
<el-popover
popper-class="my-popper-class"
placement="top"
@@ -13,16 +11,16 @@
:content="$t('entity.switchToAdvancedSearch')"
>
<template #reference>
<i class="cn-icon cn-icon-filter" @click="changeMode"></i>
<i class="cn-icon cn-icon-filter margin-r-12" @click="changeMode"></i>
</template>
</el-popover>
</span>
<span v-show="isCloseIcon" class="search__suffix search__suffix-close" @click="cleanParams">
</div>
<div v-show="isCloseIcon" class="search__suffix-close" @click="cleanParams">
<i class="el-icon-error"></i>
</span>
<span class="search__suffix" @click="search">
</div>
<div class="search__suffix" :class="showList ? 'new-search__suffix' : 'entity-explorer-search'" @click="search">
<i class="el-icon-search"></i>
</span>
</div>
</div>
</template>
@@ -70,7 +68,7 @@ export default {
mode: {
name: 'sql'
},
placeholder: '',
placeholder: 'Enter...',
lineNumbers: false
})
this.codeMirror.setOption('extraKeys', {
@@ -99,19 +97,10 @@ export default {
if (str) {
const parser = new Parser(this.columnList)
const keyInfo = parser.comparedEntityKey(parser.handleEntityTypeByStr(str))
const metaList = parser.parseStr(_.cloneDeep(str)).metaList
const keywordList = []
metaList.forEach(item => {
if (item.column && item.column.type === columnType.fullText) {
keywordList.push({ type: item.column.type, value: item.column.label })
} else if (item.column && item.column.type === columnType.string) {
keywordList.push({ type: item.column.type, value: item.value.value })
}
})
if (keyInfo.isKey) {
const errorList = parser.validateStr(keyInfo.key)
if (_.isEmpty(errorList)) {
this.$emit('search', { ...parser.parseStr(keyInfo.key), str: str, keywordList: keywordList })
this.$emit('search', { ...parser.parseStr(keyInfo.key), str: str })
} else {
this.$message.error(handleErrorTip(errorList[0]))
}
@@ -234,9 +223,6 @@ export default {
toRaw(this.codeMirror).setValue(this.str)
}
if (q) {
if (q.indexOf('+') > -1) {
q = q.replace('+', '')
}
if (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1) {
q = decodeURI(q)
} else {

View File

@@ -1414,8 +1414,8 @@ export default class Parser {
} else if (i.toLowerCase() === 'tag') {
lastObj[i] = `has(${i},${commonObj[i]})`
} else {
// 单独存在的,直接保留 todo 后续观察当初添加单引号动机和问题
lastObj[i] = `${i} = ${commonObj[i]}`
// 单独存在的,直接保留
lastObj[i] = `${i} = '${commonObj[i]}'`
}
}

View File

@@ -1,39 +1,35 @@
<template>
<div class="pagination" >
<el-config-provider :locale="locale">
<el-pagination
ref="page"
@size-change="size"
@prev-click="prev"
@next-click="next"
@current-change="current"
:current-page="pageObj.pageNo"
:page-sizes="pageSizes?pageSizes:[20, 50, 100]"
:page-size="Number(pageObj.pageSize)"
:layout="layout"
:total="pageObj.total"
v-bind="bind"
>
<el-select v-model="pageSize" :placeholder="pageSize+$t('pageSize')" size="mini"
:popper-append-to-body="appendToBody" class="pagination-size-select" @change="size"
:popper-class="popClass" @visible-change="popperVisible">
<el-option v-for="(item, index) in pageSizes" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
<el-pagination
ref="page"
@size-change="size"
@prev-click="prev"
@next-click="next"
@current-change="current"
:current-page="pageObj.pageNo"
:page-sizes="pageSizes?pageSizes:[20, 50, 100]"
:page-size="Number(pageObj.pageSize)"
:layout="layout"
:total="pageObj.total"
v-bind="bind"
>
<el-select v-model="pageSize" :placeholder="pageSize+$t('pageSize')" size="mini"
:popper-append-to-body="appendToBody" class="pagination-size-select" @change="size"
:popper-class="popClass" @visible-change="popperVisible">
<el-option v-for="(item, index) in pageSizes" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-pagination>
</el-config-provider>
</el-pagination>
</div>
</template>
<script>
import { defaultPageSize, storageKey, ZH, EN } from '@/utils/constants'
import { defaultPageSize, storageKey } from '@/utils/constants'
import { urlParamsHandler, overwriteUrl } from '@/utils/tools'
import { ref } from 'vue'
import { useRoute } from 'vue-router'
import { parseInt } from 'lodash'
import ElConfigProvider from 'element-plus'
import cn from 'element-plus/lib/locale/lang/zh-cn'
import en from 'element-plus/lib/locale/lang/en'
export default {
name: 'pagination',
@@ -64,15 +60,9 @@ export default {
const { query } = useRoute()
const pageSize = ref(defaultPageSize)
const currentPageNo = ref(props.storePageNoOnUrl ? (query.pageNo || (props.pageObj.pageNo || 1)) : (props.pageObj.pageNo || 1))
const language = localStorage.getItem(storageKey.language) || EN // 初始未选择默认 en 英文
let locale = en
if (language === ZH) {
locale = cn
}
return {
pageSize,
currentPageNo,
locale
currentPageNo
}
},
data () {

View File

@@ -18,30 +18,28 @@
<div v-if="dropdownFlag" class="date-range-panel">
<el-row class="date-range-panel-top" style="position: relative">
<el-col :span="16" class="date-range-panel-content date-range-panel-content-left">
<div class="date-range-title" style="padding-left: 0">{{$t('dateTime.absoluteTimeRange')}}</div>
<el-config-provider :locale="locale">
<el-date-picker
v-model="newDateValue"
ref="newDatePicker"
popper-class="my-date-picker"
style="position: absolute;top: -53px;left: -536px;"
:clearable="false"
:default-time="defaultTime"
:unlink-panels="true"
type="datetimerange"
@change="timeArrChange"
/>
</el-config-provider>
<div class="content-title">{{$t('dateTime.from')}}</div>
<div class="date-range-title" style="padding-left: 0">Absolute time range</div>
<el-date-picker
v-model="newDateValue"
ref="newDatePicker"
popper-class="my-date-picker"
style="position: absolute;top: -53px;left: -536px;"
:clearable="false"
:default-time="defaultTime"
:unlink-panels="true"
type="datetimerange"
@change="timeArrChange"
/>
<div class="content-title">From</div>
<div @click="myDatePickerShow" tabindex="1" class="content-input">
{{ dateFormatByAppearance(getMillisecond(myStartTime)) }}
</div>
<div class="content-title">{{$t('dateTime.to')}}</div>
<div class="content-title">To</div>
<div @click="myDatePickerShow" tabindex="2" class="content-input">
{{ dateFormatByAppearance(getMillisecond(myEndTime)) }}
</div>
<div class="date-range-title" style="padding-left: 0">{{$t('dateTime.recentlyUsedRanges')}}</div>
<div class="date-range-title" style="padding-left: 0">Recently used absolute ranges</div>
<div class="date-range-history">
<div v-for="(item, index) in rangeHistoryArr" :key="index" class="date-range-history-item"
@click="historyChange(item)">
@@ -55,7 +53,7 @@
:span="8"
class="date-range-panel-content date-range-panel-content-right"
style="border-left: 1px solid rgba(0,0,0,0.09);">
<div class="date-range-title">{{$t('dateTime.relativeTimeRanges')}}</div>
<div class="date-range-title">Relatime time ranges</div>
<ul class="date-range-item">
<li v-for="item in dateRangeArr"
@click="quickChange(item.value)"
@@ -81,12 +79,9 @@
<script>
import { ref, computed, watch, reactive } from 'vue'
import { EN, storageKey, ZH } from '@/utils/constants'
import { storageKey } from '@/utils/constants'
import { getMillisecond, millTimestampDiffFromTz, timestampToList } from '@/utils/date-util'
import { useStore } from 'vuex'
import ElConfigProvider from 'element-plus'
import cn from 'element-plus/lib/locale/lang/zh-cn'
import en from 'element-plus/lib/locale/lang/en'
export default {
name: 'DateTimeRange',
@@ -110,31 +105,6 @@ export default {
}
},
emits: ['change'],
data () {
return {
dateRangeArr: [
{ value: 5, name: this.$t('dateTime.last5Mins') }, // 'last 5 mins'
{ value: 15, name: this.$t('dateTime.last15Mins') },
{ value: 30, name: this.$t('dateTime.last30Mins') },
{ value: 60, name: this.$t('dateTime.last1Hour') }, // dateTime.last1Hour
{ value: 180, name: this.$t('dateTime.last3Hours') },
{ value: 360, name: this.$t('dateTime.last6Hours') },
{ value: 720, name: this.$t('dateTime.last12Hours') },
{ value: 1440, name: this.$t('dateTime.last1Day') }, // dateTime.last2Days
{ value: 2880, name: this.$t('dateTime.last2Days') }
]
}
},
computed: {
showDetail () {
let str = ''
if (this.dateRangeValue !== -1) {
const rangeItem = this.dateRangeArr.find(item => item.value === this.dateRangeValue)
str = rangeItem ? rangeItem.name : this.dateRangeArr[0].name
}
return str
}
},
setup (props, ctx) {
// data
const store = useStore()
@@ -154,12 +124,24 @@ export default {
const rangeHistory = ref(localStorage.getItem(storageKey.dataRangeHistory) ? JSON.parse(localStorage.getItem(storageKey.dataRangeHistory)) : [])
const dateRangeValue = props.dateRange ? ref(props.dateRange) : ref(60)
const isCustom = ref(dateRangeValue.value === -1)
const dateRangeArr = [
{ value: 5, name: 'last 5 mins' },
{ value: 15, name: 'last 15 mins' },
{ value: 30, name: 'last 30 mins' },
{ value: 60, name: 'last 1 hour' },
{ value: 180, name: 'last 3 hours' },
{ value: 360, name: 'last 6 hours' },
{ value: 720, name: 'last 12 hours' },
{ value: 1440, name: 'last 1 day' },
{ value: 2880, name: 'last 2 days' }
]
const dropdownFlag = ref(false)
// 默认日历选择时间即开始时间YYYY-MM-DD 00:00:00,结束时间YYYY-MM-DD 59:59:59
const defaultTime = ref([
new Date(2023, 1, 1, 0, 0, 0),
new Date(2023, 1, 2, 23, 59, 59)
])
// computed
const utcStr = computed(() => {
let str = 'UTC '
@@ -177,6 +159,13 @@ export default {
str += ':00 '
return str
})
const showDetail = computed(() => {
let str = ''
if (dateRangeValue.value !== -1) {
str = dateRangeArr.find(item => item.value === dateRangeValue.value).name
}
return str
})
const rangeHistoryArr = rangeHistory
// refs
@@ -300,12 +289,6 @@ export default {
})
}
}
const language = localStorage.getItem(storageKey.language) || EN // 初始未选择默认 en 英文
let locale = en
if (language === ZH) {
locale = cn
}
return {
myStartTime,
myEndTime,
@@ -314,11 +297,13 @@ export default {
utcStr,
rangeEchartsData,
address,
dateRangeArr,
defaultTime,
dateRangeValue,
isCustom,
newDateValue,
newDatePicker,
showDetail,
rangeHistory,
rangeHistoryArr,
getMillisecond,
@@ -328,8 +313,7 @@ export default {
timeArrChange,
returnValue,
quickChange,
historyChange,
locale
historyChange
}
}
}

View File

@@ -58,7 +58,7 @@
<script>
import axios from 'axios'
import { storageKey, EN } from '@/utils/constants'
import { storageKey } from '@/utils/constants'
export default {
name: 'TopToolMoreOptions',
@@ -108,7 +108,7 @@ export default {
if (this.paramsType) {
form.append('type', this.paramsType)
}
form.append('language', localStorage.getItem(storageKey.language) ? localStorage.getItem(storageKey.language) : EN)
form.append('language', localStorage.getItem(storageKey.language) ? localStorage.getItem(storageKey.language) : 'en')
axios.post(this.importUrl, form, { 'Content-Type': 'multipart/form-data' }).then(response => {
if (response.status === 200 && response.data.msg === 'success') {
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.importSuccess') })
@@ -128,7 +128,7 @@ export default {
this.importFile = null
},
downloadTemplate () {
const language = localStorage.getItem(storageKey.language) || EN // 初始未选择默认 en 英文
const language = localStorage.getItem(storageKey.language) || 'en' // 初始未选择默认 en 英文
const fileName = this.exportFileName + '-' + this.$t('overall.template') + '-' + this.getTimeString() + '.json'
let url = null
@@ -159,7 +159,7 @@ export default {
})
}
params.pageSize = -1
params.language = localStorage.getItem(storageKey.language) || EN
params.language = localStorage.getItem(storageKey.language) || 'en'
this.export(this.exportUrl, params, this.exportFileName + '-' + this.getTimeString() + '.json')
this.closeDialog()

View File

@@ -13,12 +13,12 @@
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<div id="header-to-english" :style="language === EN?'color:#0091ff':''" @click="changeLocal(EN)">
<div id="header-to-english" :style="language === 'en'?'color:#0091ff':''" @click="changeLocal('en')">
English
</div>
</el-dropdown-item>
<el-dropdown-item>
<div id="header-to-chinese" :style="language === ZH?'color:#0091ff':''" @click="changeLocal(ZH)">
<div id="header-to-chinese" :style="language === 'cn'?'color:#0091ff':''" @click="changeLocal('cn')">
中文
</div>
</el-dropdown-item>
@@ -42,11 +42,11 @@
</div>
<div class="cn-header__nav">
<i class="cn-icon cn-icon-a-NetworkAnalytics"></i>
<el-breadcrumb class="header__left-breadcrumb" separator=">" v-if="route.startsWith('/panel')">
<el-breadcrumb-item class="header__left-breadcrumb-item" :id="`breadcrumb${item.value}`" :title="index===3?item.value:''"
<el-breadcrumb class="header__left-breadcrumb" separator=">">
<el-breadcrumb-item class="header__left-breadcrumb-item" :id="`breadcrumb${item.value}`" :title="item.value"
v-for="(item,index) in breadcrumb" :key="item.value">
<template v-if="index===3" >
<div class="header__left-breadcrumb-item-select" >
<template v-if="index===3">
<div class="header__left-breadcrumb-item-select">
<el-popover placement="bottom-start"
ref="breadcrumbPopover"
:show-arrow="false"
@@ -113,13 +113,6 @@
</template>
</el-breadcrumb-item>
</el-breadcrumb>
<el-breadcrumb class="header__left-breadcrumb" separator=">" v-else>
<el-breadcrumb-item class="header__left-breadcrumb-item" :id="`breadcrumb${item.value}`"
v-for="(item,index) in breadcrumb" :key="item.value">
<span v-if="item.clickable" class="route-menu" @click="jumpOther(item.route,index)">{{ item.value }}</span>
<span v-else>{{ item.value }}</span>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<!-- 菜单 -->
@@ -203,9 +196,7 @@ import {
networkTable,
operationType,
storageKey,
wholeScreenRouterMapping,
ZH,
EN
wholeScreenRouterMapping
} from '@/utils/constants'
import { api } from '@/utils/api'
import { ref } from 'vue'
@@ -243,7 +234,7 @@ export default {
return {
username: localStorage.getItem(storageKey.username),
nickName: localStorage.getItem(storageKey.nickName),
language: localStorage.getItem(storageKey.language) ? localStorage.getItem(storageKey.language) : EN,
language: localStorage.getItem(storageKey.language) ? localStorage.getItem(storageKey.language) : 'en',
showChangePin: false,
from: '', // entity类型
changePassForm: {
@@ -305,9 +296,7 @@ export default {
curTabState: curTabState,
urlChangeParams: {},
wholeScreenRouterMapping,
logo: 'images/logo-header.svg',
ZH,
EN
logo: 'images/logo-header.svg'
}
},
computed: {
@@ -315,7 +304,7 @@ export default {
return this.$store.getters.menuList.find(menu => menu.code === 'networkAnalytics')
},
otherMenu () {
return this.$store.getters.menuList.filter(menu => ['networkAnalytics', 'I18N', 'entityDetail', 'entityGraph', 'detectionPolicy'].indexOf(menu.code) === -1)
return this.$store.getters.menuList.filter(menu => ['networkAnalytics', 'chart', 'I18N', 'entityDetail', 'temp', 'entityGraph', 'detectionPolicy'].indexOf(menu.code) === -1)
/* function excludeButton (menu) {
for (let i = 0; i < menu.length; i++) {
@@ -333,17 +322,15 @@ export default {
breadcrumb () {
const breadcrumb = []
this.generateBreadcrumb(breadcrumb, this.$store.getters.menuList)
if (breadcrumb) {
// panel菜单是否可以点击跳转一级菜单不可点击二级菜单可以点击
if (breadcrumb[0] && breadcrumb[1] && breadcrumb[1].route &&
breadcrumb[1].route.indexOf('/panel/') === 0) {
breadcrumb[1].clickable = true
} else { // 除panel外的菜单是否可以点击跳转:除了新增、编辑,其它均可点击
breadcrumb.forEach(item => {
if (item.value !== 'Create' && item.value !== 'Edit') {
item.clickable = true
}
})
// 写死一级和二级菜单是否可以点击跳转
if (breadcrumb[0]) {
if (['knowledgeBase'].indexOf(breadcrumb[0].code) > -1) {
breadcrumb[0].clickable = true
}
if (breadcrumb[1]) {
if (breadcrumb[1].route && breadcrumb[1].route.indexOf('/panel/') === 0) {
breadcrumb[1].clickable = true
}
}
}
@@ -379,7 +366,7 @@ export default {
},
async breadcrumb (n) {
this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
if (this.$route.path.replace('/panel/', '') === fromRoute.dnsServiceInsights) {
if (this.$route.params.typeName === fromRoute.dnsServiceInsights) {
if (this.dnsQtypeMapData.size === 0) {
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
}
@@ -397,7 +384,7 @@ export default {
async mounted () {
this.from = Object.keys(this.entityType)[0]
// 是否需要dns的qtype和rcode的数据字典
if (this.$route.path.replace('/panel/', '') === fromRoute.dnsServiceInsights) {
if (this.$route.params.typeName === fromRoute.dnsServiceInsights) {
if (this.dnsQtypeMapData.size === 0) {
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
}
@@ -418,10 +405,10 @@ export default {
const endTimeParam = query.endTime
// 若url携带了使用携带的值否则使用默认值。
const dateRangeValue = rangeParam ? parseInt(rangeParam) : 60
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
const chartTimeFilter = ref({ dateRangeValue })
if (!startTimeParam || !endTimeParam) {
const { startTime, endTime } = getNowTime(dateRangeValue)
const { startTime, endTime } = getNowTime(60)
chartTimeFilter.value.startTime = startTime
chartTimeFilter.value.endTime = endTime
} else {
@@ -436,6 +423,39 @@ export default {
},
methods: {
generateBreadcrumb (breadcrumb, menus) {
if (this.route === '/entityDetail') {
const entityMenu = menus.find(m => m.route === '/entity')
const entityDetailMenu = menus.find(m => m.route === '/entityDetail')
breadcrumb.push({
code: entityMenu.code,
value: entityMenu.i18n ? this.$t(entityMenu.i18n) : entityMenu.name,
route: entityMenu.route,
type: entityMenu.type
})
breadcrumb.push({
code: entityDetailMenu.code,
value: entityDetailMenu.i18n ? this.$t(entityDetailMenu.i18n) : entityDetailMenu.name,
route: entityDetailMenu.route,
type: entityDetailMenu.type
})
return true
} else if (this.route === '/entityGraph') {
const entityMenu = menus.find(m => m.route === '/entity')
const entityGraphMenu = menus.find(m => m.route === '/entityGraph')
breadcrumb.push({
code: entityMenu.code,
value: entityMenu.i18n ? this.$t(entityMenu.i18n) : entityMenu.name,
route: entityMenu.route,
type: entityMenu.type
})
breadcrumb.push({
code: entityGraphMenu.code,
value: entityGraphMenu.i18n ? this.$t(entityGraphMenu.i18n) : entityGraphMenu.name,
route: entityGraphMenu.route,
type: entityGraphMenu.type
})
return true
}
const menu = menus.find(m => m.route === this.route)
if (menu) {
breadcrumb.unshift({
@@ -487,7 +507,7 @@ export default {
},
getCurTabByLabel (label) {
let curTab = null
const tableType = this.$route.path.replace('/panel/', '') || 'networkOverview'
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const curTableInCode = networkTable[tableType] ? networkTable[tableType] : networkTable.networkOverview
if (curTableInCode && curTableInCode.tabList) {
curTab = curTableInCode.tabList.find(item => item.label === label)
@@ -500,7 +520,7 @@ export default {
const currentValue = document.getElementById('breadcrumbValue') ? document.getElementById('breadcrumbValue').innerText : ''
const columnName = this.getUrlParam(this.curTabState.thirdMenu, '')
let type = 'ip'
const tableType = this.$route.path.replace('/panel/', '') || 'networkOverview'
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const curTableInCode = networkTable[tableType] ? networkTable[tableType] : networkTable.networkOverview
if (curTableInCode && curTableInCode.tabList) {
const curTab = curTableInCode.tabList.find(item => item.label === columnName)
@@ -524,7 +544,7 @@ export default {
axios.get(curTableInCode.url.drilldownList, { params }).then(async response => {
if (response.status === 200) {
this.breadcrumbColumnValueListShow = response.data.data.result
if (this.$route.path.replace('/panel/', '') === fromRoute.dnsServiceInsights) {
if (this.$route.params.typeName === fromRoute.dnsServiceInsights) {
if (this.dnsQtypeMapData.size === 0) {
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
}
@@ -655,7 +675,7 @@ export default {
},
async handleCurDrilldownTableConfig (thirdMenu) {
// const userId = localStorage.getItem(storageKey.userId)
const tableType = this.$route.path.replace('/panel/', '') || 'networkOverview'
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const metric = this.getUrlParam(this.curTabState.tableMetric, 'Bits/s')
const drillDownTableConfigs = await combineDrilldownTableWithUserConfig()
const currentTableConfig = drillDownTableConfigs.find(config => config.route === tableType)
@@ -676,26 +696,7 @@ export default {
}
}
},
// 仅处理除panel外的相关路径的导航
async jumpOther (route, index) {
route = route.replace('redirect:', '')
this.showMenu = false
if (route === this.route && index > 0) { // 当前只有一级菜单时,点击不进行刷新,重新跳转
this.refresh()
return
}
if (route) {
this.$router.push({
path: route,
query: {
t: +new Date()
}
})
}
},
// 仅处理panel相关路径的导航
async jump (route, columnName, columnValue, opeType) {
route = route.replace('redirect:', '')
if (route === '/panel/linkMonitor' && opeType === 3) {
return true
}
@@ -715,7 +716,7 @@ export default {
this.$store.commit('setNetworkOverviewTabList', [])
}
// 清空网络概况的特殊面包屑
const tableType = this.$route.path.replace('/panel/', '') || 'networkOverview'
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const metric = this.getUrlParam(this.curTabState.tableMetric, 'Bits/s')
const curTab = await getDefaultCurTab(tableType, metric, columnName)
this.$store.getters.menuList.forEach(menu => {
@@ -727,6 +728,11 @@ export default {
child.columnName = columnName
this.urlChangeParams[this.curTabState.thirdMenu] = columnName
this.urlChangeParams[this.curTabState.fourthMenu] = columnValue
// const tabObjGroup = networkOverviewTabList.filter(item => item.label == columnName)
// let curTab = this.getCurTabByLabel()
// const type = curTab ? curTab.prop : ''
// this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
// this.urlChangeParams[this.curTabState.dimensionType] = type
this.urlChangeParams[this.curTabState.panelName] = columnValue
} else if (columnName) { // 点击的为列名
child.columnValue = ''

View File

@@ -23,8 +23,7 @@
<button type="button" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new option-btn" style="margin-left: 0px;" @click="expandAllOrNone" :class="{'btn-active':expandAllFlag}">展开/收缩</button>
<button type="button" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new option-btn" @click="selectAllOrNone" :class="{'btn-active':selectAllFlag}"><span ><i class="cn-icon cn-icon-delete"></i></span></button>
</div>-->
<el-checkbox v-model="isCheckAll" :label="$t('overall.all')" @change="checkAll"></el-checkbox>
<el-tree :data="menus" :default-expand-all="expandAllFlag" check-strictly="true" :props="{label:labelFormatter}" @check-change="selectChange" class="tree-border" node-key="id" ref="menuTree" show-checkbox id="role-box-input-menus">
<el-tree :data="menus" :default-expand-all="expandAllFlag" :props="{label:labelFormatter}" @check-change="selectChange" class="tree-border" node-key="id" ref="menuTree" show-checkbox id="role-box-input-menus">
<template #default="{ data }">
<span>
<i v-if="data.type === '1'" class="el-icon-menu"></i>
@@ -91,8 +90,7 @@ export default {
menus: [],
selectedIds: [],
selectAllFlag: false,
expandAllFlag: true,
isCheckAll: false
expandAllFlag: true
}
},
watch: {
@@ -152,59 +150,9 @@ export default {
labelFormatter: function (data, node) {
return data && data.i18n ? this.$t(data.i18n) : data.name
},
getChildNodes (menu) {
let nodeGroup = []
if (menu.children && menu.children.length > 0) {
nodeGroup = menu.children
const _this = this
menu.children.forEach(node => {
const childNodes = _this.getChildNodes(node)
if (childNodes && childNodes.length > 0) {
nodeGroup = nodeGroup.concat(childNodes)
}
})
}
return nodeGroup
},
checkAll () {
if (this.$refs.menuTree) {
if (this.isCheckAll) {
let nodeGroup = this.menus
const _this = this
this.menus.forEach(menu => {
const childNodes = _this.getChildNodes(menu)
if (childNodes && childNodes.length > 0) {
nodeGroup = nodeGroup.concat(childNodes)
}
})
this.$refs.menuTree.setCheckedNodes(nodeGroup)
} else {
this.$refs.menuTree.setCheckedNodes([])
}
}
},
checkParentNode(node) {
if(node && this.$refs.menuTree.getNode(node)){
let parent = this.$refs.menuTree.getNode(node).parent
let parentNode = parent.data
if(parentNode && parentNode.id && parentNode.id !== 0 ){
this.$refs.menuTree.setChecked(parentNode,true,false)
this.checkParentNode(parentNode)
}
}
},
selectChange: function (data, isCheck, childIsCheck) {
if(isCheck) {//如果是选中节点,则同步选中所有的父辈节点(有全选和半选两种状态)
this.checkParentNode(data)
} else {//如果是取消节点,则同步取消选中所有子节点
if(data.children && data.children.length > 0) {
data.children.forEach(node => {
this.$refs.menuTree.setChecked(node, false, true)
})
}
}
if (this.$refs.menuTree) {
this.editRole.menuIds = this.$refs.menuTree.getCheckedKeys(false)
this.editRole.menuIds = this.$refs.menuTree.getCheckedKeys(true)
}
},
selectAllOrNone: function () {

View File

@@ -125,16 +125,16 @@ export default {
mixins: [rightBoxMixin],
data () {
const validatePin = (rule, value, callback) => { // 确认密码
if (value && value.length < 5) {
if (value.length < 5) {
callback(new Error(this.$t('validate.atLeastFive')))
} else {
callback()
}
}
const validateConfirmPin = (rule, value, callback) => { // 确认密码的二次校验
if (_.isEmpty(value) && !_.isEmpty(this.editObject.pin)) {//密码有内容,确认密码没内容
if (value === '' && this.editObject.pin) {
callback(new Error(this.$t('config.user.confirmPin')))
} else if (!_.isEmpty(value) && value !== this.editObject.pin) {//密码有内容,确认密码也有内容,内容不一致
} else if (value !== this.editObject.pin) {
callback(new Error(this.$t('config.user.confirmPinErr')))
} else {
callback()
@@ -207,7 +207,7 @@ export default {
],
pinChange: [
{ validator: validateConfirmPin, trigger: 'blur' },
{ validator: validatePin, trigger: 'blur' }
{ pattern: /^[a-zA-Z0-9]{5,64}$/, message: this.$t('validate.atLeastFive') }
],
roleIds: [
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }

View File

@@ -52,17 +52,13 @@
</template>
<template v-else-if="item.prop === 'status'">
<el-switch
v-if="scope.row.id && hasPermission('editUser')"
v-if="scope.row.id"
v-model="scope.row.status"
active-value="1"
:disabled="(scope.row.username === loginName) || (scope.row.username==='admin' && scope.row.id===1) || scope.row.buildIn === 1"
inactive-value="0"
@change="()=>{statusChange(scope.row)}">
</el-switch>
<template v-else>
<span v-if="scope.row.status === '1'">{{$t('detection.create.enabled')}}</span>
<span v-else>{{$t('detection.create.disabled')}}</span>
</template>
</template>
<span v-else>{{scope.row[item.prop] || '-'}}</span>
</template>

View File

@@ -11,7 +11,7 @@
<div class="block-mode-title">{{ $t('detection.policy.indicatorMatch') }}</div>
<div class="block-mode-content">
{{ $t('detection.policy.indicatorMatchIntroduce') }}
<div v-if="language===ZH" style="color: rgba(0,0,0,0)">0</div>
<div v-if="language==='cn'" style="color: rgba(0,0,0,0)">0</div>
</div>
<div :class="settingObj.ruleType===detectionRuleType.indicator?'block-mode-btn-active':'block-mode-btn'"
@click="selectMode(detectionRuleType.indicator)">{{ $t('overall.select') }}
@@ -109,7 +109,7 @@
</template>
<script>
import { detectionRuleType, storageKey, detectionUnitList, ZH, EN } from '@/utils/constants'
import { detectionRuleType, storageKey, detectionUnitList } from '@/utils/constants'
import { switchStatus } from '@/utils/tools'
export default {
@@ -160,8 +160,7 @@ export default {
}
]
},
language: EN,
ZH
language: 'en'
}
},
watch: {
@@ -184,7 +183,7 @@ export default {
methods: {
switchStatus,
initData () {
this.language = localStorage.getItem(storageKey.language) || EN
this.language = localStorage.getItem(storageKey.language) || 'en'
this.categoryList = detectionUnitList.categoryList
this.eventTypeList = detectionUnitList.eventTypeList
},

View File

@@ -61,7 +61,7 @@
<div class="reference-tag__group">
<span class="reference-tag" v-for="(refer, index) in scope.row[item.prop].slice(0,2)" >{{refer}}</span>
</div>
<div class="reference-more">+{{scope.row[item.prop].length - 2}} {{$t('overall.more')}}</div>
<div class="reference-more">+{{scope.row[item.prop].length - 2}} more</div>
</div>
</template>
<div class="reference-tag__tip">
@@ -70,11 +70,9 @@
</el-popover>
</templage>
<template v-else>
<div class="reference-tag__show">
<div class="reference-tag__group">
<span class="reference-tag" v-for="(refer, index) in scope.row[item.prop]" >{{refer}}</span>
</div>
</div>
<template v-for="(refer, index) in scope.row[item.prop]">
<div class="type-tag">{{refer}}</div>
</template>
</template>
</template>
<template v-else-if="item.prop === 'opTime' || item.prop === 'ctime'">
@@ -98,7 +96,6 @@
</template>
<template v-else-if="item.prop === 'status'">
<el-switch v-model="scope.row.status"
v-if="hasPermission('editUserDefinedLibrary')"
active-color="#38ACD2"
inactive-color="#C0CEDB"
:active-value="1"
@@ -106,10 +103,6 @@
@change="changeStatus($event,scope.row.knowledgeId)"
>
</el-switch>
<template v-else>
<span v-if="scope.row.status === 1">{{$t('detection.create.enabled')}}</span>
<span v-else>{{$t('detection.create.disabled')}}</span>
</template>
</template>
<template v-else-if="item.prop === 'color'">
<div class="knowledge-color">
@@ -163,7 +156,7 @@ export default {
}, {
label: this.$t('knowledge.reference'),
prop: 'reference',
width: 190,
width: 180,
show: true
}, {
label: this.$t('overall.color'),

View File

@@ -7,7 +7,6 @@
<div class="card-content">
<div class="card-operate">
<el-switch v-model="data.status"
v-if="hasPermission('editBuiltInKnowledgeBase')"
class="card-enable"
active-color="#38ACD2"
inactive-color="#C0CEDB"
@@ -21,12 +20,12 @@
<img :src="data.iconUrl"/>
</div>
<div class="card-title">
<div class="card-title-name" :title="$t(data.label)">{{$t(data.label)}}</div>
<div class="card-title-name" :title="data.label">{{data.label}}</div>
</div>
<div class="card-desc" :title="$t(data.desc)">{{$t(data.desc) || '—'}}</div>
<div class="card-desc" :title="data.desc">{{data.desc ? data.desc : '—'}}</div>
</div>
<div class="card-operate__footer">
<button v-if="data.showUpdate && hasPermission('editBuiltInKnowledgeBase')"
<button v-if="data.showUpdate"
class="top-tool-btn--update"
@click="jumpToUpdatePage(data,true)">
<i class="cn-icon-update-knowledge-base cn-icon"></i>
@@ -45,12 +44,12 @@
<img :src="data.iconUrl"/>
</div>
<div class="card-title">
<div class="card-title-name" :title="$t(data.label)">{{$t(data.label)}}</div>
<div class="card-title-name" :title="data.label">{{data.label}}</div>
</div>
<div class="card-desc" :title="data.desc ? $t(data.desc) : '—'">{{data.desc ? $t(data.desc) : '—'}}</div>
<div class="card-desc" :title="data.desc ? data.desc:'—'">{{data.desc ? data.desc : '—'}}</div>
</div>
<div class="card-operate__footer">
<button v-if="data.showUpdate && hasPermission('editBuiltInKnowledgeBase')" :title="$t('overall.update')" class="top-tool-btn--update"
<button v-if="data.showUpdate" :title="$t('overall.update')" class="top-tool-btn--update"
@click="jumpToUpdatePage(data,false)">
<i class="cn-icon-update-knowledge-base cn-icon"></i>
<span>{{$t('overall.update')}}</span>
@@ -78,7 +77,7 @@
<div class="update-right">
<div class="knowledge-enable">
<div class="update-title">
<div class="card-title-name" :title="$t(updateKnowledge.label)">{{$t(updateKnowledge.label)}}</div>
<div class="card-title-name" :title="updateKnowledge.label">{{updateKnowledge.label}}</div>
</div>
<el-switch v-model="updateKnowledge.status"
active-color="#38ACD2"
@@ -86,11 +85,11 @@
:active-value="1"
:inactive-value="0"
:before-change="(knowledgeId) => confirmSwitchLearning(updateKnowledge.knowledgeId)"
v-if="updateKnowledge.source === 'cn_psiphon3_ip' && hasPermission('editBuiltInKnowledgeBase')"
v-if="updateKnowledge.source === 'cn_psiphon3_ip'"
>
</el-switch>
</div>
<div class="knowledge-desc" :title="updateKnowledge.desc ? $t(updateKnowledge.desc) : '-'">{{updateKnowledge.desc ? $t(updateKnowledge.desc) : '-'}}</div>
<div class="knowledge-desc" :title="updateKnowledge.desc">{{updateKnowledge.desc ? updateKnowledge.desc : ''}}</div>
</div>
</div>
<template v-if="!showAddUpdateDialog">
@@ -112,7 +111,7 @@
</el-tabs>
<div class="update-operate">
<button :title="$t('overall.update')" class="top-tool-btn--update"
@click="uploadRecord"><!--:disabled="hasUpdatingRecord"-->
@click="uploadRecord">
<i class="cn-icon-update-knowledge-base cn-icon"></i>
<span>{{$t('overall.update')}}</span>
</button>
@@ -124,7 +123,7 @@
</div>
<div class="update-operate">
<button :title="$t('overall.update')" class="top-tool-btn--update"
@click="uploadRecord"><!-- :disabled="hasUpdatingRecord" -->
@click="uploadRecord">
<i class="cn-icon-update-knowledge-base cn-icon"></i>
<span>{{$t('overall.update')}}</span>
</button>
@@ -151,7 +150,7 @@
<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="updateKnowledge.source !== 'cn_psiphon3_ip' || activeTab === 'updateRecord'">
<el-table-column prop="user" :label="$t('knowledgeBase.operator')" width="150" v-if="activeTab === 'updateRecord'">
<template #default="scope" :column="item">
<span>{{$_.get(scope.row, 'user.name', '-')}}</span>
</template>
@@ -257,7 +256,7 @@
</el-form>
</div>
<div class="dialog-footer">
<el-button @click="cancle">{{ $t('overall.cancel') }}</el-button>
<el-button @click="showAddUpdateDialog = false">{{ $t('overall.cancel') }}</el-button>
<el-button type="primary" @click="submitConfirm">{{ $t('tip.confirm') }}</el-button>
</div>
</template>
@@ -284,8 +283,8 @@
<div class="dialog-message">{{ confirmSwitchLearningTip }}</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="cancleSwitch">{{ $t('overall.cancel') }}</el-button>
<el-button type="primary" @click="switchLearning">{{$t('tip.confirm')}}</el-button>
<el-button @click="showConfirmSwitch = false">{{ $t('overall.cancel') }}</el-button>
<el-button type="primary" @click="switchLearning">OK</el-button>
</span>
</template>
</el-dialog>
@@ -296,7 +295,7 @@
import table from '@/mixins/table'
import Loading from '@/components/common/Loading'
import { getSecond, getMillisecond, xAxisTimeFormatter, xAxisTimeRich } from '@/utils/date-util'
import { knowledgeCategoryValue, unitTypes, storageKey, builtInKnowledgeBaseBasicInfo, knowledgeCardUpdateRecordType } from '@/utils/constants'
import { knowledgeCategoryValue, unitTypes, storageKey, builtInKnowledgeBaseBasicInfo } from '@/utils/constants'
import { ref, shallowRef } from 'vue'
import { api } from '@/utils/api'
import { detectionTooltipFormatter } from '@/views/charts/charts/tools'
@@ -340,7 +339,6 @@ export default {
psiphon3Loading: false,
updateLogLoading: false,
showConfirmSwitch: false,
// timer: null,
switchKnowledgeId: '',
activeTab: 'updateRecord',
isNoDataForPsiphon3: false,
@@ -350,7 +348,6 @@ export default {
tabType: 'total',
mousemoveCursor: '',
selectTime: 1440,
// hasUpdatingRecord: false,
tabs: [
{
name: 'knowledgeBase.total',
@@ -383,6 +380,12 @@ export default {
setup () {
// 没上传过文件的提示
const uploadErrorTip = ref('')
const nowMill = window.$dayJs.tz().valueOf()
const timeFilter = ref({
startTime: nowMill - 1000 * 60 * 60 * 24,
endTime: nowMill,
dateRangeValue: 1440
})
return {
baseUrl: BASE_CONFIG.baseUrl,
apiVersion: BASE_CONFIG.apiVersion,
@@ -394,7 +397,8 @@ export default {
fileList: ref([]),
uploadFileSizeLimit: 1024 * 1024 * 1024,
myChart: shallowRef(null),
chartOption: shallowRef(null)
chartOption: shallowRef(null),
timeFilter
}
},
methods: {
@@ -423,6 +427,7 @@ export default {
},
xAxis: {
type: 'time',
boundaryGap: ['1%', '3%'],
axisLine: {
show: false
},
@@ -466,10 +471,9 @@ export default {
},
init (val, show, active, n) {
this.psiphon3Loading = true
const endTime = window.$dayJs.tz().valueOf()
const params = {
startTime: getSecond(endTime - this.selectTime * 60 * 1000),
endTime: getSecond(endTime)
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
const url = api.knowledgeBaseTimedistribution.replace('{{knowledgeId}}', this.updateKnowledge.knowledgeId).replace('{{type}}', this.tabType)
axios.get(url, { params: params }).then(response => {
@@ -482,9 +486,7 @@ export default {
const chartsData = res.data.result.map(item => {
return [getMillisecond(item.statTime), item.count]
})
if (this.activeTab === knowledgeCardUpdateRecordType.intelligenceLearning) {
this.echartsInit(chartsData)
}
this.echartsInit(chartsData)
}
} else {
this.httpError(res)
@@ -532,14 +534,14 @@ export default {
})
},
timeChange () {
this.timeFilter.endTime = window.$dayJs.tz().valueOf()
this.timeFilter.startTime = this.timeFilter.endTime - this.selectTime * 60 * 1000
if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
this.init()
}
if (this.activeTab === knowledgeCardUpdateRecordType.intelligenceLearning) {
this.$nextTick(() => {
this.handleActiveBar()
})
}
this.$nextTick(() => {
this.handleActiveBar()
})
},
activeChange (item) { // isClick:代表是通过点击操作来的
if (item) {
@@ -553,11 +555,9 @@ export default {
mouseenterTab (item) {
if (this.isNoDataForPsiphon3) return
this.mousemoveCursor = item.class
if (this.activeTab === knowledgeCardUpdateRecordType.intelligenceLearning) {
this.$nextTick(() => {
this.handleActiveBar()
})
}
this.$nextTick(() => {
this.handleActiveBar()
})
},
mouseleaveTab () {
this.mousemoveCursor = ''
@@ -587,9 +587,17 @@ export default {
uploadSuccess (response) {
this.uploadLoading = false
this.uploaded = true
/* this.uploaded = response.code === 200
if (response.code === 200) { */
this.$message.success(this.$t('tip.success'))
this.showAddUpdateDialog = false
this.getCurTabData()
if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
this.init()
}
/* } else {
this.$message.error(this.$t('tip.uploadFailed', { msg: response.message }))
} */
},
beforeUpload (file) {
this.uploadLoading = true
@@ -601,9 +609,6 @@ export default {
submit () {
this.$refs.knowledgeUpload.submit()
},
cancle () {
this.showAddUpdateDialog = false
},
clickCard (data, event) {
if (data.isSelected) { // 原来为选中,当前点击后未选中
const index = this.checkList.indexOf(data)
@@ -654,11 +659,9 @@ export default {
await this.init()
}
this.showUpdate()
if (this.activeTab === knowledgeCardUpdateRecordType.intelligenceLearning) {
this.$nextTick(() => {
this.handleActiveBar()
})
}
this.$nextTick(() => {
this.handleActiveBar()
})
},
uploadRecord () {
this.showAddUpdateDialog = true
@@ -671,12 +674,12 @@ export default {
pageSize: -1
}
if (this.showEnable) {
if (this.activeTab === knowledgeCardUpdateRecordType.updateRecord) {
if (this.activeTab === 'updateRecord') {
params = {
...params,
opUser: -1
}
} else if (this.activeTab === knowledgeCardUpdateRecordType.intelligenceLearning) {
} else if (this.activeTab === 'intelligenceLearning') {
params = {
...params,
opUser: 0
@@ -690,15 +693,6 @@ export default {
if (this.updateHistoryList[0]) {
this.currentVersion = this.updateHistoryList[0].commitVersion + 1
}
/*
this.hasUpdatingRecord = false
this.updateHistoryList.forEach(item => {
if (item.isUpdating) { // if(item.isUpdating){//????????
this.hasUpdatingRecord = true
}
})
*/
}).catch(e => {
console.error(e)
}).finally(() => {
@@ -709,7 +703,7 @@ export default {
handleClick (tab) {
this.getCurTabData()
if (tab.index === '1') {
this.timeChange()
this.init()
}
},
clearSelect () {
@@ -749,9 +743,6 @@ export default {
this.switchKnowledgeId = id
return false
},
cancleSwitch () {
this.showConfirmSwitch = false
},
switchLearning () {
const hint = this.aiTaggingList.find(d => d.knowledgeId === this.switchKnowledgeId)
const toStatus = hint.status === 0 ? 1 : 0
@@ -774,19 +765,20 @@ export default {
},
watch: {
tabType (n) {
this.timeChange()
this.$nextTick(() => {
this.handleActiveBar()
})
},
/*
hasUpdatingRecord (n) {
if (n) { // update record页存在“正在更新”的记录时每20秒自动请求一次接口
this.timer = setTimeout(() => {
this.getCurTabData()
}, 20000)
} else { // 直到出现新的记录,出现新记录后(失败或者成功),取消定时请求接口,右上角"update"按钮恢复可用。"正在更新"和"失败都会有对应的强调样式
clearTimeout(this.timer)
timeFilter: {
handler () {
if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
this.init()
}
this.$nextTick(() => {
this.handleActiveBar()
})
}
},
*/
tableData: {
handler (n) {
if (this.tableData && this.tableData.length > 0) {
@@ -822,7 +814,9 @@ export default {
handler (n) {
if (!n) {
this.fileList = []
this.timeChange()
if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
this.init()
}
} else {
if (this.myChart) {
this.myChart.dispose()
@@ -849,7 +843,7 @@ export default {
})
},
beforeUnmount () {
//clearTimeout(this.timer)
clearTimeout(this.timer)
window.removeEventListener('resize', this.resize)
const dom = document.getElementById('psiphonBarChart')
if (dom) {

View File

@@ -1,10 +1,10 @@
import { createI18n } from 'vue-i18n/index'
import { storageKey, EN } from '@/utils/constants'
import { storageKey } from '@/utils/constants'
import { getI18n } from '@/utils/api'
import store from '@/store'
const i18n = createI18n({
locale: localStorage.getItem(storageKey.language) || EN
locale: localStorage.getItem(storageKey.language) || 'en'
})
export async function loadI18n () {
if (!store.state.i18n) {

View File

@@ -5,8 +5,9 @@ import router from '@/router'
import store from '@/store'
import App from '@/App.vue'
import '@/utils/http.js'
import { hasPermission } from '@/permission'
import commonMixin from '@/mixins/common'
import { cancelWithChange, noData, myHighLight } from '@/utils/tools'
import { cancelWithChange, noData } from '@/utils/tools'
import { ClickOutside } from 'element-plus/lib/directives'
import i18n from '@/i18n'
// import '@/mock/index.js'
@@ -36,10 +37,10 @@ app.use(i18n)
app.use(hljsVuePlugin)
app.use(VueGridLayout)
app.directive('has', hasPermission) // 注册指令
app.directive('ele-click-outside', ClickOutside)
app.directive('cancel', cancelWithChange)
app.directive('no-data', noData)
app.directive('high-light', myHighLight)
app.config.globalProperties.$_ = _
app.mixin(commonMixin)

View File

@@ -1,4 +1,4 @@
import { hasPermission } from '@/permission'
import { hasButton } from '@/permission'
import { dateFormatByAppearance } from '@/utils/date-util'
import { commonErrorTip } from '@/utils/constants'
export default {
@@ -28,7 +28,9 @@ export default {
}
},
methods: {
hasPermission,
hasButton (code) {
return hasButton(this.$store.getters.buttonList, code)
},
errorMsgHandler (axiosError) {
if (axiosError.response) {
if (axiosError.response.data) {

View File

@@ -17,7 +17,7 @@ export default {
// 请求数据 relationshipUrlOne => 路由 refOne => ref
getRelatedServerDataOne (relationshipUrlOne, refOne) {
this.loadingRelationshipOne = true
axios.get(relationshipUrlOne, { params: this.getQueryParams(DEFAULT_TIME_FILTER_RANGE.entity.relatedEntity) }).then(response => {
axios.get(relationshipUrlOne, { params: this.getQueryParams() }).then(response => {
if (response.status === 200) {
const relationshipDataOne = []
if (response.data.data.result.length > 0) {
@@ -33,7 +33,7 @@ export default {
},
getRelatedServerDataTwo (relationshipUrlTow, refTow) {
this.loadingRelationshipTwo = true
axios.get(relationshipUrlTow, { params: this.getQueryParams(DEFAULT_TIME_FILTER_RANGE.entity.relatedEntity) }).then(response => {
axios.get(relationshipUrlTow, { params: this.getQueryParams() }).then(response => {
if (response.status === 200) {
const relationshipDataTwo = []
if (response.data.data.result.length > 0) {

View File

@@ -1,4 +1,4 @@
import { chartTableOrderOptionsMapping, storageKey, knowledgeCategoryValue, ZH } from '@/utils/constants'
import { chartTableOrderOptionsMapping, storageKey, knowledgeCategoryValue } from '@/utils/constants'
import { getWidthByLanguage } from '@/utils/tools'
import { api } from '@/utils/api'
import axios from 'axios'
@@ -58,7 +58,7 @@ export default {
const language = localStorage.getItem(storageKey.language)
// 文字所占宽度一个英文字母占7px中文16px
let num = getWidthByLanguage(language) || 7
if (language !== ZH) {
if (language !== 'cn') {
num = num + 1 // 最后一位加空格
}

View File

@@ -32,19 +32,14 @@ router.beforeEach(async (to, from, next) => {
store.commit('setMenuList', menuList)
store.commit('setButtonList', buttonList)
store.commit('setRoleList', roleList)
const homeRoute = {
path: '/',
name: 'home',
component: () => import('@/components/layout/Home'),
children: []
}
handleRoutes(menuList, homeRoute.children)
router.addRoute(homeRoute)
next({ ...to, replace: true })
} else {
if (to.path) {
}
if (to.path) {
next()
/* if (hasMenu(store.getters.menuList, to.path)) {
next()
}
} else {
ElMessage.error('No access') // TODO 国际化
} */
}
}
} else {
@@ -65,14 +60,14 @@ router.beforeEach(async (to, from, next) => {
}
})
// menuList中是否包含code
export function hasMenu (menuList, code) {
// menuList中是否包含route权限
export function hasMenu (menuList, route) {
return menuList.some(menu => {
if (menu.code === code) {
if (menu.route === route) {
return true
} else {
if (menu.children) {
if (hasMenu(menu.children, code)) {
if (hasMenu(menu.children, route)) {
return true
}
}
@@ -101,9 +96,36 @@ export function hasButton (buttonList, code) {
return buttonList.some(button => button === code)
}
// 根据code从menuList和buttonList中判断是否有权限
export function hasPermission (code) {
return hasButton(store.getters.buttonList, code) || hasMenu(store.getters.menuList, code)
// 用法 v-has="code" | v-has="[code...]" 任意匹配一个 | v-has:all="[code...]" 全匹配
export const hasPermission = {
beforeMount (el, binding) {
// 节点权限处理
const buttonCode = binding.value
const arg = binding.arg
if (buttonCode) {
if (buttonCode instanceof Array) {
let has = true
if (arg && arg === 'all') { // 全匹配
buttonCode.forEach(button => {
if (has) {
has = hasButton(store.getters.buttonList, button)
}
})
} else { // 任意匹配
has = buttonCode.some(button => {
return hasButton(store.getters.buttonList, button)
})
}
if (!has) {
el.parentNode.removeChild(el)
}
} else { // 单个匹配
if (!hasButton(store.getters.buttonList, buttonCode)) {
el.parentNode && el.parentNode.removeChild(el)
}
}
}
}
}
// 根据orderNum排序
@@ -138,100 +160,3 @@ export function getWelcomeMenu (menu) {
}
}
}
export function handleComponent (code) {
switch (code) {
case 'networkOverview':
case 'networkAppPerformance':
case 'dnsServiceInsights':
case 'linkMonitor':
return () => import('@/views/charts2/Panel')
case 'entity':
return () => import('@/views/entityExplorer/EntityExplorer')
case 'entityDetail':
return () => import('@/views/entityExplorer/EntityDetail')
case 'entityGraph':
return () => import('@/views/entityExplorer/EntityGraph')
case 'securityEvents':
case 'performanceEvents':
return () => import('@/views/detections/Index')
case 'detectionPolicy':
return () => import('@/views/detections/detectionPolicies/Index')
case 'createDetectionPolicy':
case 'editDetectionPolicy':
return () => import('@/views/detections/detectionPolicies/PolicyForm')
case 'report':
return () => import('@/views/report/Report')
case 'knowledgeBase':
return () => import('@/views/setting/KnowledgeBase')
case 'userDefinedLibrary':
return () => import('@/views/setting/KnowledgeBaseUserDefinedList')
case 'createUserDefinedLibrary':
case 'editUserDefinedLibrary':
return () => import('@/views/setting/KnowledgeBaseForm')
case 'administration':
return () => import('@/views/administration/Index')
case 'user':
return () => import('@/views/administration/User')
case 'role':
return () => import('@/views/administration/Roles')
case 'operationLog':
return () => import('@/views/administration/OperationLog')
case 'appearance':
return () => import('@/views/administration/Appearance')
case 'I18N':
return () => import('@/views/administration/I18n')
default:
return null
}
}
export function handleRoutes (menus, routes) {
menus.forEach(menu => {
if (menu.route === '' && (!menu.children || menu.children.length < 0)) {
return false
}
// administration的路由使用了嵌套其他的是平铺
if (menu.pid === 0 && menu.code === 'administration') {
const path = menu.route.replace('redirect:', '')
if (menu.children && menu.children.length > 0) {
const route = {
name: menu.name,
path,
redirect: menu.children[0].route,
component: handleComponent(menu.code),
children: []
}
menu.children.forEach(c => {
route.children.push({
name: c.name,
path: c.route,
component: handleComponent(c.code)
})
})
routes.push(route)
}
} else {
if (menu.route && menu.route.startsWith('redirect:')) {
const path = menu.route.replace('redirect:', '')
if (menu.children && menu.children.length > 0) {
routes.push({
name: menu.name,
path,
redirect: menu.children[0].route
})
handleRoutes(menu.children, routes)
}
} else {
routes.push({
name: menu.code,
path: menu.route,
component: handleComponent(menu.code)
})
}
if (menu.children && menu.children.length > 0) {
handleRoutes(menu.children, routes)
}
}
})
}

View File

@@ -5,6 +5,106 @@ const routes = [
{
path: '/login',
component: () => import('@/Login')
},
{
path: '/',
component: () => import('@/components/layout/Home'),
children: [
{
name: 'panel',
path: '/panel/:typeName',
component: () => import('@/views/charts2/Panel')
},
{
path: '/report/builtIn',
component: () => import('@/views/report/Report')
},
{
path: '/entity',
component: () => import('@/views/entityExplorer/EntityExplorer')
},
{
path: '/entityDetail',
component: () => import('@/views/entityExplorer/EntityDetail')
},
{
path: '/entityGraph',
component: () => import('@/views/entityExplorer/EntityGraph')
},
{
path: '/detection',
redirect: '/detection/securityEvent'
},
{
path: '/detection/:typeName',
component: () => import('@/views/detections/Index')
},
{
path: '/businessLog/viewer',
component: () => import('@/views/businessLog/Viewer')
},
{
path: '/knowledgeBase',
component: () => import('@/views/setting/KnowledgeBase')
},
{
path: '/knowledgeBase/userDefinedLibrary',
component: () => import('@/views/setting/KnowledgeBase')
},
{
path: '/knowledgeBase/userDefinedLibrary/create',
component: () => import('@/views/setting/KnowledgeBaseForm')
},
{
path: '/knowledgeBase/userDefinedLibrary/edit',
component: () => import('@/views/setting/KnowledgeBaseForm')
},
{
name: 'Administration',
path: '/administration',
redirect: '/administration/user',
component: () => import('@/views/administration/Index'),
children: [
{
name: 'User',
path: '/administration/user',
component: () => import('@/views/administration/User')
},
{
name: 'Role',
path: '/administration/role',
component: () => import('@/views/administration/Roles')
},
{
name: 'OperationLog',
path: '/administration/operationLog',
component: () => import('@/views/administration/OperationLog')
},
{
name: 'Appearance',
path: '/administration/appearance',
component: () => import('@/views/administration/Appearance')
}
]
},
{
name: 'I18n',
path: '/i18n',
component: () => import('@/views/administration/I18n')
},
{
path: '/detectionPolicy',
component: () => import('@/views/detections/detectionPolicies/Index')
},
{
path: '/detectionPolicy/create',
component: () => import('@/views/detections/detectionPolicies/PolicyForm')
},
{
path: '/detectionPolicy/edit',
component: () => import('@/views/detections/detectionPolicies/PolicyForm')
}
]
}
]

View File

@@ -1,6 +1,6 @@
import axios from 'axios'
import router from '@/router'
import { getWelcomeMenu, sortByOrderNum, handleRoutes } from '@/permission'
import { getWelcomeMenu, sortByOrderNum } from '@/permission'
import { ElMessage } from 'element-plus' // dependent on utc plugin
import { dbDrilldownTableConfig, storageKey } from '@/utils/constants'
import { getConfigVersion } from '@/utils/tools'
@@ -64,14 +64,7 @@ const user = {
store.commit('setMenuList', menuList)
store.commit('setButtonList', res2.data.buttons)
store.commit('setRoleList', res2.data.roles)
const homeRoute = {
path: '/',
name: 'home',
component: () => import('@/components/layout/Home'),
children: []
}
handleRoutes(menuList, homeRoute.children)
router.addRoute(homeRoute)
if (res.loginSuccessPath) {
let tempArr = res.loginSuccessPath.split('?')
const path = tempArr[0]

View File

@@ -38,7 +38,6 @@ export const storageKey = {
leftMenuShrink: 'cn-left-menu-shrink',
unsavedChange: 'cn-unsaved-change',
entitySearchHistory: 'cn-entity-search-history',
detectionSearchHistory: 'cn-detection-search-history',
echartLegendFontSize: 'echartLegendFontSize',
echartLabelFontSize: 'echartLabelFontSize',
tokenExpireCurrentPath: 'token-expire-current-path',
@@ -75,7 +74,6 @@ export const panelTypeAndRouteMapping = {
ipEntityDetail: 21,
domainEntityDetail: 22,
appEntityDetail: 23,
subscribeEntityDetail: 24,
cryptocurrency: 7,
ipDrillDownTest: 8,
linkMonitor: 14,
@@ -100,11 +98,6 @@ export const entityType = {
ip: 'IP'
}
export const knowledgeCardUpdateRecordType = {
updateRecord: 'updateRecord',
intelligenceLearning: 'intelligenceLearning'
}
export const entityDetailTabsName = {
informationAggregation: 'informationAggregation',
relatedEntity: 'relatedEntity',
@@ -220,7 +213,7 @@ export const detectionPageType = {
}
export const listScrollPath = [
'/entity',
'/entityExplorer',
'/detection/performanceEvent',
'/detection/securityEvent'
]
@@ -1799,8 +1792,6 @@ export const langData = [
{ value: 'zh', label: 'zh' },
{ value: 'en', label: 'en' }
]
export const ZH = 'zh'
export const EN = 'en'
export const performanceMetricMapping = {
'dns error': 'DNS Error Rate',
@@ -1813,61 +1804,61 @@ export const builtInKnowledgeBaseBasicInfo = [
knowledgeId: 10,
label: 'Psiphon3 VPN',
iconUrl: 'images/knowledge-base-logo/psiphon3-vpn.png',
desc: 'knowledgeBase.desc.psiphon3'
desc: 'Psiphon3 is a circumvention software for Windows and other platforms that provides uncensored access to Internet content.'
},
{
knowledgeId: 5,
label: 'network.domainCategory',
label: 'Domain Category',
iconUrl: 'images/knowledge-base-logo/fqdn.png',
desc: 'knowledgeBase.desc.domainCategory'
desc: 'Domain category provides basic information including categories, providers, reputation score.'
},
{
knowledgeId: 6,
label: 'knowledgeBase.domainWhois',
label: 'Domain Whois',
iconUrl: 'images/knowledge-base-logo/fqdn-whois.png',
desc: 'knowledgeBase.desc.domainWhois'
desc: 'Domain whois contains registration and ownership information for domain names. It includes details like domain registrar, registrant, creation/expiry dates, and contact information.'
},
{
knowledgeId: 2,
label: 'IP ASN',
iconUrl: 'images/knowledge-base-logo/ip-asn.png',
desc: 'knowledgeBase.desc.ipAsn'
desc: 'ASN Database associates IP addresses with their corresponding Autonomous System Numbers, which are unique identifiers assigned to internet networks. This database helps identify the network and its owner, facilitating network analysis and monitoring tasks.'
},
{
knowledgeId: 3,
label: 'knowledgeBase.dnsServerInfo',
label: 'DNS Server Info',
iconUrl: 'images/knowledge-base-logo/dns-server-info.png',
desc: 'knowledgeBase.desc.dnsServer'
desc: 'A DNS Server Info stores information about Domain Name System (DNS) servers. It includes details such as IP addresses, host names, locations, software name, operation system, and roles of the servers.'
},
{
knowledgeId: 9,
label: 'knowledgeBase.appCategory',
label: 'APP Category',
iconUrl: 'images/knowledge-base-logo/app-category.png',
desc: 'knowledgeBase.desc.appCategory'
desc: 'APP category provides basic information for over 3000 popular applications, including their categories and service providers.'
},
{
knowledgeId: 7,
label: 'knowledgeBase.ioc',
label: 'Indicators of Compromise',
iconUrl: 'images/knowledge-base-logo/indicators-of-compromise.png',
desc: 'knowledgeBase.desc.ioc'
desc: 'Indicator of Compromise (IoC) refers to forensic artifacts, such as unusual network traffic or malicious files, indicating a security breach or cyberattack.'
},
{
knowledgeId: 4,
label: 'ICP',
iconUrl: 'images/knowledge-base-logo/icp.png',
desc: 'knowledgeBase.desc.icp'
desc: 'ICP (Internet Content Provider) license is a permit issued by Chinese authorities, mandatory for websites to legally operate and publish content within mainland China.'
},
{
knowledgeId: 1,
label: 'knowledgeBase.ipLocation',
label: 'IP Location',
iconUrl: 'images/knowledge-base-logo/ip-location.png',
desc: 'knowledgeBase.desc.ipLocation'
desc: 'IP location Database is a repository containing geographical data associated with IP addresses, such as country, city, ISP, organization, latitude, longitude, and other relevant details.'
},
{
knowledgeId: 8,
label: 'eventType.anonymity',
label: 'Anonymity',
iconUrl: 'images/knowledge-base-logo/anonymity.png',
desc: 'knowledgeBase.desc.anonymity'
desc: 'Communication system that conceals users\' identities and activities to protect privacy and prevent tracking or surveillance. This database provides lists of Tor nodes, I2P nodes, obfs4, etc.'
}
]

View File

@@ -80,15 +80,15 @@ export const dataForNetworkOverviewLine = {
options2: [
{
value: 'Average',
label: 'overall.average'
label: 'Average'
},
{
value: '95th Percentile',
label: ['overall.percentileNumber', { number: 95 }]
label: '95th Percentile'
},
{
value: 'Maximum',
label: 'overall.maximum'
label: 'Maximum'
}
],
tabsTemplate: [
@@ -200,15 +200,15 @@ export const dataForDnsTrafficLine = {
options2: [
{
value: 'Average',
label: 'overall.average'
label: 'Average'
},
{
value: '95th Percentile',
label: ['overall.percentileNumber', { number: 95 }]
label: '95th Percentile'
},
{
value: 'Maximum',
label: 'overall.maximum'
label: 'Maximum'
}
],
tabs: [

View File

@@ -1,13 +1,12 @@
import { ElMessageBox, ElMessage } from 'element-plus'
import i18n from '@/i18n'
import _ from 'lodash'
import { storageKey, iso36112, topDomain, echartsFontSize, dbGeoDataTableName, networkTable, dbDrilldownTableConfig, ZH, EN } from '@/utils/constants'
import { storageKey, iso36112, topDomain, echartsFontSize, dbGeoDataTableName, networkTable, dbDrilldownTableConfig } from '@/utils/constants'
import { getIso36112JsonData, getDictList } from '@/utils/api'
import { format } from 'echarts'
import router from '@/router'
import store from '@/store'
import indexedDBUtils from '@/indexedDB'
import { columnType } from '@/components/advancedSearch/meta/meta'
export const tableSort = {
// 是否需要排序
@@ -1249,10 +1248,10 @@ export function getQueryByFlag2 (type, condition) {
*/
export function getWidthByLanguage (language) {
switch (language) {
case EN: {
case 'en': {
return 7
}
case ZH: {
case 'cn': {
return 16
}
}
@@ -1361,89 +1360,3 @@ export function getTagColor (color) {
return `color: ${color};border-color: ${color};background-color: ${backgroundColor};`
}
}
/**
* 字段高亮
* 用法: <span v-high-light=[{type: 'string', value: '搜索'}, {type: 'fullText', value: '高亮'}]>搜索关键字高亮<span>
* 其中type为fullText的为模糊搜索
* @type {{updated(*, *): (*|undefined)}}
*/
export const myHighLight = {
updated (el, binding) {
if (el && binding.value) {
const { value } = binding
if (value && value.length > 0) {
const text = _.cloneDeep(el.innerHTML)
const regex = new RegExp(value.map(item => `${item.value}`).join('|'), 'g')
if (el.getElementsByClassName('highlight__text').length === 0) {
const newText = text.replace(regex, (match) => {
// 将value中的value提取出来对比string即精准搜索fullText模糊搜索
for (const item of value) {
if ((item.type === columnType.string && item.value === el.innerHTML) || el.className.indexOf('high-location') > -1) {
if (el.className.indexOf('high-light-block') > -1) {
return `<span class="highlight__block">${match}</span>`
} else {
return `<span class="highlight__text">${match}</span>`
}
} else if (item.type === columnType.fullText && item.value === match) {
if (el.className.indexOf('high-light-block') > -1) {
return `<span class="highlight__block">${match}</span>`
} else {
return `<span class="highlight__text">${match}</span>`
}
}
}
return match
})
if (newText && newText !== '-') {
// 此处不用el.className.indexOf('high-light-block')判断是因为block可能会有多个有一个满足所有的都会渲染
if (newText.indexOf('highlight__block') > -1) {
el.style.cssText = el.style.cssText + 'background: #FEECC2;'
// 此处是相关app、相关ip、相关domain弹窗获取不到dom的草错
let dom
if (document.getElementById('showRelatedApp')) {
dom = document.getElementById('showRelatedApp')
} else if (document.getElementById('showRelatedDomain')) {
dom = document.getElementById('showRelatedDomain')
}
if (dom) {
const itemDom = dom.getElementsByClassName('high-light-block')
if (itemDom) {
for (let i = 0; i < itemDom.length; i++) {
if (itemDom[i].innerHTML === el.innerHTML) {
itemDom[i].style.cssText = itemDom[i].style.cssText + 'background: #FEECC2;'
}
}
}
}
} else {
el.innerHTML = newText
}
} else {
return newText
}
}
}
}
}
}
export const changeTimeByDate = (date) => {
if (date) {
const nowDate = Date.now()
const oldDate = isNaN(date) ? Date.parse(date) : date
const diff = Math.floor((nowDate - oldDate) / 1000)
if (diff < 60) {
return diff + i18n.global.t('entity.search.secondsAgo')
} else if (diff >= 60 && diff < 3600) {
const minutes = Math.floor(diff / 60)
return minutes === 1 ? `${minutes} ${i18n.global.t('entity.search.minuteAgo')}` : `${minutes} ${i18n.global.t('entity.search.minutesAgo')}`
} else if (diff >= 3600 && diff < 86400) {
const hours = Math.floor(diff / 3600)
return hours === 1 ? `${hours} ${i18n.global.t('entity.search.hourAgo')}` : `${hours} ${i18n.global.t('entity.search.hoursAgo')}`
} else {
return date
}
}
}

View File

@@ -48,9 +48,7 @@
</el-form-item>
</el-form>
<div class="edit-appearance-base__footer">
<button style="position: relative;" :class="{'footer__btn--disabled': blockOperation.save}" :disabled="blockOperation.save" class="footer__btn" @click="save"
v-if="hasPermission('editAppearence')"
>
<button style="position: relative;" :class="{'footer__btn--disabled': blockOperation.save}" :disabled="blockOperation.save" class="footer__btn" @click="save">
<loading size="small" :loading="blockOperation.save"></loading>
<span>{{$t('overall.save')}}</span>
</button>
@@ -60,7 +58,7 @@
</template>
<script>
import { api } from '@/utils/api'
import { storageKey, ZH, EN } from '@/utils/constants'
import { storageKey } from '@/utils/constants'
import axios from 'axios'
import dayjs from 'dayjs'
@@ -99,12 +97,12 @@ export default {
{
id: 1,
label: 'English',
value: EN
value: 'en'
},
{
id: 2,
label: '中文',
value: ZH
value: 'zh'
}
]
}

View File

@@ -11,19 +11,16 @@
>
<template v-slot:top-tool-left>
<button id="roles-add" class="top-tool-btn margin-r-10 top-tool-btn--create"
v-if="hasPermission('createRole')"
@click="add">
<i class="cn-icon-xinjian cn-icon"></i>
<span>{{$t('overall.create')}}</span>
</button>
<button id="roles-edit" class="top-tool-btn margin-r-10" :disabled="disableEdit"
v-if="hasPermission('editRole')"
@click="edit">
<i class="cn-icon-edit cn-icon"></i>
<span>{{$t('overall.edit')}}</span>
</button>
<button id="roles-delete" class="top-tool-btn margin-r-10" :disabled="disableDelete"
v-if="hasPermission('deleteRole')"
@click="delBatch">
<i class="cn-icon-delete cn-icon"></i>
<span>{{$t('overall.delete')}}</span>

View File

@@ -11,19 +11,16 @@
>
<template #top-tool-left>
<button id="account-add" class="top-tool-btn margin-r-10 top-tool-btn--create"
v-if="hasPermission('createUser')"
@click="add">
<i class="cn-icon-xinjian cn-icon"></i>
<span>{{$t('overall.create')}}</span>
</button>
<button id="account-edit" class="top-tool-btn margin-r-10" :disabled="disableEdit"
v-if="hasPermission('editUser')"
@click="editSelectRecord">
<i class="cn-icon-edit cn-icon"></i>
<span>{{$t('overall.edit')}}</span>
</button>
<button id="account-delete" class="top-tool-btn margin-r-10" :disabled="disableDelete"
v-if="hasPermission('deleteUser')"
@click="delBatch">
<i class="cn-icon-delete cn-icon"></i>
<span>{{$t('overall.delete')}}</span>

View File

@@ -5,12 +5,12 @@
v-if="panel.params && panel.params.wholeScreenScroll"
id="wholeScreenBox"
>
<!-- <dns-screen v-if="currentPath === wholeScreenRouterMapping.dns"
<dns-screen v-if="currentPath === wholeScreenRouterMapping.dns"
:copy-data-list="chartList"
ref="dnsScreen"
:time-filter="timeFilter"
:entity="entity">
</dns-screen>-->
</dns-screen>
</div>
<div id="panelList" v-if="!isEntityDetail" class="panel-list">
<div id="cn-panel" class="cn-panel2">
@@ -49,7 +49,7 @@
<script>
import { useRoute, useRouter } from 'vue-router'
import { ref } from 'vue'
// import DnsScreen from '@/views/charts/wholeScreenScroll/DnsScreen'
import DnsScreen from '@/views/charts/wholeScreenScroll/DnsScreen'
import { panelTypeAndRouteMapping, wholeScreenRouterMapping } from '@/utils/constants'
import { api, getPanelList, getChartList } from '@/utils/api'
import { getNowTime } from '@/utils/date-util'
@@ -66,9 +66,9 @@ export default {
isEntityDetail: Boolean,
typeName: String
},
/* components: {
components: {
DnsScreen
}, */
},
data () {
return {
chartList: [], // 普通panel的chart
@@ -104,8 +104,8 @@ export default {
setup (props, ctx) {
const panel = ref({})
let panelType = 1 // 取得panel的type
const { path } = useRoute()
panelType = props.entity ? props.entity.type : panelTypeAndRouteMapping[path.replace('/panel/', '')]
const { params } = useRoute()
panelType = props.entity ? props.entity.type : panelTypeAndRouteMapping[params.typeName]
// date
const dateRangeValue = 60

View File

@@ -338,10 +338,7 @@ export function axisFormatter (params) {
return str
}
export function tooLongFormatter (name) {
return format.truncateText(name, 160, '12px')
}
export function tooLongFormatterFor2Columns (name) {
return format.truncateText(name, 100, '12px')
return format.truncateText(name, 110, '12px')
}
export function timeHorizontalFormatter (params) {
let str = '<div>'

View File

@@ -1,7 +1,7 @@
<template>
<div class="panel-box2" :class="{'panel-box2--entity-detail': entity && entity.entityType}">
<div class="panel__header" v-if="!entity">
<div class="panel__title">{{panelName ? panelName:(panel.i18n ? $t(panel.i18n) : panel.name)}}
<div class="panel__title">{{panelName?panelName:(panel.i18n ? $t(panel.i18n) : panel.name)}}
<div v-if="showScore" class="score">
<div class="circle-icon" v-if="score <= 2 || score === '-'" :class="{'data-score-red': score <= 2 || score === '-'}" ></div>
<div class="circle-icon" v-else-if="score <= 4" :class="{'data-score-yellow': score <= 4}" ></div>
@@ -31,7 +31,7 @@
@change="metricChange"
>
<template #prefix>
<span class="select-prefix">{{$t('detections.metric')}}:</span>
<span class="select-prefix">Metric:</span>
</template>
<el-option v-for="item in metricOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
@@ -148,7 +148,7 @@ export default {
// this.panelName = this.$store.getters.getPanelName
const pName = this.$route.query.panelName ? this.$t(this.$route.query.panelName) : ''
const curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
if (this.$route.path.replace('/panel/', '') === fromRoute.dnsServiceInsights) {
if (this.$route.params.typeName === fromRoute.dnsServiceInsights) {
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
this.$store.commit('setDnsQtypeMapData', this.dnsQtypeMapData)
@@ -249,11 +249,12 @@ export default {
const panel = ref({})
let panelType = 1 // 取得panel的type
let { query, path } = useRoute()
let { params, query, path } = useRoute()
// 获取路由跳转过的历史状态,赋值给当前界面,起到保留状态的作用,如浏览器的回退前进等
const routerObj = store.getters.getRouterHistoryList.find(item => item.t === query.t)
if (routerObj) {
params = routerObj.params
query = routerObj.query
path = routerObj.path
@@ -291,19 +292,19 @@ export default {
} else if (thirdPanel) {
panelType = Number(thirdPanel)
} else {
panelType = props.entity ? props.entity.type : panelTypeAndRouteMapping[path.replace('/panel/', '')]
panelType = props.entity ? props.entity.type : panelTypeAndRouteMapping[params.typeName]
}
// 获取url携带的range、startTime、endTime
const rangeParam = query.range
const startTimeParam = query.startTime
const endTimeParam = query.endTime
// 若url携带了使用携带的值否则使用默认值。
// 优先级url > config.js > 默认值。
const dateRangeValue = rangeParam ? parseInt(rangeParam) : (DEFAULT_TIME_FILTER_RANGE.dashboard || 60)
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
const timeFilter = ref({ dateRangeValue })
if (!startTimeParam || !endTimeParam) {
const { startTime, endTime } = getNowTime(dateRangeValue)
const { startTime, endTime } = getNowTime(60)
timeFilter.value.startTime = getSecond(startTime)
timeFilter.value.endTime = getSecond(endTime)
// 如果没有时间参数就将参数写入url
@@ -518,7 +519,7 @@ export default {
},
jumpEntityDetail () {
const { href } = this.$router.resolve({
path: '/entity/detail',
path: '/entityDetail',
query: {
entityType: this.entityType,
entityName: this.entityValue

View File

@@ -1,5 +1,4 @@
import { entityDetailRelatedEntitiesShowSize, entityDetailTabsName } from '@/utils/constants'
import { getSecond } from '@/utils/date-util'
import { entityDetailRelatedEntitiesShowSize } from '@/utils/constants'
export default {
props: {
@@ -29,59 +28,6 @@ export default {
}
}
},
getParamsByTabType (tabType) {
let params = {
resource: this.entity.entityName
}
let dataRangeValue = 60 * 24 * 7
switch (tabType) {
case entityDetailTabsName.relatedEntity:
dataRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.relatedEntity
break
case entityDetailTabsName.performanceEvent:
dataRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.performanceEvent
break
case entityDetailTabsName.securityEvent:
dataRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.securityEvent
break
case entityDetailTabsName.openPort:
dataRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.openPort
break
case entityDetailTabsName.informationAggregation:
dataRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.informationAggregation
break
case entityDetailTabsName.behaviorPattern:
dataRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.behaviorPattern
break
default:
dataRangeValue = 60 * 24 * 7
}
if (dataRangeValue !== 0) {
const endTime = window.$dayJs.tz().valueOf()
const startTime = endTime - dataRangeValue * 60 * 1000
params = {
...params,
startTime: getSecond(startTime),
endTime: getSecond(endTime)
}
}
return params
},
getParams () {
const range = this.timeFilter.dateRangeValue
let params = {
resource: this.entity.entityName
}
if (range !== 0) {
params = {
...params,
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
}
return params
},
handleShowDataNum (showListInfo, allList) {
if (allList.length <= entityDetailRelatedEntitiesShowSize) {
showListInfo.num = allList.length

View File

@@ -43,7 +43,7 @@
</div>
</div>-->
<div class="line-select-reference-line">
<span>{{$t('network.referenceLine')}}&nbsp;:&nbsp;</span>
<span>{{$t('network.referenceLine')}}:</span>
<div class="line-select__operation">
<el-select
size="mini"
@@ -54,9 +54,7 @@
:popper-append-to-body="false"
@change="referenceSelectChange"
>
<el-option :key="options2[0].value" :label="$t(options2[0].label)" :value="options2[0].value"></el-option>
<el-option :key="options2[1].value" :label="$t(options2[1].label[0], options2[1].label[1])" :value="options2[1].value"></el-option>
<el-option :key="options2[2].value" :label="$t(options2[2].label)" :value="options2[2].value"></el-option>
<el-option v-for="item in options2" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
</div>
@@ -257,14 +255,6 @@ export default {
label: {
formatter (params) {
const arr = unitConvert(params.value, unitTypes.number).join('')
const referIndex = _this.options2.findIndex(o => o.value === _this.lineRefer)
if (referIndex > -1) {
if (referIndex === 1) {
return _this.$t(_this.options2[1].label[0], _this.options2[1].label[1]) + '(' + arr + echartsData[0].unitType + ')'
} else {
return _this.$t(_this.options2[referIndex].label) + '(' + arr + echartsData[0].unitType + ')'
}
}
return _this.lineRefer + '(' + arr + echartsData[0].unitType + ')'
},
position: 'insideStartTop',

View File

@@ -1,7 +1,7 @@
<template>
<div class="entity-detail-basic-info">
<chart-error v-if="showError" :content="errorMsg"/>
<div class="entity-type">{{entityTypeName}}</div>
<div class="entity-type">{{entityType[entity.entityType]}}</div>
<div class="entity-basic-info">
<div class="entity-basic-info__name">
<span id="entityName">{{entity.entityName}}</span>
@@ -90,29 +90,6 @@ export default {
hideTagArea: false
}
},
computed: {
entityTypeName () {
const type = this.entity.entityType
let entityTypeName = '-'
switch (type) {
case ('ip'): {
entityTypeName = 'IP'
break
}
case ('domain'): {
entityTypeName = this.$t('overall.domain')
break
}
case ('app'): {
entityTypeName = 'APP'
break
}
default:
break
}
return entityTypeName
}
},
methods: {
getTagColor,
tagValueHandler (value) {
@@ -282,7 +259,7 @@ export default {
icon: 'cn-icon cn-icon-graph',
label: i18n.global.t('entities.graph'),
url: resolvePath({
path: '/entity/graph',
path: '/entityGraph',
query: {
entityType: props.entity.entityType,
entityName: props.entity.entityName

View File

@@ -124,12 +124,12 @@ export default {
const rangeParam = query.range
const startTimeParam = query.startTime
const endTimeParam = query.endTime
// 若url携带了使用携带的值否则使用默认值。
// 优先级url > config.js > 默认值。
const dateRangeValue = rangeParam ? parseInt(rangeParam) : (DEFAULT_TIME_FILTER_RANGE.entity.trafficLine || 60)
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
const timeFilter = ref({ dateRangeValue })
if (!startTimeParam || !endTimeParam) {
const { startTime, endTime } = getNowTime(dateRangeValue)
const { startTime, endTime } = getNowTime(60)
timeFilter.value.startTime = startTime
timeFilter.value.endTime = endTime
} else {

View File

@@ -14,13 +14,13 @@
<span :style="{color: tab.name === activeTab ? '#046ECA' : '#717171'}">{{ tab.tag }}</span>
</el-tag>
</template>
<information-aggregation v-if="tab.name === entityDetailTabsName.informationAggregation && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" @checkTag="setTag"></information-aggregation>
<domain-name-resolution v-else-if="tab.name === entityDetailTabsName.relatedEntity && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" @checkTag="setTag"></domain-name-resolution>
<digital-certificate v-else-if="tab.name === entityDetailTabsName.digitalCertificate && tab.name === activeTab" @toggleLoading="setLoading" @checkTag="setTag" />
<security-event v-else-if="tab.name === entityDetailTabsName.securityEvent && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" @checkTag="setTag" />
<performance-event v-else-if="tab.name === entityDetailTabsName.performanceEvent && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" @checkTag="setTag" />
<open-port v-else-if="tab.name === entityDetailTabsName.openPort && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" @checkTag="setTag"></open-port>
<behavior-pattern v-else-if="tab.name === entityDetailTabsName.behaviorPattern && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" @checkTag="setTag"></behavior-pattern>
<information-aggregation v-if="tab.name === entityDetailTabsName.informationAggregation && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" @checkTag="setTag"></information-aggregation>
<domain-name-resolution v-else-if="tab.name === entityDetailTabsName.relatedEntity && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" :timeFilter="oneDayTimeFilter" @checkTag="setTag"></domain-name-resolution>
<digital-certificate v-else-if="tab.name === entityDetailTabsName.digitalCertificate && tab.name === activeTab" @toggleLoading="setLoading" :timeFilter="oneDayTimeFilter" @checkTag="setTag" />
<security-event v-else-if="tab.name === entityDetailTabsName.securityEvent && tab.name === activeTab" @toggleLoading="setLoading" :timeFilter="oneDayTimeFilter" @checkTag="setTag" />
<performance-event v-else-if="tab.name === entityDetailTabsName.performanceEvent && tab.name === activeTab" @toggleLoading="setLoading" :timeFilter="oneDayTimeFilter" @checkTag="setTag" />
<open-port v-else-if="tab.name === entityDetailTabsName.openPort && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" :timeFilter="oneDayTimeFilter" @checkTag="setTag"></open-port>
<behavior-pattern v-else-if="tab.name === entityDetailTabsName.behaviorPattern && tab.name === activeTab" @toggleLoading="setLoading" :entity="entity" :timeFilter="oneDayTimeFilter" @checkTag="setTag"></behavior-pattern>
</el-tab-pane>
</el-tabs>
</div>
@@ -58,7 +58,12 @@ export default {
},
data () {
return {
timer: null
timer: null,
// 最近一天的时间
oneDayTimeFilter: {
startTime: window.$dayJs.tz().valueOf() - 1440 * 60 * 1000,
endTime: window.$dayJs.tz().valueOf()
}
}
},
watch: {
@@ -109,17 +114,22 @@ export default {
},
methods: {
initData () {
const url = this.getUrlByEntityType(this.entity.entityType)
const informationAggregation = axios.get(`${api.entity.informationAggregation}/${this.entity.entityType}?resource=${this.entity.entityName}&pageSize=100&pageNo=1`, { params: this.getParamsByTabType(entityDetailTabsName.informationAggregation) })
const openPort = axios.get(url, { params: this.getParamsByTabType(entityDetailTabsName.openPort) })
const security = axios.get(`${api.entity.security}/${this.entity.entityType}`, { params: this.getParamsByTabType(entityDetailTabsName.securityEvent) })
const performance = axios.get(`${api.entity.performance}/${this.entityType}`, { params: this.getParamsByTabType(entityDetailTabsName.performanceEvent) })
const params = {
resource: this.entity.entityName
// startTime: getSecond(this.oneDayTimeFilter.startTime),
// endTime: getSecond(this.oneDayTimeFilter.endTime)
}
Promise.allSettled([informationAggregation, openPort, security, performance]).then(response => {
const informationAggregationResponse = response[0].value
if (informationAggregationResponse.status === 200) {
const url = this.getUrlByEntityType(this.entity.entityType)
const informationAggregation = axios.get(`${api.entity.informationAggregation}/${this.entity.entityType}?resource=${this.entity.entityName}&pageSize=100&pageNo=1`, { params: params })
const openPort = axios.get(url, { 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 })
Promise.all([informationAggregation, openPort]).then(response => {
if (response[0].status === 200) {
const list = []
informationAggregationResponse.data.data.result.forEach(r => {
response[0].data.data.result.forEach(r => {
Object.keys(r).forEach(k => {
const aggregation = {
createTime: r[k].createTime,
@@ -142,42 +152,40 @@ export default {
}
})
})
this.initSetTag(entityDetailTabsName.informationAggregation, list.length)
}
const openPortResponse = response[1].value
if (openPortResponse.status === 200) {
this.initSetTag(entityDetailTabsName.openPort, openPortResponse.data.data.result.length)
if (response[1].status === 200) {
this.initSetTag(entityDetailTabsName.openPort, response[1].data.data.result.length)
}
const securityResponse = response[2].value
if (securityResponse.status === 200) {
this.initSetTag(entityDetailTabsName.securityEvent, securityResponse.data.data.result.length)
}
// let performanceResponse = response[3].value
// if (performanceResponse.status === 200) {
// this.initSetTag(entityDetailTabsName.performanceEvent, performanceResponse.data.data.result.length)
// if (response[2].status === 200) {
// this.initSetTag(entityDetailTabsName.securityEvent, response[2].data.data.result.length)
// }
// if (response[3].status === 200) {
// this.initSetTag(entityDetailTabsName.performanceEvent, response[3].data.data.result.length)
// }
this.initSetTag(entityDetailTabsName.securityEvent, 0)
this.initSetTag(entityDetailTabsName.performanceEvent, 0)
})
const relatedEntityParams = this.getParamsByTabType(entityDetailTabsName.relatedEntity)
// 域名解析
if (this.entity.entityType === 'app') {
const ipsOfApp = axios.get(api.entity.domainNameResolutionAboutIpsOfApp, { params: relatedEntityParams })
const domainsOfApp = axios.get(api.entity.domainNameResolutionAboutDomainsOfApp, { params: relatedEntityParams })
const ipsOfApp = axios.get(api.entity.domainNameResolutionAboutIpsOfApp, { params: params })
const domainsOfApp = axios.get(api.entity.domainNameResolutionAboutDomainsOfApp, { params: params })
this.promiseData(ipsOfApp, domainsOfApp)
}
if (this.entity.entityType === 'ip') {
const appsOfIp = axios.get(api.entity.domainNameResolutionAboutAppsOfIp, { params: relatedEntityParams })
const domainsOfIp = axios.get(api.entity.domainNameResolutionAboutDomainsOfIp, { params: relatedEntityParams })
const behaviorPattern = axios.get(api.entity.behaviorPattern, { params: relatedEntityParams })
const appsOfIp = axios.get(api.entity.domainNameResolutionAboutAppsOfIp, { params: params })
const domainsOfIp = axios.get(api.entity.domainNameResolutionAboutDomainsOfIp, { params: params })
const behaviorPattern = axios.get(api.entity.behaviorPattern, { params: params })
this.promiseData(appsOfIp, domainsOfIp, behaviorPattern)
}
if (this.entity.entityType === 'domain') {
const appsOfDomain = axios.get(api.entity.domainNameResolutionAboutAppsOfDomain, { params: relatedEntityParams })
const ipsOfDomain = axios.get(api.entity.domainNameResolutionAboutIpsOfDomain, { params: relatedEntityParams })
const fqdnsOfDomain = axios.get(api.entity.domainNameResolutionAboutFQDNsOfDomain, { params: relatedEntityParams })
const appsOfDomain = axios.get(api.entity.domainNameResolutionAboutAppsOfDomain, { params: params })
const ipsOfDomain = axios.get(api.entity.domainNameResolutionAboutIpsOfDomain, { params: params })
const fqdnsOfDomain = axios.get(api.entity.domainNameResolutionAboutFQDNsOfDomain, { params: params })
this.promiseData(appsOfDomain, ipsOfDomain, fqdnsOfDomain)
}
},

View File

@@ -8,8 +8,8 @@
<div class="behavior-pattern-legend__item" v-for="(data, index) in tableData" :key="index">
<div class="legend-icon" :style="`background:${chartColorForBehaviorPattern[index%10]};`"></div>
<div class="legend-name">{{data.name}}</div>
<div class="legend-value" >{{ valueToRangeValue(data.value, unitTypes.number).join('')}}</div>
<div class="legend-percent">{{ valueToRangeValue(data.percent, unitTypes.percent).join('') }}</div>
<div class="legend-value" >{{ unitConvert(data.value, unitTypes.number).join('')}}</div>
<div class="legend-percent">{{ unitConvert(data.percent, unitTypes.percent).join('') }}</div>
</div>
</div>
<div id="entityIpRoseType" class="behavior-pattern-chart"></div>
@@ -20,12 +20,12 @@
</template>
<script>
import { dateFormatByAppearance, getNowTime } from '@/utils/date-util'
import { dateFormatByAppearance } from '@/utils/date-util'
import * as echarts from 'echarts'
import { pieChartOption4 } from '@/views/charts2/charts/options/echartOption'
import { shallowRef, ref } from 'vue'
import { shallowRef } from 'vue'
import { entityDetailTabsName, chartColorForBehaviorPattern, unitTypes } from '@/utils/constants'
import { valueToRangeValue } from '@/utils/unit-convert'
import unitConvert from '@/utils/unit-convert'
import axios from 'axios'
import { api } from '@/utils/api'
import { useRoute } from 'vue-router'
@@ -49,20 +49,13 @@ export default {
const { query } = useRoute()
const entityType = query.entityType
const entityName = query.entityName
// range取 config.js 中配置的值
const dateRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.behaviorPattern
const timeFilter = ref({ dateRangeValue })
const { startTime, endTime } = getNowTime(dateRangeValue)
timeFilter.value.startTime = startTime
timeFilter.value.endTime = endTime
return {
entityType,
entityName,
myChart: shallowRef(null),
chartColorForBehaviorPattern,
unitTypes,
timeFilter
unitTypes
}
},
async mounted () {
@@ -74,7 +67,7 @@ export default {
}, 200)
},
methods: {
valueToRangeValue,
unitConvert,
toUpperCaseByString,
dateFormatByAppearance,
initEcharts () {
@@ -137,7 +130,9 @@ export default {
})
},
async initData () {
const params = this.getParams()
const params = {
resource: this.entityName
}
this.toggleLoading(true)
await axios.get(`${api.entity.behaviorPattern}`, { params: params }).then(response => {
const res = response.data
@@ -149,18 +144,22 @@ export default {
if (!this.isNoData) {
const data = res.data.result
this.tableData = []
let sum = 0
if (data && data[0]) {
const dataObject = data[0]
Object.keys(dataObject).forEach(key => {
const value = Number(dataObject[key]) ? Number(dataObject[key]) : 0
if (value !== 0 && key !== 'total') {
if (value !== 0) {
sum = sum + value
this.tableData.push({
name: key,
value: value,
percent: dataObject.total ? value / dataObject.total : '-'
value: value
})
}
})
this.tableData.forEach(item => {
item.percent = item.value / sum
})
this.tableData = this.tableData.sort(reverseSortBy('value'))
this.$emit('checkTag', entityDetailTabsName.behaviorPattern, this.tableData.length)
if (this.tableData.length === 0) {

View File

@@ -70,15 +70,15 @@
<script>
import axios from 'axios'
import { api } from '@/utils/api'
import { getNowTime } from '@/utils/date-util'
import chartMixin from '@/views/charts2/chart-mixin'
import chartNoData from '@/views/charts/charts/ChartNoData'
import { entityDetailTabsName } from '@/utils/constants'
import { ref } from 'vue'
export default {
name: 'DomainNameResolution',
mixins: [chartMixin],
props: {
},
components: {
chartNoData
},
@@ -105,24 +105,16 @@ export default {
errorMsg2: ''
}
},
setup (props) {
// range取 config.js 中配置的值
const dateRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.relatedEntity
const timeFilter = ref({ dateRangeValue })
const { startTime, endTime } = getNowTime(dateRangeValue)
timeFilter.value.startTime = startTime
timeFilter.value.endTime = endTime
return {
timeFilter
}
},
mounted () {
this.initData()
},
methods: {
initData () {
const params = this.getParams()
const params = {
resource: this.entity.entityName
// startTime: getSecond(this.timeFilter.startTime),
// endTime: getSecond(this.timeFilter.endTime)
}
if (this.entity.entityType === 'app') {
const ipsOfApp = axios.get(api.entity.domainNameResolutionAboutIpsOfApp, { params: params })
const domainsOfApp = axios.get(api.entity.domainNameResolutionAboutDomainsOfApp, { params: params })

View File

@@ -72,9 +72,8 @@ import chartMixin from '@/views/charts2/chart-mixin'
import axios from 'axios'
import { api } from '@/utils/api'
import { entityDetailTabsName, entityDetailTags, tagValueLabelMapping } from '@/utils/constants'
import { dateFormatByAppearance, getNowTime } from '@/utils/date-util'
import { dateFormatByAppearance } from '@/utils/date-util'
import chartNoData from '@/views/charts/charts/ChartNoData'
import { ref } from 'vue'
export default {
name: 'InformationAggregation',
@@ -84,18 +83,6 @@ export default {
loading: true
}
},
setup (props) {
// range取 config.js 中配置的值
const dateRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.informationAggregation
const timeFilter = ref({ dateRangeValue })
const { startTime, endTime } = getNowTime(dateRangeValue)
timeFilter.value.startTime = startTime
timeFilter.value.endTime = endTime
return {
timeFilter
}
},
mixins: [chartMixin],
components: { chartNoData },
methods: {
@@ -121,12 +108,7 @@ export default {
this.showError = false
this.toggleLoading(true)
this.informationAggregationList = []
const params = this.getParams()
let timeStr = ''
if (params.startTime && params.endTime) {
timeStr = '&startTime=' + params.startTime + '&endTime=' + params.endTime
}
axios.get(`${api.entity.informationAggregation}/${this.entity.entityType}?resource=${this.entity.entityName}&pageSize=100&pageNo=1${timeStr}`).then(response => {
axios.get(`${api.entity.informationAggregation}/${this.entity.entityType}?resource=${this.entity.entityName}&pageSize=100&pageNo=1`).then(response => {
const res = response.data
if (response.status === 200) {
// this.isNoData = res.data.result.length === 0

View File

@@ -7,7 +7,7 @@
<div class="type-data">
<div class="type-title">
<span class="title-mark"></span>
<span class="type-title-word">{{ $t('entities.tab.currentOpenPortsAndServices') }}</span>({{ openPortList.length }})
<span class="type-title-word">{{ $t('entities.tab.currentDevelopmentPortsAndServices') }}</span>({{ openPortList.length }})
</div>
<div class="type-content">
<div v-for="(openPort, index) in openPortList.slice(0,showOpenPortListInfo.num)" :key="index" class="data-item">
@@ -27,8 +27,6 @@ import chartMixin from '@/views/charts2/chart-mixin'
import { api } from '@/utils/api'
import chartNoData from '@/views/charts/charts/ChartNoData'
import { entityDetailTabsName } from '@/utils/constants'
import { ref } from 'vue'
import { getNowTime } from '@/utils/date-util'
export default {
name: 'OpenPort',
@@ -52,21 +50,16 @@ export default {
mounted () {
this.initData()
},
setup (props) {
// range取 config.js 中配置的值
const dateRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.openPort
const timeFilter = ref({ dateRangeValue })
const { startTime, endTime } = getNowTime(dateRangeValue)
timeFilter.value.startTime = startTime
timeFilter.value.endTime = endTime
return {
timeFilter
}
setup () {
},
methods: {
initData () {
const params = this.getParams()
const params = {
resource: this.entity.entityName
// startTime: getSecond(this.timeFilter.startTime),
// endTime: getSecond(this.timeFilter.endTime)
}
this.toggleLoading(true)
const url = this.getUrlByEntityType(this.entity.entityType)
axios.get(url, { params: params }).then(response => {

View File

@@ -26,7 +26,7 @@
<div class="basic-info__item" v-if="item.eventSeverity">
<i class="cn-icon cn-icon-severity-level"></i>
<span>{{ $t('network.severity') }}&nbsp;:&nbsp;&nbsp;</span>
<span :test-id="`severity${index}`">{{ changeSecurity(item.eventSeverity) }}</span>
<span :test-id="`severity${index}`">{{ toUpperCaseByString(item.eventSeverity) || '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-time2"></i>
@@ -50,8 +50,8 @@
</template>
<script>
import { dateFormatByAppearance, getNowTime } from '@/utils/date-util'
import { eventSeverityColor, entityDetailTabsName, securityLevel } from '@/utils/constants'
import { dateFormatByAppearance } from '@/utils/date-util'
import { eventSeverityColor, entityDetailTabsName } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import axios from 'axios'
import { api } from '@/utils/api'
@@ -60,7 +60,6 @@ import chartMixin from '@/views/charts2/chart-mixin'
import ChartError from '@/components/common/Error'
import { toUpperCaseByString } from '@/utils/tools'
import ChartNoData from '@/views/charts/charts/ChartNoData'
import { ref } from 'vue'
export default {
name: 'PerformanceEvent',
@@ -78,36 +77,33 @@ export default {
const { query } = useRoute()
const entityType = query.entityType
const entityName = query.entityName
// range取 config.js 中配置的值
const dateRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.performanceEvent
const timeFilter = ref({ dateRangeValue })
const { startTime, endTime } = getNowTime(dateRangeValue)
timeFilter.value.startTime = startTime
timeFilter.value.endTime = endTime
return {
entityType,
entityName,
timeFilter
entityName
}
},
mounted () {
this.initData()
/*
// this.initData()
this.isNoData = true
this.$emit('checkTag', entityDetailTabsName.performanceEvent, 0)
this.toggleLoading(true)
const timer = setTimeout(() => {
this.toggleLoading(false)
clearInterval(timer)
}, 200) */
}, 200)
},
methods: {
unitConvert,
toUpperCaseByString,
dateFormatByAppearance,
initData () {
const params = this.getParams()
const params = {
resource: this.entityName
// startTime: getSecond(this.timeFilter.startTime),
// endTime: getSecond(this.timeFilter.endTime)
}
this.toggleLoading(true)
axios.get(`${api.entity.performance}/${this.entityType}`, { params: params }).then(response => {
const res = response.data
@@ -134,18 +130,6 @@ export default {
this.showError = true
this.errorMsg = this.errorMsgHandler(e)
this.$emit('checkTag', entityDetailTabsName.performanceEvent, 0)
},
changeSecurity (value) {
if (value) {
const obj = securityLevel.find(d => d.value === value)
let label = value
if (obj) {
label = this.$t(obj.label)
}
return label
} else {
return '-'
}
}
}
}

View File

@@ -9,7 +9,7 @@
:key="item.eventId">
<div class="cn-detection--list">
<div class="cn-detection__case entity-detail-security">
<div class="cn-detection__icon"></div>
<div class="cn-detection__icon" :style="`background-color: ${eventSeverityColor[item.eventSecurity]}`"></div>
<div class="cn-detection__row">
<div class="cn-detection__header">
<span
@@ -17,7 +17,7 @@
class="detection-event-severity-color-block"
:style="`background-color: ${eventSeverityColor[item.eventSeverity]}`">
</span>
<span class="detection-event-severity-block">{{ item.eventName || '-' }}</span>
<span class="detection-event-severity-block">{{ toUpperCaseByString(item.securityType) || '-' }}</span>
<i class="cn-icon cn-icon-attacker"></i>
<span :test-id="`offender-ip${index}`">{{ item.offenderIp || '-' }}</span>
<div class="domain">{{ item.offenderDomain }}</div>
@@ -38,7 +38,7 @@
<div class="basic-info__item" v-if="item.eventSeverity">
<i class="cn-icon cn-icon-severity-level"></i>
<span>{{ $t('network.severity') }}&nbsp;:&nbsp;&nbsp;</span>
<span>{{ changeSecurity(item.eventSeverity) }}</span>
<span>{{ toUpperCaseByString(item.eventSeverity) || '-' }}</span>
</div>
<div class="basic-info__item" v-if="item.eventType">
<i class="cn-icon cn-icon-event-type"></i>
@@ -76,8 +76,8 @@
</template>
<script>
import { dateFormatByAppearance, getNowTime } from '@/utils/date-util'
import { eventSeverityColor, entityDetailTabsName, securityLevel } from '@/utils/constants'
import { dateFormatByAppearance } from '@/utils/date-util'
import { eventSeverityColor, entityDetailTabsName } from '@/utils/constants'
import unitConvert from '@/utils/unit-convert'
import axios from 'axios'
import { api } from '@/utils/api'
@@ -85,7 +85,6 @@ import { useRoute } from 'vue-router'
import chartMixin from '@/views/charts2/chart-mixin'
import { toUpperCaseByString } from '@/utils/tools'
import chartNoData from '@/views/charts/charts/ChartNoData'
import { ref } from 'vue'
export default {
name: 'SecurityEvent',
@@ -103,36 +102,33 @@ export default {
const { query } = useRoute()
const entityType = query.entityType
const entityName = query.entityName
// range取 config.js 中配置的值
const dateRangeValue = DEFAULT_TIME_FILTER_RANGE.entity.securityEvent
const timeFilter = ref({ dateRangeValue })
const { startTime, endTime } = getNowTime(dateRangeValue)
timeFilter.value.startTime = startTime
timeFilter.value.endTime = endTime
return {
entityType,
entityName,
timeFilter
entityName
}
},
mounted () {
this.initData()
/*
// this.initData()
this.isNoData = true
this.$emit('checkTag', entityDetailTabsName.securityEvent, 0)
this.toggleLoading(true)
const timer = setTimeout(() => {
this.toggleLoading(false)
clearInterval(timer)
}, 200) */
}, 200)
},
methods: {
unitConvert,
toUpperCaseByString,
dateFormatByAppearance,
initData () {
const params = this.getParams()
const params = {
resource: this.entityName
// startTime: getSecond(this.timeFilter.startTime),
// endTime: getSecond(this.timeFilter.endTime)
}
this.toggleLoading(true)
axios.get(`${api.entity.security}/${this.entityType}`, { params: params }).then(response => {
const res = response.data
@@ -159,18 +155,6 @@ export default {
this.isNoData = false
this.showError = true
this.errorMsg = this.errorMsgHandler(e)
},
changeSecurity (value) {
if (value) {
const obj = securityLevel.find(d => d.value === value)
let label = value
if (obj) {
label = this.$t(obj.label)
}
return label
} else {
return '-'
}
}
}
}

View File

@@ -12,7 +12,7 @@
import chartMixin from '@/views/charts2/chart-mixin'
import { getSecond } from '@/utils/date-util'
import { api } from '@/utils/api'
import { storageKey, ZH } from '@/utils/constants'
import { storageKey } from '@/utils/constants'
import PopoverContent from './LinkDirectionGrid/PopoverContent'
import { computeScore } from '@/utils/tools'
import axios from 'axios'
@@ -156,9 +156,11 @@ export default {
})
// 一行如果无数据则删除该行默认10*10矩阵
this.handleXRowNoData(linkGridData, 0)
const rowXIndex = 0
this.handleXRowNoData(linkGridData, rowXIndex)
// 一列如果无数据则删除该列默认10*10矩阵
this.handleYRowNoData(linkGridData, 0)
const rowYIndex = 0
this.handleYRowNoData(linkGridData, rowYIndex)
this.isLinkNoData = linkGridData.length === 0
this.linkGridData = linkGridData
}
@@ -176,9 +178,9 @@ export default {
// 接口数据乱序,根据入方向排序,再根据同个入方向下的出方向进行排序
nextLinkData.sort((a, b) => {
if (a.inLinkDirection !== b.inLinkDirection) {
return a.inLinkDirection.localeCompare(b.inLinkDirection, ZH)
return a.inLinkDirection.localeCompare(b.inLinkDirection, 'zh')
}
return a.outLinkDirection.localeCompare(b.outLinkDirection, ZH)
return a.outLinkDirection.localeCompare(b.outLinkDirection, 'zh')
})
this.isNextNoData = nextLinkData.length === 0
@@ -255,9 +257,11 @@ export default {
})
// 一行如果无数据则删除该行默认3*3矩阵
this.handleXRowNoData(nextGridData, 0)
const rowXIndex = 0
this.handleXRowNoData(nextGridData, rowXIndex)
// 一列如果无数据则删除该列默认3*3矩阵
this.handleYRowNoData(nextGridData, 0)
const rowYIndex = 0
this.handleYRowNoData(nextGridData, rowYIndex)
this.isNextNoData = nextGridData.length === 0
this.nextGridData = nextGridData
@@ -353,7 +357,7 @@ export default {
* @param index
*/
handleXRowNoData (data, index) {
if (data && data.length > 0) {
if (data) {
const item = data[index]
let tempList = []
if (item) {
@@ -376,7 +380,7 @@ export default {
*/
handleYRowNoData (data, index) {
const rowList = []
if (data && data.length > 0) {
if (data) {
data.forEach(item => {
if (item.out[index]) {
if (item.out[index].noData) {

View File

@@ -37,7 +37,7 @@
</div>
<div class="line-select line-header-right">
<div class="line-select-metric">
<span>{{$t('detections.metric')}}:</span>
<span>{{$t('network.metric')}}:</span>
<div class="line-select__operation">
<el-select
size="mini"

View File

@@ -326,7 +326,7 @@ export default {
if (tabType) {
const oldCurTab = this.getUrlParam(this.curTabState.networkOverviewBeforeTab, '')
const curTable = networkTable.networkOverview
const tableType = this.$route.path.replace('/panel/', '') || 'networkOverview'
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const metric = this.getUrlParam(this.curTabState.tableMetric, 'Bits/s')
const list = await getUserDrilldownTableConfig(tableType, metric)
const tabGroup = list.filter(item => item.label === tabType)
@@ -493,9 +493,11 @@ export default {
}
})
})
if (!show) { // 非滚动滚动条操作,直接覆盖之前的数据
if (val) {
this.providerOptions = res.data.list
} else { // 滚动条操作,则将新数据和之前的数据组合
} else if (!val && !show) {
this.providerOptions = res.data.list
} else {
this.providerOptions.push(...res.data.list)
this.appListData([], this.providerOptions)
}
@@ -517,9 +519,11 @@ export default {
}
})
})
if (!show) { // 非滚动滚动条操作,直接覆盖之前的数据
if (val) {
this.appOptions = res.data.list
} else { // 滚动条操作,则将新数据和之前的数据组合
} else if (!val && !show) {
this.appOptions = res.data.list
} else {
this.appOptions.push(...res.data.list)
this.appListData(this.appOptions, [])
}

View File

@@ -66,7 +66,7 @@ export default {
startTime: this.timeFilter && this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : '',
endTime: this.timeFilter && this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : ''
}
/* this.toggleLoading(true)
/*this.toggleLoading(true)
axios.get(api.netWorkOverview.ddosEventAnalysis, { params: params }).then(response => {
const res = response.data
if (response.status === 200) {
@@ -85,7 +85,7 @@ export default {
this.errorMsg = this.errorMsgHandler(e)
}).finally(() => {
this.toggleLoading(false)
}) */
})*/
this.toggleLoading(false)
}
},

View File

@@ -32,7 +32,7 @@
</div>
<div class="line-select line-header-right">
<div class="line-select-reference-line">
<span>{{ $t('network.referenceLine') }}&nbsp;:&nbsp;</span>
<span>{{ $t('network.referenceLine') }}:</span>
<div class="line-select__operation">
<el-select
size="mini"
@@ -43,9 +43,7 @@
:popper-append-to-body="false"
@change="referenceSelectChange"
>
<el-option :key="options2[0].value" :label="$t(options2[0].label)" :value="options2[0].value"></el-option>
<el-option :key="options2[1].value" :label="$t(options2[1].label[0], options2[1].label[1])" :value="options2[1].value"></el-option>
<el-option :key="options2[2].value" :label="$t(options2[2].label)" :value="options2[2].value"></el-option>
<el-option v-for="item in options2" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
</div>
@@ -276,14 +274,6 @@ export default {
label: {
formatter (params) {
const arr = valueToRangeValue(params.value, unitTypes.number).join('')
const referIndex = _this.options2.findIndex(o => o.value === _this.lineRefer)
if (referIndex > -1) {
if (referIndex === 1) {
return _this.$t(_this.options2[1].label[0], _this.options2[1].label[1]) + '(' + arr + echartsData[0].unitType + ')'
} else {
return _this.$t(_this.options2[referIndex].label) + '(' + arr + echartsData[0].unitType + ')'
}
}
return _this.lineRefer + '(' + arr + echartsData[0].unitType + ')'
},
position: 'insideStartTop',

View File

@@ -289,9 +289,7 @@ import {
dbDrilldownTableConfig,
fromRoute,
drillDownPanelTypeMapping,
commonErrorTip,
ZH,
EN
commonErrorTip
} from '@/utils/constants'
import axios from 'axios'
import unitConvert, { valueToRangeValue } from '@/utils/unit-convert'
@@ -503,7 +501,7 @@ export default {
const currentValue = document.getElementById('tabSearchValue' + tabProp) ? document.getElementById('tabSearchValue' + tabProp).value : ''
const columnName = curTab ? curTab.label : ''
let type = 'ip'
const tableType = this.$route.path.replace('/panel/', '') || 'networkOverview'
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const curTableInCode = networkTable[tableType] ? networkTable[tableType] : networkTable.networkOverview
if (curTableInCode && curTableInCode.tabList) {
const curTab = curTableInCode.tabList.find(item => item.label === columnName)
@@ -536,7 +534,7 @@ export default {
axios.get(url, { params }).then(async response => {
if (response.status === 200) {
this.tabSearchColumnValueListShow = response.data.data.result
if (this.$route.path.replace('/panel/', '') === fromRoute.dnsServiceInsights) {
if (this.$route.params.typeName === fromRoute.dnsServiceInsights) {
if (this.dnsQtypeMapData.size === 0) {
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
}
@@ -1172,10 +1170,10 @@ export default {
// 数字可按照排序的要求进行自定义,我这边产品的要求是
// 数字0->9->大写字母A->Z->小写字母a->z->中文拼音a->z
if (/^[\u4e00-\u9fa5]$/.test(char)) {
return [ZH, 300]
return ['zh', 300]
}
if (/^[a-zA-Z]$/.test(char)) {
return [EN, 200]
return ['en', 200]
}
if (/^[0-9]$/.test(char)) {
return ['number', 100]
@@ -1224,9 +1222,9 @@ export default {
if (char1 === char2) {
continue
} else {
if (char1Type[0] === ZH) {
if (char1Type[0] === 'zh') {
res = char2.localeCompare(char1)
} else if (char1Type[0] === EN) {
} else if (char1Type[0] === 'en') {
res = char2.charCodeAt(0) - char1.charCodeAt(0)
} else {
res = char2 - char1
@@ -1264,9 +1262,9 @@ export default {
if (char1 === char2) {
continue
} else {
if (char1Type[0] === ZH) {
if (char1Type[0] === 'zh') {
res = char1.localeCompare(char2)
} else if (char1Type[0] === EN) {
} else if (char1Type[0] === 'en') {
res = char1.charCodeAt(0) - char2.charCodeAt(0)
} else {
res = char1 - char2
@@ -2262,9 +2260,10 @@ export default {
this.drillDownTableConfigs = null
this.curTable = null
this.commonColumnList = null
this.userId = localStorage.getItem(storageKey.userId)
this.drillDownTableConfigs = await combineDrilldownTableWithUserConfig()
this.tableType = this.$route.path.replace('/panel/', '') || 'networkOverview'
this.tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
// 是否需要dns的qtype和rcode的数据字典
if (this.tableType === fromRoute.dnsServiceInsights) {
this.dnsQtypeMapData = this.$store.getters.getDnsQtypeMapData
@@ -2346,6 +2345,8 @@ export default {
await this.saveUserLocalConfig()
this.getChartData()
},
setup (props) {
},
beforeUnmount () {
// 以下元素,检测到内存并未释放
this.unitConvert = null

View File

@@ -322,7 +322,7 @@ export default {
const tabType = 'network.applicationCategories'
const oldCurTab = this.getUrlParam(this.curTabState.networkOverviewBeforeTab, '')
const curTable = networkTable.networkAppPerformance
const tableType = this.$route.path.replace('/panel/', '') || 'networkOverview'
const tableType = this.$route.params ? this.$route.params.typeName : 'networkOverview'
const metric = this.getUrlParam(this.curTabState.tableMetric, 'Bits/s')
const list = await getUserDrilldownTableConfig(tableType, metric)
const tabGroup = list.filter(item => item.label === tabType)

View File

@@ -150,7 +150,7 @@ export default {
limit: 10,
type: this.metric
}
/* axios.get(api.npm.events.dimensionEvents, { params }).then(res => {
/*axios.get(api.npm.events.dimensionEvents, { params }).then(res => {
if (res.status === 200) {
this.showError = false
if (!res.data.data.result || res.data.data.result.length === 0) {
@@ -168,7 +168,7 @@ export default {
this.errorMsg = this.errorMsgHandler(e)
}).finally(() => {
this.toggleLoading(false)
}) */
})*/
this.isNoData = true
this.toggleLoading(false)
},

View File

@@ -110,7 +110,7 @@ export default {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime)
}
/* this.toggleLoading(true)
/*this.toggleLoading(true)
axios.get(api.npm.events.recentEvents, { params: params }).then(response => {
const res = response.data
if (response.status === 200) {
@@ -151,7 +151,7 @@ export default {
this.errorMsg = this.errorMsgHandler(e)
}).finally(() => {
this.toggleLoading(false)
}) */
})*/
this.isNoData = true
this.toggleLoading(false)
},

View File

@@ -12,15 +12,15 @@
placeholder=" "
:popper-append-to-body="false"
>
<el-option value="Server" :label="$t('overall.server')">{{$t('overall.server')}}</el-option>
<el-option value="Client" :label="$t('overall.client')">{{$t('overall.client')}}</el-option>
<el-option value="Server">Server</el-option>
<el-option value="Client">Client</el-option>
</el-select>
<el-select
size="mini"
v-model="location"
class="map-select map-select__location"
clearable
:placeholder="$t('overall.country')"
placeholder="All"
filterable
popper-class="map-select-down"
:popper-append-to-body="false"

View File

@@ -21,7 +21,7 @@
<template #default="scope" :column="item">
<div class="data-recent-table">
<template v-if="item.prop === 'eventSeverity'">
<span class="data-recent-table-severity" :class="scope.row[item.prop]" :test-id="`eventSeverity-${scope.row.eventSeverity}-${scope.$index}`">{{ getEventSeverity(scope.row[item.prop]) }}</span>
<span class="data-recent-table-severity" :class="scope.row[item.prop]" :test-id="`eventSeverity-${scope.row.eventSeverity}-${scope.$index}`">{{scope.row[item.prop]}}</span>
</template>
<template v-else-if="item.prop === 'eventKey'">
<span class="data-recent-table-entity click-active" @click="jumpPage(scope.row)" :test-id="`eventKey-${splitEventKey(scope.row.eventKey)}-${scope.$index}`">{{splitEventKey(scope.row[item.prop])}}</span>
@@ -57,7 +57,6 @@ import ChartError from '@/components/common/Error'
import axios from 'axios'
import { dataForNpmRecentEvents } from '@/utils/static-data'
import { beforeRouterPush } from '@/utils/tools'
import { securityLevel } from '@/utils/constants'
export default {
name: 'NpmRecentEvents',
@@ -159,14 +158,6 @@ export default {
this.isNoData = false
this.showError = true
this.errorMsg = this.errorMsgHandler(res)
},
getEventSeverity (severity) {
const obj = securityLevel.find(d => d.value === severity)
if (obj) {
return this.$t(obj.label)
} else {
return severity
}
}
},
mounted () {

View File

@@ -3,7 +3,7 @@
<div class="npm-traffic-line-header">
<div class="npm-traffic-line-title"></div>
<div class="line-select-metric">
<span>{{$t('detections.metric')}}:</span>
<span>{{$t('network.metric')}}:</span>
<div class="line-select__operation">
<el-select
size="mini"

View File

@@ -257,8 +257,7 @@ export const pieChartOption4 = {
show: false,
position: 'middle',
formatter: '{b}: {c}'
},
barMinHeight: 5
}
}],
animation: false
}

View File

@@ -1,36 +1,31 @@
<template>
<div class="detection-filter-case">
<div class="filter-case__header">{{$t('detections.filters')}}</div>
<div class="new-detection-filter-title">{{$t('detections.filters')}}</div>
<div class="no-data" v-if="isNoData">{{ $t('npm.noData') }}</div>
<template v-for="(filter, index) in filterData" :key="index">
<div class="detection-filter" v-show="filter.data.length > 0">
<div class="filter__header">{{filter.title}}</div>
<div class="filter__body" style="position: relative">
<loading :loading="loadingLeft" style="top: -5px;"></loading>
<div class="filter__body-item"
v-for="(data, i) in filter.data.slice(0, filter.showIndex)"
:key="i"
@click="clickFilterItem(data.label, filter.column, index)">
<div class="filter__body-item-left">
<div class="filter__body-item-left-index">{{ i+1 }}</div>
<div class="filter__body-item-left-label">
<el-tooltip :content="data.label" placement="top" effect="light" :disabled="disabledLabel">
<span @mouseenter="handleMouse(`filter${index}${i}`)" :id="`filter${index}${i}`">
<span>{{ data.label }}</span>
</span>
</el-tooltip>
</div>
</div>
<div class="filter__body-item-right">{{ data.count }}</div>
<div class="filter__header" @click="filter.collapse = !filter.collapse">
<span class="new-detection-filter-header-title">{{filter.title}}</span>
<i class="el-icon-arrow-right new-detection-filter-icon" :class="{ 'arrow-rotate': !filter.collapse }"></i>
</div>
<el-collapse-transition>
<div class="filter__body" v-show="!filter.collapse">
<el-checkbox-group v-model="filter.value">
<template v-for="(d, i) in filter.data" :key="i">
<el-checkbox :label="d.value" v-if="!filter.showIndex || filter.showIndex >= i">
<div class="filter__checkbox-label">
<div style="display: flex">
<span class="severity-color-block" v-if="filter.column === 'eventSeverity'" :style="`background-color: ${eventSeverityColor[d.value]}`"></span>
<span :style="filter.column === 'eventSeverity' ? 'padding-left: 10px' : ''">{{d.label}}</span>
</div>
<div v-if="d.count || d.count === 0">{{d.count}}</div>
</div>
</el-checkbox>
</template>
</el-checkbox-group>
<div class="filter__more" v-if="filter.showMore" @click="showMore(filter)">{{$t('overall.showMore')}}</div>
</div>
</div>
<div v-show="filter.showMore" @click="showMore(filter)"
:class="filter.showDisabled? 'filter-no-show-more' : 'filter-show-more'">
{{ $t('overall.showMore') }}
</div>
<div class="filter-hr"></div>
</el-collapse-transition>
</div>
</template>
</div>
@@ -47,36 +42,13 @@ export default {
},
data () {
return {
eventSeverityColor,
disabledLabel: true
eventSeverityColor
}
},
methods: {
showMore (filter) {
filter.showIndex && (filter.showIndex += 5)
filter.showIndex >= (filter.data.length - 1) && (filter.showDisabled = true)
},
clickFilterItem (name, data, index) {
if (index === 0) {
let status = 0
if (name === this.$t('detections.active')) {
status = '0'
} else if (name === this.$t('detections.ended')) {
status = '1'
}
this.$emit('filter', status, data)
} else {
this.$emit('filter', name, data)
}
},
handleMouse (id) {
const dom = document.getElementById(id)
if (dom) {
const width = document.getElementById(id).offsetWidth
this.disabledLabel = width < 180
} else {
this.disabledLabel = true
}
filter.showIndex && (filter.showIndex += 10)
filter.showIndex >= (filter.data.length - 1) && (filter.showMore = false)
}
},
computed: {

View File

@@ -1,7 +1,7 @@
<template>
<div class="explorer-search explorer-search--show-list">
<div class="explorer-search__input-case explorer-search__input-case--question-mark-in-line" style="position: relative">
<div class="explorer-search__input entity__search">
<div class="explorer-search__input-case explorer-search__input-case--question-mark-in-line">
<div class="explorer-search__input">
<advanced-search
ref="search"
:column-list="columnList[pageType]"
@@ -13,36 +13,6 @@
@search="search"
></advanced-search>
</div>
<div class="explorer-search__foot-list" v-ele-click-outside="esc">
<div class="explorer-search__block" @click="triggerHistory">
<i class="cn-icon cn-icon-time"></i>
<div class="search-dividing-line"></div>
</div>
<transition name="el-zoom-in-top">
<div class="search__history" v-if="showHistory">
<div class="history__items-new">
<el-table
:data="history"
scrollbar-always-on="false"
@row-click="selectHistory"
style="overflow-x: unset"
empty-text=" "
>
<el-table-column prop="str" :label="$t('overall.expression')" min-width="560" />
<el-table-column prop="date" :label="$t('overall.time')" sortable width="200">
<template #default="scope">
<span>{{ changeTimeByDate(scope.row.date) }}</span>
</template>
</el-table-column>
</el-table>
</div>
<div class="clear-all">
<span @click="clearHistory" v-if="!$_.isEmpty(history)">{{$t('entity.clearAll')}}</span>
<div v-else>{{$t('overall.noRecords')}}</div>
</div>
</div>
</transition>
</div>
<!-- <div class="search-symbol-inline">-->
<!-- <i class="cn-icon cn-icon-help"></i>-->
<!-- </div>-->
@@ -55,9 +25,6 @@ import AdvancedSearch from '@/components/advancedSearch/Index'
import { schemaDetectionSecurity } from '@/utils/static-data'
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import { storageKey } from '@/utils/constants'
import _ from 'lodash'
import { changeTimeByDate } from '@/utils/tools'
export default {
name: 'DetectionSearch',
props: {
@@ -128,9 +95,7 @@ export default {
label: 'OR'
}
],
showList: true,
showHistory: false,
history: []
showList: true
}
},
emits: ['search'],
@@ -157,66 +122,70 @@ export default {
}
this.$emit('search', metaList, sql)
}, */
changeTimeByDate,
search ({ str, q, metaList }) {
if (str) {
// 加入搜索记录将记录数量控制在30以内
const oldHistory = localStorage.getItem(storageKey.detectionSearchHistory)
let arr = []
const newItem = { str, date: this.dateFormatByAppearance(new Date()) }
if (!_.isEmpty(oldHistory)) {
const oldArr = JSON.parse(oldHistory)
if (str === oldArr[0].str) {
oldArr[0].date = this.dateFormatByAppearance(new Date())
} else {
oldArr.unshift(newItem)
}
arr = [...oldArr]
if (arr.length > 30) {
arr = arr.slice(0, 30)
}
} else {
arr.push(newItem)
}
localStorage.setItem(storageKey.detectionSearchHistory, JSON.stringify(arr))
}
search ({ q, metaList }) {
this.$emit('search', { q, metaList })
},
changeParams (params) {
this.$refs.search.addParams(params)
},
selectHistory (row) {
this.$refs.search.setStr(row.str)
this.showHistory = false
changeParams (params) { // params: { column: columnName, oldValue: [...], newValue: [...] }
// 向下传递时需要再转换一次param格式为[{column, operator, value}, ...]
if (params.oldValue.length === 0 && params.newValue.length === 1) {
// 1.参数值数量从0到1直接addParams
const p = {
column: params.column,
operator: '=',
value: params.newValue
}
this.$refs.search.addParams([p])
} else if (params.oldValue.length === 1 && params.newValue.length === 0) {
// 2.参数值数量从1到0直接removeParams
const p = {
column: params.column,
operator: '=',
value: params.oldValue
}
this.$refs.search.removeParams([p])
} else if (params.oldValue.length === 2 && params.newValue.length === 1) {
// 3.参数值数量从多到1operator由'in'改为'='
const oldParam = {
column: params.column,
operator: 'IN',
value: params.oldValue
}
const newParam = {
column: params.column,
operator: '=',
value: params.newValue
}
this.$refs.search.changeParams([{ newParam, oldParam }])
} else if (params.oldValue.length === 1 && params.newValue.length === 2) {
// 4.参数值数量从1到多, operator由'='改为'in'
const oldParam = {
column: params.column,
operator: '=',
value: params.oldValue
}
const newParam = {
column: params.column,
operator: 'IN',
value: params.newValue
}
this.$refs.search.changeParams([{ newParam, oldParam }])
} else {
// 5.参数值数量从多到多加1或者减1
const oldParam = {
column: params.column,
operator: 'IN',
value: params.oldValue
}
const newParam = {
column: params.column,
operator: 'IN',
value: params.newValue
}
this.$refs.search.changeParams([{ newParam, oldParam }])
}
this.$nextTick(() => {
if (this.$refs.search.$refs.textMode) {
this.$refs.search.$refs.textMode.focus()
}
this.emitter.emit('advanced-search')
})
if (this.showList) {
this.$nextTick(() => {
this.emitter.emit('advanced-search')
})
}
},
clearHistory () {
localStorage.setItem(storageKey.detectionSearchHistory, '')
this.history = []
},
triggerHistory () {
this.showHistory = !this.showHistory
if (this.showHistory) {
const history = localStorage.getItem(storageKey.detectionSearchHistory)
if (!_.isEmpty(history)) {
this.history = JSON.parse(history)
}
}
},
esc () {
const timer = setTimeout(() => {
this.showHistory = false
clearTimeout(timer)
}, 100)
}
}
}

View File

@@ -4,7 +4,7 @@
<div class="explorer-top-tools explorer-detection-top-tools">
<div class="explorer-top-tools-title">{{$t('overall.detections')}}</div>
<div style="display: flex">
<div class="explorer-top-tools-block" @click="jumpNewDetetion" v-if="hasPermission('detectionPolicy')">
<div class="explorer-top-tools-block" @click="jumpNewDetetion">
<i class="cn-icon cn-icon-configure-policies detection-icon-setting"></i>
<span>{{$t('config.detections.configurePolicies')}}</span>
</div>
@@ -21,12 +21,13 @@
:end-time="timeFilter.endTime"/>
</div>
</div>
<div style="width: 100%; padding-bottom: 50px;">
<div style="width: 100%;padding-bottom: 47px;">
<chart-tabs :data="tabsData" router></chart-tabs>
</div>
<!-- 搜索组件 -->
<detection-search
class="detection-border"
ref="search"
:page-type="pageType"
@search="search"
@@ -47,7 +48,6 @@
:filter-data="filterData[pageType]"
:q="q"
:time-filter="timeFilter"
@filter="getFilter"
></detection-filter>
<div class="detection__list">
@@ -138,8 +138,6 @@ import { useRoute } from 'vue-router'
import Loading from '@/components/common/Loading'
import ChartTabs from '@/components/common/ChartTabs'
import { useStore } from 'vuex'
import { tooLongFormatter } from '@/views/charts/charts/tools'
import { format } from 'echarts'
export default {
name: 'Index',
@@ -174,12 +172,12 @@ export default {
// }
],
chartInit: [],
// pageObj: {
// pageNo: 1,
// pageSize: defaultPageSize,
// total: 0,
// resetPageNo: true
// },
pageObj: {
pageNo: 1,
pageSize: defaultPageSize,
total: 0,
resetPageNo: true
},
q: '',
detectionPageType,
filterData: {
@@ -190,7 +188,6 @@ export default {
topColumn: 'status',
collapse: false,
value: [], // value之间是or的关系
showMore: false,
data: [] // 从接口动态获取,本项在获得数据后需要特殊处理左边框颜色
},
{
@@ -199,7 +196,6 @@ export default {
topColumn: 'severity',
collapse: false,
value: [], // value之间是or的关系
showMore: false,
data: [] // 从接口动态获取,本项在获得数据后需要特殊处理左边框颜色
},
{
@@ -208,9 +204,6 @@ export default {
topColumn: 'event_type',
collapse: false,
value: [],
showMore: true,
showDisabled: true,
showIndex: 5, // index作为showMore分割从1开始而非0
data: [] // 从接口动态获取
},
{
@@ -220,21 +213,43 @@ export default {
collapse: false,
value: [],
showMore: true,
showDisabled: true,
showIndex: 5,
showIndex: 9,
data: [] // 从接口动态获取
},
// {
// title: this.$t('detections.victimLocation'),
// column: 'victimLocationCountry',
// collapse: false,
// value: [],
// showMore: false,
// showIndex: 9,
// data: [
// {
// label: 'China',
// value: 'china',
// count: 50
// }
// ] // 从接口动态获取
// },
{
title: this.$t('detections.offenderIp'),
column: 'offenderIP',
topColumn: 'offender_ip',
collapse: false,
value: [],
showMore: true,
showDisabled: true,
showIndex: 5,
showMore: false,
showIndex: 9,
data: [] // 从接口动态获取
}
// {
// title: this.$t('detections.offenderLocation'),
// column: 'offenderLocationCountry',
// collapse: false,
// value: [],
// showMore: false,
// showIndex: 9,
// data: [] // 从接口动态获取
// }
],
performanceEvent: [
{
@@ -271,8 +286,7 @@ export default {
isStatisticsActiveAttackNoData: false,
loading: false,
oldActiveEntitySearchValue: '',
initFlag: true, // 初始化标识初始化时保证mounted执行
detectionChart:shallowRef(null)
initFlag: true // 初始化标识初始化时保证mounted执行
}
},
methods: {
@@ -280,11 +294,6 @@ export default {
axios.get(api.detection[this.pageType].statusStatistics, { params }).then(res => {
if (res.status === 200) {
const data = res.data.data.result
if (data && data.length > 0) {
data.sort((a, b) => {
return Number(b.count) - Number(a.count)
})
}
this.filterData[this.pageType][0].data = data.map(r => {
let label = ''
if (r.status === '0') {
@@ -379,11 +388,6 @@ export default {
initEventSeverityData (params) {
axios.get(api.detection[this.pageType].severityStatistics, { params }).then(res => {
const data = res.data.data.result
if (data && data.length > 0) {
data.sort((a, b) => {
return Number(b.count) - Number(a.count)
})
}
this.statisticsSeverityData = data
if (!this.$_.isEmpty(data)) {
this.filterData[this.pageType][1].data = data.map(r => ({ label: r.severity, value: r.severity, count: r.count }))
@@ -406,7 +410,6 @@ export default {
if (this.pageType === 'performanceEvent') {
vm.filterData.performanceEvent[0].value = vm.triggerFilterDataValue(vm.filterData.performanceEvent[0].value, e.data.name)
} else if (this.pageType === 'securityEvent') {
this.getFilter(e.data.name, vm.filterData.securityEvent[1].column)
vm.filterData.securityEvent[1].value = vm.triggerFilterDataValue(vm.filterData.securityEvent[1].value, e.data.name)
}
})
@@ -427,11 +430,6 @@ export default {
value: r.eventType,
count: r.count
}))
const { showMore, showIndex, showDisabled } = this.computeFilterPage(this.filterData[this.pageType][2].data)
this.filterData[this.pageType][2].showMore = showMore
this.filterData[this.pageType][2].showIndex = showIndex
this.filterData[this.pageType][2].showDisabled = showDisabled
const chartDom = document.getElementById(`detectionCategoryPer${this.pageType}`)
let detectionChart = echarts.getInstanceByDom(chartDom)
if (detectionChart) {
@@ -443,15 +441,6 @@ export default {
securityTypeOption.series[0].data = data.map(d => {
return { value: d.count, name: d.eventType }
})
if (chartDom) {
let oneColumnWidth = (chartDom.clientWidth * 0.56) - 30
if (data.length > 6) {
oneColumnWidth = (chartDom.clientWidth * 0.56) / 2 - 30
}
securityTypeOption.legend.formatter = function (name) {
return format.truncateText(name, oneColumnWidth, '12px')
}
}
detectionChart.setOption(securityTypeOption)
const vm = this
@@ -463,9 +452,6 @@ export default {
}).catch(e => {
console.error(e)
this.filterData[this.pageType][2].data = []
this.filterData[this.pageType][2].showMore = false
this.filterData[this.pageType][2].showIndex = 5
this.filterData[this.pageType][2].showDisabled = true
this.$message.error(this.errorMsgHandler(e))
})
},
@@ -481,45 +467,28 @@ export default {
count: r.count
}))
this.isCheckFilterByQ(params, 2)
const { showMore, showIndex, showDisabled } = this.computeFilterPage(this.filterData[this.pageType][2].data)
this.filterData[this.pageType][2].showMore = showMore
this.filterData[this.pageType][2].showIndex = showIndex
this.filterData[this.pageType][2].showDisabled = showDisabled
const chartDom = document.getElementById(`detectionCategoryPer${this.pageType}`)
this.detectionChart = echarts.getInstanceByDom(chartDom)
if (this.detectionChart) {
echarts.dispose(this.detectionChart)
let detectionChart = echarts.getInstanceByDom(chartDom)
if (detectionChart) {
echarts.dispose(detectionChart)
}
this.detectionChart = echarts.init(chartDom)
//this.chartInit.push(shallowRef(detectionChart))
detectionChart = echarts.init(chartDom)
this.chartInit.push(shallowRef(detectionChart))
const securityTypeOption = this.$_.cloneDeep(pieForSeverity)
securityTypeOption.series[0].data = data.map(d => {
return { value: d.count, name: d.eventType, itemStyle: { color: getAttackColor(d.eventType) } }
})
if (chartDom) {
let oneColumnWidth = (chartDom.clientWidth * 0.56) - 30
if (data.length > 6) {
oneColumnWidth = (chartDom.clientWidth * 0.56) / 2 - 30
}
securityTypeOption.legend.formatter = function (name) {
return format.truncateText(name, oneColumnWidth, '12px')
}
}
this.detectionChart.setOption(securityTypeOption)
detectionChart.setOption(securityTypeOption)
const vm = this
this.detectionChart.off('click')
this.detectionChart.on('click', e => {
this.getFilter(e.data.name, vm.filterData.securityEvent[2].column)
detectionChart.off('click')
detectionChart.on('click', e => {
vm.filterData.securityEvent[2].value = vm.triggerFilterDataValue(vm.filterData.securityEvent[2].value, e.data.name)
})
}
}).catch(e => {
console.error(e)
this.filterData[this.pageType][2].data = []
this.filterData[this.pageType][2].showMore = false
this.filterData[this.pageType][2].showIndex = 5
this.filterData[this.pageType][2].showDisabled = true
this.$message.error(this.errorMsgHandler(e))
})
},
@@ -535,10 +504,9 @@ export default {
count: r.count
}))
this.isCheckFilterByQ(params, 4)
const { showMore, showIndex, showDisabled } = this.computeFilterPage(this.filterData[this.pageType][4].data)
const { showMore, showIndex } = this.computeFilterPage(this.filterData[this.pageType][4].data)
this.filterData[this.pageType][4].showMore = showMore
this.filterData[this.pageType][4].showIndex = showIndex
this.filterData[this.pageType][4].showDisabled = showDisabled
const chartDom = document.getElementById(`detectionActiveAttacker${this.pageType}`)
let detectionChart = echarts.getInstanceByDom(chartDom)
@@ -558,18 +526,14 @@ export default {
const vm = this
detectionChart.off('click')
detectionChart.on('click', e => {
if (e.data) {
vm.getFilter(e.data[1], vm.filterData.securityEvent[4].column)
vm.filterData.securityEvent[4].value = vm.triggerFilterDataValue(vm.filterData.securityEvent[4].value, e.data[1])
}
vm.filterData.securityEvent[4].value = vm.triggerFilterDataValue(vm.filterData.securityEvent[4].value, e.data[1])
})
}
}).catch(e => {
console.error(e)
this.filterData[this.pageType][4].data = []
this.filterData[this.pageType][4].showMore = false
this.filterData[this.pageType][4].showIndex = 5
this.filterData[this.pageType][4].showDisabled = true
this.filterData[this.pageType][4].showIndex = 9
this.$message.error(this.errorMsgHandler(e))
})
},
@@ -579,16 +543,14 @@ export default {
const data = res.data.data.result
this.filterData[this.pageType][3].data = data.map(r => ({ label: r.victimIp, value: r.victimIp, count: r.count }))
this.isCheckFilterByQ(params, 3)
const { showMore, showIndex, showDisabled } = this.computeFilterPage(this.filterData[this.pageType][3].data)
const { showMore, showIndex } = this.computeFilterPage(this.filterData[this.pageType][3].data)
this.filterData[this.pageType][3].showMore = showMore
this.filterData[this.pageType][3].showIndex = showIndex
this.filterData[this.pageType][3].showDisabled = showDisabled
}).catch(e => {
console.error(e)
this.filterData[this.pageType][3].data = []
this.filterData[this.pageType][3].showMore = false
this.filterData[this.pageType][3].showIndex = 5
this.filterData[this.pageType][3].showDisabled = true
this.filterData[this.pageType][3].showIndex = 9
this.$message.error(this.errorMsgHandler(e))
})
},
@@ -669,9 +631,8 @@ export default {
},
computeFilterPage (data) {
return {
showMore: data.length > 0,
showDisabled: data.length <= 5,
showIndex: 5
showMore: data.length > 10,
showIndex: 9
}
},
queryList (q) {
@@ -755,7 +716,7 @@ export default {
this.q = ''
this.metaList = []
}
if (this.pageObj.resetPageNo && !this.initFlag) {
if (this.pageObj.resetPageNo) {
this.pageObj.pageNo = 1
} else {
this.pageObj.resetPageNo = true
@@ -813,11 +774,11 @@ export default {
this.search(this.metaList, this.q)
},
pageNo (val) {
this.pageObj.pageNo = val || 1
this.pageObj.resetPageNo = false
// 初始化时mounted和pageNo都会调用列表接口且pageNo先执行
// 初始化保证mounted执行后续pageNo变动则不影响接口调用
if (!this.initFlag) {
this.pageObj.pageNo = val || 1
this.pageObj.resetPageNo = false
this.search(this.metaList, this.q)
}
},
@@ -842,28 +803,10 @@ export default {
},
resize () {
this.chartInit.forEach(e => { e.value.resize() })
const chartDom = document.getElementById(`detectionCategoryPer${this.pageType}`)
this.detectionChart = echarts.getInstanceByDom(chartDom)
if(this.detectionChart){
let securityTypeOption = this.$_.cloneDeep(this.detectionChart.getOption())
echarts.dispose(this.detectionChart)
if (chartDom) {
this.detectionChart = echarts.init(chartDom)
let oneColumnWidth = (chartDom.clientWidth * 0.56) - 30
if (this.statisticsCategoryData.length > 6) {
oneColumnWidth = (chartDom.clientWidth * 0.56) / 2 - 30
}
securityTypeOption.legend[0].formatter = function (name) {
return format.truncateText(name, oneColumnWidth, '12px')
}
this.detectionChart.setOption(securityTypeOption)
}
}
},
jumpNewDetetion () {
this.$router.push({
path: '/detection/policy',
path: '/detectionPolicy',
query: {
t: +new Date()
}
@@ -880,34 +823,11 @@ export default {
if (obj) {
this.filterData[this.pageType][index].value = [obj.value]
this.filterData[this.pageType][index].flag = true
} else {
this.filterData[this.pageType][index].value = []
this.filterData[this.pageType][index].flag = true
}
} else {
this.filterData[this.pageType][index].value = []
this.filterData[this.pageType][index].flag = true
}
},
getFilter (name, topColumn) {
if (topColumn === 'tag') {
const params = {
column: topColumn,
operator: 'has',
value: name
}
this.$refs.search.changeParams([params])
} else {
const params = {
column: topColumn,
operator: '=',
value: name
}
this.$refs.search.changeParams([params])
}
this.$nextTick(() => {
this.emitter.emit('advanced-search')
})
}
},
mounted () {
@@ -926,11 +846,7 @@ export default {
}
}
this.queryFilter(q)
if (this.initFlag) {
this.timer = setTimeout(() => {
this.initFlag = false
}, 1000)
}
this.initFlag = false
this.queryList(q)
this.debounceFunc = this.$_.debounce(this.resize, 300)
window.addEventListener('resize', this.debounceFunc)
@@ -1000,6 +916,78 @@ export default {
},
timeFilter () {
this.search(this.metaList, this.q)
},
'filterData.securityEvent.0.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[0].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[0].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[0].flag = false
}
}
},
'filterData.securityEvent.1.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[1].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[1].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[1].flag = false
}
}
},
'filterData.securityEvent.2.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[2].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[2].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[2].flag = false
}
}
},
'filterData.securityEvent.3.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[3].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[3].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[3].flag = false
}
}
},
'filterData.securityEvent.4.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[4].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[4].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[4].flag = false
}
}
},
'filterData.securityEvent.5.value': {
deep: true,
handler (n, o) {
if (!this.filterData.securityEvent[5].flag) {
this.$refs.search.changeParams({ column: this.filterData.securityEvent[5].column, oldValue: o, newValue: n })
} else {
this.filterData.securityEvent[5].flag = false
}
}
},
'filterData.performanceEvent.0.value': {
deep: true,
handler (n, o) {
this.$refs.search.changeParams({ column: this.filterData.performanceEvent[0].column, oldValue: o, newValue: n })
}
},
'filterData.performanceEvent.1.value': {
deep: true,
handler (n, o) {
this.$refs.search.changeParams({ column: this.filterData.performanceEvent[1].column, oldValue: o, newValue: n })
}
}
},
beforeUnmount () {
@@ -1007,10 +995,11 @@ export default {
},
setup () {
const store = useStore()
let { query, path } = useRoute()
let { params, query, path } = useRoute()
// 获取路由跳转过的历史状态,赋值给当前界面,起到保留状态的作用,如浏览器的回退前进等
const routerObj = store.getters.getRouterHistoryList.find(item => item.t === query.t)
if (routerObj) {
params = routerObj.params
query = routerObj.query
path = routerObj.path
@@ -1018,16 +1007,15 @@ export default {
const newUrl = urlParamsHandler(window.location.href, useRoute().query, query)
overwriteUrl(newUrl)
}
const pageType = path.replace('/detection/', '')
const pageType = params.typeName
// 获取url携带的range、startTime、endTime
const rangeParam = query.range
const startTimeParam = query.startTime
const endTimeParam = query.endTime
// 优先级url > config.js > 默认值。
const dateRangeValue = rangeParam ? parseInt(rangeParam) : (DEFAULT_TIME_FILTER_RANGE.detection || 60)
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
const timeFilter = ref({ dateRangeValue })
if (!startTimeParam || !endTimeParam) {
const { startTime, endTime } = getNowTime(dateRangeValue)
const { startTime, endTime } = getNowTime(60)
timeFilter.value.startTime = getSecond(startTime)
timeFilter.value.endTime = getSecond(endTime)
// 如果没有时间参数就将参数写入url
@@ -1037,17 +1025,9 @@ export default {
timeFilter.value.startTime = parseInt(startTimeParam)
timeFilter.value.endTime = parseInt(endTimeParam)
}
const pageObj = ref({
pageNo: query.pageNo ? parseInt(query.pageNo) : 1,
// 是否重置pageNo在执行新搜索时是true
resetPageNo: true,
pageSize: query.pageSize ? parseInt(query.pageSize) : defaultPageSize,
total: 0
})
return {
timeFilter,
pageType,
pageObj
pageType
}
}
}

View File

@@ -30,7 +30,6 @@
:isNoData="isNoData"
:custom-table-title="tools.customTableTitle"
:table-data="tableData"
:policy-detail="policyDetail"
:is-selected-status="isSelectedStatus"
:all-count="18"
@selectionChange="selectionChange"
@@ -76,7 +75,7 @@
<div class="detection-drawer">
<el-drawer v-model="showDrawer" :with-header="false">
<detection-drawer :drawer-info="drawerInfo" @edit="onEdit" />
<detection-drawer :drawer-info="drawerInfo"></detection-drawer>
</el-drawer>
</div>
@@ -90,7 +89,6 @@ import { api } from '@/utils/api'
import dataListMixin from '@/mixins/data-list'
import DetectionDrawer from '@/views/detections/detectionPolicies/PolicyDrawer'
import axios from 'axios'
import { useRoute } from 'vue-router'
export default {
name: 'Index',
@@ -120,40 +118,14 @@ export default {
drawerInfo: {},
filterParams: {},
policyTotal: 0,
policyEnabledNum: 0,
policyDetail: {}
}
},
mounted () {
const { query } = useRoute()
if (query.name && query.ruleId) {
this.getPolicyDetail(query.ruleId)
policyEnabledNum: 0
}
},
methods: {
getPolicyDetail (id) {
if (id) {
axios.get(`${api.detection.detail}/${id}`).then(res => {
if (res.status === 200) {
if (!res.data.data) {
throw new Error('No data found, id: ' + this.ruleId)
}
this.policyDetail = res.data.data
this.selectionChange([res.data.data])
this.onRowDoubleClick(res.data.data)
} else {
console.error(res.data)
}
}).catch(e => {
console.error(e)
this.$message.error(this.errorMsgHandler(e))
})
}
},
onSearch (keyWord) {
this.filterParams = {
...this.filterParams,
q: keyWord
name: keyWord
}
this.search(this.filterParams, 'detection')
},
@@ -168,7 +140,7 @@ export default {
},
onCreate () {
this.$router.push({
path: '/detection/policy/create',
path: '/detectionPolicy/create',
query: {
t: +new Date()
}
@@ -177,12 +149,11 @@ export default {
onEdit () {
const pageNo = this.$router.currentRoute.value.query.pageNo
this.$router.push({
path: '/detection/policy/edit',
path: '/detectionPolicy/edit',
query: {
t: +new Date(),
pageNoForTable: pageNo || 1,
id: this.batchDeleteObjs[0].ruleId,
name: this.$route.query.name || ''
id: this.batchDeleteObjs[0].ruleId
}
})
},

View File

@@ -2,10 +2,7 @@
<div class="detection-drawer" style="height: 100vh;overflow: scroll;padding-bottom: 90px">
<div class="drawer-basic">
<div class="drawer-basic-header">
<div class="drawer-basic-id">
<div>ID: {{ drawerInfo.ruleId }}</div>
<i @click="onEdit" class="cn-icon cn-icon-bianji1"></i>
</div>
<div class="drawer-basic-id">ID: {{ drawerInfo.ruleId }}</div>
<div :class="`detection-tag-status${drawerInfo.status}`">
{{ $t(switchStatus(drawerInfo.status)) }}
</div>
@@ -85,7 +82,7 @@
<div class="detection-drawer-collapse" style="margin: 20px 0">
<el-collapse v-model="activeTrigger">
<el-collapse-item :title="$t('detection.create.trigger')" name="trigger">
<div class="drawer-collapse-content" v-if="language===EN">
<div class="drawer-collapse-content" v-if="language==='en'">
<div class="drawer-collapse-trigger">
Triggered when conditions occur at least
<span style="color: #046ECA">
@@ -105,7 +102,7 @@
</div>
</div>
</div>
<div class="drawer-collapse-content" v-if="language===ZH">
<div class="drawer-collapse-content" v-if="language==='cn'">
<div class="drawer-collapse-trigger">
当条件为
<span style="color: #046ECA">
@@ -134,7 +131,7 @@
<script>
import { switchStatus, toUpperCaseByString } from '@/utils/tools'
import { detectionUnitList, eventSeverityColor, securityLevel, storageKey, ZH, EN } from '@/utils/constants'
import { detectionUnitList, eventSeverityColor, securityLevel, storageKey } from '@/utils/constants'
import axios from 'axios'
import { api } from '@/utils/api'
@@ -152,11 +149,9 @@ export default {
detailData: {},
eventSeverityColor,
severityList: [],
language: EN,
language: 'en',
atLeast: 0,
times: 'time',
ZH,
EN
times: 'time'
}
},
watch: {
@@ -171,7 +166,7 @@ export default {
}
},
mounted () {
this.language = localStorage.getItem(storageKey.language) || EN
this.language = localStorage.getItem(storageKey.language) || 'en'
},
methods: {
switchStatus,
@@ -248,9 +243,6 @@ export default {
} else {
return '-'
}
},
onEdit () {
this.$emit('edit')
}
}
}

View File

@@ -6,8 +6,8 @@
{{ ruleId ? $t('detection.editEventPolicies') : $t('detection.createEventPolicies') }}
</div>
<!--第一步General Settings-->
<div class="detection-form-content">
<!--第一步General Settings-->
<div class="detection-form-collapse">
<el-collapse v-model="activeNames">
<el-collapse-item name="1">
@@ -43,7 +43,7 @@
<!--第三步Trigger-->
<div class="detection-form-collapse">
<el-collapse v-model="activeNames" class="policy-form-trigger">
<el-collapse v-model="activeNames">
<el-collapse-item name="3">
<template #title>
<div class="form-collapse-header">
@@ -53,7 +53,7 @@
</template>
<div class="form-collapse-content margin-t-18">
<el-form v-if="language===EN" class="trigger-block margin-b-20" ref="form3" :model="triggerObj" :rules="rules">
<el-form v-if="language==='en'" class="trigger-block margin-b-20" ref="form3" :model="triggerObj" :rules="rules">
<div class="trigger-block-item margin-b-10">
<div>At least</div>
<el-form-item prop="atLeast">
@@ -94,7 +94,7 @@
</el-form-item>
</div>
</el-form>
<el-form v-if="language===ZH" class="trigger-block margin-b-20" ref="form3" :model="triggerObj" :rules="rules">
<el-form v-if="language==='cn'" class="trigger-block margin-b-20" ref="form3" :model="triggerObj" :rules="rules">
<div class="trigger-block-item margin-b-10">
<el-form-item prop="interval">
@@ -136,20 +136,18 @@
不活跃将重置计数
</div>
</el-form>
<div class="form-setting__btn1">
<div class="btn1">
<el-button @click="createPolicy('')">{{ $t('overall.save') }}</el-button>
</div>
<el-button @click="createPolicy('enabled')">{{ $t('overall.save') }} & {{ $t('detection.create.enablePolicy') }}</el-button>
</div>
</div>
</el-collapse-item>
</el-collapse>
</div>
</div>
<div class="policy-form__footer">
<div class="policy-form__footer__btn">
<div class="btn1">
<el-button @click="cancel">{{ $t('overall.cancel') }}</el-button>
</div>
<el-button @click="createPolicy">{{ $t('overall.save') }}</el-button>
</div>
</div>
</div>
</template>
@@ -162,7 +160,7 @@ import { useRoute } from 'vue-router'
import { ref } from 'vue'
import { getDurationsTimeByType, getTimeByDurations } from '@/utils/date-util'
import Loading from '@/components/common/Loading'
import { storageKey, detectionUnitList, ZH, EN } from '@/utils/constants'
import { storageKey, detectionUnitList } from '@/utils/constants'
export default {
name: 'DetectionForm',
@@ -259,9 +257,7 @@ export default {
intervalList: [],
editObj: {},
isComplete: true, // 参数完整标识默认完整照顾编辑模式false即不完整
language: EN,
ZH,
EN
language: 'en'
}
},
components: {
@@ -270,10 +266,10 @@ export default {
Loading
},
mounted () {
this.language = localStorage.getItem(storageKey.language) || EN
if (this.language === EN) {
this.language = localStorage.getItem(storageKey.language) || 'en'
if (this.language === 'en') {
this.intervalList = detectionUnitList.intervalList
} else if (this.language === ZH) {
} else if (this.language === 'cn') {
this.intervalList = detectionUnitList.intervalListCN
}
this.getDetailInfo()
@@ -334,7 +330,7 @@ export default {
console.error(e)
this.$message.error(this.errorMsgHandler(e))
this.$router.push({
path: '/detection/policy',
path: '/detectionPolicy',
query: {
pageNo: this.pageNoForTable ? Number(this.pageNoForTable) : 1,
t: +new Date()
@@ -371,7 +367,7 @@ export default {
}
},
/** 创建policy */
createPolicy () {
createPolicy (flag) {
const settingLen = Object.keys(this.settingObj).length
const ruleLen = Object.keys(this.ruleObj).length
@@ -380,6 +376,9 @@ export default {
if (valid) {
// 最终提交form
const formObj = this.$_.cloneDeep({ ...this.settingObj, ruleConfig: JSON.stringify(this.ruleObj), ruleTrigger: this.triggerObj })
if (flag) {
formObj.status = 1
}
// 将时间转为参数所需如5分钟转为PT5M
formObj.ruleTrigger.resetInterval = getDurationsTimeByType(formObj.ruleTrigger.resetInterval, formObj.ruleTrigger.resetIntervalVal)
formObj.ruleTrigger.interval = getDurationsTimeByType(formObj.ruleTrigger.interval, formObj.ruleTrigger.intervalVal)
@@ -403,7 +402,7 @@ export default {
})
this.$router.push({
path: '/detection/policy',
path: '/detectionPolicy',
query: {
t: +new Date()
}
@@ -419,6 +418,7 @@ export default {
this.myLoading = false
})
} else {
console.log('进来')
this.myLoading = true
axios.put(api.detection.create.create, formObj).then(response => {
if (response.status === 200) {
@@ -428,18 +428,12 @@ export default {
message: this.$t('tip.saveSuccess')
})
const { query } = this.$route
const queryInfo = {
pageNo: self.pageNoForTable ? Number(self.pageNoForTable) : 1,
t: +new Date()
}
if (query.name && query.id) {
queryInfo.ruleId = query.id
queryInfo.name = this.settingObj.name
}
this.$router.push({
path: '/detection/policy',
query: queryInfo
path: '/detectionPolicy',
query: {
pageNo: self.pageNoForTable ? Number(self.pageNoForTable) : 1,
t: +new Date()
}
})
} else {
console.error(response.data.message)
@@ -497,134 +491,7 @@ export default {
return { flag: false, msg: this.$t('policy.dateTimeRangeSeconds') }
}
}
},
cancel () {
const { query } = this.$route
const queryInfo = {
pageNo: this.pageNoForTable ? Number(this.pageNoForTable) : 1,
t: +new Date()
}
if (query.name && query.id) {
queryInfo.ruleId = query.id
queryInfo.name = this.settingObj.name
}
this.$refs.form3.validate(valid => {
if (this.settingObj.settingNoContinue || this.ruleObj.settingNoContinue || !valid) {
this.$confirm(this.$t('tip.leavePage'), {
confirmButtonText: this.$t('tip.confirm'),
cancelButtonText: this.$t('overall.cancel'),
message: this.$t('tip.leavePageTips'),
title: this.$t('tip.leavePage'),
type: 'warning',
iconClass: 'width:0px;height:0px;',
customClass: 'del-model'
}).then(() => {
this.$router.push({
path: '/detection/policy',
query: queryInfo
})
}).catch(() => {})
} else {
this.$router.push({
path: '/detection/policy',
query: queryInfo
})
}
})
}
}
}
</script>
<style lang="scss">
.del-model {
display: flex;
flex-direction: column;
padding-bottom: 0 !important;
width: 480px !important;
height: 190px;
.el-message-box__header {
display: flex;
flex-direction: row;
border-bottom: 1px solid #eee;
height: 42px;
background: #F7F7F7;
box-shadow: 0 1px 0 0 rgba(53, 54, 54, 0.08);
padding-left: 20px;
padding-top: 14px;
padding-bottom: 14px;
.el-message-box__headerbtn {
display: flex !important;
flex-direction: row-reverse;
justify-content: center;
align-items: center;
font-size: 10px;
line-height: 10px;
padding-right: 5px !important;
i {
width: 10px;
height: 10px;
}
}
.el-message-box__title {
font-size: 14px !important;
color: #353636;
letter-spacing: 0;
font-weight: 400;
}
}
.el-message-box__content {
height: 96px;
font-size: 14px;
color: #353636;
letter-spacing: 0;
line-height: 22px;
font-weight: 400;
padding-top: 8px;
padding-right: 20px;
padding-left: 20px;
.el-message-box__message {
padding-left: 0 !important;
padding-right: 0 !important;
}
}
.el-message-box__btns {
height: 52px;
border-top: 1px solid #eee;
box-shadow: inset 0 -1px 0 0 rgba(0, 0, 0, 0.07);
padding: 11px 0 12px !important;
.el-button--small {
padding: 8px 21px !important;
line-height: 12px;
font-family: NotoSansHans-Medium !important;
font-size: 12px;
font-weight: 500;
min-height: 28px;
}
.el-button:nth-child(1) {
margin-right: 20px;
width: 80px;
height: 28px;
color: #353636;
}
.el-button:nth-child(2) {
width: 80px;
height: 28px;
margin-right: 20px;
margin-left: 0 !important;
background-color: #2d8cf0;
border-color: #2d8cf0;
}
}
}
</style>

View File

@@ -5,7 +5,6 @@
ref="dataTable"
:data="tableData"
height="100%"
tooltip-effect="light"
border
empty-text=" "
@header-dragend="dragend"
@@ -32,7 +31,6 @@
:sortable="item.sortable"
:width="`${item.width}`"
class="data-column"
:show-overflow-tooltip="['library'].indexOf(item.prop) > -1"
>
<template #header>
<span class="data-column__span">{{ item.label }}</span>
@@ -84,7 +82,6 @@ import { dateFormatByAppearance } from '@/utils/date-util'
import { switchStatus } from '@/utils/tools'
import _ from 'lodash'
import { detectionUnitList } from '@/utils/constants'
import { useRoute } from 'vue-router'
export default {
name: 'DetectionTable',
@@ -92,9 +89,6 @@ export default {
isNoData: {
type: Boolean,
default: false
},
policyDetail: {
type: Object
}
},
mixins: [table],
@@ -152,17 +146,6 @@ export default {
]
}
},
mounted () {
const { query } = useRoute()
// 初始化勾选状态
if (query.name && query.ruleId && this.policyDetail) {
this.selectionChange([this.policyDetail])
const timer = setTimeout(() => {
this.$refs.dataTable.toggleAllSelection([this.policyDetail])
clearTimeout(timer)
}, 400)
}
},
watch: {
tableData: {
immediate: true,

View File

@@ -3,7 +3,6 @@
<div class="top-tools__left">
<button
id="knowledge-base-add"
v-if="hasPermission('createDetectionPolicy')"
:title="$t('knowledgeBase.createKnowledgeBase')"
class="top-tool-btn margin-r-10 top-tool-btn--create"
@click="onCreate"
@@ -14,7 +13,6 @@
<button
:disabled="disableEdit"
v-if="hasPermission('editDetectionPolicy')"
id="knowledge-base-edit"
:title="$t('knowledgeBase.editKnowledgeBase')"
class="top-tool-btn margin-r-10"
@@ -26,7 +24,6 @@
<button
:disabled="disableDelete"
v-if="hasPermission('deleteDetectionPolicy')"
id="knowledge-base-delete"
:title="$t('knowledgeBase.deleteKnowledgeBase')"
class="top-tool-btn margin-r-10"
@@ -50,9 +47,6 @@
</template>
<script>
import { useRoute } from 'vue-router'
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
export default {
name: 'DetectionTools',
props: {
@@ -70,21 +64,9 @@ export default {
keyWord: ''
}
},
mounted () {
const { query } = useRoute()
if (query.name) {
this.keyWord = query.name
this.onSearch()
}
},
methods: {
onSearch () {
this.$emit('search', this.keyWord)
if (!this.keyWord) {
const query = this.$route.query
delete query.name
this.reloadUrl(query, 'clear')
}
},
onCreate () {
this.$emit('create')
@@ -94,14 +76,6 @@ export default {
},
onDelete (data) {
this.$emit('delete', data)
},
reloadUrl (newParam, clean) {
const { query } = this.$route
let newUrl = urlParamsHandler(window.location.href, query, newParam)
if (clean) {
newUrl = urlParamsHandler(window.location.href, query, newParam, clean)
}
overwriteUrl(newUrl)
}
}
}

View File

@@ -187,7 +187,7 @@ export const pieForSeverity = {
legend: {
orient: 'vertical',
type: 'plain',
left: '44%',
left: '60%',
top: 'middle',
icon: 'circle',
itemWidth: 10, // 设置宽度
@@ -203,7 +203,7 @@ export const pieForSeverity = {
type: 'pie',
selectedMode: 'single',
radius: ['43%', '65%'],
center: ['22%', '50%'],
center: ['30%', '50%'],
data: [],
label: {
show: false

View File

@@ -243,7 +243,7 @@ export default {
},
goDetail (type, name) {
const { href } = this.$router.resolve({
path: '/entity/detail',
path: '/entityDetail',
query: {
entityType: type,
entityName: name

View File

@@ -274,7 +274,7 @@ export default {
},
goDetail (type, name) {
const { href } = this.$router.resolve({
path: '/entity/detail',
path: '/entityDetail',
query: {
entityType: type,
entityName: name

View File

@@ -235,7 +235,7 @@ export default {
},
goDetail (type, name) {
const { href } = this.$router.resolve({
path: '/entity/detail',
path: '/entityDetail',
query: {
entityType: type,
entityName: name

View File

@@ -10,7 +10,7 @@
<span class="row__content--link">{{detection.victimIp}}</span>&nbsp;&nbsp;communicated with&nbsp;<span class="row__content--link">{{detection.offenderIp}}</span>&nbsp;&nbsp;that was associated with the indicator of {{detection.eventName}}.
</div>
<div class="row__content1" v-else>
{{ $_.get(basicInfo, 'ruleInfo.description', '-') || '-' }}
{{basicInfo.ruleDescription || '-'}}
</div>
</div>
<div class="overview__title">Fields</div>
@@ -71,7 +71,7 @@
<div class="row__content">{{ $_.get(basicInfo, 'domainInfo.category.categoryGroup', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label">{{ $t('detection.domainReputationLevel') }}</div>
<div class="row__label">{{ $t('entities.reputationLevel') }}</div>
<div class="row__content" v-if="$_.get(basicInfo, 'domainInfo.category.reputationLevel')">
<div
class="row__tag row__tag__level"
@@ -242,17 +242,6 @@
</template>
</div>
<div class="overview__right">
<div v-if="$_.get(basicInfo, 'ruleInfo.ruleId') >= 10000">
<div class="overview__title">{{ $t('detections.goToPolicy') }}</div>
<div class="overview__row">
<div class="row__content">
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span> &nbsp;
<span class="row__content--link" @click="goPolicyPage">
{{ $_.get(basicInfo, 'ruleInfo.name', '-') || '-' }} (ID: {{ $_.get(basicInfo, 'ruleInfo.ruleId', '-') || '-' }})
</span>
</div>
</div>
</div>
<div class="overview__title">{{ $t('detections.goToVictim') }}</div>
<div class="overview__row">
<div class="row__content">
@@ -442,7 +431,10 @@ export default {
dateFormatByAppearance,
/** 初始化实体详情 */
initEntityDetail () {
// 调接口查询攻击者和受害者IP、Domain、APP的更多信息
// 为完整填充IP信息攻击者ip、受害者ip都进行调用
// 根据detection的eventInfo对象的ioc_type进行判断若为domainmalware信息从domain详情中获取并填充domain信息
// 若ioc_type为ip则调用ip接口填充malware信息
// 最后调用app填充app信息。经上获取完整实体详情则最少需要调用4次接口
if (this.detection.offenderIp) {
axios.get(`${api.detection.securityEvent.ipDetail}?resource=${this.detection.offenderIp}`).then(res => {
if (res.status === 200) {
@@ -474,7 +466,7 @@ export default {
if (this.detection.ruleId) {
axios.get(`${api.detection.detail}/${this.detection.ruleId}`).then(res => {
if (res.status === 200) {
this.basicInfo.ruleInfo = res.data.data
this.basicInfo.ruleDescription = res.data.data.description
}
})
}
@@ -499,7 +491,7 @@ export default {
goDetail (type, name) {
if (name) {
const { href } = this.$router.resolve({
path: '/entity/detail',
path: '/entityDetail',
query: {
entityType: type,
entityName: name
@@ -507,19 +499,6 @@ export default {
})
window.open(href, '_blank')
}
},
goPolicyPage () {
if (this.basicInfo.ruleInfo.name && Number(this.basicInfo.ruleInfo.ruleId) >= 10000) {
const { href } = this.$router.resolve({
path: '/detection/policy',
query: {
t: +new Date(),
name: this.basicInfo.ruleInfo.name,
ruleId: this.basicInfo.ruleInfo.ruleId
}
})
window.open(href, '_blank')
}
}
},
mounted () {

View File

@@ -39,11 +39,6 @@ export default {
entityData.appName = query.entityName
break
}
case 'subscribe': {
panelType = panelTypeAndRouteMapping.subscribeEntityDetail
entityData.appName = query.entityName
break
}
default: {
panelType = panelTypeAndRouteMapping.ipEntityDetail
break

View File

@@ -4,16 +4,8 @@
:class="{'entity-explorer--show-list': showList}">
<!-- 顶部工具栏在列表页显示 -->
<div class="explorer-top-tools explorer-top-tools-new" style="margin: 2px 0;" v-show="showList">
<div class="explorer-entity-top-tools">
<div class="explorer-detection-top-tools">
<div class="explorer-top-tools-title" style="padding: 0;margin-left: -10px;">{{$t('network.entity')}}</div>
<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>
<!-- 搜索组件 -->
@@ -44,26 +36,16 @@
<div style="display: flex;flex-direction: column;height: calc(100% - 42px);">
<div class="explorer-result" v-if="showList" style="position: relative;">
<loading :loading="loadingCount" style="width: 240px"></loading>
<span>{{ summaryCount.totalCount }}&nbsp;</span>{{$t('overall.results')}}IP
<span>{{ summaryCount.ipCount }}</span>{{$t('overall.domain')}}
<span>{{ summaryCount.totalCount }}&nbsp;</span>resultsIP
<span>{{ summaryCount.ipCount }}</span>Domain
<span>{{ summaryCount.domainCount }}</span>APP
<span>{{ summaryCount.appCount }}</span>
<span class="entity-hide-entity" v-if="q">
<el-checkbox
v-model="isHideRelatedEntities"
:label="$t('entity.hideRelatedEntities')"
:disabled="listData.length===0"
@change="hideRelatedEntities"
size="large" />
</span>
</div>
<entity-list
style="width: 100%;"
:list-data="listData"
:list-mode="listMode"
:keywordList="keywordList"
:pageObj="pageObj"
:time-filter="timeFilter"
@pageSize="pageSize"
@@ -110,7 +92,7 @@
<div class="entity-overview">
<div class="overview-left">
<span class="overview-left-loading">
<span class="overview-left-loading-span">{{$t('overall.domain')}}</span>
<span class="overview-left-loading-span">Domain</span>
</span>
</div>
<div class="overview-right">
@@ -192,8 +174,6 @@ import Parser from '@/components/advancedSearch/meta/parser'
import { handleErrorTip } from '@/components/advancedSearch/meta/error'
import { columnList } from '@/utils/static-data'
import { useRoute } from 'vue-router'
import { columnType } from '@/components/advancedSearch/meta/meta'
import DateTimeRange from '@/components/common/TimeRange/DateTimeRange'
export default {
name: 'entity-explorer',
@@ -201,8 +181,7 @@ export default {
Loading,
ExplorerSearch,
EntityFilter,
EntityList,
DateTimeRange
EntityList
},
data () {
return {
@@ -221,6 +200,13 @@ export default {
entityIpNew: '-',
entityIpActive: '-',
// pageObj: {
// pageNo: 1,
// // 是否重置pageNo在执行新搜索时是true
// resetPageNo: true,
// pageSize: defaultPageSize,
// total: 0
// },
newFilterData: [
{
icon: 'cn-icon cn-icon-registration-country',
@@ -298,13 +284,12 @@ export default {
initFlag: true, // 初始化标志避免初始化时pageSize和pageNo会调用搜索
timer: null, // 初始化标志的延时器,需要销毁
summaryCount: {
totalCount: 0,
total: 0,
domainCount: 0,
ipCount: 0,
appCount: 0
},
loadingCount: false, // 实体基数统计的loading
keywordList: []
loadingCount: false // 实体基数统计的loading
}
},
methods: {
@@ -317,13 +302,6 @@ export default {
},
reload (s, e, v) {
this.dateTimeRangeChange(s, e, v)
const { startTime, endTime } = getNowTime(this.timeFilter.dateRangeValue)
const newParam = {
range: this.timeFilter.dateRangeValue,
startTime: getSecond(startTime),
endTime: getSecond(endTime)
}
this.reloadUrl(newParam)
},
// methods
dateTimeRangeChange (s, e, v) {
@@ -383,7 +361,6 @@ export default {
this.q = ''
this.metaList = []
}
this.getKeyword(param.keywordList)
// 参数q避免切换页码时地址栏参数q为空
let urlQ = ''
@@ -391,8 +368,6 @@ export default {
urlQ = encodeURI(param.str)
} else if (this.q) {
urlQ = encodeURI(this.q)
} else if (!this.q) {
this.isHideRelatedEntities = false
}
// 在非列表模式下选择tag模式在地址栏输入内容时将mode添加到地址栏
@@ -414,7 +389,7 @@ export default {
if (!this.showList) {
// 首页进入搜索时重载页面,视觉上进入列表页面
this.$router.push({
path: '/entity',
path: '/entityExplorer',
query: {
listMode: this.listMode,
q: urlQ,
@@ -442,21 +417,19 @@ export default {
},
pageSize (val) {
this.pageObj.pageSize = val
const keywordList = this.getKeywordListByMetaList(this.metaList)
if (this.initFlag) {
if (val !== 20) {
this.search({ metaList: this.metaList, q: this.q, keywordList: keywordList })
this.search({ metaList: this.metaList, q: this.q })
}
} else {
this.search({ metaList: this.metaList, q: this.q, keywordList: keywordList })
this.search({ metaList: this.metaList, q: this.q })
}
},
pageNo (val) {
if (!this.initFlag) {
this.pageObj.pageNo = val
this.pageObj.resetPageNo = false
const keywordList = this.getKeywordListByMetaList(this.metaList)
this.search({ metaList: this.metaList, q: this.q, keywordList: keywordList })
this.search({ metaList: this.metaList, q: this.q })
}
},
// 点击上一页箭头
@@ -516,8 +489,8 @@ export default {
/** 新版查询filter数据 */
queryFilterNew (params) {
const queryParams = {
startTime: getSecond(params.startTime),
endTime: getSecond(params.endTime),
// startTime: getSecond(params.startTime),
// endTime: getSecond(params.endTime),
resource: params.q || ''
}
this.loadingLeft = true
@@ -575,16 +548,16 @@ export default {
const queryParams = {
pageSize: params.pageSize,
pageNo: params.pageNo,
startTime: getSecond(params.startTime),
endTime: getSecond(params.endTime),
resource: params.q || '',
hideRelated: this.isHideRelatedEntities
// startTime: getSecond(params.startTime),
// endTime: getSecond(params.endTime),
resource: params.q || ''
}
axios.get(api.entity.entityList.list, { params: queryParams }).then(response => {
if (response.status === 200) {
this.listData = []
this.$nextTick(() => {
this.listData = response.data.data.list
this.pageObj.total = response.data.data.total
})
} else {
this.$message.error(response.data.message)
@@ -597,21 +570,19 @@ export default {
queryCount (params) {
this.loadingCount = true
const queryParams = {
startTime: getSecond(params.startTime),
endTime: getSecond(params.endTime),
resource: params.q || '',
hideRelated: this.isHideRelatedEntities
// startTime: getSecond(params.startTime),
// endTime: getSecond(params.endTime),
resource: params.q || ''
}
axios.get(api.entity.entityList.summaryCount, { params: queryParams }).then(response => {
if (response.status === 200) {
this.summaryCount = response.data.data
this.pageObj.total = response.data.data.totalCount
} else {
this.summaryCount = { totalCount: 0, domainCount: 0, ipCount: 0, appCount: 0 }
this.summaryCount = { total: 0, domainCount: 0, ipCount: 0, appCount: 0 }
}
}).catch(e => {
console.error(e)
this.summaryCount = { totalCount: 0, domainCount: 0, ipCount: 0, appCount: 0 }
console.log(e)
this.summaryCount = { total: 0, domainCount: 0, ipCount: 0, appCount: 0 }
}).finally(() => {
this.loadingCount = false
})
@@ -704,13 +675,11 @@ export default {
}
}
const parser = new Parser(columnList)
const metaList = parser.parseStr(_.cloneDeep(str)).metaList
const keywordList = this.getKeywordListByMetaList(metaList)
const keyInfo = parser.comparedEntityKey(parser.handleEntityTypeByStr(str))
if (keyInfo.isKey) {
const errorList = parser.validateStr(keyInfo.key)
if (_.isEmpty(errorList)) {
this.search({ ...parser.parseStr(keyInfo.key), str: str, keywordList: keywordList })
this.search({ ...parser.parseStr(keyInfo.key), str: str })
} else {
this.$message.error(handleErrorTip(errorList[0]))
}
@@ -758,55 +727,10 @@ export default {
}).catch((e) => {
}).finally(() => {
})
},
getKeywordListByMetaList (metaList) {
if (metaList) {
const keywordList = []
metaList.forEach(item => {
if (item.column && item.column.type === columnType.fullText) {
keywordList.push({ type: item.column.type, value: item.column.label })
} else if (item.column && item.column.type === columnType.string) {
keywordList.push({ type: item.column.type, value: item.value.value })
}
})
return keywordList
}
},
getKeyword (list) {
if (list) {
const metaList = JSON.parse(JSON.stringify(list))
const keyList = []
metaList.forEach(item => {
if (item.value) {
keyList.push({ type: item.type, value: this.getKeyValue(item.value) })
}
})
this.keywordList = keyList
} else {
this.keywordList = []
}
},
getKeyValue (str) {
if (str[0] === "'" && str[str.length - 1] === "'") {
str = str.substring(1, str.length)
str = str.substring(0, str.length - 1)
}
if (str[0] === '%') {
str = str.substring(1, str.length)
}
if (str[str.length - 1] === '%') {
str = str.substring(0, str.length - 1)
}
return str
},
hideRelatedEntities (e) {
this.isHideRelatedEntities = e
this.reloadUrl({ hideRelated: e })
this.queryList({ q: this.q, ...this.pageObj, ...this.timeFilter })
this.queryCount({ q: this.q, ...this.pageObj, ...this.timeFilter })
}
},
mounted () {
this.getEntityIndexData()
let { q, listMode } = this.$route.query
// 如果地址栏有listMode即列表页并非首页则开始搜索
@@ -817,13 +741,7 @@ export default {
q = decodeURI(q)
}
// %位置不为0即内容包含非英文时
let str1 = ''
if (q) {
str1 = q.substring(q.indexOf('%'), q.indexOf('%') + 3)
}
if (q && q.indexOf('+') > -1) {
q = q.replace('+', '')
}
const str1 = q.substring(q.indexOf('%'), q.indexOf('%') + 3)
if (q && q.indexOf('%') > 0 && (str1 !== '%20' || str1 === '%25')) {
q = decodeURI(q)
}
@@ -833,10 +751,6 @@ export default {
this.$store.commit('resetScoreBase')
this.queryScoreBase()
}
if (!this.showList) {
this.getEntityIndexData()
}
},
watch: {
timeFilter () {
@@ -849,11 +763,11 @@ export default {
const rangeParam = query.range
const startTimeParam = query.startTime
const endTimeParam = query.endTime
// 优先级url > config.js > 默认值。
const dateRangeValue = rangeParam ? parseInt(rangeParam) : (DEFAULT_TIME_FILTER_RANGE.entity.list || 60)
// 若url携带了使用携带的值否则使用默认值。
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
const timeFilter = ref({ dateRangeValue })
if (!startTimeParam || !endTimeParam) {
const { startTime, endTime } = getNowTime(dateRangeValue)
const { startTime, endTime } = getNowTime(60)
timeFilter.value.startTime = startTime
timeFilter.value.endTime = endTime
} else {
@@ -867,11 +781,9 @@ export default {
pageSize: query.pageSize ? parseInt(query.pageSize) : defaultPageSize,
total: 0
})
const isHideRelatedEntities = ref(query.hideRelated ? JSON.parse(query.hideRelated) : false) // 隐藏相关实体默认false不隐藏
return {
timeFilter,
pageObj,
isHideRelatedEntities
pageObj
}
},
beforeUnmount () {

View File

@@ -5,7 +5,7 @@
<div class="graph-detail__icon"><i :class="iconClass"></i></div>
<div class="graph-detail-header">
<div class="entity-graph-type">{{entityTypeName}}</div>
<div class="entity-graph-type">{{ $_.get(node, 'myData.entityType') ? entityType[$_.get(node, 'myData.entityType')] : '-' }}</div>
<div class="graph-basic-info">
<div class="graph-basic-info-name__block">
<div class="graph-basic-info-name" :title="$_.get(node, 'id', '')" id="entityName">{{ $_.get(node, 'id', '') }}</div>
@@ -144,27 +144,6 @@ export default {
}
return className
},
entityTypeName () {
const type = _.get(this.node, 'myData.entityType', '')
let entityTypeName = '-'
switch (type) {
case ('ip'): {
entityTypeName = 'IP'
break
}
case ('domain'): {
entityTypeName = this.$t('overall.domain')
break
}
case ('app'): {
entityTypeName = 'APP'
break
}
default:
break
}
return entityTypeName
},
handleDate () {
return function (key) {
const date = _.get(this.node, key, '')

View File

@@ -11,7 +11,6 @@
v-for="(data, index) in listData"
:entity="data"
:listMode="listMode"
:keywordList="keywordList"
:timeFilter="timeFilter"
:key="index"
:ref="`entityRow${index}`"
@@ -66,8 +65,7 @@ export default {
pageObj: Object,
loading: Boolean,
timeFilter: Object,
listMode: String,
keywordList: Array
listMode: String
},
components: {
'entity-card': Card,

View File

@@ -11,20 +11,8 @@
<div class="cn-entity__row">
<!--标签-->
<div class="cn-entity__header" style="display: flex;">
<span class="cn-entity__header-title" v-high-light="keywordList">{{ entityData.entityValue || 'Unknown' }}</span>
<span v-show="entityData.isRelated">
<el-popover
popper-class="my-popper-class"
placement="right"
trigger="hover"
:content="$t('entity.relatedEntities')"
>
<template #reference>
<i class="cn-icon cn-icon-related entity-related-entity"></i>
</template>
</el-popover>
</span>
<span class="entity-detail entity-row-tag" :style="{'margin-top' : entityData.isRelated ? '4px':'1px'}">
<span class="cn-entity__header-title">{{ entityData.entityValue || 'Unknown' }}</span>
<span class="entity-detail" style="display: flex;margin-left: 6px;margin-top: 1px;flex-wrap: wrap;margin-bottom: -10px;">
<span v-for="(item, index) in levelTwoTags"
:key="index"
class="entity-tag entity-tag--small margin-r-10 margin-b-10"
@@ -42,29 +30,29 @@
<div class="basic-info__item">
<i class="cn-icon cn-icon-country"></i>
<span class="row-item-label">{{ $t('overall.country') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value" v-high-light="keywordList">{{ $_.get(entityData, 'location.country', '-') || '-' }}</span>
<span class="row-item-value">{{ $_.get(entityData, 'location.country', '-') || '-' }}</span>
</div>
<div class="basic-info__item1">
<div class="basic-info__item">
<i class="cn-icon cn-icon-position"></i>
<span class="row-item-label">{{ $t('overall.city') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value high-location" v-high-light="keywordList">{{ entityData.location ? ipLocationRegion(entityData.location) : '-' }}</span>
<span class="row-item-value">{{ entityData.location ? ipLocationRegion(entityData.location) : '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-cloud"></i>
<span class="row-item-label">{{ $t('entities.asn') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value" v-high-light="keywordList">{{ $_.get(entityData, 'asn.asn', '-') || '-' }}</span>
<span class="row-item-value">{{ $_.get(entityData, 'asn.asn', '-') || '-' }}</span>
</div>
</template>
<template v-else-if="entityData.entityType === 'domain'">
<div class="basic-info__item">
<i class="cn-icon cn-icon-category-group"></i>
<span class="row-item-label">{{ $t('entities.category') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value" v-high-light="keywordList">{{ $_.get(entityData, 'category.categoryGroup', '-') || '-' }}</span>
<span class="row-item-value">{{ $_.get(entityData, 'category.categoryGroup', '-') || '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-sub-category"></i>
<span class="row-item-label">{{ $t('entities.subcategory') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value" v-high-light="keywordList">{{ $_.get(entityData, 'category.categoryName', '-') || '-' }}</span>
<span class="row-item-value">{{ $_.get(entityData, 'category.categoryName', '-') || '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-credit-rating"></i>
@@ -76,7 +64,7 @@
<div class="basic-info__item">
<i class="cn-icon cn-icon-category2"></i>
<span class="row-item-label">{{ $t('entities.category') }}&nbsp;:&nbsp;&nbsp;</span>
<span class="row-item-value" v-high-light="keywordList">{{ $_.get(entityData, 'category.appCategory', '-') || '-' }}</span>
<span class="row-item-value">{{ $_.get(entityData, 'category.appCategory', '-') || '-' }}</span>
</div>
<div class="basic-info__item">
<i class="cn-icon cn-icon-sub-category"></i>
@@ -158,7 +146,7 @@
<template v-if="!loadingNetworkQuality && score !=='-'">
<span v-for="(dot, i) in scoreDot" :key="i" :class="dot.class"></span>
</template>
<span style="padding-left: 4px;">{{score}}</span>
<span>{{score}}</span>
<loading :loading="loadingNetworkQuality" size="small"></loading>
</span>
</div>
@@ -188,7 +176,7 @@
<el-collapse-transition>
<div class="cn-entity__detail-overview" v-if="!isCollapse">
<el-divider></el-divider>
<detail-overview :entity="entityData" :time-filter="timeFilter" :keywordList="keywordList" @reloadEntity="getEntity" />
<detail-overview :entity="entityData" :time-filter="timeFilter" @reloadEntity="getEntity" />
</div>
</el-collapse-transition>
</div>
@@ -211,8 +199,7 @@ export default {
props: {
index: Number,
timeFilter: Object,
listMode: String,
keywordList: Array
listMode: String
},
components: {
Loading,

View File

@@ -8,11 +8,11 @@
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.category')}}</div>
<div class="row__content" v-high-light="keywordList">{{ $_.get(entity, 'category.appCategory', '-') || '-' }}</div>
<div class="row__content">{{$_.get(entity, 'category.appCategory', '-') || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.subcategory')}}</div>
<div class="row__content" v-high-light="keywordList">{{ $_.get(entity, 'category.appSubcategory', '-') || '-' }}</div>
<div class="row__content">{{$_.get(entity, 'category.appSubcategory', '-') || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.riskLevel')}}</div>
@@ -20,9 +20,7 @@
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('overall.remark')}}</div>
<div class="row__content">
<span v-high-light="keywordList">{{ $_.get(entity, 'category.appDescription', '-') || '-' }}</span>
</div>
<div class="row__content">{{$_.get(entity, 'category.appDescription', '-') || '-'}}</div>
</div>
</div>
</div>
@@ -91,7 +89,7 @@
<loading :loading="loadingRelationshipOne" size="small" style="left: 1rem;"></loading>
</div>
<div class="data-item high-light-block" v-high-light="keywordList" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
{{item.value}}
</div>
<div v-if="relationshipDataOne.length===0 && !loadingRelationshipOne">-</div>
@@ -100,7 +98,7 @@
<div class="data-item show-more-related" id="related-app-more" @click.stop="showMoreApp" style="position: relative">...</div>
<div v-if="isShowMoreApp" class="app-popover_block" id="showRelatedApp">
<div class="popover-content" v-for="(item, index) in relationshipDataOne" :key="index">
<span v-if="!item.show" class="high-light-block" v-high-light="keywordList">{{item.value}}</span>
<span v-if="!item.show">{{item.value}}</span>
</div>
</div>
</div>
@@ -115,7 +113,7 @@
<loading :loading="loadingRelationshipTwo" size="small" style="left: 1rem;"></loading>
</div>
<div class="data-item high-light-block" v-high-light="keywordList" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
{{item.value}}
</div>
<div v-if="relationshipDataTwo.length===0 && !loadingRelationshipTwo">-</div>
@@ -124,7 +122,7 @@
<div class="data-item show-more-related" id="related-domain-more" @click.stop="showMoreDomain" style="position: relative">...</div>
<div v-if="isShowMoreDomain" class="domain-popover_block" id="showRelatedDomain">
<div v-for="(item, index) in relationshipDataTwo" :key="index">
<span v-if="!item.show" class="high-light-block" v-high-light="keywordList">{{item.value}}</span>
<span v-if="!item.show">{{item.value}}</span>
</div>
</div>
</div>
@@ -172,7 +170,7 @@
</div>
<div class="overview__row overview__row--small-font" v-for="(security, index) in entityData.securityList" :key="index">
<div class="row__label row__label--width130">{{security.startTime ? dateFormatByAppearance(Number(security.startTime)) : '-'}}</div>
<div class="row__label row__label--width130">{{dateFormatByAppearance(security.startTime) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(security)">{{security.eventSeverity}}</div>
</div>
@@ -216,7 +214,7 @@ import Chart from '@/views/charts/Chart'
import _ from 'lodash'
import axios from 'axios'
import relatedServer from '@/mixins/relatedServer'
import { dateFormatByAppearance, getMillisecond, getSecond, getNowTime } from '@/utils/date-util'
import { dateFormatByAppearance, getMillisecond } from '@/utils/date-util'
import Loading from '@/components/common/Loading'
import { ref } from 'vue'
@@ -227,9 +225,6 @@ export default {
Chart,
Loading
},
props: {
keywordList: Array
},
data () {
return {
// entityData: {}
@@ -320,21 +315,9 @@ export default {
methods: {
getMillisecond,
dateFormatByAppearance,
getQueryParams (dateRangeValue) {
if (dateRangeValue) {
// range取 config.js 中配置的值
const { startTime, endTime } = getNowTime(dateRangeValue)
return {
startTime: getSecond(startTime),
endTime: getSecond(endTime),
resource: this.entity.entityValue
}
} else {
return {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
resource: this.entity.entityValue
}
getQueryParams () {
return {
resource: this.entity.entityValue
}
},
getPerformanceQueryParams () {

View File

@@ -1,13 +1,13 @@
<template>
<div class="entity-detail-overview">
<template v-if="entity.entityType === 'ip'">
<ip-overview :entity="entity" :time-filter="timeFilter" :keywordList="keywordList" @reloadEntity="getEntity"></ip-overview>
<ip-overview :entity="entity" :time-filter="timeFilter" @reloadEntity="getEntity"></ip-overview>
</template>
<template v-else-if="entity.entityType === 'domain'">
<domain-overview :entity="entity" :time-filter="timeFilter" :keywordList="keywordList" @reloadEntity="getEntity"></domain-overview>
<domain-overview :entity="entity" :time-filter="timeFilter" @reloadEntity="getEntity"></domain-overview>
</template>
<template v-else-if="entity.entityType === 'app'">
<app-overview :entity="entity" :time-filter="timeFilter" :keywordList="keywordList" @reloadEntity="getEntity"></app-overview>
<app-overview :entity="entity" :time-filter="timeFilter" @reloadEntity="getEntity"></app-overview>
</template>
</div>
</template>
@@ -22,8 +22,7 @@ export default {
name: 'DetailOverview',
props: {
entity: Object,
timeFilter: Object,
keywordList: Array
timeFilter: Object
},
components: {
'domain-overview': Domain,

View File

@@ -4,11 +4,11 @@
<div class="overview__content">
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.category')}}</div>
<div class="row__content" v-high-light="keywordList">{{ $_.get(entityData, 'category.categoryName', '-') || '-' }}</div>
<div class="row__content">{{$_.get(entityData, 'category.categoryName', '-') || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.domainDetail.categoryGroup')}}</div>
<div class="row__content" v-high-light="keywordList">{{ $_.get(entityData, 'category.categoryGroup', '-') || '-' }}</div>
<div class="row__content">{{$_.get(entityData, 'category.categoryGroup', '-') || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.reputationLevel')}}</div>
@@ -20,7 +20,7 @@
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.org')}}</div>
<div class="row__content" v-high-light="keywordList">{{ $_.get(entityData, 'whois.registrantOrg', '-') || '-' }}</div>
<div class="row__content">{{$_.get(entityData, 'whois.registrantOrg', '-') || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.icpCompanyName')}}</div>
@@ -97,7 +97,7 @@
<loading :loading="loadingRelationshipOne" size="small" style="left: 1rem;"></loading>
</div>
<div class="data-item high-light-block" v-high-light="keywordList" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
{{item.value}}
</div>
<div v-if="relationshipDataOne.length===0 && !loadingRelationshipOne">-</div>
@@ -106,7 +106,7 @@
<div class="data-item show-more-related" id="related-app-more" @click.stop="showMoreApp" style="position: relative">...</div>
<div v-if="isShowMoreApp" class="app-popover_block" id="showRelatedApp">
<div class="popover-content" v-for="(item, index) in relationshipDataOne" :key="index">
<span v-if="!item.show" class="high-light-block" v-high-light="keywordList">{{item.value}}</span>
<span v-if="!item.show">{{item.value}}</span>
</div>
</div>
</div>
@@ -119,7 +119,7 @@
<div v-if="loadingRelationshipTwo" style="position: relative;width: 450px;">
<loading :loading="loadingRelationshipTwo" size="small" style="left: 1rem;"></loading>
</div>
<div class="data-item high-light-block" v-high-light="keywordList" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
{{item.value}}
</div>
<div v-if="relationshipDataTwo.length===0 && !loadingRelationshipTwo">-</div>
@@ -128,7 +128,7 @@
<div class="data-item show-more-related" id="related-domain-more" @click.stop="showMoreDomain" style="position: relative">...</div>
<div v-if="isShowMoreDomain" class="domain-popover_block" id="showRelatedDomain">
<div v-for="(item, index) in relationshipDataTwo" :key="index">
<span v-if="!item.show" class="high-light-block" v-high-light="keywordList">{{item.value}}</span>
<span v-if="!item.show">{{item.value}}</span>
</div>
</div>
</div>
@@ -149,7 +149,7 @@
<div class="row__content">{{entityData.performanceNum}}</div>
</div>
<div class="overview__row overview__row--small-font" v-for="(performance, index) in entityData.performanceList" :key="index">
<div class="row__label row__label--width130">{{performance.startTime ? dateFormatByAppearance(Number(performance.startTime)) : '-'}}</div>
<div class="row__label row__label--width130">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(performance)">{{performance.eventSeverity}}</div>
</div>
@@ -176,7 +176,7 @@
</div>
<div class="overview__row overview__row--small-font" v-for="(security, i) in entityData.securityList" :key="i">
<div class="row__label row__label--width130">{{security.startTime ? dateFormatByAppearance(Number(security.startTime)) : '-'}}</div>
<div class="row__label row__label--width130">{{dateFormatByAppearance(getMillisecond(security.startTime)) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(security)">{{security.eventSeverity}}</div>
</div>
@@ -219,7 +219,7 @@ import Chart from '@/views/charts/Chart'
import _ from 'lodash'
import axios from 'axios'
import relatedServer from '@/mixins/relatedServer'
import { dateFormatByAppearance, getMillisecond, getSecond, getNowTime } from '@/utils/date-util'
import { dateFormatByAppearance, getMillisecond, getSecond } from '@/utils/date-util'
import Loading from '@/components/common/Loading'
import { ref } from 'vue'
@@ -229,9 +229,6 @@ export default {
Loading,
Chart
},
props: {
keywordList: Array
},
mixins: [entityDetailMixin, relatedServer],
data () {
return {
@@ -324,21 +321,16 @@ export default {
methods: {
getMillisecond,
dateFormatByAppearance,
getQueryParams (dateRangeValue) {
if (dateRangeValue) {
// range取 config.js 中配置的值
const { startTime, endTime } = getNowTime(dateRangeValue)
return {
startTime: getSecond(startTime),
endTime: getSecond(endTime),
resource: this.entity.entityValue
}
} else {
return {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
resource: this.entity.entityValue
}
getQueryParams () {
return {
resource: this.entity.entityValue
}
},
getQueryParamsWithTime () {
return {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
domain: this.entity.entityValue
}
},
getPerformanceQueryParams () {
@@ -360,7 +352,7 @@ export default {
})
},
getBasicProperties () {
axios.get(this.basicProperties, { params: this.getQueryParams() }).then(response => {
axios.get(this.basicProperties, { params: this.getQueryParamsWithTime() }).then(response => {
if (response.status === 200) {
this.entityData = {
...this.entityData,

View File

@@ -10,22 +10,18 @@
<img v-if="entity.location.country===countryNameIdMapping.Unknown || !countryNameIdMapping[entity.location.country]" src="../../../../../public/images/flag/Unknown.svg" class="filter-country-flag">
<img v-else :src="require(`../../../../../public/images/flag/${countryNameIdMapping[entity.location.country]}.png`)" class="filter-country-flag" >
</div>
<span v-high-light="keywordList" class="high-location">{{ ipLocationRegion(entity.location) }}</span>
{{ipLocationRegion(entity.location)}}
</div>
<div v-else>-</div>
</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">ASN</div>
<div class="row__content" v-high-light="keywordList">{{ $_.get(entity, 'asn.asn', '-') || '-' }}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">ISP</div>
<div class="row__content" v-high-light="keywordList">{{ $_.get(entityData, 'location.isp', '-') || '-' }}</div>
<div class="row__content">{{$_.get(entity, 'asn.asn', '-') || '-'}}</div>
</div>
<div class="overview__row">
<div class="row__label row__label--width130">{{$t('entities.openPort')}}</div>
<div class="row__content high-location" style="word-break: break-word;" v-high-light="keywordList">{{ openPort }}</div>
<div class="row__content" style="word-break: break-word;">{{ openPort }}</div>
</div>
</div>
</div>
@@ -132,7 +128,7 @@
<loading :loading="loadingRelationshipOne" size="small" style="left: 1rem;"></loading>
</div>
<div class="data-item high-light-block" v-high-light="keywordList" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataOne" :key="index">
{{item.value}}
</div>
<div v-if="relationshipDataOne.length===0 && !loadingRelationshipOne">-</div>
@@ -141,7 +137,7 @@
<div class="data-item show-more-related" id="related-app-more" @click.stop="showMoreApp" style="position: relative">...</div>
<div v-if="isShowMoreApp" class="app-popover_block" id="showRelatedApp">
<div class="popover-content" v-for="(item, index) in relationshipDataOne" :key="index">
<span v-if="!item.show" class="high-light-block" v-high-light="keywordList">{{item.value}}</span>
<span v-if="!item.show">{{item.value}}</span>
</div>
</div>
</div>
@@ -155,7 +151,7 @@
<loading :loading="loadingRelationshipTwo" size="small" style="left: 1rem;"></loading>
</div>
<div class="data-item high-light-block" v-high-light="keywordList" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
<div class="data-item" v-show="item.show" v-for="(item, index) in relationshipDataTwo" :key="index">
{{item.value}}
</div>
<div v-if="relationshipDataTwo.length===0 && !loadingRelationshipTwo">-</div>
@@ -164,7 +160,7 @@
<div class="data-item show-more-related" id="related-domain-more" @click.stop="showMoreDomain" style="position: relative">...</div>
<div v-if="isShowMoreDomain" class="domain-popover_block" id="showRelatedDomain">
<div v-for="(item, index) in relationshipDataTwo" :key="index">
<span v-if="!item.show" class="high-light-block" v-high-light="keywordList">{{item.value}}</span>
<span v-if="!item.show">{{item.value}}</span>
</div>
</div>
</div>
@@ -185,7 +181,7 @@
<div class="row__content">{{entityData.performanceNum}}</div>
</div>
<div class="overview__row overview__row--small-font" v-for="(performance, index) in entityData.performanceList" :key="index">
<div class="row__label row__label--width130">{{performance.startTime ? dateFormatByAppearance(Number(performance.startTime)) : '-'}}</div>
<div class="row__label row__label--width130">{{dateFormatByAppearance(performance.startTime) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(performance)">{{performance.eventSeverity}}</div>
</div>
@@ -212,7 +208,7 @@
</div>
<div class="overview__row overview__row--small-font" v-for="(security, index) in entityData.securityList" :key="index">
<div class="row__label row__label--width130">{{security.startTime ? dateFormatByAppearance(Number(security.startTime)) : '-'}}</div>
<div class="row__label row__label--width130">{{dateFormatByAppearance(security.startTime) || '-'}}</div>
<div class="row__content row__content--width90">
<div class="alert-level-tag alert-level-tag--high" :class="iconClass(security)">{{security.eventSeverity}}</div>
</div>
@@ -255,7 +251,7 @@ import { valueToRangeValue } from '@/utils/unit-convert'
import Chart from '@/views/charts/Chart'
import _ from 'lodash'
import relatedServer from '@/mixins/relatedServer'
import { dateFormatByAppearance, getMillisecond, getSecond, getNowTime } from '@/utils/date-util'
import { dateFormatByAppearance, getMillisecond } from '@/utils/date-util'
import Loading from '@/components/common/Loading'
import axios from 'axios'
@@ -266,9 +262,6 @@ export default {
Loading,
Chart
},
props: {
keywordList: Array
},
data () {
return {
entityType: 'ip',
@@ -408,21 +401,9 @@ export default {
methods: {
getMillisecond,
dateFormatByAppearance,
getQueryParams (dateRangeValue) {
if (dateRangeValue) {
// range取 config.js 中配置的值
const { startTime, endTime } = getNowTime(dateRangeValue)
return {
startTime: getSecond(startTime),
endTime: getSecond(endTime),
resource: this.entity.entityValue
}
} else {
return {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
resource: this.entity.entityValue
}
getQueryParams () {
return {
resource: this.entity.entityValue
}
},
getPerformanceQueryParams () {
@@ -449,8 +430,8 @@ export default {
},
getOpenPort () {
const params = {
startTime: getSecond(this.timeFilter.startTime),
endTime: getSecond(this.timeFilter.endTime),
// startTime: getSecond(this.timeFilter.startTime),
// endTime: getSecond(this.timeFilter.endTime),
resource: this.entity.entityValue
}

View File

@@ -121,7 +121,7 @@ export default {
this.sentChart = echarts.init(document.getElementById(`entityDetailSend${this.entityName}`))
this.receivedChart = echarts.init(document.getElementById(`entityDetailReceived${this.entityName}`))
this.loadingTraffic = true
axios.get(this.trafficUrl, { params: this.getQueryParams(DEFAULT_TIME_FILTER_RANGE.entity.trafficLine) }).then(response => {
axios.get(this.trafficUrl, { params: this.getQueryParams() }).then(response => {
if (response.status === 200 && response.data.data.result && response.data.data.result.length > 0) {
response.data.data.result.forEach(t => {
if (t.legend === 'rate') {
@@ -278,7 +278,7 @@ export default {
this.performanceScoreData = {}
this.scoreDataState = false
if (this.networkQuantityUrl) {
axios.get(this.networkQuantityUrl, { params: this.getQueryParams(DEFAULT_TIME_FILTER_RANGE.entity.trafficLine) }).then(response => {
axios.get(this.networkQuantityUrl, { params: this.getQueryParams() }).then(response => {
if (response.status === 200) {
this.performanceScoreData = {
establishLatencyMs: response.data.data.result.establishLatencyMsAvg || null,
@@ -347,7 +347,7 @@ export default {
queryEntityDetailPerformance () {
this.loadingAlert = true
axios.get(this.performanceUrl, { params: this.getQueryParams(DEFAULT_TIME_FILTER_RANGE.entity.performanceEvent) }).then(response => {
axios.get(this.performanceUrl, { params: this.getQueryParams() }).then(response => {
if (response.status === 200) {
this.entityData.performanceNum = response.data.data.result.length
this.performanceData = response.data.data.result
@@ -359,7 +359,7 @@ export default {
queryEntityDetailSecurity () {
this.loadingSecurityEvents = true
axios.get(this.securityUrl, { params: this.getQueryParams(DEFAULT_TIME_FILTER_RANGE.entity.securityEvent) }).then(response => {
axios.get(this.securityUrl, { params: this.getQueryParams() }).then(response => {
if (response.status === 200) {
this.entityData.securityNum = response.data.data.result.length
this.securityData = response.data.data.result
@@ -436,9 +436,9 @@ export default {
queryEntityDetail () {
this.queryEntityDetailTraffic()
// this.queryEntityDetailPerformance()
this.queryEntityDetailSecurity()
// this.queryEntityDetailSecurity()
this.queryEntityDetailNetworkQuantity()
/* if (this.entity.entityType === 'ip') {
/*if (this.entity.entityType === 'ip') {
if (!this.entityData.dnsServerRole) {
this.loadingDns = true
}
@@ -449,7 +449,7 @@ export default {
this.queryDnsServerInfoRate()
}, 200)
})
} */
}*/
},
resize () {

Some files were not shown because too many files have changed in this diff Show More