Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
374c66fcff | ||
|
|
705572b245 | ||
|
|
0152c46d05 | ||
|
|
64f376e22a | ||
|
|
5b89fca77c | ||
|
|
d1f5997b88 | ||
|
|
88002a8fc4 | ||
|
|
556a9b03b4 | ||
|
|
ca5c81d8be | ||
|
|
02779c26d1 | ||
|
|
20692705e9 | ||
|
|
bc3bc7eaf3 | ||
|
|
d05ae06af6 | ||
|
|
ca3d8766ba | ||
|
|
00e73adadb | ||
|
|
4ede5768e4 | ||
|
|
541692f50f | ||
|
|
89294c98e1 | ||
|
|
8fd283c1e7 | ||
|
|
90b90fdd3c | ||
|
|
72ee214877 | ||
|
|
99f97b76a7 | ||
|
|
b0260ea41a | ||
|
|
a7d6ffb4b4 | ||
|
|
dbc68077ca | ||
|
|
186e115adf | ||
|
|
6c5233a760 | ||
|
|
2df67c1972 | ||
|
|
cb3b66bdf7 | ||
|
|
6ba0ca0a82 | ||
|
|
00df0414c2 | ||
|
|
20a4bb22ef | ||
|
|
00bb6f8c5f | ||
|
|
e61c664802 | ||
|
|
a4dff135d1 | ||
|
|
0bd87db92f | ||
|
|
407d9ec667 | ||
|
|
e7637dd866 | ||
|
|
59c2b26d6c | ||
|
|
8b5b36a621 | ||
|
|
7762658864 | ||
|
|
eb25dc6aa7 | ||
|
|
1fff8f49c9 | ||
|
|
47d8212abe | ||
|
|
94940d745c | ||
|
|
030af380fd | ||
|
|
e9f21038b5 | ||
|
|
e355e427fb | ||
|
|
6dea1ee890 | ||
|
|
1fae281b8b | ||
|
|
60a527c765 | ||
|
|
3daa875a25 | ||
|
|
b4fcbd260b | ||
|
|
871781ab70 | ||
|
|
9bb9967353 | ||
|
|
327ae1956d | ||
|
|
4d4d197a80 | ||
|
|
46f1a880cd | ||
|
|
d1c9eba029 | ||
|
|
643ada9172 | ||
|
|
d0aa64fb9c | ||
|
|
5b7dd6da90 | ||
|
|
97d793471c | ||
|
|
6a2d5a0efe | ||
|
|
b90810470e | ||
|
|
d8865b74d7 | ||
|
|
012d873b71 | ||
|
|
fefca1588f | ||
|
|
f6af25e5e6 | ||
|
|
c5c7b58720 | ||
|
|
40d43acb6c | ||
|
|
7d34b8388c | ||
|
|
d2feedb319 | ||
|
|
0f52bd5362 | ||
|
|
48b3e2aebd | ||
|
|
9208a4fff2 | ||
|
|
19747cf326 | ||
|
|
c2de6c853c | ||
|
|
b0a7d44c42 | ||
|
|
3b641e1878 | ||
|
|
0a9d5591d5 | ||
|
|
0e82bebaac | ||
|
|
85db8cd745 | ||
|
|
c960c60790 | ||
|
|
18b62f1e3d | ||
|
|
11540d3c34 | ||
|
|
5fbab86a80 | ||
|
|
ed9a2c4e1f | ||
|
|
b94bc23a86 | ||
|
|
328f226a86 | ||
|
|
660950a73c | ||
|
|
8f9308a04e | ||
|
|
133c9a23c0 | ||
|
|
bc4a6c2a9e | ||
|
|
5798c0c5a7 | ||
|
|
15ac00d548 | ||
|
|
95217b84a5 | ||
|
|
24e549a444 | ||
|
|
e16d351efd | ||
|
|
ccec756baa | ||
|
|
a47e04fae2 | ||
|
|
8cc6edbdd4 | ||
|
|
afa86464d9 | ||
|
|
16e63ab905 | ||
|
|
6f72b2258f | ||
|
|
5a4301e3aa | ||
|
|
96c380001c | ||
|
|
40365decf6 | ||
|
|
ac9c16d464 | ||
|
|
7abe436127 | ||
|
|
d85e2d347f | ||
|
|
cc61cbc05c | ||
|
|
7cc2439dd2 | ||
|
|
8ba062054c | ||
|
|
cdb1d4baec | ||
|
|
1886f8214f | ||
|
|
aaaecfd9a1 | ||
|
|
9ab00df342 | ||
|
|
33293aaaa3 | ||
|
|
5cb105784a | ||
|
|
4e0e49585e |
@@ -39,9 +39,9 @@ build_project:
|
|||||||
stage: build_project
|
stage: build_project
|
||||||
script:
|
script:
|
||||||
- echo "npm install ..."
|
- echo "npm install ..."
|
||||||
- cnpm install --save-dev --unsafe-perm
|
- npm install --save-dev --unsafe-perm
|
||||||
- echo "npm run build"
|
- echo "npm run build"
|
||||||
- cnpm run build
|
- npm run build
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
|
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
|
||||||
when: on_success
|
when: on_success
|
||||||
|
|||||||
27006
package-lock.json
generated
27006
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
68
package.json
68
package.json
@@ -10,63 +10,64 @@
|
|||||||
"analyz": "cross-env NODE_ENV=production npm_config_report=true npm run build"
|
"analyz": "cross-env NODE_ENV=production npm_config_report=true npm run build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@amcharts/amcharts4": "^4.10.24",
|
"@amcharts/amcharts4": "~4.10.0",
|
||||||
"@amcharts/amcharts4-geodata": "^4.1.20",
|
"@amcharts/amcharts4-geodata": "^4.1.20",
|
||||||
"@antv/g6": "^4.8.17",
|
"@antv/g6": "^4.8.17",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"babel-plugin-lodash": "^3.3.4",
|
"babel-plugin-lodash": "~3.3.0",
|
||||||
"codemirror": "^5.65.1",
|
"codemirror": "^5.65.1",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "~3.31.0",
|
||||||
"dayjs": "^1.10.5",
|
"dayjs": "^1.10.5",
|
||||||
"dexie": "^3.2.2",
|
"dexie": "~3.2.0",
|
||||||
"echarts": "^5.1.1",
|
"echarts": "^5.1.1",
|
||||||
"element-plus": "^1.0.2-beta.44",
|
"element-plus": "~1.0.2-beta.71",
|
||||||
"lib-flexible": "^0.3.2",
|
"lib-flexible": "^0.3.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"moment-timezone": "^0.5.33",
|
"moment-timezone": "^0.5.33",
|
||||||
"node-sass": "^4.14.1",
|
"node-sass": "~4.14.0",
|
||||||
"postcss-plugin-px2rem": "^0.8.1",
|
"postcss-plugin-px2rem": "~0.8.1",
|
||||||
"postcss-px2rem-exclude": "0.0.6",
|
"postcss-px2rem-exclude": "0.0.6",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "~8.0.2",
|
||||||
"sass-resources-loader": "^2.2.1",
|
"sass-resources-loader": "~2.2.5",
|
||||||
"tiny-emitter": "^2.1.0",
|
"tiny-emitter": "^2.1.0",
|
||||||
"vue": "^3.0.0",
|
"vue": "~3.3.0",
|
||||||
"vue-grid-layout": "^3.0.0-beta1",
|
"vue-grid-layout": "^3.0.0-beta1",
|
||||||
"vue-i18n": "^9.1.6",
|
"vue-i18n": "~9.2.0",
|
||||||
"vue-router": "^4.0.8",
|
"vue-router": "~4.2.0",
|
||||||
"vuex": "^4.0.1"
|
"vuex": "~4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.12.1",
|
"@babel/cli": "~7.22.0",
|
||||||
"@babel/core": "^7.11.4",
|
"@babel/core": "~7.22.5",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
"@babel/plugin-proposal-class-properties": "~7.18.0",
|
||||||
"@babel/plugin-proposal-private-methods": "^7.12.1",
|
"@babel/plugin-proposal-private-methods": "~7.18.0",
|
||||||
"@babel/plugin-transform-runtime": "^7.12.1",
|
"@babel/plugin-transform-runtime": "~7.22.0",
|
||||||
"@babel/plugin-proposal-private-property-in-object": "^7.12.1",
|
"@babel/plugin-proposal-private-property-in-object": "~7.21.0",
|
||||||
"@babel/preset-env": "^7.11.5",
|
"@babel/preset-env": "~7.22.0",
|
||||||
"@babel/preset-typescript": "^7.10.4",
|
"@babel/preset-typescript": "~7.22.0",
|
||||||
"@commitlint/cli": "^9.1.2",
|
"@commitlint/cli": "^9.1.2",
|
||||||
"@commitlint/config-conventional": "^9.1.2",
|
"@commitlint/config-conventional": "^9.1.2",
|
||||||
"@highlightjs/vue-plugin": "^2.0.1",
|
"@highlightjs/vue-plugin": "^2.0.1",
|
||||||
"@rollup/plugin-commonjs": "^15.1.0",
|
"@rollup/plugin-commonjs": "^15.1.0",
|
||||||
"@rollup/plugin-node-resolve": "^9.0.0",
|
"@rollup/plugin-node-resolve": "^9.0.0",
|
||||||
"@rollup/plugin-typescript": "^6.0.0",
|
"@rollup/plugin-typescript": "^6.0.0",
|
||||||
"@testing-library/jest-dom": "^5.16.5",
|
"@testing-library/jest-dom": "~5.16.0",
|
||||||
"@testing-library/user-event": "^14.4.3",
|
"@testing-library/user-event": "~14.4.0",
|
||||||
"@testing-library/vue": "^6.4.2",
|
"@testing-library/vue": "~6.6.0",
|
||||||
"@types/jest": "^26.0.24",
|
"@types/jest": "~26.0.0",
|
||||||
"@types/lodash": "^4.14.161",
|
"@types/lodash": "^4.14.161",
|
||||||
"@typescript-eslint/eslint-plugin": "^3.10.1",
|
"@typescript-eslint/eslint-plugin": "^3.10.1",
|
||||||
"@typescript-eslint/parser": "^3.10.1",
|
"@typescript-eslint/parser": "^3.10.1",
|
||||||
"@vue/babel-plugin-jsx": "^1.0.0",
|
"@vue/babel-plugin-jsx": "~1.1.0",
|
||||||
"@vue/babel-preset-app": "^5.0.8",
|
"@vue/babel-preset-app": "~5.0.0",
|
||||||
"@vue/cli-plugin-babel": "~4.5.0",
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
"@vue/cli-service": "~4.5.0",
|
"@vue/cli-service": "~4.5.0",
|
||||||
"@vue/compiler-sfc": "^3.0.0",
|
"@vue/compiler-sfc": "~3.3.0",
|
||||||
"@vue/component-compiler-utils": "^3.2.0",
|
"@vue/component-compiler-utils": "~3.3.0",
|
||||||
"@vue/test-utils": "^2.2.7",
|
"@vue/test-utils": "~2.4.0",
|
||||||
|
"@vue/server-renderer": "~3.3.0",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-jest": "^26.0.0",
|
"babel-jest": "^26.0.0",
|
||||||
"compression-webpack-plugin": "^8.0.1",
|
"compression-webpack-plugin": "^8.0.1",
|
||||||
@@ -77,11 +78,10 @@
|
|||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.3.1",
|
"eslint-plugin-promise": "^4.3.1",
|
||||||
"eslint-plugin-vue": "^7.7.0",
|
"eslint-plugin-vue": "^7.7.0",
|
||||||
"jest": "^26.0.0",
|
"jest": "~26.6.0",
|
||||||
"ts-jest": "^26.4.4",
|
"ts-jest": "~26.5.0",
|
||||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||||
"vue-jest": "^5.0.0-alpha.10",
|
"vue-jest": "^5.0.0-alpha.10"
|
||||||
"vue3-ace-editor": "^2.0.2"
|
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const BASE_CONFIG = {
|
const BASE_CONFIG = {
|
||||||
baseUrl: 'http://192.168.44.54:8091/',
|
baseUrl: 'http://192.168.44.54:8090/',
|
||||||
version: '23.06',
|
version: '23.10',
|
||||||
apiVersion: 'v1'
|
apiVersion: 'v1'
|
||||||
}
|
}
|
||||||
|
|||||||
1
public/geojson/frenchPolynesiaLow.json
Normal file
1
public/geojson/frenchPolynesiaLow.json
Normal file
File diff suppressed because one or more lines are too long
1
public/geojson/lesothoLow.json
Normal file
1
public/geojson/lesothoLow.json
Normal file
File diff suppressed because one or more lines are too long
1
public/geojson/liberiaLow.json
Normal file
1
public/geojson/liberiaLow.json
Normal file
File diff suppressed because one or more lines are too long
11
public/geojson/mauritiusLow.json
Normal file
11
public/geojson/mauritiusLow.json
Normal file
File diff suppressed because one or more lines are too long
@@ -83,6 +83,71 @@
|
|||||||
|
|
||||||
.entity-detail-event-block {
|
.entity-detail-event-block {
|
||||||
width: calc(100% - 2px);
|
width: calc(100% - 2px);
|
||||||
|
.behavior-pattern {
|
||||||
|
height:100% ;
|
||||||
|
position: relative;
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
.behavior-pattern-legend {
|
||||||
|
display:flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
padding:10px 18px 10px 18px;
|
||||||
|
width:400px;
|
||||||
|
.behavior-pattern-legend__item {
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #353636;
|
||||||
|
line-height: 12px;
|
||||||
|
margin-bottom:11px;
|
||||||
|
.legend-icon {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
margin: 3px 8px 0 0;
|
||||||
|
border-radius: 1px;;
|
||||||
|
}
|
||||||
|
.legend-name {
|
||||||
|
width:180px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.legend-value{
|
||||||
|
display: flex;
|
||||||
|
justify-content: left;
|
||||||
|
margin-left:20px;
|
||||||
|
width:90px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.legend-percent {
|
||||||
|
margin-left:20px;
|
||||||
|
width:70px;
|
||||||
|
justify-content: left;
|
||||||
|
display: flex;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.behavior-pattern-chart{
|
||||||
|
height: calc(100% - 50px);
|
||||||
|
width:calc(100% - 400px);
|
||||||
|
position: relative
|
||||||
|
}
|
||||||
|
.chart-bottom-dot__left {
|
||||||
|
position: absolute;
|
||||||
|
height: 0;
|
||||||
|
width: 195px;
|
||||||
|
border-bottom: 1px dashed #d3d3d3;
|
||||||
|
top: 319px;left: 575px;
|
||||||
|
}
|
||||||
|
.chart-bottom-dot__right {
|
||||||
|
position: absolute;
|
||||||
|
height: 0;
|
||||||
|
width: 195px;
|
||||||
|
border-bottom: 1px dashed #d3d3d3;
|
||||||
|
top: 319px;left: 830px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.entity-detail-event-error {
|
.entity-detail-event-error {
|
||||||
|
|||||||
@@ -128,24 +128,25 @@ $blue: #046ECA;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.link-statistical-dimension {
|
||||||
|
.row-dot {
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.row-dot {
|
.green-dot {
|
||||||
margin-top: 5px;
|
width: 7px;
|
||||||
margin-right: 5px;
|
height: 7px;
|
||||||
}
|
border-radius: 50%;
|
||||||
|
background: #749F4D;
|
||||||
|
}
|
||||||
|
|
||||||
.green-dot {
|
.red-dot {
|
||||||
width: 7px;
|
width: 7px;
|
||||||
height: 7px;
|
height: 7px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #749F4D;
|
background: #E26154;
|
||||||
}
|
}
|
||||||
|
|
||||||
.red-dot {
|
|
||||||
width: 7px;
|
|
||||||
height: 7px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #E26154;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-popover-up, .item-popover-down {
|
.item-popover-up, .item-popover-down {
|
||||||
|
|||||||
@@ -31,8 +31,12 @@
|
|||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
|
|
||||||
|
.block-mode-icon1 {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
.block-mode-icon {
|
.block-mode-icon {
|
||||||
font-size: 16px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +212,15 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 0 14px;
|
padding: 0 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn1 {
|
||||||
|
margin-right: 10px;
|
||||||
|
.el-button {
|
||||||
|
background: #F5F6F7;
|
||||||
|
border: 1px solid rgba(215,215,215,1);
|
||||||
|
color: #353636;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-setting__btn1 {
|
.form-setting__btn1 {
|
||||||
|
|||||||
@@ -101,6 +101,12 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
|
|
||||||
|
.policy-form-item {
|
||||||
|
.el-form-item__error {
|
||||||
|
width: 260px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-input--mini .el-input__inner {
|
.el-input--mini .el-input__inner {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
background-color: rgba(0, 0, 0, 0.16) !important;
|
background-color: rgba(0, 0, 0, 0.16) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detection-drawer-title, .basic-function-value, basic-description-value {
|
.detection-drawer-title, .basic-function-value, basic-description-value, .drawer-trigger-minutes {
|
||||||
font-family: NotoSansSChineseRegular;
|
font-family: NotoSansSChineseRegular;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #717171;
|
color: #717171;
|
||||||
@@ -58,6 +58,10 @@
|
|||||||
color: #046ECA;
|
color: #046ECA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drawer-trigger-minutes {
|
||||||
|
color: #353636;
|
||||||
|
}
|
||||||
|
|
||||||
.detection-drawer-collapse {
|
.detection-drawer-collapse {
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
border: 1px solid rgba(226, 229, 236, 1);
|
border: 1px solid rgba(226, 229, 236, 1);
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
width: 5px;
|
width: 5px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cn-detection__row {
|
.cn-detection__row {
|
||||||
@@ -88,6 +89,7 @@
|
|||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
font-size: xx-small;
|
font-size: xx-small;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
margin-top: -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.circle {
|
.circle {
|
||||||
@@ -95,7 +97,7 @@
|
|||||||
height: 10px;
|
height: 10px;
|
||||||
border: 2px solid #da5656;
|
border: 2px solid #da5656;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
margin-top: 4px;
|
margin-top: 1px;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,10 +121,12 @@
|
|||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
.detection-event-severity-block {
|
.detection-event-severity-block {
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #046EC9;
|
color: #046EC9;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 2px 10px;
|
padding: 0 10px;
|
||||||
background: rgba(56,172,210,0.10);
|
background: rgba(56,172,210,0.10);
|
||||||
border: 1px solid #ADC7DB;
|
border: 1px solid #ADC7DB;
|
||||||
box-shadow: 0 2px 4px 0 rgba(51,51,51,0.02);
|
box-shadow: 0 2px 4px 0 rgba(51,51,51,0.02);
|
||||||
@@ -262,3 +266,8 @@
|
|||||||
color: #FFD82D !important;
|
color: #FFD82D !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.detection-list-icon {
|
||||||
|
margin-top: 1px;
|
||||||
|
font-size: 16px !important;
|
||||||
|
}
|
||||||
|
|||||||
@@ -60,12 +60,14 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row__content {
|
.row__content, .row__content1 {
|
||||||
display: flex;
|
display: flex;
|
||||||
//color: #3976CB;
|
//color: #3976CB;
|
||||||
color: #046ECA;
|
color: #046ECA;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
&.row__content--link {
|
&.row__content--link {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
@@ -87,6 +89,21 @@
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
color: #1890FF;
|
color: #1890FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.row__content__icon {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 5px;
|
||||||
|
color: #1890FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row__content__svg {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.row__content1 {
|
||||||
|
display: block;
|
||||||
|
padding-right: 50px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,13 +232,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.row__tag {
|
.row__tag, .row__tag__level {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
//color: white;
|
//color: white;
|
||||||
}
|
}
|
||||||
|
.row__tag__level {
|
||||||
|
height: 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.performance-event-remark {
|
.performance-event-remark {
|
||||||
font-family: NotoSansSChineseRegular;
|
font-family: NotoSansSChineseRegular;
|
||||||
|
|||||||
@@ -61,22 +61,19 @@
|
|||||||
|
|
||||||
.detection-tag-status0 {
|
.detection-tag-status0 {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-family: NotoSansHans-Medium;
|
|
||||||
background: rgba(113, 113, 113, 0.12);
|
background: rgba(113, 113, 113, 0.12);
|
||||||
color: #717171;
|
color: #717171;
|
||||||
padding: 0 12px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detection-tag-status1 {
|
.detection-tag-status1 {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-family: NotoSansHans-Medium;
|
|
||||||
background: rgba(126, 159, 84, 0.12);
|
background: rgba(126, 159, 84, 0.12);
|
||||||
color: #7E9F54;
|
color: #7E9F54;
|
||||||
padding: 0 8px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detection-table-library {
|
.detection-table-library {
|
||||||
font-family: NotoSansSChineseRegular;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #046ECA;
|
color: #046ECA;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|||||||
@@ -4,6 +4,18 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
.detections {
|
||||||
|
.entity__pagination{
|
||||||
|
bottom: 9px;
|
||||||
|
height: 40px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.detections__container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
.detection__list {
|
.detection__list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -349,6 +349,24 @@
|
|||||||
.data-score-green {
|
.data-score-green {
|
||||||
background: #749F4D;
|
background: #749F4D;
|
||||||
}
|
}
|
||||||
|
.score-dot {
|
||||||
|
display: inline-block;
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #CBCBCB;
|
||||||
|
margin-right: 4px;
|
||||||
|
|
||||||
|
&.score-dot--red {
|
||||||
|
background-color: #E26154;
|
||||||
|
}
|
||||||
|
&.score-dot--yellow {
|
||||||
|
background-color: #E5A219;
|
||||||
|
}
|
||||||
|
&.score-dot--green {
|
||||||
|
background-color: #749F4D;
|
||||||
|
}
|
||||||
|
}
|
||||||
height:24px;
|
height:24px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #046ECA;
|
color: #046ECA;
|
||||||
|
|||||||
@@ -174,6 +174,25 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #353636;
|
color: #353636;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
||||||
|
.score-dot {
|
||||||
|
display: inline-block;
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #CBCBCB;
|
||||||
|
margin-right: 4px;
|
||||||
|
|
||||||
|
&.score-dot--red {
|
||||||
|
background-color: #E26154;
|
||||||
|
}
|
||||||
|
&.score-dot--yellow {
|
||||||
|
background-color: #E5A219;
|
||||||
|
}
|
||||||
|
&.score-dot--green {
|
||||||
|
background-color: #749F4D;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "cn-icon"; /* Project id 2614877 */
|
font-family: "cn-icon"; /* Project id 2614877 */
|
||||||
src: url('iconfont.woff2?t=1693386443164') format('woff2'),
|
src: url('iconfont.woff2?t=1698229141457') format('woff2'),
|
||||||
url('iconfont.woff?t=1693386443164') format('woff'),
|
url('iconfont.woff?t=1698229141457') format('woff'),
|
||||||
url('iconfont.ttf?t=1693386443164') format('truetype');
|
url('iconfont.ttf?t=1698229141457') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.cn-icon {
|
.cn-icon {
|
||||||
@@ -13,6 +13,18 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cn-icon-indicator-match:before {
|
||||||
|
content: "\e80c";
|
||||||
|
}
|
||||||
|
|
||||||
|
.cn-icon-threshold:before {
|
||||||
|
content: "\e80d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.cn-icon-behavior:before {
|
||||||
|
content: "\e61c";
|
||||||
|
}
|
||||||
|
|
||||||
.cn-icon-category-group:before {
|
.cn-icon-category-group:before {
|
||||||
content: "\e6c7";
|
content: "\e6c7";
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -624,6 +624,11 @@ export default {
|
|||||||
const parser = new Parser(this.columnList)
|
const parser = new Parser(this.columnList)
|
||||||
if (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1) {
|
if (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1) {
|
||||||
q = decodeURI(q)
|
q = decodeURI(q)
|
||||||
|
} else {
|
||||||
|
const str1 = q.substring(q.indexOf('%'), q.indexOf('%') + 3)
|
||||||
|
if (q.indexOf('%') > 0 && (str1 !== '%20' || str1 === '%25')) {
|
||||||
|
q = decodeURI(q)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.metaList = parser.parseStr(q).metaList
|
this.metaList = parser.parseStr(q).metaList
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,6 +225,11 @@ export default {
|
|||||||
if (q) {
|
if (q) {
|
||||||
if (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1) {
|
if (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1) {
|
||||||
q = decodeURI(q)
|
q = decodeURI(q)
|
||||||
|
} else {
|
||||||
|
const str1 = q.substring(q.indexOf('%'), q.indexOf('%') + 3)
|
||||||
|
if (q.indexOf('%') > 0 && (str1 !== '%20' || str1 === '%25')) {
|
||||||
|
q = decodeURI(q)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 为避免地址栏任意输入导致全查询的q带QUERY,解析时不识别导致的语法错误
|
// 为避免地址栏任意输入导致全查询的q带QUERY,解析时不识别导致的语法错误
|
||||||
// 如地址栏输入116.178.222.171,此时的q很长,刷新界面时需要把q里的116.178.222.171拿出来进行搜索
|
// 如地址栏输入116.178.222.171,此时的q很长,刷新界面时需要把q里的116.178.222.171拿出来进行搜索
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import { ElMessage } from 'element-plus'
|
|||||||
import i18n from '@/i18n'
|
import i18n from '@/i18n'
|
||||||
|
|
||||||
const strReg = {
|
const strReg = {
|
||||||
all: /^[\da-zA-Z\s.'><!=-_(),%]$/,
|
// 需要不限制语言,正则过滤中英日俄语出错实现语言都通过。留个记录观察,后续校验
|
||||||
|
all: /^[\da-zA-Z\u4E00-\u9FA5\u3040-\u309F\u0800-\u4e00\u0400-\u04FF\u2000-\u206F\s.'><!=-_(),%]$/,
|
||||||
key: /^(?![\d])[\da-zA-Z\s.'-_]$/,
|
key: /^(?![\d])[\da-zA-Z\s.'-_]$/,
|
||||||
value: /^[\da-zA-Z\s.'-_%]$/
|
value: /^[\da-zA-Z\u4E00-\u9FA5\u3040-\u309F\u0800-\u4e00\u0400-\u04FF\u2000-\u206F\s.'-_%]$/
|
||||||
}
|
}
|
||||||
const operatorList = ['=', ' in ', ' IN ', ' like ', ' LIKE ', 'HAS(', 'has(']
|
const operatorList = ['=', ' in ', ' IN ', ' like ', ' LIKE ', 'HAS(', 'has(']
|
||||||
|
|
||||||
@@ -527,7 +528,9 @@ export default class Parser {
|
|||||||
}
|
}
|
||||||
// 在单引号里,又在括号里,则遇到逗号、右括号就报错
|
// 在单引号里,又在括号里,则遇到逗号、右括号就报错
|
||||||
if (isInBracket && isInApostrophe) {
|
if (isInBracket && isInApostrophe) {
|
||||||
if ([',', ')'].indexOf(strArr[j]) > -1) {
|
// if ([',', ')'].indexOf(strArr[j]) > -1) {
|
||||||
|
// 目前有ip in ('1.1.1.1,2.2.2.2')该情况,后续待验证
|
||||||
|
if ([')'].indexOf(strArr[j]) > -1) {
|
||||||
errorList.push(new ParserError(j, errorTypes.syntaxError, errorDesc.syntaxError.unclosedApostrophe))
|
errorList.push(new ParserError(j, errorTypes.syntaxError, errorDesc.syntaxError.unclosedApostrophe))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -709,6 +712,13 @@ export default class Parser {
|
|||||||
meta.column.label = token.value
|
meta.column.label = token.value
|
||||||
meta.column.type = columnType.fullText
|
meta.column.type = columnType.fullText
|
||||||
}
|
}
|
||||||
|
} else if (nextToken.type === types.rightBracket) {
|
||||||
|
// 此处操作为ip='1,2' and has(tag,'222')中 ,'222')的情况
|
||||||
|
if (prevToken) {
|
||||||
|
if (prevToken.type === types.comma && token.type === types.commonStr && nextToken.type === types.rightBracket) {
|
||||||
|
meta.value.value = token.value
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
errorList.push(new ParserError(token.end, errorTypes.syntaxError, errorDesc.syntaxError.unexpectedString))
|
errorList.push(new ParserError(token.end, errorTypes.syntaxError, errorDesc.syntaxError.unexpectedString))
|
||||||
break
|
break
|
||||||
@@ -1163,7 +1173,9 @@ export default class Parser {
|
|||||||
const arr = []
|
const arr = []
|
||||||
// 如果出现this.columnList中的字段,如IP\Domain\App\Country等,则不进行模糊搜索,将str返回出去
|
// 如果出现this.columnList中的字段,如IP\Domain\App\Country等,则不进行模糊搜索,将str返回出去
|
||||||
this.columnList.forEach(item => {
|
this.columnList.forEach(item => {
|
||||||
arr.push(item.label.toLowerCase())
|
// todo 取消了大小写校验,后续观察是否出现问题
|
||||||
|
// arr.push(item.label.toLowerCase())
|
||||||
|
arr.push(item.label)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 因为手动输入时可能会输入and,所以将操作符的AND转换为and,统一处理
|
// 因为手动输入时可能会输入and,所以将操作符的AND转换为and,统一处理
|
||||||
@@ -1173,7 +1185,9 @@ export default class Parser {
|
|||||||
newStr = newStr.replace(new RegExp(arr[i], 'g'), arr[i])
|
newStr = newStr.replace(new RegExp(arr[i], 'g'), arr[i])
|
||||||
}
|
}
|
||||||
// 检查str字段在arr中是否出现,true为出现过
|
// 检查str字段在arr中是否出现,true为出现过
|
||||||
const result = arr.some(item => newStr.toLowerCase().includes(item))
|
// todo 取消了大小写校验,后续观察是否出现问题
|
||||||
|
// const result = arr.some(item => newStr.toLowerCase().includes(item))
|
||||||
|
const result = arr.some(item => newStr.includes(item))
|
||||||
if (newStr.indexOf(' and ') > -1) {
|
if (newStr.indexOf(' and ') > -1) {
|
||||||
// 将单引号包裹的and拿出来放到数组tempList里,原来的单引号包裹内容用temp即'it is test keyword{键值}'代替
|
// 将单引号包裹的and拿出来放到数组tempList里,原来的单引号包裹内容用temp即'it is test keyword{键值}'代替
|
||||||
// 再将字符串用and转换为数组,遍历数组,发现值为temp的,获取键值,根据键值获取tempList的值组合起来,
|
// 再将字符串用and转换为数组,遍历数组,发现值为temp的,获取键值,根据键值获取tempList的值组合起来,
|
||||||
@@ -1184,7 +1198,7 @@ export default class Parser {
|
|||||||
|
|
||||||
// 将单引号包裹的and内容集合起来
|
// 将单引号包裹的and内容集合起来
|
||||||
while ((match = regex.exec(newStr)) !== null) {
|
while ((match = regex.exec(newStr)) !== null) {
|
||||||
if (match[1].includes('and')) {
|
if (match[1].includes(' and ')) {
|
||||||
tempList.push(match[1])
|
tempList.push(match[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1224,7 +1238,8 @@ export default class Parser {
|
|||||||
// 不区分大小写,用this.columnList里的label
|
// 不区分大小写,用this.columnList里的label
|
||||||
arr.forEach(item => {
|
arr.forEach(item => {
|
||||||
if (str.toLowerCase().indexOf(item.toLowerCase()) > -1) {
|
if (str.toLowerCase().indexOf(item.toLowerCase()) > -1) {
|
||||||
str = str.replace(new RegExp(item, 'gi'), item)
|
// todo 记录一下此处取消了转小写转换,后续搜索验证
|
||||||
|
// str = str.replace(new RegExp(item, 'gi'), item)
|
||||||
if (!operatorList.some(ite => str.includes(ite)) && str.toLowerCase() !== item.toLowerCase()) {
|
if (!operatorList.some(ite => str.includes(ite)) && str.toLowerCase() !== item.toLowerCase()) {
|
||||||
str = this.checkFormatByStr(str)
|
str = this.checkFormatByStr(str)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,12 +254,14 @@ export default {
|
|||||||
const returnValue = () => {
|
const returnValue = () => {
|
||||||
store.commit('setTimeFilter', { startTime: myStartTime.value, endTime: myEndTime.value, range: dateRangeValue.value })
|
store.commit('setTimeFilter', { startTime: myStartTime.value, endTime: myEndTime.value, range: dateRangeValue.value })
|
||||||
cancelHttp()
|
cancelHttp()
|
||||||
const obj = rangeHistory.value.find(d => d.start === myStartTime.value && d.end === myEndTime.value)
|
if (rangeHistory.value[0]) {
|
||||||
if (!obj) {
|
const d = rangeHistory.value[0]
|
||||||
rangeHistory.value.unshift({
|
if (d.start !== myStartTime.value || d.end !== myEndTime.value) {
|
||||||
start: myStartTime.value,
|
rangeHistory.value.unshift({
|
||||||
end: myEndTime.value
|
start: myStartTime.value,
|
||||||
})
|
end: myEndTime.value
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!rangeHistory.value[0]) {
|
if (!rangeHistory.value[0]) {
|
||||||
rangeHistory.value.unshift({
|
rangeHistory.value.unshift({
|
||||||
|
|||||||
@@ -99,7 +99,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="index===2">
|
<template v-else-if="index===2">
|
||||||
<span v-if="route===wholeScreenRouterMapping.dns">{{ $t(item.value) }}</span>
|
<span v-if="route===wholeScreenRouterMapping.dns || !route.startsWith('/panel')">{{ $t(item.value) }}</span>
|
||||||
<span v-else class="route-menu" @click="jump(route,item.value,'',3)">{{ $t(item.value) }}</span>
|
<span v-else class="route-menu" @click="jump(route,item.value,'',3)">{{ $t(item.value) }}</span>
|
||||||
</template>
|
</template>
|
||||||
<!-- index=0和index=1的点击跳转由breadcrumb里的数据控制 -->
|
<!-- index=0和index=1的点击跳转由breadcrumb里的数据控制 -->
|
||||||
@@ -392,7 +392,7 @@ export default {
|
|||||||
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
|
this.dnsRcodeMapData = await getDnsMapData('dnsRcode')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let path = this.$route.path;
|
const path = this.$route.path
|
||||||
if (path.indexOf('panel') > -1 && path.indexOf('linkMonitor') === -1) {
|
if (path.indexOf('panel') > -1 && path.indexOf('linkMonitor') === -1) {
|
||||||
await this.initDropdownList()
|
await this.initDropdownList()
|
||||||
}
|
}
|
||||||
@@ -424,7 +424,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
generateBreadcrumb (breadcrumb, menus) {
|
generateBreadcrumb (breadcrumb, menus) {
|
||||||
if (this.route === '/entityDetail') {
|
if (this.route === '/entityDetail') {
|
||||||
const entityMenu = menus.find(m => m.route === '/entityExplorer')
|
const entityMenu = menus.find(m => m.route === '/entity')
|
||||||
const entityDetailMenu = menus.find(m => m.route === '/entityDetail')
|
const entityDetailMenu = menus.find(m => m.route === '/entityDetail')
|
||||||
breadcrumb.push({
|
breadcrumb.push({
|
||||||
code: entityMenu.code,
|
code: entityMenu.code,
|
||||||
@@ -440,7 +440,7 @@ export default {
|
|||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
} else if (this.route === '/entityGraph') {
|
} else if (this.route === '/entityGraph') {
|
||||||
const entityMenu = menus.find(m => m.route === '/entityExplorer')
|
const entityMenu = menus.find(m => m.route === '/entity')
|
||||||
const entityGraphMenu = menus.find(m => m.route === '/entityGraph')
|
const entityGraphMenu = menus.find(m => m.route === '/entityGraph')
|
||||||
breadcrumb.push({
|
breadcrumb.push({
|
||||||
code: entityMenu.code,
|
code: entityMenu.code,
|
||||||
@@ -455,22 +455,6 @@ export default {
|
|||||||
type: entityGraphMenu.type
|
type: entityGraphMenu.type
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
} else if (this.route === '/detectionsNew') {
|
|
||||||
const detectionMenu = menus.find(m => m.route === '/detection')
|
|
||||||
const policyMenu = menus.find(m => m.route === '/detectionsNew')
|
|
||||||
breadcrumb.push({
|
|
||||||
code: detectionMenu.code,
|
|
||||||
value: detectionMenu.i18n ? this.$t(detectionMenu.i18n) : detectionMenu.name,
|
|
||||||
route: detectionMenu.route,
|
|
||||||
type: detectionMenu.type
|
|
||||||
})
|
|
||||||
breadcrumb.push({
|
|
||||||
code: policyMenu.code,
|
|
||||||
value: policyMenu.i18n ? this.$t(policyMenu.i18n) : policyMenu.name,
|
|
||||||
route: policyMenu.route,
|
|
||||||
type: policyMenu.type
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
const menu = menus.find(m => m.route === this.route)
|
const menu = menus.find(m => m.route === this.route)
|
||||||
if (menu) {
|
if (menu) {
|
||||||
@@ -786,6 +770,7 @@ export default {
|
|||||||
t: +new Date()
|
t: +new Date()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
return
|
||||||
} else if (opeType === 3) {
|
} else if (opeType === 3) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
query: {
|
query: {
|
||||||
@@ -794,6 +779,7 @@ export default {
|
|||||||
t: +new Date()
|
t: +new Date()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
return
|
||||||
} else if (opeType !== 4) {
|
} else if (opeType !== 4) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
query: {
|
query: {
|
||||||
@@ -803,6 +789,7 @@ export default {
|
|||||||
t: +new Date()
|
t: +new Date()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (route === this.route) {
|
if (route === this.route) {
|
||||||
this.refresh()
|
this.refresh()
|
||||||
|
|||||||
@@ -1,408 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="right-box right-box-user">
|
|
||||||
<div class="right-box__header">
|
|
||||||
<div class="header__title">{{editObject.id ? $t('config.chart.edit') : $t('config.chart.add')}}</div>
|
|
||||||
<div class="header__operation">
|
|
||||||
<span v-cancel="{object: editObject, func: esc}"><i class="cn-icon cn-icon-close"></i></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="right-box__container">
|
|
||||||
<div class="container__form">
|
|
||||||
<el-form ref="chartForm" :model="editObject" :rules="editObject.id ? rules2 : rules" label-position="top" label-width="120px">
|
|
||||||
<!--name-->
|
|
||||||
<el-form-item :label="$t('overall.name')" prop="name">
|
|
||||||
<el-input id="chart-input-name" v-model="editObject.name" :disabled="editObject.name==='admin' && editObject.id === 1"
|
|
||||||
maxlength="64" placeholder="" show-word-limit size="small" type="text"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<!--i18n-->
|
|
||||||
<el-form-item :label="$t('config.chart.i18n')" prop="i18n">
|
|
||||||
<el-input id="chart-input-i18n" v-model="editObject.i18n"
|
|
||||||
maxlength="64" placeholder="" show-word-limit size="small" type="text"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<!--type-->
|
|
||||||
<el-form-item :label="$t('config.chart.type')" prop="type">
|
|
||||||
<el-select id="chart-type"
|
|
||||||
v-model="editObject.type"
|
|
||||||
class="right-box__select"
|
|
||||||
clearable
|
|
||||||
collapse-tags
|
|
||||||
placeholder=""
|
|
||||||
popper-class="right-box-select-dropdown prevent-clickoutside"
|
|
||||||
size="small"
|
|
||||||
@change="()=>{ this.$forceUpdate() }">
|
|
||||||
|
|
||||||
<el-option
|
|
||||||
v-for="item in options"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value">
|
|
||||||
<span style="float: left">{{ item.label }}</span><span style="float: right;color: #909399;font-size: 13px;">{{ item.remark }}</span>
|
|
||||||
</el-option>
|
|
||||||
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<!--panel-->
|
|
||||||
<el-form-item :label="$t('config.chart.panel')" prop="panelId">
|
|
||||||
<el-select id="chart-input-panelId"
|
|
||||||
v-model="editObject.panelId"
|
|
||||||
class="right-box__select"
|
|
||||||
clearable
|
|
||||||
collapse-tags
|
|
||||||
placeholder=""
|
|
||||||
:disabled="editObject.id?true:false"
|
|
||||||
popper-class="right-box-select-dropdown prevent-clickoutside"
|
|
||||||
size="small"
|
|
||||||
@change="getChartData">
|
|
||||||
|
|
||||||
<el-option :key="panelTypeAndRouteMapping.trafficSummary" :label="$t('trafficSummary.trafficSummary')" :value="panelTypeAndRouteMapping.trafficSummary"></el-option>
|
|
||||||
<el-option :key="panelTypeAndRouteMapping.networkAppPerformance" :label="$t('networkAppPerformance.networkAppPerformance')" :value="panelTypeAndRouteMapping.networkAppPerformance"></el-option>
|
|
||||||
<el-option :key="panelTypeAndRouteMapping.cryptocurrency" :label="$t('overall.cryptocurrency')" :value="panelTypeAndRouteMapping.cryptocurrency"></el-option>
|
|
||||||
<el-option :key="panelTypeAndRouteMapping.dnsServiceInsights" :label="$t('dnsServiceInsights.dnsServiceInsights')" :value="panelTypeAndRouteMapping.dnsServiceInsights"></el-option>
|
|
||||||
<el-option :key="panelTypeAndRouteMapping.ipEntityDetail" :label="$t('entities.ipEntityDetail')" :value="panelTypeAndRouteMapping.ipEntityDetail"></el-option>
|
|
||||||
<el-option :key="panelTypeAndRouteMapping.domainEntityDetail" :label="$t('entities.domainEntityDetail')" :value="panelTypeAndRouteMapping.domainEntityDetail"></el-option>
|
|
||||||
<el-option :key="panelTypeAndRouteMapping.appEntityDetail" :label="$t('entities.appEntityDetail')" :value="panelTypeAndRouteMapping.appEntityDetail"></el-option>
|
|
||||||
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<!--pid-->
|
|
||||||
<el-form-item :label="$t('config.chart.pid')" prop="pid">
|
|
||||||
<el-select id="chart-pid"
|
|
||||||
v-model="editObject.pid"
|
|
||||||
class="right-box__select"
|
|
||||||
clearable
|
|
||||||
collapse-tags
|
|
||||||
placeholder=""
|
|
||||||
:disabled="editObject.id?true:false"
|
|
||||||
popper-class="right-box-select-dropdown prevent-clickoutside"
|
|
||||||
size="small"
|
|
||||||
@change="()=>{ this.$forceUpdate() }">
|
|
||||||
|
|
||||||
<template v-for="chart in chartData" :key="chart.id">
|
|
||||||
<el-option :label="chart.name" :value="chart.id"></el-option>
|
|
||||||
</template>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<!--x-->
|
|
||||||
<el-form-item :label="$t('config.chart.x')" prop="x">
|
|
||||||
<el-input id="chart-input-x" v-model="editObject.x"
|
|
||||||
maxlength="64" placeholder="" show-word-limit size="small" type="text"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<!--y-->
|
|
||||||
<el-form-item :label="$t('config.chart.y')" prop="y">
|
|
||||||
<el-input id="chart-input-y" v-model="editObject.y"
|
|
||||||
maxlength="64" placeholder="" show-word-limit size="small" type="text"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<!--w-->
|
|
||||||
<el-form-item :label="$t('config.chart.w')" prop="w">
|
|
||||||
<el-input id="chart-input-x" v-model="editObject.w"
|
|
||||||
maxlength="64" placeholder="" show-word-limit size="small" type="text"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<!--h-->
|
|
||||||
<el-form-item :label="$t('config.chart.h')" prop="h">
|
|
||||||
<el-input id="chart-input-y" v-model="editObject.h"
|
|
||||||
maxlength="64" placeholder="" show-word-limit size="small" type="text"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<!--params-->
|
|
||||||
<el-form-item :label="$t('config.chart.params')" prop="params">
|
|
||||||
<v-ace-editor
|
|
||||||
v-model:value="editObject.params"
|
|
||||||
lang="json"
|
|
||||||
theme="chrome"
|
|
||||||
style="height: 300px" />
|
|
||||||
</el-form-item>
|
|
||||||
<!--remark-->
|
|
||||||
<el-form-item :label="$t('config.chart.remark')">
|
|
||||||
<el-input maxlength="1024" show-word-limit :rows="2" size='mini' type="textarea" v-model="editObject.remark" id="chart-box-remark"/>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="right-box__footer">
|
|
||||||
<button id="chart-edit-cancel" v-cancel="{object: editObject, func: esc}" class="footer__btn footer__btn--light">
|
|
||||||
<span>{{$t('overall.cancel')}}</span>
|
|
||||||
</button>
|
|
||||||
<button id="chart-edit-save" :class="{'footer__btn--disabled': blockOperation.save}" :disabled="blockOperation.save" class="footer__btn" @click="save">
|
|
||||||
<span>{{$t('overall.save')}}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import rightBoxMixin from '@/mixins/right-box'
|
|
||||||
import axios from 'axios'
|
|
||||||
import { panelTypeAndRouteMapping, storageKey } from '@/utils/constants'
|
|
||||||
import { api } from '@/utils/api'
|
|
||||||
import { VAceEditor } from 'vue3-ace-editor'
|
|
||||||
import 'ace-builds/src-noconflict/mode-javascript'
|
|
||||||
import 'ace-builds/src-noconflict/mode-json'
|
|
||||||
import 'ace-builds/src-noconflict/theme-chrome'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'ChartBox',
|
|
||||||
mixins: [rightBoxMixin],
|
|
||||||
components: {
|
|
||||||
VAceEditor
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
url: api.chart,
|
|
||||||
loginName: localStorage.getItem(storageKey.username),
|
|
||||||
panelTypeAndRouteMapping: panelTypeAndRouteMapping,
|
|
||||||
rules: { // 表单校验规则
|
|
||||||
name: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
type: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
panel_id: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
x: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
y: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
w: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
h: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
rules2: { // 表单校验规则
|
|
||||||
name: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
type: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
panel_id: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
x: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
y: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
w: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
h: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
chartData: [],
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
value: 1,
|
|
||||||
label: 'map-1',
|
|
||||||
remark: '流量流向地图-连线'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 2,
|
|
||||||
label: 'map-2',
|
|
||||||
remark: '地图-色块'
|
|
||||||
}, {
|
|
||||||
value: 3,
|
|
||||||
label: 'map-3',
|
|
||||||
remark: '地图-点'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 4,
|
|
||||||
label: 'map-4',
|
|
||||||
remark: '地图-点'
|
|
||||||
}, {
|
|
||||||
value: 11,
|
|
||||||
label: 'line-1',
|
|
||||||
remark: '折线图-常规'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 61,
|
|
||||||
label: 'table-1',
|
|
||||||
remark: '表格'
|
|
||||||
}, {
|
|
||||||
value: 62,
|
|
||||||
label: 'table-2',
|
|
||||||
remark: 'DNS记录'
|
|
||||||
}, {
|
|
||||||
value: 63,
|
|
||||||
label: 'table-3',
|
|
||||||
remark: '挖矿活跃ip'
|
|
||||||
}, {
|
|
||||||
value: 31,
|
|
||||||
label: 'pie-1',
|
|
||||||
remark: '饼图-带联动表格'
|
|
||||||
}, {
|
|
||||||
value: 51,
|
|
||||||
label: 'singleValue-1',
|
|
||||||
remark: '单值图'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 91,
|
|
||||||
label: 'tab-container',
|
|
||||||
remark: 'tab标签(容器)'
|
|
||||||
}, {
|
|
||||||
value: 92,
|
|
||||||
label: 'tab-item',
|
|
||||||
remark: 'tab标签(标签页)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 93,
|
|
||||||
label: 'title',
|
|
||||||
remark: '标题'
|
|
||||||
}, {
|
|
||||||
value: 94,
|
|
||||||
label: 'group',
|
|
||||||
remark: '组'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 12,
|
|
||||||
label: 'line-2',
|
|
||||||
remark: '折线图-带统计'
|
|
||||||
}, {
|
|
||||||
value: 52,
|
|
||||||
label: 'singleValue-2',
|
|
||||||
remark: '详情单值图'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 53,
|
|
||||||
label: 'singleValue-3',
|
|
||||||
remark: '单值图'
|
|
||||||
}, {
|
|
||||||
value: 13,
|
|
||||||
label: 'line-3',
|
|
||||||
remark: '折线图-堆叠面积'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 21,
|
|
||||||
label: 'bar-1',
|
|
||||||
remark: '柱状图'
|
|
||||||
}, {
|
|
||||||
value: 22,
|
|
||||||
label: 'bar-2',
|
|
||||||
remark: '开放端口'
|
|
||||||
}, {
|
|
||||||
value: 23,
|
|
||||||
label: 'bar-3',
|
|
||||||
remark: '挖矿事件统计(time类型柱状图)'
|
|
||||||
}, {
|
|
||||||
value: 24,
|
|
||||||
label: 'bar-4',
|
|
||||||
remark: '矿机所属单位(category类型柱状图)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 32,
|
|
||||||
label: 'pie-2',
|
|
||||||
remark: '饼图-常规'
|
|
||||||
}, {
|
|
||||||
value: 33,
|
|
||||||
label: 'pie-3',
|
|
||||||
remark: '托管域名'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 34,
|
|
||||||
label: 'pie-4',
|
|
||||||
remark: '相关域名'
|
|
||||||
}, {
|
|
||||||
value: 42,
|
|
||||||
label: 'relation-2',
|
|
||||||
remark: '关系图谱'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 43,
|
|
||||||
label: 'relation-3',
|
|
||||||
remark: '访问链路图'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 82,
|
|
||||||
label: 'base-2',
|
|
||||||
remark: 'APP基本信息'
|
|
||||||
}, {
|
|
||||||
value: 83,
|
|
||||||
label: 'list-1',
|
|
||||||
remark: 'Whois'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 84,
|
|
||||||
label: 'list-2',
|
|
||||||
remark: 'DNS记录'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 85,
|
|
||||||
label: 'list-3',
|
|
||||||
remark: '近期挖矿事件'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setup () {
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
if (this.editObject.id) {
|
|
||||||
this.getChartData(this.editObject.panelId)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
'editObject.panelId': function (newValue, oldValue) {
|
|
||||||
this.editObject.pid = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
isCurrentUser (username) {
|
|
||||||
return localStorage.getItem(storageKey.username) === username
|
|
||||||
},
|
|
||||||
/* 密码失去焦点 检验确认密码 */
|
|
||||||
pinBlur () {
|
|
||||||
if (this.editObject.pin && this.editObject.pinChange) {
|
|
||||||
this.$refs.chartForm.validateField('pinChange')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
save () {
|
|
||||||
if (this.blockOperation.save) { return }
|
|
||||||
this.blockOperation.save = true
|
|
||||||
|
|
||||||
this.$refs.chartForm.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
if (this.editObject.id) {
|
|
||||||
axios.put(this.url, this.editObject).then(res => {
|
|
||||||
this.blockOperation.save = false
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
|
||||||
this.esc(true)
|
|
||||||
} else {
|
|
||||||
this.$message.error(res.data.message)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
axios.post(this.url, this.editObject).then(res => {
|
|
||||||
this.blockOperation.save = false
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
|
||||||
this.esc(true)
|
|
||||||
} else {
|
|
||||||
this.$message.error(res.data.message)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.blockOperation.save = false
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
async getChartData (value) {
|
|
||||||
await axios.get(api.chart, { params: { panelId: value } }).then(response => {
|
|
||||||
if (response.status === 200) {
|
|
||||||
this.chartData = response.data.data.list
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="right-box">
|
|
||||||
<div class="right-box__header">
|
|
||||||
<div class="header__title">{{editObject.id ? $t('overall.edit') : $t('overall.new')}}</div>
|
|
||||||
<div class="header__operation">
|
|
||||||
<span v-cancel="{object: editObject, func: esc}"><i class="cn-icon cn-icon-close"></i></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="right-box__container">
|
|
||||||
<div class="container__form">
|
|
||||||
<el-form ref="form" :model="editObject" :rules="rules" label-position="top" label-width="120px">
|
|
||||||
<!--name-->
|
|
||||||
<el-form-item :label="$t('overall.name')" prop="name">
|
|
||||||
<el-input id="proxy-name" v-model="editObject.name"
|
|
||||||
maxlength="64" placeholder="" show-word-limit size="small" type="text"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<!--path-->
|
|
||||||
<el-form-item :label="$t('overall.path')" prop="path">
|
|
||||||
<el-input id="proxy-path" v-model="editObject.path"
|
|
||||||
placeholder="" show-word-limit size="small" type="text"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<!--method-->
|
|
||||||
<el-form-item :label="$t('overall.method')" prop="method">
|
|
||||||
<el-select id="proxy-method"
|
|
||||||
v-model="editObject.method"
|
|
||||||
placeholder=" "
|
|
||||||
size="small"
|
|
||||||
class="right-box__select"
|
|
||||||
popper-class="right-box-select-dropdown prevent-clickoutside"
|
|
||||||
>
|
|
||||||
<el-option value="get"></el-option>
|
|
||||||
<el-option value="post"></el-option>
|
|
||||||
<el-option value="put"></el-option>
|
|
||||||
<el-option value="fetch"></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<!--version-->
|
|
||||||
<el-form-item :label="$t('overall.version')" prop="version">
|
|
||||||
<el-input id="proxy-version" v-model="editObject.version" placeholder="" size="small" type="text"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<!--target-->
|
|
||||||
<el-form-item :label="$t('galaxyProxy.targetUrl')" prop="targetUrl">
|
|
||||||
<el-input id="proxy-targetUrl" v-model="editObject.targetUrl" placeholder="" size="small" type="text"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<!--target param-->
|
|
||||||
<el-form-item :label="$t('galaxyProxy.targetParam')" prop="targetParam">
|
|
||||||
<!-- <prism-editor class="my-editor" v-model="editObject.targetParam" :highlight="jsonHl" line-numbers></prism-editor>-->
|
|
||||||
<v-ace-editor
|
|
||||||
v-model:value="editObject.targetParam"
|
|
||||||
lang="json"
|
|
||||||
theme="chrome"
|
|
||||||
style="height: 300px" />
|
|
||||||
</el-form-item>
|
|
||||||
<!--target header-->
|
|
||||||
<el-form-item :label="$t('galaxyProxy.targetHeader')" prop="targetHeader">
|
|
||||||
<v-ace-editor
|
|
||||||
v-model:value="editObject.targetHeader"
|
|
||||||
lang="json"
|
|
||||||
theme="chrome"
|
|
||||||
style="height: 300px" />
|
|
||||||
</el-form-item>
|
|
||||||
<!--pre handle-->
|
|
||||||
<el-form-item label="Pre handle" prop="preHandle">
|
|
||||||
<v-ace-editor
|
|
||||||
v-model:value="editObject.preHandle"
|
|
||||||
lang="javascript"
|
|
||||||
theme="chrome"
|
|
||||||
style="height: 300px" />
|
|
||||||
</el-form-item>
|
|
||||||
<!--post handle-->
|
|
||||||
<el-form-item label="Post handle" prop="postHandle">
|
|
||||||
<v-ace-editor
|
|
||||||
v-model:value="editObject.postHandle"
|
|
||||||
lang="javascript"
|
|
||||||
theme="chrome"
|
|
||||||
style="height: 300px" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="right-box__footer">
|
|
||||||
<button id="asset-edit-cancel" v-cancel="{object: editObject, func: esc}" class="footer__btn footer__btn--light">
|
|
||||||
<span>{{$t('overall.cancel')}}</span>
|
|
||||||
</button>
|
|
||||||
<button id="asset-edit-save" :class="{'footer__btn--disabled': blockOperation.save}" :disabled="blockOperation.save" class="footer__btn" @click="save">
|
|
||||||
<span>{{$t('overall.save')}}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import rightBoxMixin from '@/mixins/right-box'
|
|
||||||
import { api } from '@/utils/api'
|
|
||||||
import { VAceEditor } from 'vue3-ace-editor'
|
|
||||||
import 'ace-builds/src-noconflict/mode-javascript'
|
|
||||||
import 'ace-builds/src-noconflict/mode-json'
|
|
||||||
import 'ace-builds/src-noconflict/theme-chrome'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'GalaxyProxyBox',
|
|
||||||
mixins: [rightBoxMixin],
|
|
||||||
components: {
|
|
||||||
VAceEditor
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
url: api.galaxyProxy,
|
|
||||||
rules: { // 表单校验规则
|
|
||||||
name: [
|
|
||||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
class="right-box__select"
|
class="right-box__select"
|
||||||
clearable
|
clearable
|
||||||
collapse-tags
|
collapse-tags
|
||||||
placeholder=""
|
placeholder=" "
|
||||||
popper-class="right-box-select-dropdown prevent-clickoutside"
|
popper-class="right-box-select-dropdown prevent-clickoutside"
|
||||||
size="small"
|
size="small"
|
||||||
@change="()=>{ this.$forceUpdate() }">
|
@change="()=>{ this.$forceUpdate() }">
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
class="right-box__select"
|
class="right-box__select"
|
||||||
clearable
|
clearable
|
||||||
collapse-tags
|
collapse-tags
|
||||||
placeholder=""
|
placeholder=" "
|
||||||
popper-class="right-box-select-dropdown prevent-clickoutside"
|
popper-class="right-box-select-dropdown prevent-clickoutside"
|
||||||
size="small"
|
size="small"
|
||||||
@change="()=>{ this.$forceUpdate() }">
|
@change="()=>{ this.$forceUpdate() }">
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
class="right-box__select"
|
class="right-box__select"
|
||||||
clearable
|
clearable
|
||||||
collapse-tags
|
collapse-tags
|
||||||
placeholder=""
|
placeholder=" "
|
||||||
popper-class="right-box-select-dropdown prevent-clickoutside"
|
popper-class="right-box-select-dropdown prevent-clickoutside"
|
||||||
size="small">
|
size="small">
|
||||||
<template v-for="lang in langData" :key="lang.value">
|
<template v-for="lang in langData" :key="lang.value">
|
||||||
@@ -70,20 +70,20 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!--theme-->
|
<!--theme-->
|
||||||
<el-form-item :label="$t('config.user.theme')" prop="i18n">
|
<!-- <el-form-item :label="$t('config.user.theme')" prop="i18n">
|
||||||
<el-select id="account-input-roleIds"
|
<el-select id="account-input-roleIds"
|
||||||
v-model="editObject.theme"
|
v-model="editObject.theme"
|
||||||
class="right-box__select"
|
class="right-box__select"
|
||||||
clearable
|
clearable
|
||||||
collapse-tags
|
collapse-tags
|
||||||
placeholder=""
|
placeholder=" "
|
||||||
popper-class="right-box-select-dropdown prevent-clickoutside"
|
popper-class="right-box-select-dropdown prevent-clickoutside"
|
||||||
size="small">
|
size="small">
|
||||||
<template v-for="theme in themeData" :key="theme.value">
|
<template v-for="theme in themeData" :key="theme.value">
|
||||||
<el-option :label="theme.label" :value="theme.value"></el-option>
|
<el-option :label="theme.label" :value="theme.value"></el-option>
|
||||||
</template>
|
</template>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>-->
|
||||||
<!--enable-->
|
<!--enable-->
|
||||||
<el-form-item :label="$t('config.user.enable')">
|
<el-form-item :label="$t('config.user.enable')">
|
||||||
<el-switch
|
<el-switch
|
||||||
|
|||||||
@@ -1,329 +0,0 @@
|
|||||||
<template>
|
|
||||||
<el-dialog
|
|
||||||
v-model="show"
|
|
||||||
:top="top"
|
|
||||||
:modal="modal"
|
|
||||||
:custom-class="customClass"
|
|
||||||
:show-close="showClose"
|
|
||||||
:width="width"
|
|
||||||
@close="closeDebug"
|
|
||||||
@open="openDebug"
|
|
||||||
destroy-on-close
|
|
||||||
>
|
|
||||||
|
|
||||||
<div class="debug-wrapper">
|
|
||||||
<el-select v-model="name" filterable placeholder="Select" class="item item-1" allow-create
|
|
||||||
@change="changPath">
|
|
||||||
<template v-for="(proxy,index) in galaxyProxyData" :key="proxy.id">
|
|
||||||
<el-option :label="proxy.name" :value="index"></el-option>
|
|
||||||
</template>
|
|
||||||
</el-select>
|
|
||||||
<div class="item item-2 sub-grid-send">
|
|
||||||
<el-select v-model="method" filterable placeholder="Select" style="width:100px;" >
|
|
||||||
<el-option
|
|
||||||
v-for="item in methodOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
<el-input v-model="fullPathWithParams" placeholder="Please input" readonly/>
|
|
||||||
<el-button @click="send">{{$t('galaxyProxy.debug.send')}}</el-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item item-3 sub-grid-params">
|
|
||||||
<div class="sub-grid-params-add">
|
|
||||||
<span style="padding-left: 15px;">{{$t('galaxyProxy.debug.requestParams')}}</span>
|
|
||||||
<el-button size="mini" @click="handleAddDetails"><i class="cn-icon-add cn-icon"></i></el-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-table :data="paramsTableData"
|
|
||||||
width="100%"
|
|
||||||
@selection-change="handleDetailSelectionChange"
|
|
||||||
:row-class-name="rowClassName"
|
|
||||||
empty-text=""
|
|
||||||
ref="tb">
|
|
||||||
|
|
||||||
<el-table-column type="selection" align="center" label="" width="30px" style="border-left:0px;" />
|
|
||||||
|
|
||||||
<el-table-column prop="key" align="center" width="80px" >
|
|
||||||
<template #header>
|
|
||||||
<div class="table-operation-title">{{$t('galaxyProxy.debug.key')}}</div>
|
|
||||||
</template>
|
|
||||||
<template #default="scope">
|
|
||||||
<el-input @change="paramsChange(scope.row)" v-model="scope.row.key"></el-input>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<el-table-column prop="value" align="center" >
|
|
||||||
<template #header>
|
|
||||||
<div class="table-operation-title">{{$t('galaxyProxy.debug.value')}}</div>
|
|
||||||
</template>
|
|
||||||
<template #default="scope">
|
|
||||||
<el-input @change="paramsChange(scope.row)" v-model="scope.row.value"></el-input>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
<el-table-column align="center" style="border-right:0px;" width="70px">
|
|
||||||
<template #header>
|
|
||||||
<div class="table-operation-title">{{$t('overall.option')}}</div>
|
|
||||||
</template>
|
|
||||||
<template #default="scope">
|
|
||||||
<div @click="deleteRow(scope.$index)" class="debug__params-delete">{{$t('overall.delete')}}</div>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<template v-slot:empty>
|
|
||||||
<div style="height:0px;"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</el-table>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="item item-4">
|
|
||||||
<div class="request-header" >{{$t('galaxyProxy.debug.request.header')}}</div>
|
|
||||||
<div class="request-header-content" ><pre v-html="proxyRequestHeader" style="height: 98%;width: 98%;margin-left: -15px;margin-top: -10px;"></pre></div>
|
|
||||||
<div class="response-header">{{$t('galaxyProxy.debug.response.header')}}</div>
|
|
||||||
<div class="response-body">{{$t('galaxyProxy.debug.response.body')}}</div>
|
|
||||||
<div class="response-header-content"><pre v-html="proxyResponseHeader" style="height: 98%;width: 98%;margin-left: -15px;margin-top: -10px;"></pre></div>
|
|
||||||
<div class="response-body-content color-pre__style">
|
|
||||||
<v-ace-editor
|
|
||||||
v-model:value="proxyResponseBody"
|
|
||||||
lang="json"
|
|
||||||
readonly="true"
|
|
||||||
theme="chrome"
|
|
||||||
style="height: 100%" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { api } from '@/utils/api'
|
|
||||||
import { getForDebug, postForDebug } from '@/utils/http'
|
|
||||||
import axios from 'axios'
|
|
||||||
import { VAceEditor } from 'vue3-ace-editor'
|
|
||||||
import 'ace-builds/src-noconflict/mode-javascript'
|
|
||||||
import 'ace-builds/src-noconflict/mode-json'
|
|
||||||
import 'ace-builds/src-noconflict/theme-chrome'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'GalaxyProxyDebug',
|
|
||||||
components: {
|
|
||||||
VAceEditor
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
showDebug: Boolean,
|
|
||||||
top: {
|
|
||||||
type: String,
|
|
||||||
default: '5vh'
|
|
||||||
},
|
|
||||||
modal: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
customClass: {
|
|
||||||
type: String,
|
|
||||||
default: 'proxy-debug__dialog'
|
|
||||||
},
|
|
||||||
showClose: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
width: { // 高度需要通过customClass自行定义
|
|
||||||
type: [String, Number],
|
|
||||||
default: '90vw'
|
|
||||||
},
|
|
||||||
curGalaxyProxy: Object // 实体,{ name: '', path: '', icon: icon-class }
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
show: false,
|
|
||||||
galaxyProxyData: [],
|
|
||||||
name: '',
|
|
||||||
paramsTableData: [
|
|
||||||
|
|
||||||
],
|
|
||||||
// 选中的数据
|
|
||||||
checkedDetail: {},
|
|
||||||
checkedRowData: [],
|
|
||||||
methodOptions: [
|
|
||||||
{
|
|
||||||
value: 'GET',
|
|
||||||
label: 'GET'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'POST',
|
|
||||||
label: 'POST'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
method: 'GET',
|
|
||||||
path: '', // 不带参数的路径,用于请求URL
|
|
||||||
fullPathWithParams: '', // 带参数的完整路径,用于界面显示
|
|
||||||
proxyResponseBody: '',
|
|
||||||
proxyRequestHeader: '',
|
|
||||||
proxyResponseHeader: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setup () {
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
|
|
||||||
handleAddDetails () {
|
|
||||||
if (this.paramsTableData == undefined) {
|
|
||||||
this.paramsTableData = new Array()
|
|
||||||
}
|
|
||||||
const obj = {}
|
|
||||||
obj.key = ''
|
|
||||||
obj.value = ''
|
|
||||||
|
|
||||||
this.paramsTableData.push(obj)
|
|
||||||
},
|
|
||||||
|
|
||||||
// 删除当前行
|
|
||||||
deleteRow (index) {
|
|
||||||
this.paramsTableData.splice(index, 1)
|
|
||||||
this.updateUrlParams()
|
|
||||||
},
|
|
||||||
|
|
||||||
rowClassName ({ row, rowIndex }) {
|
|
||||||
// 把每一行的索引放进row
|
|
||||||
row.index = rowIndex
|
|
||||||
},
|
|
||||||
|
|
||||||
// 参数发送改变时
|
|
||||||
paramsChange (row) {
|
|
||||||
this.fullPathWithParams = this.path
|
|
||||||
this.checkedDetail = {}
|
|
||||||
this.checkedRowData.forEach(t => {
|
|
||||||
if (t.key != '') {
|
|
||||||
this.checkedDetail[t.key] = t.value
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (this.fullPathWithParams != '') {
|
|
||||||
this.updateUrlParams()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
updateUrlParams () {
|
|
||||||
this.fullPathWithParams = this.path
|
|
||||||
let params = ''
|
|
||||||
for (const key in this.checkedDetail) {
|
|
||||||
if (key != '') {
|
|
||||||
params = params + key + '=' + this.checkedDetail[key] + '&'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (params.endsWith('&')) {
|
|
||||||
params = params.substring(0, params.length - 1)
|
|
||||||
}
|
|
||||||
if (params != '') {
|
|
||||||
this.fullPathWithParams = this.fullPathWithParams + '?' + params
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 单选框选中数据
|
|
||||||
handleDetailSelectionChange (selection) {
|
|
||||||
this.checkedDetail = {}
|
|
||||||
this.checkedRowData = selection
|
|
||||||
selection.forEach((item, index) => {
|
|
||||||
this.checkedDetail[item.key] = item.value
|
|
||||||
})
|
|
||||||
this.updateUrlParams()
|
|
||||||
},
|
|
||||||
|
|
||||||
async getGalaxyProxyData (value) {
|
|
||||||
await axios.get(api.galaxyProxy + '?pageSize=-1').then(response => {
|
|
||||||
if (response.status === 200) {
|
|
||||||
this.galaxyProxyData = response.data.data.list
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
syntaxUrl (json) {
|
|
||||||
if (typeof json != 'string') {
|
|
||||||
json = JSON.stringify(json, undefined, 2)
|
|
||||||
}
|
|
||||||
return json = json.replace(/,/g, '&').replace(/{/g, '').replace(/}/g, '').replace(/"/g, '').replace(/:/g, '=').replace(/ /g, '')
|
|
||||||
},
|
|
||||||
|
|
||||||
changPath (index) {
|
|
||||||
// 修改input的值
|
|
||||||
this.path = axios.defaults.baseURL + 'interface' + this.galaxyProxyData[index].path
|
|
||||||
this.updateUrlParams()
|
|
||||||
this.method = this.galaxyProxyData[index].method.toUpperCase()
|
|
||||||
},
|
|
||||||
|
|
||||||
send () {
|
|
||||||
// this.path = "galaxy/setting?pageNo=1&pageSize=1"
|
|
||||||
// 注意有GET与POST两种方式
|
|
||||||
if (this.method.toUpperCase() == 'GET') {
|
|
||||||
getForDebug(this.path, this.checkedDetail).then(response => {
|
|
||||||
this.proxyResponseBody = this.syntaxJson(JSON.parse(JSON.stringify(response.data)))
|
|
||||||
this.proxyResponseHeader = this.syntaxJson(JSON.parse(JSON.stringify(response.headers)))
|
|
||||||
this.proxyRequestHeader = this.syntaxJson(JSON.parse(JSON.stringify(response.config.headers)))
|
|
||||||
this.proxyResponseHeader = this.proxyResponseHeader.replace(/{/g, '').replace(/}/g, '').replace(/"/g, '')
|
|
||||||
this.proxyRequestHeader = this.proxyRequestHeader.replace(/{/g, '').replace(/}/g, '').replace(/"/g, '')
|
|
||||||
})
|
|
||||||
} else if (this.method.toUpperCase() == 'POST') {
|
|
||||||
postForDebug(this.path, this.checkedDetail).then(response => {
|
|
||||||
if (response) {
|
|
||||||
this.proxyResponseBody = this.syntaxJson(JSON.parse(JSON.stringify(response.data)))
|
|
||||||
this.proxyResponseHeader = this.syntaxJson(JSON.parse(JSON.stringify(response.headers)))
|
|
||||||
this.proxyRequestHeader = this.syntaxJson(JSON.parse(JSON.stringify(response.config.headers)))
|
|
||||||
|
|
||||||
this.proxyResponseHeader = this.proxyResponseHeader.replace(/{/g, '').replace(/}/g, '').replace(/"/g, '')
|
|
||||||
this.proxyRequestHeader = this.proxyRequestHeader.replace(/{/g, '').replace(/}/g, '').replace(/"/g, '')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 格式化json
|
|
||||||
syntaxJson (json) {
|
|
||||||
if (typeof json != 'string') {
|
|
||||||
json = JSON.stringify(json, undefined, 2)
|
|
||||||
}
|
|
||||||
return json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
||||||
},
|
|
||||||
closeDebug () {
|
|
||||||
this.paramsTableData = []// JSON.parse(JSON.stringify(paramsTableData))
|
|
||||||
this.proxyResponseBody = ''
|
|
||||||
this.proxyResponseHeader = ''
|
|
||||||
this.proxyRequestHeader = ''
|
|
||||||
this.name = ''
|
|
||||||
this.path = ''
|
|
||||||
this.fullPathWithParams = ''
|
|
||||||
for (const key in this.curGalaxyProxy) {
|
|
||||||
delete this.curGalaxyProxy[key]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openDebug () {
|
|
||||||
if (this.curGalaxyProxy.path) {
|
|
||||||
this.name = this.curGalaxyProxy.name
|
|
||||||
this.path = axios.defaults.baseURL + 'interface' + this.curGalaxyProxy.path
|
|
||||||
this.fullPathWithParams = this.path
|
|
||||||
this.method = this.curGalaxyProxy.method.toUpperCase()
|
|
||||||
} else {
|
|
||||||
this.name = ''
|
|
||||||
this.path = ''
|
|
||||||
this.method = 'GET'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
// 获取代理名称及路径
|
|
||||||
this.getGalaxyProxyData()
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
showDebug (n, o) {
|
|
||||||
this.show = n
|
|
||||||
},
|
|
||||||
show (n, o) {
|
|
||||||
this.$emit('update:show-debug', n)
|
|
||||||
},
|
|
||||||
path (n, o) {
|
|
||||||
this.updateUrlParams()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -4,56 +4,60 @@
|
|||||||
<div class="block-mode">
|
<div class="block-mode">
|
||||||
<!--todo 图标没有,后期换-->
|
<!--todo 图标没有,后期换-->
|
||||||
<div class="block-mode-left">
|
<div class="block-mode-left">
|
||||||
<i class="cn-icon cn-icon-setting2 block-mode-icon"></i>
|
<i class="cn-icon cn-icon-indicator-match block-mode-icon1"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="block-mode-right">
|
<div class="block-mode-right" style="position:relative;">
|
||||||
<div class="block-mode-title">Indicator Match</div>
|
<div class="block-mode-title">{{ $t('detection.policy.indicatorMatch') }}</div>
|
||||||
<div class="block-mode-content">
|
<div class="block-mode-content">
|
||||||
Use indicators from intelligencesources to detect matchingevents and alerts.
|
{{ $t('detection.policy.indicatorMatchIntroduce') }}
|
||||||
|
<div v-if="language==='cn'" style="color: rgba(0,0,0,0)">0</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="settingObj.ruleType===detectionRuleType.indicator?'block-mode-btn-active':'block-mode-btn'"
|
<div :class="settingObj.ruleType===detectionRuleType.indicator?'block-mode-btn-active':'block-mode-btn'"
|
||||||
@click="selectMode(detectionRuleType.indicator)">select
|
@click="selectMode(detectionRuleType.indicator)">{{ $t('overall.select') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="block-mode">
|
<div class="block-mode" style="cursor: no-drop;">
|
||||||
<!--todo 图标没有,后期换-->
|
|
||||||
<div class="block-mode-left">
|
<div class="block-mode-left">
|
||||||
<i class="cn-icon cn-icon-setting2 block-mode-icon"></i>
|
<i class="cn-icon cn-icon-threshold block-mode-icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="block-mode-right">
|
<div class="block-mode-right">
|
||||||
<div class="block-mode-title">Threshold</div>
|
<div class="block-mode-title">{{ $t('detection.policy.threshold') }}</div>
|
||||||
<div class="block-mode-content">
|
<div class="block-mode-content">
|
||||||
Aggregate query results to detect when number of matches exceeds threshold.
|
{{ $t('detection.policy.thresholdIntroduce') }}
|
||||||
</div>
|
</div>
|
||||||
<div :class="settingObj.ruleType===detectionRuleType.threshold?'block-mode-btn-active':'block-mode-btn'"
|
<!--todo 当前版本暂时不可选择-->
|
||||||
@click="selectMode(detectionRuleType.threshold)">select
|
<div style="cursor: no-drop;" :class="settingObj.ruleType===detectionRuleType.threshold?'block-mode-btn-active':'block-mode-btn'">
|
||||||
|
{{ $t('overall.select') }}
|
||||||
</div>
|
</div>
|
||||||
|
<!-- <div :class="settingObj.ruleType===detectionRuleType.threshold?'block-mode-btn-active':'block-mode-btn'"-->
|
||||||
|
<!-- @click="selectMode(detectionRuleType.threshold)">select-->
|
||||||
|
<!-- </div>-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--category-->
|
<!--category-->
|
||||||
<el-form ref="form" :model="settingObj" label-position="top" :rules="rules">
|
<el-form ref="form" :model="settingObj" label-position="top" :rules="rules">
|
||||||
<el-form-item label="Category" prop="category" class="form-setting__block margin-b-20">
|
<el-form-item :label="$t('overall.category')" prop="category" class="form-setting__block margin-b-20">
|
||||||
<el-select v-model="settingObj.category" class="form-setting__select" placeholder=" " size="mini" @change="changeEditFlag">
|
<el-select :disabled="settingObj.ruleId" v-model="settingObj.category" class="form-setting__select" placeholder=" " size="mini" @change="changeEditFlag">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in categoryList"
|
v-for="item in categoryList"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="item.label"
|
:label="$t(item.label)"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!--type-->
|
<!--type-->
|
||||||
<el-form-item label="Type" prop="eventType" class="form-setting__block margin-b-20">
|
<el-form-item :label="$t('overall.type')" prop="eventType" class="form-setting__block margin-b-20">
|
||||||
<el-select v-model="settingObj.eventType" placeholder=" " size="mini" class="form-setting__select" @change="changeEditFlag">
|
<el-select v-model="settingObj.eventType" placeholder=" " size="mini" class="form-setting__select" @change="changeEditFlag">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in typeList"
|
v-for="item in eventTypeList"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
@@ -62,32 +66,32 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!--name-->
|
<!--name-->
|
||||||
<el-form-item label="Name" prop="name" class="form-setting__block margin-b-20">
|
<el-form-item :label="$t('overall.name')" prop="name" class="form-setting__block margin-b-20">
|
||||||
<el-input
|
<el-input
|
||||||
maxlength="64"
|
maxlength="64"
|
||||||
show-word-limit
|
show-word-limit
|
||||||
placeholder=""
|
placeholder=""
|
||||||
v-model="settingObj.name"
|
v-model="settingObj.name"
|
||||||
@input="changeEditFlag"
|
@blur="changeEditFlag"
|
||||||
class="form-setting__input" />
|
class="form-setting__input" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!--Description-->
|
<!--Description-->
|
||||||
<div class="form-setting__block margin-b-20">
|
<div class="form-setting__block margin-b-20">
|
||||||
<div class="block-title">Description</div>
|
<div class="block-title">{{ $t('config.dataSet.description') }}</div>
|
||||||
<el-input
|
<el-input
|
||||||
maxlength="255"
|
maxlength="255"
|
||||||
show-word-limit
|
show-word-limit
|
||||||
v-model="settingObj.description"
|
v-model="settingObj.description"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
resize='none'
|
resize='none'
|
||||||
@input="changeEditFlag"
|
@blur="changeEditFlag"
|
||||||
class="form-setting__textarea" />
|
class="form-setting__textarea" />
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<div class="form-setting__block margin-b-20">
|
<div class="form-setting__block margin-b-20">
|
||||||
<div class="block-title">Policy Status</div>
|
<div class="block-title">{{ $t('detection.create.policyStatus') }}</div>
|
||||||
<el-switch
|
<el-switch
|
||||||
v-model="settingObj.status"
|
v-model="settingObj.status"
|
||||||
@change="changeEditFlag"
|
@change="changeEditFlag"
|
||||||
@@ -95,30 +99,36 @@
|
|||||||
inactive-color="#C0CEDB"
|
inactive-color="#C0CEDB"
|
||||||
:active-value="1"
|
:active-value="1"
|
||||||
:inactive-value="0"
|
:inactive-value="0"
|
||||||
:active-text="switchStatus(settingObj.status)"/>
|
:active-text="$t(switchStatus(settingObj.status))"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-setting__btn">
|
<div class="form-setting__btn">
|
||||||
<el-button @click="onContinue">Continue</el-button>
|
<el-button @click="onContinue">{{ $t('detection.create.continue') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { detectionRuleType } from '@/utils/constants'
|
import { detectionRuleType, storageKey, detectionUnitList } from '@/utils/constants'
|
||||||
import { switchStatus } from '@/utils/tools'
|
import { switchStatus } from '@/utils/tools'
|
||||||
import axios from 'axios'
|
|
||||||
import { api } from '@/utils/api'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'GeneralSettings',
|
name: 'GeneralSettings',
|
||||||
|
props: {
|
||||||
|
editObj: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
isComplete: {
|
||||||
|
type: Boolean
|
||||||
|
}
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
detectionRuleType,
|
detectionRuleType,
|
||||||
categoryList: [],
|
categoryList: [],
|
||||||
typeList: [],
|
eventTypeList: [],
|
||||||
settingObj: {
|
settingObj: {
|
||||||
ruleType: detectionRuleType.threshold,
|
ruleType: detectionRuleType.indicator,
|
||||||
category: '',
|
category: '',
|
||||||
eventType: '',
|
eventType: '',
|
||||||
name: '',
|
name: '',
|
||||||
@@ -149,6 +159,21 @@ export default {
|
|||||||
trigger: 'blur'
|
trigger: 'blur'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
language: 'en'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
editObj (newVal) {
|
||||||
|
if (newVal.ruleId) {
|
||||||
|
this.settingObj = JSON.parse(JSON.stringify({ ...newVal }))
|
||||||
|
this.settingObj.editFlag = false
|
||||||
|
this.settingObj.saveFlag = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isComplete (newVal) {
|
||||||
|
if (!newVal) {
|
||||||
|
this.onContinue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -158,15 +183,9 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
switchStatus,
|
switchStatus,
|
||||||
initData () {
|
initData () {
|
||||||
axios.get(api.detection.statistics, { params: { pageSize: -1 } }).then(response => {
|
this.language = localStorage.getItem(storageKey.language) || 'en'
|
||||||
if (response.status === 200) {
|
this.categoryList = detectionUnitList.categoryList
|
||||||
this.categoryList = response.data.data.categoryList || []
|
this.eventTypeList = detectionUnitList.eventTypeList
|
||||||
this.typeList = response.data.data.typeList || []
|
|
||||||
} else {
|
|
||||||
console.error(response.data)
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
selectMode (ruleType) {
|
selectMode (ruleType) {
|
||||||
this.settingObj.ruleType = ruleType
|
this.settingObj.ruleType = ruleType
|
||||||
@@ -174,9 +193,16 @@ export default {
|
|||||||
},
|
},
|
||||||
changeEditFlag () {
|
changeEditFlag () {
|
||||||
this.settingObj.editFlag = true
|
this.settingObj.editFlag = true
|
||||||
|
if (this.settingObj.ruleType && this.settingObj.category && this.settingObj.eventType && this.settingObj.name) {
|
||||||
|
this.settingObj.settingNoContinue = true
|
||||||
|
this.onContinue()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/** 点击继续,进行第二步 */
|
/** 点击继续,进行第二步 */
|
||||||
onContinue () {
|
onContinue (e) {
|
||||||
|
if (e) {
|
||||||
|
delete this.settingObj.settingNoContinue
|
||||||
|
}
|
||||||
this.$refs.form.validate(valid => {
|
this.$refs.form.validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.settingObj.editFlag = false
|
this.settingObj.editFlag = false
|
||||||
@@ -188,7 +214,3 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -9,8 +9,7 @@
|
|||||||
<div class="key-search">
|
<div class="key-search">
|
||||||
<el-input v-model="searchKey" @keyup.enter="onSearch" size="mini" placeholder="Search for">
|
<el-input v-model="searchKey" @keyup.enter="onSearch" size="mini" placeholder="Search for">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<!--todo 该图标名称错误,已在iconfont修改,后续记得改过来-->
|
<i class="cn-icon cn-icon-search key-search-icon"></i>
|
||||||
<i class="cn-icon cn-icon-serach key-search-icon"></i>
|
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@
|
|||||||
<div class="key-table">
|
<div class="key-table">
|
||||||
<loading :loading="loading"></loading>
|
<loading :loading="loading"></loading>
|
||||||
|
|
||||||
<el-table :data="tableData" style="width: 100%" @row-click="rowClick">
|
<el-table :data="tableData" style="width: 100%" :row-class-name="tableRowClassName" @row-click="rowClick">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-for="(item, index) in tableTitle"
|
v-for="(item, index) in tableTitle"
|
||||||
:key="`col-${index}`"
|
:key="`col-${index}`"
|
||||||
@@ -73,6 +72,9 @@ export default {
|
|||||||
showDrawer: {
|
showDrawer: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
delKeyId: {
|
||||||
|
type: String
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@@ -116,6 +118,16 @@ export default {
|
|||||||
this.myDrawer = this.showDrawer
|
this.myDrawer = this.showDrawer
|
||||||
this.getTopKeysData()
|
this.getTopKeysData()
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
delKeyId (newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
const obj = this.tableData.find(d => d.keyId === newVal)
|
||||||
|
if (obj) {
|
||||||
|
obj.filterKey = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
unitConvert,
|
unitConvert,
|
||||||
dateFormatByAppearance,
|
dateFormatByAppearance,
|
||||||
@@ -150,6 +162,7 @@ export default {
|
|||||||
},
|
},
|
||||||
/** 单击topKeys弹窗某一项 */
|
/** 单击topKeys弹窗某一项 */
|
||||||
rowClick (data) {
|
rowClick (data) {
|
||||||
|
data.filterKey = true
|
||||||
this.$emit('keyRowClick', data)
|
this.$emit('keyRowClick', data)
|
||||||
},
|
},
|
||||||
onRefresh () {
|
onRefresh () {
|
||||||
@@ -161,6 +174,11 @@ export default {
|
|||||||
httpError (e) {
|
httpError (e) {
|
||||||
this.showError = true
|
this.showError = true
|
||||||
this.errorMsg = this.errorMsgHandler(e)
|
this.errorMsg = this.errorMsgHandler(e)
|
||||||
|
},
|
||||||
|
tableRowClassName (row) {
|
||||||
|
if (row.row.filterKey) {
|
||||||
|
return 'key-click-row'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,4 +249,8 @@ export default {
|
|||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-table .key-click-row {
|
||||||
|
background: #F5F7FA !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<el-form ref="form" :model="thresholdRuleObj" label-position="top" :rules="rules">
|
<el-form ref="form" :model="thresholdRuleObj" label-position="top" :rules="rules">
|
||||||
<!--source-->
|
<!--source-->
|
||||||
<el-form-item label="Source" prop="dataSource" class="form-setting__block margin-b-20">
|
<el-form-item :label="$t('config.user.source')" prop="dataSource" class="form-setting__block margin-b-20">
|
||||||
<el-select v-model="thresholdRuleObj.dataSource" placeholder=" " size="mini" class="form-setting__select">
|
<el-select v-model="thresholdRuleObj.dataSource" placeholder=" " size="mini" class="form-setting__select">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in sourceList"
|
v-for="item in sourceList"
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<!--Dimensions-->
|
<!--Dimensions-->
|
||||||
<div class="form-setting__block margin-b-20">
|
<div class="form-setting__block margin-b-20">
|
||||||
<div class="block-title">Dimensions</div>
|
<div class="block-title">{{ $t('detection.create.dimensions') }}</div>
|
||||||
<div class="block-dimension">
|
<div class="block-dimension">
|
||||||
<div class="block-dimension-tag" v-for="(ite, ind) in dimensionList" :key="ind">{{ ite.label }}</div>
|
<div class="block-dimension-tag" v-for="(ite, ind) in dimensionList" :key="ind">{{ ite.label }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
size="mini"
|
size="mini"
|
||||||
oninput="value=value.replace(/[^\d]/g,'')"
|
oninput="value=value.replace(/[^\d]/g,'')"
|
||||||
v-model="item.value"></el-input>
|
v-model="item.value"></el-input>
|
||||||
<i class="cn-icon cn-icon-close" @click="delFilterItem(index)"></i>
|
<i class="cn-icon cn-icon-close" @click="delFilterItem(index, item)"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="height: 10px;"></div>
|
<div style="height: 10px;"></div>
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
|
|
||||||
<!--Condition模块-->
|
<!--Condition模块-->
|
||||||
<div class="form-setting__block margin-b-20">
|
<div class="form-setting__block margin-b-20">
|
||||||
<div class="block-title">Condition</div>
|
<div class="block-title">{{ $t('detection.create.condition') }}</div>
|
||||||
|
|
||||||
<el-form ref="form2" :model="thresholdRuleObj" label-position="top">
|
<el-form ref="form2" :model="thresholdRuleObj" label-position="top">
|
||||||
<div class="definition-condition-block" v-for="(item, index) in thresholdRuleObj.conditionData" :key="index">
|
<div class="definition-condition-block" v-for="(item, index) in thresholdRuleObj.conditionData" :key="index">
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
v-for="item in metricList"
|
v-for="item in metricList"
|
||||||
:key="item.label"
|
:key="item.label"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value"
|
:value="item.label"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<div class="condition-add" @click="addCondition">
|
<div class="condition-add" @click="addCondition">
|
||||||
<i class="cn-icon cn-icon-add"></i>Add Condition
|
<i class="cn-icon cn-icon-add"></i>{{ $t('detection.create.addCondition') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -154,6 +154,7 @@
|
|||||||
<history-top-keys
|
<history-top-keys
|
||||||
v-if="showDrawer"
|
v-if="showDrawer"
|
||||||
:showDrawer="showDrawer"
|
:showDrawer="showDrawer"
|
||||||
|
:delKeyId="delKeyId"
|
||||||
@closeDrawer="onCloseDrawer"
|
@closeDrawer="onCloseDrawer"
|
||||||
@keyRowClick="getRowClick"
|
@keyRowClick="getRowClick"
|
||||||
></history-top-keys>
|
></history-top-keys>
|
||||||
@@ -163,24 +164,24 @@
|
|||||||
<div v-if="mySettingObj.ruleType===detectionRuleType.indicator">
|
<div v-if="mySettingObj.ruleType===detectionRuleType.indicator">
|
||||||
<el-form ref="form" :model="indicatorRuleObj" label-position="top" :rules="rules">
|
<el-form ref="form" :model="indicatorRuleObj" label-position="top" :rules="rules">
|
||||||
<!--Source-->
|
<!--Source-->
|
||||||
<el-form-item label="Source" prop="dataSource" class="form-setting__block margin-b-20">
|
<el-form-item :label="$t('config.user.source')" prop="dataSource" class="form-setting__block margin-b-20">
|
||||||
<el-select v-model="indicatorRuleObj.dataSource" class="form-setting__select" placeholder=" " size="mini">
|
<el-select v-model="indicatorRuleObj.dataSource" class="form-setting__select" placeholder=" " size="mini" @change="handleParamsComplete">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in sourceList"
|
v-for="item in sourceList"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="item.label"
|
:label="$t(item.label)"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!--Library-->
|
<!--Library-->
|
||||||
<el-form-item label="Library" prop="knowledgeId" class="form-setting__block margin-b-20">
|
<el-form-item :label="$t('detection.library')" prop="knowledgeId" class="form-setting__block margin-b-20">
|
||||||
<el-select v-model="indicatorRuleObj.knowledgeId" class="form-setting__select" placeholder=" " size="mini">
|
<el-select v-model="indicatorRuleObj.knowledgeId" class="form-setting__select" filterable placeholder=" " size="mini" @change="handleParamsComplete">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in libraryList"
|
v-for="item in libraryList"
|
||||||
:key="item.knowledgeId"
|
:key="item.knowledgeId"
|
||||||
:label="item.label"
|
:label="item.name"
|
||||||
:value="item.knowledgeId"
|
:value="item.knowledgeId"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
@@ -188,7 +189,7 @@
|
|||||||
|
|
||||||
<!--Level-->
|
<!--Level-->
|
||||||
<el-form-item :label="$t('detection.level')" prop="level" class="form-setting__block">
|
<el-form-item :label="$t('detection.level')" prop="level" class="form-setting__block">
|
||||||
<el-select v-model="indicatorRuleObj.level" class="condition__select form-setting__select" placeholder=" " size="mini">
|
<el-select v-model="indicatorRuleObj.level" class="condition__select form-setting__select" placeholder=" " size="mini" @change="handleParamsComplete">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<div
|
<div
|
||||||
class="condition__select__icon"
|
class="condition__select__icon"
|
||||||
@@ -198,7 +199,7 @@
|
|||||||
<el-option
|
<el-option
|
||||||
v-for="item in levelList"
|
v-for="item in levelList"
|
||||||
:key="item.label"
|
:key="item.label"
|
||||||
:label="item.label"
|
:label="$t(item.label)"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
@@ -207,22 +208,29 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-setting__btn">
|
<div class="form-setting__btn">
|
||||||
<el-button @click="onContinue">Continue</el-button>
|
<el-button @click="onContinue">{{ $t('detection.create.continue') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
|
||||||
import { api } from '@/utils/api'
|
|
||||||
import HistoryTopKeys from '@/components/table/detection/HistoryTopKeys'
|
import HistoryTopKeys from '@/components/table/detection/HistoryTopKeys'
|
||||||
import { eventSeverityColor, detectionRuleType } from '@/utils/constants'
|
import { eventSeverityColor, detectionRuleType, detectionUnitList, securityLevel } from '@/utils/constants'
|
||||||
|
import axios from 'axios'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { api } from '@/utils/api'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RuleDefinition',
|
name: 'RuleDefinition',
|
||||||
props: {
|
props: {
|
||||||
settingObj: {
|
settingObj: {
|
||||||
type: Object
|
type: Object
|
||||||
|
},
|
||||||
|
editObj: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
isComplete: {
|
||||||
|
type: Boolean
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@@ -232,11 +240,31 @@ export default {
|
|||||||
settingObj: {
|
settingObj: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
deep: true,
|
deep: true,
|
||||||
handler (newVal, oldVal) {
|
handler (newVal) {
|
||||||
if (!newVal.editFlag && newVal.saveFlag) {
|
if (!newVal.editFlag && newVal.saveFlag) {
|
||||||
this.mySettingObj = JSON.parse(JSON.stringify(newVal))
|
this.mySettingObj = JSON.parse(JSON.stringify(newVal))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
editObj: {
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
handler (newVal) {
|
||||||
|
if (newVal) {
|
||||||
|
if (newVal.ruleType === detectionRuleType.indicator) {
|
||||||
|
this.indicatorRuleObj = this.$_.cloneDeep(newVal.ruleConfigObj)
|
||||||
|
this.indicatorRuleObj.knowledgeId = newVal.ruleConfigObj.knowledgeBase.knowledgeId
|
||||||
|
}
|
||||||
|
if (newVal.ruleType === detectionRuleType.threshold) {
|
||||||
|
this.thresholdRuleObj = this.$_.cloneDeep(newVal.ruleConfigObj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isComplete (newVal) {
|
||||||
|
if (!newVal) {
|
||||||
|
this.onContinue()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
@@ -244,7 +272,7 @@ export default {
|
|||||||
eventSeverityColor,
|
eventSeverityColor,
|
||||||
detectionRuleType,
|
detectionRuleType,
|
||||||
mySettingObj: {
|
mySettingObj: {
|
||||||
ruleType: detectionRuleType.threshold
|
ruleType: detectionRuleType.indicator
|
||||||
},
|
},
|
||||||
dimensionList: [], // Dimensions数据
|
dimensionList: [], // Dimensions数据
|
||||||
// ruleType为Indicator时表单数据
|
// ruleType为Indicator时表单数据
|
||||||
@@ -327,7 +355,8 @@ export default {
|
|||||||
than: '>',
|
than: '>',
|
||||||
less: '<',
|
less: '<',
|
||||||
equal: '='
|
equal: '='
|
||||||
}
|
},
|
||||||
|
delKeyId: '' // 删除的keyId
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
@@ -341,18 +370,31 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initData () {
|
initData () {
|
||||||
axios.get(api.detection.statistics, { params: { pageSize: -1 } }).then(response => {
|
this.sourceList = detectionUnitList.sourceList || []
|
||||||
if (response.status === 200) {
|
this.levelList = securityLevel || []
|
||||||
this.sourceList = response.data.data.sourceList || []
|
// threshold模式还没确定,所以数据暂时静态数据,后续根据需要修改
|
||||||
this.levelList = response.data.data.levelList || []
|
this.conditionList = detectionUnitList.conditionList || []
|
||||||
this.conditionList = response.data.data.conditionList || []
|
this.metricList = detectionUnitList.metricList || []
|
||||||
this.metricList = response.data.data.metricList || []
|
|
||||||
this.libraryList = response.data.data.libraryList || []
|
if (this.mySettingObj.ruleType === this.detectionRuleType.indicator) {
|
||||||
} else {
|
axios.get(api.knowledgeBaseList, { params: { pageSize: -1 } }).then(response => {
|
||||||
console.error(response.data)
|
if (response.status === 200) {
|
||||||
}
|
this.libraryList = _.get(response, 'data.data.list', []).filter(l => l.isBuiltIn === 0)
|
||||||
}).finally(() => {
|
} else {
|
||||||
})
|
console.error(response.data.message)
|
||||||
|
this.libraryList = []
|
||||||
|
if (response.data.message) {
|
||||||
|
this.$message.error(response.data.message)
|
||||||
|
} else {
|
||||||
|
this.$message.error(this.$t('tip.somethingWentWrong'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
this.libraryList = []
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/** 单击History Top Keys列表某行,filter添加数据 */
|
/** 单击History Top Keys列表某行,filter添加数据 */
|
||||||
getRowClick (data) {
|
getRowClick (data) {
|
||||||
@@ -364,6 +406,7 @@ export default {
|
|||||||
},
|
},
|
||||||
/** filter模块点击add按钮 */
|
/** filter模块点击add按钮 */
|
||||||
addFilter (data) {
|
addFilter (data) {
|
||||||
|
this.delKeyId = ''
|
||||||
this.showFilter = true
|
this.showFilter = true
|
||||||
if (this.selectList.length === 0) {
|
if (this.selectList.length === 0) {
|
||||||
this.getFilterList()
|
this.getFilterList()
|
||||||
@@ -445,11 +488,15 @@ export default {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
/** 删除filter某一项 */
|
/** 删除filter某一项 */
|
||||||
delFilterItem (i) {
|
delFilterItem (i, item) {
|
||||||
|
this.delKeyId = item.keyId
|
||||||
this.thresholdRuleObj.filterList.splice(i, 1)
|
this.thresholdRuleObj.filterList.splice(i, 1)
|
||||||
},
|
},
|
||||||
/** 点击继续,展开第三步 */
|
/** 点击继续,展开第三步 */
|
||||||
onContinue () {
|
onContinue (e) {
|
||||||
|
if (e) {
|
||||||
|
delete this.indicatorRuleObj.ruleNoContinue
|
||||||
|
}
|
||||||
this.$refs.form.validate(valid => {
|
this.$refs.form.validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (this.mySettingObj.ruleType === detectionRuleType.indicator) {
|
if (this.mySettingObj.ruleType === detectionRuleType.indicator) {
|
||||||
@@ -482,6 +529,12 @@ export default {
|
|||||||
obj[item.level] = str
|
obj[item.level] = str
|
||||||
})
|
})
|
||||||
this.thresholdRuleObj.conditions = obj
|
this.thresholdRuleObj.conditions = obj
|
||||||
|
},
|
||||||
|
handleParamsComplete () {
|
||||||
|
if (this.indicatorRuleObj.dataSource && this.indicatorRuleObj.knowledgeId && this.indicatorRuleObj.level) {
|
||||||
|
this.indicatorRuleObj.ruleNoContinue = true
|
||||||
|
this.onContinue()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,11 @@
|
|||||||
>
|
>
|
||||||
</el-switch>
|
</el-switch>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="item.prop === 'color'">
|
||||||
|
<div class="knowledge-color">
|
||||||
|
<span class="knowledge-color__icon" :class="colorName(scope.row[item.prop])"></span> <span>{{colorText(scope.row[item.prop])}}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<span v-else>{{scope.row[item.prop] || '-'}}</span>
|
<span v-else>{{scope.row[item.prop] || '-'}}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -153,6 +158,11 @@ export default {
|
|||||||
prop: 'reference',
|
prop: 'reference',
|
||||||
width: 180,
|
width: 180,
|
||||||
show: true
|
show: true
|
||||||
|
}, {
|
||||||
|
label: this.$t('overall.color'),
|
||||||
|
prop: 'color',
|
||||||
|
width: 180,
|
||||||
|
show: true
|
||||||
}, {
|
}, {
|
||||||
label: this.$t('overall.remark'),
|
label: this.$t('overall.remark'),
|
||||||
prop: 'description',
|
prop: 'description',
|
||||||
@@ -189,6 +199,23 @@ export default {
|
|||||||
show: true,
|
show: true,
|
||||||
width: 80
|
width: 80
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
knowledgeBaseColor: [
|
||||||
|
{
|
||||||
|
label: this.$t('knowledge.info'),
|
||||||
|
value: 'rgb(119,131,145)',
|
||||||
|
name: 'info'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('knowledge.benign'),
|
||||||
|
value: 'rgb(116,159,77)',
|
||||||
|
name: 'benign'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('knowledge.malicious'),
|
||||||
|
value: 'rgb(226,97,84)',
|
||||||
|
name: 'malicious'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -221,6 +248,20 @@ export default {
|
|||||||
const t = knowledgeBaseSource.find(t => t.value === type)
|
const t = knowledgeBaseSource.find(t => t.value === type)
|
||||||
return t ? t.name : ''
|
return t ? t.name : ''
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
colorText () {
|
||||||
|
const vm = this
|
||||||
|
return function (color) {
|
||||||
|
const t = vm.knowledgeBaseColor.find(t => t.value === color)
|
||||||
|
return t ? t.label : vm.knowledgeBaseColor[0].label
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colorName () {
|
||||||
|
const vm = this
|
||||||
|
return function (color) {
|
||||||
|
const t = vm.knowledgeBaseColor.find(t => t.value === color)
|
||||||
|
return t ? t.name : vm.knowledgeBaseColor[0].name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,27 +3,18 @@
|
|||||||
<div class="card-type-title" v-if="aiTaggingList.length > 0">{{$t('knowledgeBase.intelligenceLearning')}}</div>
|
<div class="card-type-title" v-if="aiTaggingList.length > 0">{{$t('knowledgeBase.intelligenceLearning')}}</div>
|
||||||
<el-checkbox-group v-model="checkList" >
|
<el-checkbox-group v-model="checkList" >
|
||||||
<div class="card-box" v-for="data in aiTaggingList" :key="data.knowledgeId">
|
<div class="card-box" v-for="data in aiTaggingList" :key="data.knowledgeId">
|
||||||
<div @click="isSelectedStatus && data.isBuiltIn !== 1 && clickCard(data,$event)" @mouseenter="mouseenter(data)" @mouseleave="mouseleave(data)" class="card-item" :class="data.isSelected ? 'card-selected' : ''">
|
<div @click="isSelectedStatus && data.isBuiltIn !== 1 && clickCard(data,$event)" @mouseenter="mouseenter(data)" @mouseleave="mouseleave(data)" class="card-item" :class="data.isSelected ? 'card-selected' : ''">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="card-operate">
|
<div class="card-operate">
|
||||||
<el-tooltip
|
<el-switch v-model="data.status"
|
||||||
effect="light"
|
class="card-enable"
|
||||||
trigger="hover"
|
active-color="#38ACD2"
|
||||||
:content="$t('tip.notAvailable')"
|
inactive-color="#C0CEDB"
|
||||||
placement="right"
|
:active-value="1"
|
||||||
popper-class="panel-tooltip"
|
:inactive-value="0"
|
||||||
|
:before-change="(knowledgeId) => confirmSwitchLearning(data.knowledgeId)"
|
||||||
>
|
>
|
||||||
<el-switch v-model="data.status"
|
</el-switch>
|
||||||
class="card-enable"
|
|
||||||
active-color="#38ACD2"
|
|
||||||
inactive-color="#C0CEDB"
|
|
||||||
:disabled="true"
|
|
||||||
:active-value="1"
|
|
||||||
:inactive-value="0"
|
|
||||||
@change="changeStatus($event,data.knowledgeId)"
|
|
||||||
>
|
|
||||||
</el-switch>
|
|
||||||
</el-tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-icon">
|
<div class="card-icon">
|
||||||
<img :src="data.iconUrl"/>
|
<img :src="data.iconUrl"/>
|
||||||
@@ -75,7 +66,9 @@
|
|||||||
|
|
||||||
<div class="center-dialog">
|
<div class="center-dialog">
|
||||||
<el-dialog v-model="showUpdateDialog"
|
<el-dialog v-model="showUpdateDialog"
|
||||||
|
:destroy-on-close="true"
|
||||||
:custom-class="showAddUpdateDialog ? 'update-knowledge update-knowledge--upload' : 'update-knowledge'"
|
:custom-class="showAddUpdateDialog ? 'update-knowledge update-knowledge--upload' : 'update-knowledge'"
|
||||||
|
:before-close="beforeClose"
|
||||||
:after-close="handleClose">
|
:after-close="handleClose">
|
||||||
<div class="knowledge-update__top" >
|
<div class="knowledge-update__top" >
|
||||||
<div class="update-left__icon">
|
<div class="update-left__icon">
|
||||||
@@ -86,32 +79,47 @@
|
|||||||
<div class="update-title">
|
<div class="update-title">
|
||||||
<div class="card-title-name" :title="updateKnowledge.label">{{updateKnowledge.label}}</div>
|
<div class="card-title-name" :title="updateKnowledge.label">{{updateKnowledge.label}}</div>
|
||||||
</div>
|
</div>
|
||||||
<el-tooltip
|
<el-switch v-model="updateKnowledge.status"
|
||||||
effect="light"
|
active-color="#38ACD2"
|
||||||
trigger="hover"
|
inactive-color="#C0CEDB"
|
||||||
v-if="showEnable"
|
:active-value="1"
|
||||||
:content="$t('tip.notAvailable')"
|
:inactive-value="0"
|
||||||
placement="right"
|
:before-change="(knowledgeId) => confirmSwitchLearning(updateKnowledge.knowledgeId)"
|
||||||
popper-class="panel-tooltip"
|
v-if="updateKnowledge.source === 'cn_psiphon3_ip'"
|
||||||
>
|
>
|
||||||
<el-switch v-model="updateKnowledge.status"
|
</el-switch>
|
||||||
active-color="#38ACD2"
|
|
||||||
inactive-color="#C0CEDB"
|
|
||||||
:disabled="true"
|
|
||||||
:active-value="1"
|
|
||||||
:inactive-value="0"
|
|
||||||
@change="changeStatus($event,updateKnowledge.knowledgeId)"
|
|
||||||
>
|
|
||||||
</el-switch>
|
|
||||||
</el-tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="knowledge-desc" :title="updateKnowledge.desc">{{updateKnowledge.desc ? updateKnowledge.desc : '—'}}</div>
|
<div class="knowledge-desc" :title="updateKnowledge.desc">{{updateKnowledge.desc ? updateKnowledge.desc : '—'}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="!showAddUpdateDialog">
|
<template v-if="!showAddUpdateDialog">
|
||||||
<div class="knowledge-update" >
|
<div class="knowledge-update__tab" v-if="showEnable">
|
||||||
<div class="update-title">
|
<el-tabs v-model="activeTab"
|
||||||
<div class="card-title-name">update record</div>
|
class="update-log-tab"
|
||||||
|
@tab-click="handleClick"
|
||||||
|
>
|
||||||
|
<el-tab-pane :label="$t('knowledgeBase.updateRecord')"
|
||||||
|
name="updateRecord"
|
||||||
|
key="updateRecord"
|
||||||
|
ref="knowledgeUpdateRecordTab">
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane :label="$t('knowledgeBase.learningEngineLogs')"
|
||||||
|
name="intelligenceLearning"
|
||||||
|
key="intelligenceLearning"
|
||||||
|
ref="knowledgeIntelligenceLearningTab">
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<div class="update-operate">
|
||||||
|
<button :title="$t('overall.update')" class="top-tool-btn--update"
|
||||||
|
@click="uploadRecord">
|
||||||
|
<i class="cn-icon-update-knowledge-base cn-icon"></i>
|
||||||
|
<span>{{$t('overall.update')}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="knowledge-update" v-else>
|
||||||
|
<div class="update-title" >
|
||||||
|
<div class="card-title-name">{{$t('knowledgeBase.updateRecord')}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="update-operate">
|
<div class="update-operate">
|
||||||
<button :title="$t('overall.update')" class="top-tool-btn--update"
|
<button :title="$t('overall.update')" class="top-tool-btn--update"
|
||||||
@@ -121,23 +129,92 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div :style="{height: updateKnowledge.source === 'cn_psiphon3_ip' && activeTab === 'intelligenceLearning' ? 'calc(90vh - 190px - 200px - 50px - 42px)' : 'calc(100% - 242px)', marginTop: '42px', position: 'absolute', width: 'calc(100% - 60px)'}">
|
||||||
|
<loading :loading="updateLogLoading"></loading>
|
||||||
|
</div>
|
||||||
<el-table ref="updateDataTable"
|
<el-table ref="updateDataTable"
|
||||||
border
|
border
|
||||||
:data="updateHistoryList"
|
:data="updateHistoryList"
|
||||||
@selection-change="secondSelectionChange"
|
@selection-change="secondSelectionChange"
|
||||||
width="100%"
|
width="100%"
|
||||||
class="update-dialog__table"
|
class="update-dialog__table"
|
||||||
|
:class="{
|
||||||
|
'update-dialog__table--psiphon3': updateKnowledge.source === 'cn_psiphon3_ip' && activeTab === 'intelligenceLearning',
|
||||||
|
'update-dialog__table--system-user': updateKnowledge.source === 'cn_psiphon3_ip' && activeTab !== 'intelligenceLearning'
|
||||||
|
}"
|
||||||
|
:header-cell-style="{background:'#f5f7fa',color:'#353636',fontWeight: '400',fontSize: '12px',borderRight: 'none',borderBottom: 'none'}"
|
||||||
cell-style="padding:6px 0px;font-size: 12px;color: #353636;font-weight: 400;line-height: 20px;border-right:none;"
|
cell-style="padding:6px 0px;font-size: 12px;color: #353636;font-weight: 400;line-height: 20px;border-right:none;"
|
||||||
header-cell-style="padding:8px 0px;font-size: 12px;color: #353636;font-weight: 500;border-right:none;">
|
header-cell-style="padding:8px 0px;font-size: 12px;color: #353636;font-weight: 500;border-right:none;">
|
||||||
<el-table-column prop="opTime" label="Update time" width="150" ></el-table-column>
|
<el-table-column prop="opTime" :label="$t('entities.tab.informationAggregation.updateTime')" width="150" >
|
||||||
<el-table-column prop="user" label="Operating user" width="150" >
|
<template #default="scope" :column="item">
|
||||||
|
<span>{{scope.row.opTime ? dateFormatByAppearance(scope.row.opTime) : '-'}}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="user" :label="$t('knowledgeBase.operator')" width="150" v-if="activeTab === 'updateRecord'">
|
||||||
<template #default="scope" :column="item">
|
<template #default="scope" :column="item">
|
||||||
<span>{{$_.get(scope.row, 'user.name', '-')}}</span>
|
<span>{{$_.get(scope.row, 'user.name', '-')}}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="commitVersion" label="Version information" width="150" ></el-table-column>
|
<el-table-column prop="commitVersion" :label="$t('overall.version')" width="150" ></el-table-column>
|
||||||
<el-table-column prop="description" label="Description"></el-table-column>
|
<el-table-column prop="description" :label="$t('overall.remark')"></el-table-column>
|
||||||
|
<template v-slot:empty >
|
||||||
|
<div class="table-no-data" v-if="updateHistoryList.length === 0 && !updateLogLoading">
|
||||||
|
<div class="table-no-data__title">{{ $t('npm.noData') }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-else></div>
|
||||||
|
</template>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
|
<div class="psiphon3" v-if="updateKnowledge.source === 'cn_psiphon3_ip' && activeTab === 'intelligenceLearning'">
|
||||||
|
<div class="psiphon3-title">{{$t('knowledgeBase.psiphon3IpCount')}}</div>
|
||||||
|
<div class="psiphon3-bar">
|
||||||
|
<chart-error v-if="showErrorForPsiphon3" :content="errorMsgForPsiphon3"/>
|
||||||
|
<div class="bar-header" v-else>
|
||||||
|
<div class="bar-header-left">
|
||||||
|
<div class="bar-value-active" ></div>
|
||||||
|
<div class="bar-value">
|
||||||
|
<template v-for="(item, index) in tabs" :key="index">
|
||||||
|
<div class="bar-value-tabs"
|
||||||
|
:class=" {'is-active': tabType === item.class, 'mousemove-cursor': mousemoveCursor === item.class}"
|
||||||
|
@mouseenter="mouseenterTab(item)"
|
||||||
|
@mouseleave="mouseleaveTab(item)"
|
||||||
|
@click="activeChange(item)"
|
||||||
|
>
|
||||||
|
<div class="bar-value-tabs-name">
|
||||||
|
<div :class="item.class"></div>
|
||||||
|
<div class="tabs-name" >{{ $t(item.name) }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bar-select bar-header-right">
|
||||||
|
<div class="bar-select-time">
|
||||||
|
<div class="bar-select__operation">
|
||||||
|
<el-select
|
||||||
|
size="mini"
|
||||||
|
v-model="selectTime"
|
||||||
|
placeholder=" "
|
||||||
|
popper-class="common-select"
|
||||||
|
:popper-append-to-body="false"
|
||||||
|
@change="timeChange"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<div class="calendar-popover-text"><i class="cn-icon cn-icon-Data"></i></div>
|
||||||
|
</template>
|
||||||
|
<el-option v-for="item in dateRangeArr" :key="item.value" :label="item.name" :value="item.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height: calc(100% - 24px); position: relative">
|
||||||
|
<chart-no-data v-if="isNoDataForPsiphon3 && !showErrorForPsiphon3 && !psiphon3Loading"></chart-no-data>
|
||||||
|
<loading :loading="psiphon3Loading"></loading>
|
||||||
|
<div class="chart-drawing" v-show="!isNoDataForPsiphon3 && !showErrorForPsiphon3" id="psiphonBarChart"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="showAddUpdateDialog">
|
<template v-if="showAddUpdateDialog">
|
||||||
<div class="update-knowledge-form">
|
<div class="update-knowledge-form">
|
||||||
@@ -187,6 +264,7 @@
|
|||||||
<el-dialog v-model="showConfirmDialog"
|
<el-dialog v-model="showConfirmDialog"
|
||||||
:title="$t('overall.tips')"
|
:title="$t('overall.tips')"
|
||||||
custom-class="update-knowledge-tip"
|
custom-class="update-knowledge-tip"
|
||||||
|
:width="480"
|
||||||
:before-close="handleConfirmClose">
|
:before-close="handleConfirmClose">
|
||||||
<div class="dialog-message">{{$t('knowledge.updateTips')}}</div>
|
<div class="dialog-message">{{$t('knowledge.updateTips')}}</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@@ -196,18 +274,37 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
v-model="showConfirmSwitch"
|
||||||
|
:width="330"
|
||||||
|
custom-class="confirm-knowledge-switch"
|
||||||
|
:title="$t('overall.hint')"
|
||||||
|
>
|
||||||
|
<div class="dialog-message">{{ confirmSwitchLearningTip }}</div>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="showConfirmSwitch = false">{{ $t('overall.cancel') }}</el-button>
|
||||||
|
<el-button type="primary" @click="switchLearning">OK</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import table from '@/mixins/table'
|
import table from '@/mixins/table'
|
||||||
import Loading from '@/components/common/Loading'
|
import Loading from '@/components/common/Loading'
|
||||||
|
import { getSecond, getMillisecond, xAxisTimeFormatter, xAxisTimeRich } from '@/utils/date-util'
|
||||||
import { knowledgeCategoryValue, unitTypes, storageKey, builtInKnowledgeBaseBasicInfo } from '@/utils/constants'
|
import { knowledgeCategoryValue, unitTypes, storageKey, builtInKnowledgeBaseBasicInfo } from '@/utils/constants'
|
||||||
import { ref } from 'vue'
|
import { ref, shallowRef } from 'vue'
|
||||||
import { api } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
|
import { detectionTooltipFormatter } from '@/views/charts/charts/tools'
|
||||||
|
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
import unitConvert from '@/utils/unit-convert'
|
import unitConvert from '@/utils/unit-convert'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'knowledgeBaseTableForCard',
|
name: 'knowledgeBaseTableForCard',
|
||||||
mixins: [table],
|
mixins: [table],
|
||||||
@@ -221,7 +318,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Loading
|
Loading,
|
||||||
|
ChartNoData
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
@@ -237,12 +335,57 @@ export default {
|
|||||||
updateHistoryList: [],
|
updateHistoryList: [],
|
||||||
updateObject: {},
|
updateObject: {},
|
||||||
currentVersion: 0,
|
currentVersion: 0,
|
||||||
uploadLoading: false
|
uploadLoading: false,
|
||||||
|
psiphon3Loading: false,
|
||||||
|
updateLogLoading: false,
|
||||||
|
showConfirmSwitch: false,
|
||||||
|
switchKnowledgeId: '',
|
||||||
|
activeTab: 'updateRecord',
|
||||||
|
isNoDataForPsiphon3: false,
|
||||||
|
showErrorForPsiphon3: false,
|
||||||
|
errorMsgForPsiphon3: '',
|
||||||
|
leftOffset: 0,
|
||||||
|
tabType: 'total',
|
||||||
|
mousemoveCursor: '',
|
||||||
|
selectTime: 1440,
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
name: 'knowledgeBase.total',
|
||||||
|
class: 'total',
|
||||||
|
color: '#00A7AB',
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'knowledgeBase.active',
|
||||||
|
class: 'active',
|
||||||
|
color: '#7FA054',
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'knowledgeBase.new',
|
||||||
|
class: 'new',
|
||||||
|
color: '#98709B',
|
||||||
|
data: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dateRangeArr: [
|
||||||
|
{ value: 1440, name: this.$t('dateTime.last1Day') },
|
||||||
|
{ value: 2880, name: this.$t('dateTime.last2Days') },
|
||||||
|
{ value: 10080, name: this.$t('dateTime.last7Days') },
|
||||||
|
{ value: 21600, name: this.$t('dateTime.last15Days') },
|
||||||
|
{ value: 43200, name: this.$t('dateTime.last30Days') }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup () {
|
setup () {
|
||||||
// 没上传过文件的提示
|
// 没上传过文件的提示
|
||||||
const uploadErrorTip = ref('')
|
const uploadErrorTip = ref('')
|
||||||
|
const nowMill = window.$dayJs.tz().valueOf()
|
||||||
|
const timeFilter = ref({
|
||||||
|
startTime: nowMill - 1000 * 60 * 60 * 24,
|
||||||
|
endTime: nowMill,
|
||||||
|
dateRangeValue: 1440
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
baseUrl: BASE_CONFIG.baseUrl,
|
baseUrl: BASE_CONFIG.baseUrl,
|
||||||
apiVersion: BASE_CONFIG.apiVersion,
|
apiVersion: BASE_CONFIG.apiVersion,
|
||||||
@@ -252,13 +395,174 @@ export default {
|
|||||||
uploadErrorTip,
|
uploadErrorTip,
|
||||||
fileTypeLimit: '.csv',
|
fileTypeLimit: '.csv',
|
||||||
fileList: ref([]),
|
fileList: ref([]),
|
||||||
uploadFileSizeLimit: 100 * 1024 * 1024
|
uploadFileSizeLimit: 1024 * 1024 * 1024,
|
||||||
|
myChart: shallowRef(null),
|
||||||
|
chartOption: shallowRef(null),
|
||||||
|
timeFilter
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
echartsInit (echartsData) {
|
||||||
|
const _this = this
|
||||||
|
const curTab = this.tabs.find(item => item.class === _this.tabType)
|
||||||
|
this.chartOption = {
|
||||||
|
color: curTab.color,
|
||||||
|
legend: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
formatter: (params) => {
|
||||||
|
params.seriesName = this.$t(params.seriesName)
|
||||||
|
params.borderColor = params.color
|
||||||
|
return detectionTooltipFormatter(params)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: '12%',
|
||||||
|
left: '2%',
|
||||||
|
right: '2%',
|
||||||
|
bottom: 24,
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
boundaryGap: ['1%', '3%'],
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
formatter: xAxisTimeFormatter,
|
||||||
|
rich: xAxisTimeRich
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#ECECEC'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
margin: 20
|
||||||
|
},
|
||||||
|
minInterval: 1
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: curTab.name,
|
||||||
|
data: echartsData,
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: 26
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (!this.myChart) {
|
||||||
|
this.myChart = echarts.init(document.getElementById('psiphonBarChart'))
|
||||||
|
}
|
||||||
|
this.myChart.setOption(this.chartOption)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
init (val, show, active, n) {
|
||||||
|
this.psiphon3Loading = true
|
||||||
|
const params = {
|
||||||
|
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 => {
|
||||||
|
const res = response.data
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
this.isNoDataForPsiphon3 = res.data.result.length === 0
|
||||||
|
this.showErrorForPsiphon3 = false
|
||||||
|
if (!this.isNoDataForPsiphon3) {
|
||||||
|
const chartsData = res.data.result.map(item => {
|
||||||
|
return [getMillisecond(item.statTime), item.count]
|
||||||
|
})
|
||||||
|
this.echartsInit(chartsData)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.httpError(res)
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
this.httpError(e)
|
||||||
|
}).finally(() => {
|
||||||
|
this.psiphon3Loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
httpError (e) {
|
||||||
|
this.isNoDataForPsiphon3 = false
|
||||||
|
this.showErrorForPsiphon3 = true
|
||||||
|
this.errorMsgForPsiphon3 = this.errorMsgHandler(e)
|
||||||
|
},
|
||||||
|
handleActiveBar () {
|
||||||
|
if (document.querySelector('.psiphon3-bar .bar-value-tabs.is-active')) {
|
||||||
|
const {
|
||||||
|
offsetLeft,
|
||||||
|
clientWidth,
|
||||||
|
clientLeft
|
||||||
|
} = document.querySelector('.psiphon3-bar .bar-value-tabs.is-active')
|
||||||
|
const activeBar = document.querySelector('.psiphon3-bar .bar-value-active')
|
||||||
|
activeBar.style.cssText += `width: ${clientWidth}px; left: ${offsetLeft + this.leftOffset + clientLeft}px;`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resize () {
|
||||||
|
if (this.myChart) {
|
||||||
|
this.myChart.resize()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dispatchSelectAction (type, name) {
|
||||||
|
this.myChart && this.myChart.dispatchAction({
|
||||||
|
type: type,
|
||||||
|
name: name
|
||||||
|
})
|
||||||
|
},
|
||||||
|
legendSelectChange (item) {
|
||||||
|
this.dispatchSelectAction('legendSelect', item.name)
|
||||||
|
this.tabs.forEach((t) => {
|
||||||
|
if (t.name !== item.name) {
|
||||||
|
this.dispatchSelectAction('legendUnSelect', t.name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.handleActiveBar()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
activeChange (item) { // isClick:代表是通过点击操作来的
|
||||||
|
if (item) {
|
||||||
|
this.tabType = item.class
|
||||||
|
}
|
||||||
|
this.legendSelectChange(item)
|
||||||
|
if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mouseenterTab (item) {
|
||||||
|
if (this.isNoDataForPsiphon3) return
|
||||||
|
this.mousemoveCursor = item.class
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.handleActiveBar()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
mouseleaveTab () {
|
||||||
|
this.mousemoveCursor = ''
|
||||||
|
},
|
||||||
fileChange (file, fileList) {
|
fileChange (file, fileList) {
|
||||||
console.info(!_.endsWith(file.name, '.csv'))
|
|
||||||
console.info(file.size > this.uploadFileSizeLimit)
|
|
||||||
// 判断后缀,仅支持.csv
|
// 判断后缀,仅支持.csv
|
||||||
if (!_.endsWith(file.name, '.csv')) {
|
if (!_.endsWith(file.name, '.csv')) {
|
||||||
this.fileList = []
|
this.fileList = []
|
||||||
@@ -287,10 +591,10 @@ export default {
|
|||||||
if (response.code === 200) { */
|
if (response.code === 200) { */
|
||||||
this.$message.success(this.$t('tip.success'))
|
this.$message.success(this.$t('tip.success'))
|
||||||
this.showAddUpdateDialog = false
|
this.showAddUpdateDialog = false
|
||||||
axios.get(api.knowledgeBaseLog + '/' + this.updateKnowledge.knowledgeId, { params: { pageSize: 999 } }).then(res => {
|
this.getCurTabData()
|
||||||
this.updateHistoryList = res.data.data.list
|
if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
|
||||||
this.currentVersion = this.updateHistoryList[0].commitVersion + 1
|
this.init()
|
||||||
})
|
}
|
||||||
/* } else {
|
/* } else {
|
||||||
this.$message.error(this.$t('tip.uploadFailed', { msg: response.message }))
|
this.$message.error(this.$t('tip.uploadFailed', { msg: response.message }))
|
||||||
} */
|
} */
|
||||||
@@ -325,6 +629,13 @@ export default {
|
|||||||
data.isSelected = val
|
data.isSelected = val
|
||||||
this.$emit('checkboxStatusChange', val, data)
|
this.$emit('checkboxStatusChange', val, data)
|
||||||
},
|
},
|
||||||
|
beforeClose (done) {
|
||||||
|
if (this.myChart) {
|
||||||
|
this.myChart.dispose()
|
||||||
|
this.myChart = null
|
||||||
|
}
|
||||||
|
done()
|
||||||
|
},
|
||||||
handleClose () {
|
handleClose () {
|
||||||
this.showUpdateDialog = false
|
this.showUpdateDialog = false
|
||||||
this.showAddUpdateDialog = false
|
this.showAddUpdateDialog = false
|
||||||
@@ -340,13 +651,16 @@ export default {
|
|||||||
this.showUpdateDialog = true
|
this.showUpdateDialog = true
|
||||||
this.showAddUpdateDialog = false
|
this.showAddUpdateDialog = false
|
||||||
},
|
},
|
||||||
jumpToUpdatePage (data, showEnable) {
|
async jumpToUpdatePage (data, showEnable) {
|
||||||
axios.get(api.knowledgeBaseLog + '/' + data.knowledgeId, { params: { pageSize: 999 } }).then(res => {
|
this.updateKnowledge = data
|
||||||
this.updateKnowledge = data
|
this.showEnable = showEnable
|
||||||
this.updateHistoryList = res.data.data.list
|
await this.getCurTabData()
|
||||||
this.currentVersion = this.updateHistoryList[0].commitVersion + 1
|
if (data.source === 'cn_psiphon3_ip') {
|
||||||
this.showEnable = showEnable
|
await this.init()
|
||||||
this.showUpdate()
|
}
|
||||||
|
this.showUpdate()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.handleActiveBar()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
uploadRecord () {
|
uploadRecord () {
|
||||||
@@ -355,6 +669,43 @@ export default {
|
|||||||
this.updateObject.label = this.updateKnowledge.label
|
this.updateObject.label = this.updateKnowledge.label
|
||||||
this.updateObject.description = ''
|
this.updateObject.description = ''
|
||||||
},
|
},
|
||||||
|
getCurTabData () { // showEnable:true 为psiphon3的知识库,false为其它知识库
|
||||||
|
let params = {
|
||||||
|
pageSize: -1
|
||||||
|
}
|
||||||
|
if (this.showEnable) {
|
||||||
|
if (this.activeTab === 'updateRecord') {
|
||||||
|
params = {
|
||||||
|
...params,
|
||||||
|
opUser: -1
|
||||||
|
}
|
||||||
|
} else if (this.activeTab === 'intelligenceLearning') {
|
||||||
|
params = {
|
||||||
|
...params,
|
||||||
|
opUser: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.updateLogLoading = true
|
||||||
|
this.updateHistoryList = []
|
||||||
|
axios.get(api.knowledgeBaseLog + '/' + this.updateKnowledge.knowledgeId, { params: params }).then(res => {
|
||||||
|
this.updateHistoryList = res.data.data.list
|
||||||
|
if (this.updateHistoryList[0]) {
|
||||||
|
this.currentVersion = this.updateHistoryList[0].commitVersion + 1
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
}).finally(() => {
|
||||||
|
this.updateLogLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 切换tab
|
||||||
|
handleClick (tab) {
|
||||||
|
this.getCurTabData()
|
||||||
|
if (tab.index === '1') {
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
},
|
||||||
clearSelect () {
|
clearSelect () {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.checkList = []
|
this.checkList = []
|
||||||
@@ -366,18 +717,10 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
mouseenter (card) {
|
mouseenter (card) {
|
||||||
this.tableData.forEach(t => {
|
card.showUpdate = true
|
||||||
if (t.knowledgeId === card.knowledgeId) {
|
|
||||||
card.showUpdate = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
mouseleave (card) {
|
mouseleave (card) {
|
||||||
this.tableData.forEach(t => {
|
card.showUpdate = false
|
||||||
if (t.knowledgeId === card.knowledgeId) {
|
|
||||||
card.showUpdate = false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
del (data) {
|
del (data) {
|
||||||
this.$emit('delete', data)
|
this.$emit('delete', data)
|
||||||
@@ -394,9 +737,48 @@ export default {
|
|||||||
dataType: dataType
|
dataType: dataType
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
confirmSwitchLearning (id) {
|
||||||
|
this.showConfirmSwitch = true
|
||||||
|
this.switchKnowledgeId = id
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
switchLearning () {
|
||||||
|
const hint = this.aiTaggingList.find(d => d.knowledgeId === this.switchKnowledgeId)
|
||||||
|
const toStatus = hint.status === 0 ? 1 : 0
|
||||||
|
const url = toStatus === 0 ? api.knowledgeBaseLearningStop : api.knowledgeBaseLearningStart
|
||||||
|
axios.post(`${url}?knowledgeId=${hint.knowledgeId}`).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
hint.status = toStatus
|
||||||
|
this.$message.success(this.$t('tip.success'))
|
||||||
|
} else {
|
||||||
|
console.error(res.message)
|
||||||
|
this.$message.error(this.errorMsgHandler(res))
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
|
}).finally(() => {
|
||||||
|
this.showConfirmSwitch = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
tabType (n) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.handleActiveBar()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
timeFilter: {
|
||||||
|
handler () {
|
||||||
|
if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.handleActiveBar()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
tableData: {
|
tableData: {
|
||||||
handler (n) {
|
handler (n) {
|
||||||
if (this.tableData && this.tableData.length > 0) {
|
if (this.tableData && this.tableData.length > 0) {
|
||||||
@@ -420,15 +802,35 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
activeTab (n) {
|
||||||
|
if (n === 'updateRecord') {
|
||||||
|
if (this.myChart) {
|
||||||
|
this.myChart.dispose()
|
||||||
|
this.myChart = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
showAddUpdateDialog: {
|
showAddUpdateDialog: {
|
||||||
handler (n) {
|
handler (n) {
|
||||||
if (!n) {
|
if (!n) {
|
||||||
this.fileList = []
|
this.fileList = []
|
||||||
|
if (this.updateKnowledge.source === 'cn_psiphon3_ip') {
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.myChart) {
|
||||||
|
this.myChart.dispose()
|
||||||
|
this.myChart = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
this.myChart = null
|
||||||
|
this.chartOption = null
|
||||||
|
window.addEventListener('resize', this.resize)
|
||||||
|
|
||||||
this.aiTaggingList = []
|
this.aiTaggingList = []
|
||||||
this.websketchList = []
|
this.websketchList = []
|
||||||
this.tableData.forEach(item => {
|
this.tableData.forEach(item => {
|
||||||
@@ -440,6 +842,22 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
beforeUnmount () {
|
||||||
|
clearTimeout(this.timer)
|
||||||
|
window.removeEventListener('resize', this.resize)
|
||||||
|
const dom = document.getElementById('psiphonBarChart')
|
||||||
|
if (dom) {
|
||||||
|
let myChart = echarts.getInstanceByDom(document.getElementById('psiphonBarChart'))
|
||||||
|
if (myChart) {
|
||||||
|
echarts.dispose(myChart)
|
||||||
|
}
|
||||||
|
myChart = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.myChart) {
|
||||||
|
echarts.dispose(this.myChart)
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
uploadParams () {
|
uploadParams () {
|
||||||
return {
|
return {
|
||||||
@@ -447,6 +865,20 @@ export default {
|
|||||||
action: 'overwrite',
|
action: 'overwrite',
|
||||||
description: this.updateObject.description
|
description: this.updateObject.description
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
confirmSwitchLearningTip () {
|
||||||
|
let tip = ''
|
||||||
|
if (this.switchKnowledgeId) {
|
||||||
|
const find = this.aiTaggingList.find(item => item.knowledgeId === this.switchKnowledgeId)
|
||||||
|
if (find) {
|
||||||
|
if (find.status === 0) {
|
||||||
|
tip = this.$t('tip.confirmEnablePsiphon3') + '?'
|
||||||
|
} else if (find.status === 1) {
|
||||||
|
tip = this.$t('tip.confirmDisablePsiphon3') + '?'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,64 +110,26 @@ export default {
|
|||||||
if (this.listUrl) {
|
if (this.listUrl) {
|
||||||
listUrl = this.listUrl
|
listUrl = this.listUrl
|
||||||
}
|
}
|
||||||
// todo 此段是为了避免mock没开启,打开detection界面报错提示,后续再开发detection时删除
|
axios.get(listUrl, { params: this.searchLabel }).then(response => {
|
||||||
if (listUrl === api.detection.list) {
|
if (response.status === 200) {
|
||||||
const list = []
|
this.tableData = _.get(response, 'data.data.list', [])
|
||||||
for (let i = 0; i < 20; i++) {
|
this.pageObj.total = _.get(response, 'data.data.total', 0)
|
||||||
const obj = {
|
this.isNoData = !this.tableData || this.tableData.length === 0
|
||||||
ruleId: 100000 + i,
|
} else {
|
||||||
ruleType: 'indicator_match',
|
console.error(response)
|
||||||
status: 1,
|
|
||||||
name: 'name123',
|
|
||||||
category: 'Security Event',
|
|
||||||
eventType: 'C&C',
|
|
||||||
description: 'Built-in darkweb IoC',
|
|
||||||
ruleConfig: {
|
|
||||||
knowledge: {
|
|
||||||
name: 'VPN Server IP',
|
|
||||||
category: 'user_defined'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i % 2 === 0) {
|
|
||||||
obj.ruleType = 'threshold'
|
|
||||||
obj.ruleConfig = {
|
|
||||||
dimensions: 'Destination IP/CIDR'
|
|
||||||
}
|
|
||||||
obj.description = 'abuse.ch is providing community driven threat intelligence on \n' +
|
|
||||||
'cyber threats. It is the home of a couple of projects that are \n' +
|
|
||||||
'helping internet service providers and network operators protect …'
|
|
||||||
} else {
|
|
||||||
obj.status = 0
|
|
||||||
}
|
|
||||||
list.push(obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tableData = list
|
|
||||||
this.pageObj.total = list.length
|
|
||||||
this.loading = false
|
|
||||||
} else {
|
|
||||||
axios.get(listUrl, { params: this.searchLabel }).then(response => {
|
|
||||||
if (response.status === 200) {
|
|
||||||
this.tableData = _.get(response, 'data.data.list', [])
|
|
||||||
this.pageObj.total = _.get(response, 'data.data.total', 0)
|
|
||||||
this.isNoData = !this.tableData || this.tableData.length === 0
|
|
||||||
} else {
|
|
||||||
console.error(response)
|
|
||||||
this.isNoData = true
|
|
||||||
if (response.data.message) {
|
|
||||||
this.$message.error(response.data.message)
|
|
||||||
} else {
|
|
||||||
this.$message.error(this.$t('tip.somethingWentWrong'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
this.isNoData = true
|
this.isNoData = true
|
||||||
}).finally(() => {
|
if (response.data.message) {
|
||||||
this.toggleLoading(false)
|
this.$message.error(response.data.message)
|
||||||
this.loading = false
|
} else {
|
||||||
})
|
this.$message.error(this.$t('tip.somethingWentWrong'))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.isNoData = true
|
||||||
|
}).finally(() => {
|
||||||
|
this.toggleLoading(false)
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
},
|
},
|
||||||
del (row) {
|
del (row) {
|
||||||
this.$confirm(this.$t('tip.confirmDelete'), {
|
this.$confirm(this.$t('tip.confirmDelete'), {
|
||||||
@@ -400,10 +362,23 @@ export default {
|
|||||||
this.searchLabel.orderBy = orderBy
|
this.searchLabel.orderBy = orderBy
|
||||||
this.getTableData()
|
this.getTableData()
|
||||||
},
|
},
|
||||||
search (params) {
|
search (params, flag, list) {
|
||||||
this.pageObj.pageNo = 1
|
this.pageObj.pageNo = 1
|
||||||
delete this.searchLabel.category
|
if (flag !== 'detection') {
|
||||||
delete this.searchLabel.source
|
delete this.searchLabel.category
|
||||||
|
delete this.searchLabel.source
|
||||||
|
}
|
||||||
|
if (list && list.length > 0) {
|
||||||
|
if (list.indexOf('status') > -1) {
|
||||||
|
delete this.searchLabel.status
|
||||||
|
}
|
||||||
|
if (list.indexOf('category') > -1) {
|
||||||
|
delete this.searchLabel.category
|
||||||
|
}
|
||||||
|
if (list.indexOf('eventType') > -1) {
|
||||||
|
delete this.searchLabel.eventType
|
||||||
|
}
|
||||||
|
}
|
||||||
this.getTableData(params)
|
this.getTableData(params)
|
||||||
},
|
},
|
||||||
getTimeString () {
|
getTimeString () {
|
||||||
|
|||||||
@@ -96,5 +96,41 @@ export default {
|
|||||||
this.relationshipShowMoreTwo = false
|
this.relationshipShowMoreTwo = false
|
||||||
this.relationshipShowMoreOne = false
|
this.relationshipShowMoreOne = false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
scoreDot () {
|
||||||
|
const dots = []
|
||||||
|
if (this.score === '-') {
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
dots.push({
|
||||||
|
class: 'score-dot'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
if (i < this.score) {
|
||||||
|
dots.push({
|
||||||
|
class: `score-dot ${handleClass(this.score)}`
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
dots.push({
|
||||||
|
class: 'score-dot'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dots
|
||||||
|
|
||||||
|
function handleClass (score) {
|
||||||
|
if (score <= 2) {
|
||||||
|
return 'score-dot--red'
|
||||||
|
} else if (score <= 4) {
|
||||||
|
return 'score-dot--yellow'
|
||||||
|
} else if (score <= 6) {
|
||||||
|
return 'score-dot--green'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ if (openMock) {
|
|||||||
const list = []
|
const list = []
|
||||||
for (let i = 0; i < 20; i++) {
|
for (let i = 0; i < 20; i++) {
|
||||||
const obj = {
|
const obj = {
|
||||||
ruleId: 100000 + i,
|
ruleId: 163 + i,
|
||||||
ruleType: 'indicator_match',
|
ruleType: 'indicator_match',
|
||||||
status: 1,
|
status: 1,
|
||||||
name: 'name123',
|
name: 'name123',
|
||||||
@@ -50,51 +50,17 @@ if (openMock) {
|
|||||||
Mock.mock(new RegExp(urlAndVersion + '/detection/statistics.*'), 'get', function (requestObj) {
|
Mock.mock(new RegExp(urlAndVersion + '/detection/statistics.*'), 'get', function (requestObj) {
|
||||||
const data = {
|
const data = {
|
||||||
statusList: [
|
statusList: [
|
||||||
{ status: 1 },
|
{ status: 1, count: 34 },
|
||||||
{ status: 0 }
|
{ status: 0, count: 28 }
|
||||||
],
|
],
|
||||||
categoryList: [
|
categoryList: [
|
||||||
{ value: 'security', label: 'Security Event' },
|
{ name: 'Security Event', count: 32 },
|
||||||
{ value: 'performance', label: 'Performance Event' },
|
{ name: 'Performance Event', count: 28 }
|
||||||
{ value: 'regulatory_risk', label: 'Regulatory Risk Event' }
|
|
||||||
],
|
],
|
||||||
typeList: [
|
eventTypeList: [
|
||||||
{ value: 'c&c', label: 'C&C' },
|
{ name: 'DDos', count: 15 },
|
||||||
{ value: 'ddos', label: 'DDos' },
|
{ name: 'Lateral movement', count: 17 },
|
||||||
{ value: 'lateral_movement', label: 'Lateral movement' },
|
{ name: 'Brute force', count: 12 }
|
||||||
{ value: 'brute_force', label: 'Brute force' }
|
|
||||||
],
|
|
||||||
sourceList: [
|
|
||||||
{ value: 'ip_metric', label: 'IP metric' },
|
|
||||||
{ value: 'performance_event', label: 'performance event' }
|
|
||||||
],
|
|
||||||
levelList: [
|
|
||||||
{ value: 'critical', label: 'Critical' },
|
|
||||||
{ value: 'high', label: 'High' },
|
|
||||||
{ value: 'medium', label: 'Medium' },
|
|
||||||
{ value: 'low', label: 'Low' },
|
|
||||||
{ value: 'info', label: 'Info' }
|
|
||||||
],
|
|
||||||
metricList: [
|
|
||||||
{ value: 'tcp_lostlen_ratio', label: 'Bits/second' },
|
|
||||||
{ value: 's2c_byte_retrans_ratio', label: 'Packets/second' },
|
|
||||||
{ value: 's2c_byte_retrans_ratio1', label: 'Sessions/second' }
|
|
||||||
],
|
|
||||||
conditionList: [
|
|
||||||
{ value: 'than', label: 'Greater Than' },
|
|
||||||
{ value: 'less', label: 'Greater Less' },
|
|
||||||
{ value: 'equal', label: 'Greater Equal' }
|
|
||||||
],
|
|
||||||
libraryList: [
|
|
||||||
{ value: 'library name2', knowledgeId: '101', label: 'Library name' },
|
|
||||||
{ value: 'library name1', knowledgeId: '102', label: 'Library name1' },
|
|
||||||
{ value: 'library name2', knowledgeId: '103', label: 'Library name2' }
|
|
||||||
],
|
|
||||||
intervalList: [
|
|
||||||
{ value: 'minutes', label: 'minutes' },
|
|
||||||
{ value: 'hours', label: 'hours' },
|
|
||||||
{ value: 'days', label: 'days' },
|
|
||||||
{ value: 'weeks', label: 'weeks' }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,28 +95,50 @@ if (openMock) {
|
|||||||
const ruleId = getLastValue(requestObj.url)
|
const ruleId = getLastValue(requestObj.url)
|
||||||
const data = {
|
const data = {
|
||||||
name: 'name123',
|
name: 'name123',
|
||||||
category: 'Security Event',
|
category: 'security_event',
|
||||||
ruleType: 'indicator_match',
|
ruleType: 'indicator_match',
|
||||||
eventType: 'C&C',
|
eventType: 'C&C',
|
||||||
description: 'Built-in darkweb IoC',
|
description: 'Built-in darkweb IoC',
|
||||||
status: 1,
|
status: 1,
|
||||||
ruleConfig: {
|
ruleConfig: {
|
||||||
dataSource: 'VPN Server IP',
|
dataSource: 'VPN Server IP',
|
||||||
knowledgeId: 10,
|
knowledgeBase: {
|
||||||
level: 10
|
knowledgeId: 10,
|
||||||
|
name: 'cn_ioc_darkweb',
|
||||||
|
category: 'websketch',
|
||||||
|
source: 'cn_ioc_darkweb'
|
||||||
|
},
|
||||||
|
level: 'critical'
|
||||||
},
|
},
|
||||||
trigger: {
|
ruleConfigObj: {
|
||||||
|
dataSource: 'VPN Server IP',
|
||||||
|
knowledgeBase: {
|
||||||
|
knowledgeId: '101',
|
||||||
|
name: 'cn_ioc_darkweb',
|
||||||
|
category: 'websketch',
|
||||||
|
source: 'cn_ioc_darkweb'
|
||||||
|
},
|
||||||
|
level: 'critical'
|
||||||
|
},
|
||||||
|
ruleTrigger: {
|
||||||
|
atLeast: 1,
|
||||||
|
interval: 'PT5M',
|
||||||
|
resetInterval: 'PT10M'
|
||||||
|
},
|
||||||
|
ruleTriggerObj: {
|
||||||
atLeast: 1,
|
atLeast: 1,
|
||||||
interval: 'PT5M',
|
interval: 'PT5M',
|
||||||
resetInterval: 'PT10M'
|
resetInterval: 'PT10M'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
data.ruleConfig = JSON.stringify(data.ruleConfig)
|
||||||
|
data.trigger = JSON.stringify(data.trigger)
|
||||||
|
|
||||||
if (ruleId % 2 === 0) {
|
if (ruleId % 2 === 0) {
|
||||||
data.ruleType = 'threshold'
|
data.ruleType = 'threshold'
|
||||||
data.status = 1
|
|
||||||
} else {
|
|
||||||
data.status = 0
|
data.status = 0
|
||||||
|
} else {
|
||||||
|
data.status = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
353
src/mock/detectionList.js
Normal file
353
src/mock/detectionList.js
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
import Mock from 'mockjs'
|
||||||
|
|
||||||
|
const urlAndVersion = BASE_CONFIG.baseUrl + BASE_CONFIG.apiVersion
|
||||||
|
const openMock = true
|
||||||
|
if (openMock) {
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/list.*'), 'get', function (requestObj) {
|
||||||
|
const result = []
|
||||||
|
for (let i = 0; i < 20; i++) {
|
||||||
|
const obj = {
|
||||||
|
eventId: 1212,
|
||||||
|
eventType: 'Anonymity',
|
||||||
|
eventName: 'Tor',
|
||||||
|
eventKey: '2,1.1.1,12.2.2.2',
|
||||||
|
ruleId: 2,
|
||||||
|
ruleType: 'indicator_match',
|
||||||
|
isBuiltin: 1,
|
||||||
|
severity: 'critical',
|
||||||
|
offenderIp: '1.1.1.1',
|
||||||
|
victimIp: '2.2.2.2',
|
||||||
|
domain: '*.vioee.com',
|
||||||
|
app: 'vio',
|
||||||
|
startTime: 1697092617,
|
||||||
|
endTime: 1697092777,
|
||||||
|
durationS: 30000,
|
||||||
|
matchTimes: 1,
|
||||||
|
status: 1,
|
||||||
|
eventInfo: "{\'knowledge_id\': 123, \'name\': \'example_ioc_malware\', \'ioc_type\': \'domain\', \'ioc_value\': \'iocentity.com\'}",
|
||||||
|
eventInfoObj: {
|
||||||
|
knowledge_id: 123,
|
||||||
|
name: 'example_ioc_malware',
|
||||||
|
ioc_type: 'domain',
|
||||||
|
ioc_value: 'iocentity.com'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i % 2 === 0) {
|
||||||
|
obj.status = 0
|
||||||
|
}
|
||||||
|
result.push(obj)
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
resultType: 'table',
|
||||||
|
result: result
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/severity/timedistribution.*'), 'get', function (requestObj) {
|
||||||
|
const result = [
|
||||||
|
{
|
||||||
|
statTime: 1697523900,
|
||||||
|
severity: 'critical',
|
||||||
|
count: 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statTime: 1697524200,
|
||||||
|
severity: 'high',
|
||||||
|
count: 31
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statTime: 1697524500,
|
||||||
|
severity: 'info',
|
||||||
|
count: 21
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statTime: 1697524800,
|
||||||
|
severity: 'low',
|
||||||
|
count: 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statTime: 1697525100,
|
||||||
|
severity: 'medium',
|
||||||
|
count: 32
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statTime: 1697525400,
|
||||||
|
severity: 'critical',
|
||||||
|
count: 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statTime: 1697525700,
|
||||||
|
severity: 'critical',
|
||||||
|
count: 23
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statTime: 1697526000,
|
||||||
|
severity: 'critical',
|
||||||
|
count: 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statTime: 1697526300,
|
||||||
|
severity: 'critical',
|
||||||
|
count: 21
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
resultType: 'table',
|
||||||
|
result: result
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/severity/statistics.*'), 'get', function (requestObj) {
|
||||||
|
const result = [
|
||||||
|
{
|
||||||
|
severity: 'critical',
|
||||||
|
count: 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
severity: 'high',
|
||||||
|
count: 31
|
||||||
|
},
|
||||||
|
{
|
||||||
|
severity: 'info',
|
||||||
|
count: 21
|
||||||
|
},
|
||||||
|
{
|
||||||
|
severity: 'low',
|
||||||
|
count: 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
severity: 'medium',
|
||||||
|
count: 32
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
resultType: 'table',
|
||||||
|
result: result
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/event-type/statistics.*'), 'get', function (requestObj) {
|
||||||
|
const result = [
|
||||||
|
{
|
||||||
|
eventType: 'Anonymity',
|
||||||
|
count: 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
eventType: 'Command and Control',
|
||||||
|
count: 31
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
resultType: 'table',
|
||||||
|
result: result
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/offender-ip/statistics.*'), 'get', function (requestObj) {
|
||||||
|
const result = [
|
||||||
|
{
|
||||||
|
offenderIp: '221.7.1.20',
|
||||||
|
count: 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offenderIp: '58.247.118.253',
|
||||||
|
count: 31
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
resultType: 'table',
|
||||||
|
result: result
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/victim-ip/statistics.*'), 'get', function (requestObj) {
|
||||||
|
const result = [
|
||||||
|
{
|
||||||
|
victimIp: '21.77.1.201',
|
||||||
|
count: 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
victimIp: '58.47.118.153',
|
||||||
|
count: 31
|
||||||
|
},
|
||||||
|
{
|
||||||
|
victimIp: '22.47.223.57',
|
||||||
|
count: 43
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
resultType: 'table',
|
||||||
|
result: result
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/status/statistics.*'), 'get', function (requestObj) {
|
||||||
|
const result = [
|
||||||
|
{
|
||||||
|
status: 1,
|
||||||
|
count: 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 0,
|
||||||
|
count: 31
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
resultType: 'table',
|
||||||
|
result: result
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/ip/relation/event.*'), 'get', function (requestObj) {
|
||||||
|
const result = [
|
||||||
|
{
|
||||||
|
eventId: 10010,
|
||||||
|
severity: 'high',
|
||||||
|
eventType: 'Command and Control',
|
||||||
|
offenderIp: '1.1.1.1',
|
||||||
|
victimIp: '2.2.2.2',
|
||||||
|
startTime: 1697092617
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
resultType: 'table',
|
||||||
|
result: result
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/count.*'), 'get', function (requestObj) {
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: {
|
||||||
|
resultType: 'single',
|
||||||
|
result: 123
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/entity/detail/ip.*'), 'get', function (requestObj) {
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: {
|
||||||
|
asn: {
|
||||||
|
id: 2,
|
||||||
|
asn: '14061',
|
||||||
|
organization: 'DIGITALOCEAN-ASN - DigitalOcean, LLC, US'
|
||||||
|
},
|
||||||
|
malware: {
|
||||||
|
threatType: 'command and control',
|
||||||
|
malwareName: 'IcedID',
|
||||||
|
malwareAlias: 'BokBot,IceID',
|
||||||
|
mitreAttackDescription: '[IcedID](https://attack.mitre.org/software/S0483) is a modular banking malware designed to steal financial information that has been observed in the wild since at least 2017. [IcedID](https://attack.mitre.org/software/S0483) has been downloaded by [Emotet](https://attack.mitre.org/software/S0367) in multiple campaigns.(Citation: IBM IcedID November 2017)(Citation: Juniper IcedID June 2020)',
|
||||||
|
mitreAttackPlatforms: 'Windows',
|
||||||
|
mitreAttackTechniques: '[""Asymmetric Cryptography(T1573.002)"",""Asynchronous Procedure Call(T1055.004)"",""Browser Session Hijacking(T1185)"",""Domain Account(T1087.002)"",""Ingress Tool Transfer(T1105)"",""Malicious File(T1204.002)"",""Msiexec(T1218.007)"",""Native API(T1106)"",""Obfuscated Files or Information(T1027)"",""Permission Groups Discovery(T1069)"",""Registry Run Keys / Startup Folder(T1547.001)"",""Scheduled Task(T1053.005)"",""Software Packing(T1027.002)"",""Spearphishing Attachment(T1566.001)"",""Steganography(T1027.003)"",""System Information Discovery(T1082)"",""Visual Basic(T1059.005)"",""Web Protocols(T1071.001)"",""Windows Management Instrumentation(T1047)""]',
|
||||||
|
mitreAttackGroups: '[""TA551(G0127)""]',
|
||||||
|
confidenceLevel: 'high',
|
||||||
|
reference: ''
|
||||||
|
},
|
||||||
|
location: {
|
||||||
|
continent: 'North America',
|
||||||
|
country: 'United States',
|
||||||
|
province: 'New York',
|
||||||
|
city: '',
|
||||||
|
lngwgs: '-74.006',
|
||||||
|
latwgs: '40.713',
|
||||||
|
isp: 'dba Omsoft',
|
||||||
|
owner: 'tie net'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/entity/detail/domain.*'), 'get', function (requestObj) {
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: {
|
||||||
|
malware: {
|
||||||
|
threatType: 'command and control',
|
||||||
|
malwareName: 'IcedID',
|
||||||
|
malwareAlias: 'BokBot,IceID',
|
||||||
|
mitreAttackDescription: '[IcedID](https://attack.mitre.org/software/S0483) is a modular banking malware designed to steal financial information that has been observed in the wild since at least 2017. [IcedID](https://attack.mitre.org/software/S0483) has been downloaded by [Emotet](https://attack.mitre.org/software/S0367) in multiple campaigns.(Citation: IBM IcedID November 2017)(Citation: Juniper IcedID June 2020)',
|
||||||
|
mitreAttackPlatforms: 'Windows',
|
||||||
|
mitreAttackTechniques: '[""Asymmetric Cryptography(T1573.002)"",""Asynchronous Procedure Call(T1055.004)"",""Browser Session Hijacking(T1185)"",""Domain Account(T1087.002)"",""Ingress Tool Transfer(T1105)"",""Malicious File(T1204.002)"",""Msiexec(T1218.007)"",""Native API(T1106)"",""Obfuscated Files or Information(T1027)"",""Permission Groups Discovery(T1069)"",""Registry Run Keys / Startup Folder(T1547.001)"",""Scheduled Task(T1053.005)"",""Software Packing(T1027.002)"",""Spearphishing Attachment(T1566.001)"",""Steganography(T1027.003)"",""System Information Discovery(T1082)"",""Visual Basic(T1059.005)"",""Web Protocols(T1071.001)"",""Windows Management Instrumentation(T1047)""]',
|
||||||
|
mitreAttackGroups: '[""TA551(G0127)""]',
|
||||||
|
confidenceLevel: 'high',
|
||||||
|
reference: ''
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
categoryName: '门户网站',
|
||||||
|
categoryGroup: '互联网',
|
||||||
|
reputationLevel: 'high'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Mock.mock(new RegExp(urlAndVersion + '/detection/security/entity/detail/app.*'), 'get', function (requestObj) {
|
||||||
|
return {
|
||||||
|
msg: 'OK',
|
||||||
|
code: 200,
|
||||||
|
data: {
|
||||||
|
category: {
|
||||||
|
appName: 'QQ',
|
||||||
|
appId: 333,
|
||||||
|
appCategory: '娱乐',
|
||||||
|
appSubcategory: '聊天',
|
||||||
|
appRisk: 'low',
|
||||||
|
appDescription: '聊天社交软件',
|
||||||
|
appLongname: 'Tencent qq',
|
||||||
|
appTechnology: 'socket',
|
||||||
|
appCompany: 'tencent',
|
||||||
|
appCompanyCategory: '互联网'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -3,3 +3,4 @@ import './linkMonitor'
|
|||||||
import './dns'
|
import './dns'
|
||||||
import './entity'
|
import './entity'
|
||||||
import './detection'
|
import './detection'
|
||||||
|
import './detectionList'
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const routes = [
|
|||||||
component: () => import('@/views/report/Report')
|
component: () => import('@/views/report/Report')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/entityExplorer',
|
path: '/entity',
|
||||||
component: () => import('@/views/entityExplorer/EntityExplorer')
|
component: () => import('@/views/entityExplorer/EntityExplorer')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -93,21 +93,16 @@ const routes = [
|
|||||||
component: () => import('@/views/administration/I18n')
|
component: () => import('@/views/administration/I18n')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Chart',
|
path: '/detectionPolicy',
|
||||||
path: '/chart',
|
component: () => import('@/views/detections/detectionPolicies/Index')
|
||||||
component: () => import('@/views/administration/Chart')
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/detectionsNew',
|
path: '/detectionPolicy/create',
|
||||||
component: () => import('@/views/detectionsNew/Index')
|
component: () => import('@/views/detections/detectionPolicies/PolicyForm')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/detection/policies',
|
path: '/detectionPolicy/edit',
|
||||||
component: () => import('@/views/detectionsNew/Index')
|
component: () => import('@/views/detections/detectionPolicies/PolicyForm')
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/detection/policies/create',
|
|
||||||
component: () => import('@/views/detectionsNew/DetectionForm')
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,29 @@ const panel = {
|
|||||||
routerHistoryList: [], // 路由跳转记录列表
|
routerHistoryList: [], // 路由跳转记录列表
|
||||||
dnsQtypeMapData: [],
|
dnsQtypeMapData: [],
|
||||||
dnsRcodeMapData: [],
|
dnsRcodeMapData: [],
|
||||||
|
scoreBase: {
|
||||||
|
isReady: false,
|
||||||
|
establishLatencyMs: {
|
||||||
|
p10: null,
|
||||||
|
p90: null
|
||||||
|
},
|
||||||
|
httpResponseLatency: {
|
||||||
|
p10: null,
|
||||||
|
p90: null
|
||||||
|
},
|
||||||
|
sslConLatency: {
|
||||||
|
p10: null,
|
||||||
|
p90: null
|
||||||
|
},
|
||||||
|
tcpLostlenPercent: {
|
||||||
|
p10: null,
|
||||||
|
p90: null
|
||||||
|
},
|
||||||
|
pktRetransPercent: {
|
||||||
|
p10: null,
|
||||||
|
p90: null
|
||||||
|
}
|
||||||
|
},
|
||||||
chartTabList: null // chartTabs组件的tab状态点击列表,初始化为null方便原有逻辑计算
|
chartTabList: null // chartTabs组件的tab状态点击列表,初始化为null方便原有逻辑计算
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
@@ -153,6 +176,56 @@ const panel = {
|
|||||||
setRouterHistoryList (state, list) {
|
setRouterHistoryList (state, list) {
|
||||||
state.routerHistoryList = list
|
state.routerHistoryList = list
|
||||||
},
|
},
|
||||||
|
resetScoreBase (state) {
|
||||||
|
state.scoreBase = {
|
||||||
|
isReady: false,
|
||||||
|
establishLatencyMs: {
|
||||||
|
p10: null,
|
||||||
|
p90: null
|
||||||
|
},
|
||||||
|
httpResponseLatency: {
|
||||||
|
p10: null,
|
||||||
|
p90: null
|
||||||
|
},
|
||||||
|
sslConLatency: {
|
||||||
|
p10: null,
|
||||||
|
p90: null
|
||||||
|
},
|
||||||
|
tcpLostlenPercent: {
|
||||||
|
p10: null,
|
||||||
|
p90: null
|
||||||
|
},
|
||||||
|
pktRetransPercent: {
|
||||||
|
p10: null,
|
||||||
|
p90: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setScoreBase (state, scoreBase) {
|
||||||
|
state.scoreBase = {
|
||||||
|
isReady: true,
|
||||||
|
establishLatencyMs: {
|
||||||
|
p10: scoreBase.establishLatencyMsP10,
|
||||||
|
p90: scoreBase.establishLatencyMsP90
|
||||||
|
},
|
||||||
|
httpResponseLatency: {
|
||||||
|
p10: scoreBase.httpResponseLatencyP10,
|
||||||
|
p90: scoreBase.httpResponseLatencyP90
|
||||||
|
},
|
||||||
|
sslConLatency: {
|
||||||
|
p10: scoreBase.sslConLatencyP10,
|
||||||
|
p90: scoreBase.sslConLatencyP90
|
||||||
|
},
|
||||||
|
tcpLostlenPercent: {
|
||||||
|
p10: scoreBase.tcpLostlenPercentP10,
|
||||||
|
p90: scoreBase.tcpLostlenPercentP90
|
||||||
|
},
|
||||||
|
pktRetransPercent: {
|
||||||
|
p10: scoreBase.pktRetransPercentP10,
|
||||||
|
p90: scoreBase.pktRetransPercentP90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
setChartTabList (state, list) {
|
setChartTabList (state, list) {
|
||||||
state.chartTabList = list
|
state.chartTabList = list
|
||||||
}
|
}
|
||||||
@@ -232,6 +305,12 @@ const panel = {
|
|||||||
},
|
},
|
||||||
getChartTabList (state) {
|
getChartTabList (state) {
|
||||||
return state.chartTabList
|
return state.chartTabList
|
||||||
|
},
|
||||||
|
scoreBaseReady (state) {
|
||||||
|
return state.scoreBase.isReady
|
||||||
|
},
|
||||||
|
getScoreBase (state) {
|
||||||
|
return state.scoreBase
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ const user = {
|
|||||||
localStorage.setItem(storageKey.linkInfo, res.page.list[0].cvalue)
|
localStorage.setItem(storageKey.linkInfo, res.page.list[0].cvalue)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
axios.get(api.config, { params: { ckey: 'schema_entity_explore' } }).then(response => {
|
axios.get(api.config, { params: { ckey: 'schema_explore' } }).then(response => {
|
||||||
const res = response.data
|
const res = response.data
|
||||||
if (response.status === 200 && res.page.list && res.page.list.length > 0) {
|
if (response.status === 200 && res.page.list && res.page.list.length > 0) {
|
||||||
localStorage.setItem(storageKey.schemaEntityExplore, res.page.list[0].cvalue)
|
localStorage.setItem(storageKey.schemaEntityExplore, res.page.list[0].cvalue)
|
||||||
|
|||||||
@@ -38,9 +38,12 @@ export const api = {
|
|||||||
knowledgeBase: apiVersion + '/knowledgeBase',
|
knowledgeBase: apiVersion + '/knowledgeBase',
|
||||||
knowledgeBaseList: apiVersion + '/knowledgeBase/list',
|
knowledgeBaseList: apiVersion + '/knowledgeBase/list',
|
||||||
knowledgeBaseEnable: apiVersion + '/knowledgeBase/status',
|
knowledgeBaseEnable: apiVersion + '/knowledgeBase/status',
|
||||||
|
knowledgeBaseLearningStart: apiVersion + '/knowledgeBase/intelligence-learning/start',
|
||||||
|
knowledgeBaseLearningStop: apiVersion + '/knowledgeBase/intelligence-learning/stop',
|
||||||
knowledgeBaseStatistics: apiVersion + '/knowledgeBase/statistics',
|
knowledgeBaseStatistics: apiVersion + '/knowledgeBase/statistics',
|
||||||
updateKnowledgeUrl: apiVersion + '/knowledgeBase/items/batch',
|
updateKnowledgeUrl: apiVersion + '/knowledgeBase/items/batch',
|
||||||
knowledgeBaseLog: apiVersion + '/knowledgeBase/audit/log',
|
knowledgeBaseLog: apiVersion + '/knowledgeBase/audit/log',
|
||||||
|
knowledgeBaseTimedistribution: apiVersion + '/knowledgeBase/{{knowledgeId}}/{{type}}/timedistribution',
|
||||||
|
|
||||||
// 报告相关
|
// 报告相关
|
||||||
reportJob: '/report/job',
|
reportJob: '/report/job',
|
||||||
@@ -123,7 +126,20 @@ export const api = {
|
|||||||
listBasic: '/interface/detection/security/list/basic',
|
listBasic: '/interface/detection/security/list/basic',
|
||||||
listCount: '/interface/detection/security/list/count',
|
listCount: '/interface/detection/security/list/count',
|
||||||
overviewBasic: '/interface/detection/security/detail/overview/basic',
|
overviewBasic: '/interface/detection/security/detail/overview/basic',
|
||||||
overviewEvent: '/interface/detection/security/detail/overview/event'
|
overviewEvent: '/interface/detection/security/detail/overview/event',
|
||||||
|
securityList: apiVersion + '/detection/security/list', // 安全事件列表
|
||||||
|
timeDistribution: apiVersion + '/detection/security/severity/timedistribution', // 事件严重等级分布(顶部柱状图)
|
||||||
|
severityStatistics: apiVersion + '/detection/security/severity/statistics', // 事件严重等级统计(左侧filter事件严重等级和饼图)
|
||||||
|
statusStatistics: apiVersion + '/detection/security/status/statistics', // 事件状态统计
|
||||||
|
eventTypeStatistics: apiVersion + '/detection/security/event-type/statistics', // 事件类型统计
|
||||||
|
offenderIpStatistics: apiVersion + '/detection/security/offender-ip/statistics', // 攻击者IP统计
|
||||||
|
victimIpStatistics: apiVersion + '/detection/security/victim-ip/statistics', // 受害者IP统计
|
||||||
|
relationEvent: apiVersion + '/detection/security/ip/relation/event', // IP相关近期事件
|
||||||
|
securityCount: apiVersion + '/detection/security/count', // 安全事件总数
|
||||||
|
detail: apiVersion + '/detection/security/entity/detail', // 安全事件实体详情,后面得加上实体类型
|
||||||
|
ipDetail: apiVersion + '/detection/security/entity/detail/ip', // 安全事件实体详情ip响应
|
||||||
|
domainDetail: apiVersion + '/detection/security/entity/detail/domain', // 安全事件实体详情domain响应
|
||||||
|
appDetail: apiVersion + '/detection/security/entity/detail/app' // 安全事件实体详情app响应
|
||||||
},
|
},
|
||||||
performanceEvent: {
|
performanceEvent: {
|
||||||
eventSeverityTrend: '/interface/detection/performance/filter/severityTrend',
|
eventSeverityTrend: '/interface/detection/performance/filter/severityTrend',
|
||||||
@@ -139,13 +155,13 @@ export const api = {
|
|||||||
},
|
},
|
||||||
list: apiVersion + '/rule/detection/list', // 检测规则列表
|
list: apiVersion + '/rule/detection/list', // 检测规则列表
|
||||||
detail: apiVersion + '/rule/detection', // 检测规则详情
|
detail: apiVersion + '/rule/detection', // 检测规则详情
|
||||||
delete: apiVersion + '/rule', // 检测规则删除
|
delete: apiVersion + '/rule/detection', // 检测规则删除
|
||||||
// 获取单位列表,如source、type、metric等
|
// 获取单位列表,如source、type、metric等
|
||||||
statistics: apiVersion + '/detection/statistics',
|
statistics: apiVersion + '/rule/detection/statistics',
|
||||||
// 规则新建模块
|
// 规则新建模块
|
||||||
create: {
|
create: {
|
||||||
topKeys: apiVersion + '/detection/topKeys', // topKeys列表
|
topKeys: apiVersion + '/detection/topKeys', // topKeys列表
|
||||||
create: apiVersion + '/rule/detection/create' // todo 规则新建编辑,此api为模拟,后续需要修改
|
create: apiVersion + '/rule/detection'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Dashboard
|
// Dashboard
|
||||||
@@ -248,6 +264,7 @@ export const api = {
|
|||||||
throughput: apiVersion + '/entity/detail/traffic/throughput',
|
throughput: apiVersion + '/entity/detail/traffic/throughput',
|
||||||
security: apiVersion + '/entity/detail/event/security',
|
security: apiVersion + '/entity/detail/event/security',
|
||||||
performance: apiVersion + '/entity/detail/event/performance',
|
performance: apiVersion + '/entity/detail/event/performance',
|
||||||
|
behaviorPattern: apiVersion + '/entity/detail/behavior/ip',
|
||||||
// 域名解析:ip相关app、domain
|
// 域名解析:ip相关app、domain
|
||||||
domainNameResolutionAboutAppsOfIp: apiVersion + '/entity/detail/ip/relate/apps',
|
domainNameResolutionAboutAppsOfIp: apiVersion + '/entity/detail/ip/relate/apps',
|
||||||
domainNameResolutionAboutDomainsOfIp: apiVersion + '/entity/detail/ip/relate/domains',
|
domainNameResolutionAboutDomainsOfIp: apiVersion + '/entity/detail/ip/relate/domains',
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -43,7 +43,7 @@ export function rTime (date) {
|
|||||||
}
|
}
|
||||||
// 日期转换为时间戳
|
// 日期转换为时间戳
|
||||||
export function toTime (date) {
|
export function toTime (date) {
|
||||||
return new Date(date).getTime()
|
return new Date(parseFloat(date)).getTime()
|
||||||
}
|
}
|
||||||
// 时间格式转换
|
// 时间格式转换
|
||||||
export function dateFormat (date, format = 'YYYY-MM-DD HH:mm:ss') {
|
export function dateFormat (date, format = 'YYYY-MM-DD HH:mm:ss') {
|
||||||
@@ -121,9 +121,9 @@ export function xAxisTimeFormatter (value) {
|
|||||||
':' +
|
':' +
|
||||||
(date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes())
|
(date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes())
|
||||||
// 如果是一天的开始
|
// 如果是一天的开始
|
||||||
if (date.getTime() === dayStart.getTime()) {
|
if (getSecond(date.getTime()) === getSecond(dayStart.getTime())) {
|
||||||
return '{day|' + dateFormat(date, 'YYYY-MM-DD') + '}'
|
return '{day|' + dateFormat(date, 'YYYY-MM-DD') + '}'
|
||||||
} else if (date.getTime() === hourStart.getTime()) {
|
} else if (getSecond(date.getTime()) === getSecond(hourStart.getTime())) {
|
||||||
return '{hour|' + HHmm + '}'
|
return '{hour|' + HHmm + '}'
|
||||||
} else {
|
} else {
|
||||||
return HHmm
|
return HHmm
|
||||||
@@ -137,3 +137,69 @@ export const xAxisTimeRich = {
|
|||||||
fontWeight: 'bold'
|
fontWeight: 'bold'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function switchDateTypeByStr (str) {
|
||||||
|
switch (str) {
|
||||||
|
// case 'Y':
|
||||||
|
// return 'years'
|
||||||
|
// case 'M':
|
||||||
|
// return 'months'
|
||||||
|
// case 'W':
|
||||||
|
// return 'weeks'
|
||||||
|
case 'D':
|
||||||
|
return 'days'
|
||||||
|
case 'H':
|
||||||
|
return 'hours'
|
||||||
|
case 'M':
|
||||||
|
return 'minutes'
|
||||||
|
case 'S':
|
||||||
|
return 'seconds'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchValueByDateType (str) {
|
||||||
|
switch (str) {
|
||||||
|
// case 'years':
|
||||||
|
// return 'Y'
|
||||||
|
// case 'months':
|
||||||
|
// return 'M'
|
||||||
|
// case 'weeks':
|
||||||
|
// return 'W'
|
||||||
|
case 'days':
|
||||||
|
return 'D'
|
||||||
|
case 'hours':
|
||||||
|
return 'H'
|
||||||
|
case 'minutes':
|
||||||
|
return 'M'
|
||||||
|
case 'seconds':
|
||||||
|
return 'S'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTimeByDurations (str) {
|
||||||
|
if (str && str.indexOf('P') === 0) {
|
||||||
|
const obj = {
|
||||||
|
type: '',
|
||||||
|
value: ''
|
||||||
|
}
|
||||||
|
for (let i = 1; i < str.length; i++) {
|
||||||
|
const item = str[i]
|
||||||
|
// P5D表示持续5天,PT5M持续5分钟,T是位于时间分量之前的时间指示符,即T之前是年月周日,T之后是时分秒
|
||||||
|
if (isNaN(item) && item !== 'T') {
|
||||||
|
obj.type = switchDateTypeByStr(item)
|
||||||
|
} else if (!isNaN(item)) {
|
||||||
|
obj.value += item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDurationsTimeByType (number, type) {
|
||||||
|
let T = ''
|
||||||
|
if (['hours', 'minutes', 'seconds'].indexOf(type) > -1) {
|
||||||
|
T = 'T'
|
||||||
|
}
|
||||||
|
return `P${T}${number}${switchValueByDateType(type)}`
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,42 +15,42 @@ _this.$t = _this.t
|
|||||||
export const dataForNpmTrafficLine = {
|
export const dataForNpmTrafficLine = {
|
||||||
tabs: [
|
tabs: [
|
||||||
{
|
{
|
||||||
name: _this.$t('network.total'),
|
name: 'network.total',
|
||||||
show: true,
|
show: true,
|
||||||
positioning: 0,
|
positioning: 0,
|
||||||
data: [],
|
data: [],
|
||||||
unitType: 'number'
|
unitType: 'number'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _this.$t('network.inbound'),
|
name: 'network.inbound',
|
||||||
show: true,
|
show: true,
|
||||||
positioning: 1,
|
positioning: 1,
|
||||||
data: [],
|
data: [],
|
||||||
unitType: 'number'
|
unitType: 'number'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _this.$t('network.outbound'),
|
name: 'network.outbound',
|
||||||
show: true,
|
show: true,
|
||||||
positioning: 2,
|
positioning: 2,
|
||||||
data: [],
|
data: [],
|
||||||
unitType: 'number'
|
unitType: 'number'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _this.$t('network.internal'),
|
name: 'network.internal',
|
||||||
show: true,
|
show: true,
|
||||||
positioning: 3,
|
positioning: 3,
|
||||||
data: [],
|
data: [],
|
||||||
unitType: 'number'
|
unitType: 'number'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _this.$t('network.through'),
|
name: 'network.through',
|
||||||
show: true,
|
show: true,
|
||||||
positioning: 4,
|
positioning: 4,
|
||||||
data: [],
|
data: [],
|
||||||
unitType: 'number'
|
unitType: 'number'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _this.$t('network.other'),
|
name: 'network.other',
|
||||||
show: true,
|
show: true,
|
||||||
positioning: 5,
|
positioning: 5,
|
||||||
data: [],
|
data: [],
|
||||||
@@ -58,21 +58,21 @@ export const dataForNpmTrafficLine = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
npmQuantity: [
|
npmQuantity: [
|
||||||
{ name: _this.$t('networkAppPerformance.tcpConnectionEstablishLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 0 },
|
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 0 },
|
||||||
{ name: _this.$t('networkAppPerformance.httpResponse'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 1 },
|
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 1 },
|
||||||
{ name: _this.$t('networkAppPerformance.sslResponseLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 2 },
|
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time, index: 2 },
|
||||||
{ name: _this.$t('networkAppPerformance.packetLoss'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 3 },
|
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 3 },
|
||||||
{ name: _this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 4 }
|
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 4 }
|
||||||
],
|
],
|
||||||
metricOptions: [
|
metricOptions: [
|
||||||
/* { value: 'Bits/s', label: 'Bits/s' },
|
/* { value: 'Bits/s', label: 'Bits/s' },
|
||||||
{ value: 'Packets/s', label: 'Packets/s' },
|
{ value: 'Packets/s', label: 'Packets/s' },
|
||||||
{ value: 'Sessions/s', label: 'Sessions/s' }, */
|
{ value: 'Sessions/s', label: 'Sessions/s' }, */
|
||||||
{ value: 'establishLatencyMs', label: _this.$t('networkAppPerformance.tcpConnectionEstablishLatency') },
|
{ value: 'establishLatencyMs', label: 'networkAppPerformance.tcpConnectionEstablishLatency' },
|
||||||
{ value: 'httpResponseLatency', label: _this.$t('networkAppPerformance.httpResponse') },
|
{ value: 'httpResponseLatency', label: 'networkAppPerformance.httpResponse' },
|
||||||
{ value: 'sslConLatency', label: _this.$t('networkAppPerformance.sslResponseLatency') },
|
{ value: 'sslConLatency', label: 'networkAppPerformance.sslResponseLatency' },
|
||||||
{ value: 'tcpLostlenPercent', label: _this.$t('networkAppPerformance.packetLoss') },
|
{ value: 'tcpLostlenPercent', label: 'networkAppPerformance.packetLoss' },
|
||||||
{ value: 'pktRetransPercent', label: _this.$t('overall.packetRetrans') }
|
{ value: 'pktRetransPercent', label: 'overall.packetRetrans' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,9 +175,9 @@ export const dataForLinkTrafficLine = {
|
|||||||
|
|
||||||
export const dataForNpmLine = {
|
export const dataForNpmLine = {
|
||||||
chartOptionLineData: [
|
chartOptionLineData: [
|
||||||
{ legend: _this.$t('network.total'), index: 0, invertTab: true, show: false, color: '#749F4D' },
|
{ legend: 'network.total', index: 0, invertTab: true, show: false, color: '#749F4D' },
|
||||||
{ legend: _this.$t('network.inbound'), index: 1, invertTab: true, show: false, color: '#98709B' },
|
{ legend: 'network.inbound', index: 1, invertTab: true, show: false, color: '#98709B' },
|
||||||
{ legend: _this.$t('network.outbound'), index: 2, invertTab: true, show: false, color: '#E5A219' }
|
{ legend: 'network.outbound', index: 2, invertTab: true, show: false, color: '#E5A219' }
|
||||||
],
|
],
|
||||||
npmLineColor: [
|
npmLineColor: [
|
||||||
{ legend: '', color: '#749F4D' },
|
{ legend: '', color: '#749F4D' },
|
||||||
@@ -221,27 +221,27 @@ export const dataForDnsTrafficLine = {
|
|||||||
export const dataForNpmEventsHeader = {
|
export const dataForNpmEventsHeader = {
|
||||||
chartData: [
|
chartData: [
|
||||||
{
|
{
|
||||||
eventSeverity: 'critical',
|
eventSeverity: 'overall.critical',
|
||||||
count: '-',
|
count: '-',
|
||||||
index: 0
|
index: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
eventSeverity: 'high',
|
eventSeverity: 'overall.high',
|
||||||
count: '-',
|
count: '-',
|
||||||
index: 1
|
index: 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
eventSeverity: 'medium',
|
eventSeverity: 'overall.medium',
|
||||||
count: '-',
|
count: '-',
|
||||||
index: 2
|
index: 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
eventSeverity: 'low',
|
eventSeverity: 'overall.low',
|
||||||
count: '-',
|
count: '-',
|
||||||
index: 3
|
index: 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
eventSeverity: 'info',
|
eventSeverity: 'overall.info',
|
||||||
count: '-',
|
count: '-',
|
||||||
index: 4
|
index: 4
|
||||||
}
|
}
|
||||||
@@ -334,11 +334,91 @@ export const columnList1 = [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
const securityEvent = [
|
||||||
|
{
|
||||||
|
name: 'event_type',
|
||||||
|
type: 'string',
|
||||||
|
label: 'event_type',
|
||||||
|
doc: {
|
||||||
|
constraints: {
|
||||||
|
operator_functions: '=,in,like'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'event_name',
|
||||||
|
type: 'string',
|
||||||
|
label: 'event_name',
|
||||||
|
doc: {
|
||||||
|
constraints: {
|
||||||
|
operator_functions: '=,in,like'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'severity',
|
||||||
|
type: 'string',
|
||||||
|
label: 'severity',
|
||||||
|
doc: {
|
||||||
|
constraints: {
|
||||||
|
operator_functions: '=,in,like'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'offender_ip',
|
||||||
|
type: 'string',
|
||||||
|
label: 'offender Ip',
|
||||||
|
doc: {
|
||||||
|
constraints: {
|
||||||
|
operator_functions: '=,in,like'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'victim_ip',
|
||||||
|
type: 'string',
|
||||||
|
label: 'victim Ip',
|
||||||
|
doc: {
|
||||||
|
constraints: {
|
||||||
|
operator_functions: '=,in,like'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'domain',
|
||||||
|
type: 'string',
|
||||||
|
label: 'domain',
|
||||||
|
doc: {
|
||||||
|
constraints: {
|
||||||
|
operator_functions: '=,in,like'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'app',
|
||||||
|
type: 'string',
|
||||||
|
label: 'app',
|
||||||
|
doc: {
|
||||||
|
constraints: {
|
||||||
|
operator_functions: '=,in,like'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
let schemaEntityExplore = localStorage.getItem(storageKey.schemaEntityExplore)
|
const schema = localStorage.getItem(storageKey.schemaEntityExplore)
|
||||||
schemaEntityExplore = schemaEntityExplore ? JSON.parse(schemaEntityExplore).entityMetadata.searchColumns : columnList1
|
const schemaEntityExplore = schema ? JSON.parse(schema).entityMetadata.searchColumns : columnList1
|
||||||
export const columnList = schemaEntityExplore
|
export const columnList = schemaEntityExplore
|
||||||
|
|
||||||
|
let securityEventMetadata = securityEvent
|
||||||
|
if (schema) {
|
||||||
|
if (JSON.parse(schema).securityEventMetadata) {
|
||||||
|
securityEventMetadata = JSON.parse(schema).securityEventMetadata.searchColumns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const schemaDetectionSecurity = securityEventMetadata
|
||||||
|
|
||||||
export const operatorList = ['=', '!=', /* '>', '<', '>=', '<=', */'IN', 'NOT IN', 'LIKE', 'NOT LIKE']
|
export const operatorList = ['=', '!=', /* '>', '<', '>=', '<=', */'IN', 'NOT IN', 'LIKE', 'NOT LIKE']
|
||||||
export const connectionList = [
|
export const connectionList = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -784,7 +784,7 @@ export function getChainRatio (current, prev) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function computeScore (data) {
|
export function computeScore (data, scoreBase) {
|
||||||
let score = 0
|
let score = 0
|
||||||
let k = 0
|
let k = 0
|
||||||
let totalScore = 0
|
let totalScore = 0
|
||||||
@@ -799,26 +799,14 @@ export function computeScore (data) {
|
|||||||
} else if (t === 'httpResponseLatency' || t === 'sslConLatency') {
|
} else if (t === 'httpResponseLatency' || t === 'sslConLatency') {
|
||||||
k = 0.05
|
k = 0.05
|
||||||
}
|
}
|
||||||
if (t === 'establishLatencyMs' || t === 'httpResponseLatency' || t === 'sslConLatency') {
|
if (!data[t] && data[t] !== 0) {
|
||||||
if (!data[t] && data[t] !== 0) {
|
score = 1
|
||||||
score = 1
|
} else if (data[t] <= scoreBase[t].p10) {
|
||||||
} else if (data[t] <= 50) {
|
score = 1
|
||||||
score = 1
|
} else if (data[t] >= scoreBase[t].p90) {
|
||||||
} else if (data[t] > 200) {
|
score = 0
|
||||||
score = 0
|
} else {
|
||||||
} else {
|
score = (data[t] - scoreBase[t].p90) / (scoreBase[t].p10 - scoreBase[t].p90)
|
||||||
score = (data[t] - 200) / (50 - 200)
|
|
||||||
}
|
|
||||||
} else if (t === 'tcpLostlenPercent' || t === 'pktRetransPercent') {
|
|
||||||
if (!data[t] && data[t] !== 0) {
|
|
||||||
score = 1
|
|
||||||
} else if (data[t] <= 0.01) {
|
|
||||||
score = 1
|
|
||||||
} else if (data[t] > 0.05) {
|
|
||||||
score = 0
|
|
||||||
} else {
|
|
||||||
score = (data[t] - 0.05) / (0.01 - 0.05)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
scoreArr.push(score * k)
|
scoreArr.push(score * k)
|
||||||
})
|
})
|
||||||
@@ -1318,12 +1306,13 @@ export function numberWithCommas (num) {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function switchStatus (status) {
|
export function switchStatus (status) {
|
||||||
switch (status) {
|
switch (status + '') {
|
||||||
case 0:
|
case '0':
|
||||||
return 'Disabled'
|
return 'detection.create.disabled'
|
||||||
case 1:
|
case '1':
|
||||||
return 'Enabled'
|
return 'detection.create.enabled'
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1356,3 +1345,18 @@ export function beforeRouterPush () {
|
|||||||
}
|
}
|
||||||
store.commit('setRouterHistoryList', historyList)
|
store.commit('setRouterHistoryList', historyList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置tag颜色,此为接口返回的颜色字段,color为rgb格式
|
||||||
|
* @param color
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function getTagColor (color) {
|
||||||
|
if (color) {
|
||||||
|
let backgroundColor = ''
|
||||||
|
if (color.indexOf('rgb(') > -1) {
|
||||||
|
backgroundColor = color.replace('rgb(', 'rgba(').replace(')', ',0.06)')
|
||||||
|
}
|
||||||
|
return `color: ${color};border-color: ${color};background-color: ${backgroundColor};`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div style="height: 100%;">
|
|
||||||
<cn-data-list
|
|
||||||
ref="dataList"
|
|
||||||
:tableId="tableId"
|
|
||||||
v-model:custom-table-title="tools.customTableTitle"
|
|
||||||
:api="url"
|
|
||||||
:from="fromRoute.chart"
|
|
||||||
:layout="['columnCustomize','elementSet','search']"
|
|
||||||
@search="search"
|
|
||||||
>
|
|
||||||
<template #top-tool-left>
|
|
||||||
<button id="chart-add"
|
|
||||||
class="top-tool-btn margin-r-10 top-tool-btn--create"
|
|
||||||
@click="add">
|
|
||||||
<i class="cn-icon-xinjian cn-icon"></i>
|
|
||||||
<span>{{$t('overall.create')}}</span>
|
|
||||||
</button>
|
|
||||||
<button id="chart-edit" class="top-tool-btn margin-r-10" :disabled="disableEdit"
|
|
||||||
@click="editSelectRecord">
|
|
||||||
<i class="cn-icon-edit cn-icon"></i>
|
|
||||||
<span>{{$t('overall.edit')}}</span>
|
|
||||||
</button>
|
|
||||||
<button id="chart-delete" class="top-tool-btn margin-r-10" :disabled="disableDelete"
|
|
||||||
@click="delBatch">
|
|
||||||
<i class="cn-icon-delete cn-icon"></i>
|
|
||||||
<span>{{$t('overall.delete')}}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
<template #default>
|
|
||||||
<loading :loading="loading"></loading>
|
|
||||||
<chart-table
|
|
||||||
ref="dataTable"
|
|
||||||
:api="url"
|
|
||||||
:isNoData="isNoData"
|
|
||||||
:custom-table-title="tools.customTableTitle"
|
|
||||||
:height="mainTableHeight"
|
|
||||||
:table-data="tableData"
|
|
||||||
@delete="del"
|
|
||||||
@edit="edit"
|
|
||||||
@orderBy="tableDataSort"
|
|
||||||
@reload="getTableData"
|
|
||||||
@selectionChange="selectionChange"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template #pagination>
|
|
||||||
<pagination ref="pagination" :page-obj="pageObj" :table-id="tableId" @pageNo='pageNo' @pageSize='pageSize'></pagination>
|
|
||||||
</template>
|
|
||||||
</cn-data-list>
|
|
||||||
<el-drawer
|
|
||||||
v-model="rightBox.show"
|
|
||||||
direction="rtl"
|
|
||||||
custom-class="common-right-box"
|
|
||||||
:size="700"
|
|
||||||
:with-header="false"
|
|
||||||
destroy-on-close>
|
|
||||||
<chart-box
|
|
||||||
:object="object"
|
|
||||||
@close="closeRightBox"
|
|
||||||
/>
|
|
||||||
</el-drawer>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import cnDataList from '@/components/table/CnDataList'
|
|
||||||
import dataListMixin from '@/mixins/data-list'
|
|
||||||
import chartTable from '@/components/table/administration/ChartTable'
|
|
||||||
import chartBox from '@/components/rightBox/settings/ChartBox'
|
|
||||||
import { api } from '@/utils/api'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Chart',
|
|
||||||
mixins: [dataListMixin],
|
|
||||||
components: {
|
|
||||||
cnDataList,
|
|
||||||
chartTable,
|
|
||||||
chartBox
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
url: api.chart,
|
|
||||||
listUrl: api.chartList,
|
|
||||||
blankObject: { // 空白对象
|
|
||||||
id: '',
|
|
||||||
name: '',
|
|
||||||
params: '',
|
|
||||||
i18n: ''
|
|
||||||
},
|
|
||||||
tableId: 'chartTable'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div style="height: 100%;">
|
|
||||||
<cn-data-list
|
|
||||||
ref="dataList"
|
|
||||||
:tableId="tableId"
|
|
||||||
v-model:custom-table-title="tools.customTableTitle"
|
|
||||||
:api="url"
|
|
||||||
:from="fromRoute.galaxyProxy"
|
|
||||||
:layout="['columnCustomize','elementSet','search']"
|
|
||||||
@search="search"
|
|
||||||
>
|
|
||||||
<template v-slot:top-tool-left>
|
|
||||||
<button id="galaxy-proxy-clear-cache" class="top-tool-btn margin-r-10" :title="$t('overall.clearCache')"
|
|
||||||
type="button" @click="clearCache">
|
|
||||||
<i class="cn-icon cn-icon-clear-cache"></i>
|
|
||||||
</button>
|
|
||||||
<button id="galaxy-proxy-add"
|
|
||||||
class="top-tool-btn margin-r-10 top-tool-btn--create"
|
|
||||||
@click="add">
|
|
||||||
<i class="cn-icon-xinjian cn-icon"></i>
|
|
||||||
<span>{{$t('overall.create')}}</span>
|
|
||||||
</button>
|
|
||||||
<button id="galaxy-edit" class="top-tool-btn margin-r-10" :disabled="disableEdit"
|
|
||||||
@click="editSelectRecord">
|
|
||||||
<i class="cn-icon-edit cn-icon"></i>
|
|
||||||
<span>{{$t('overall.edit')}}</span>
|
|
||||||
</button>
|
|
||||||
<button id="galaxy-delete" class="top-tool-btn margin-r-10"
|
|
||||||
@click="delBatch">
|
|
||||||
<i class="cn-icon-delete cn-icon"></i>
|
|
||||||
<span>{{$t('overall.delete')}}</span>
|
|
||||||
</button>
|
|
||||||
<button id="galaxy-proxy-debug" class="top-tool-btn margin-r-10" :title="$t('overall.debug')"
|
|
||||||
type="button" @click="debug(true,{})">
|
|
||||||
<i class="cn-icon-category cn-icon"></i>
|
|
||||||
</button>
|
|
||||||
<top-tool-more-options
|
|
||||||
ref="export"
|
|
||||||
id="model"
|
|
||||||
:params="searchLabel"
|
|
||||||
class="top-tool-export margin-l-10 margin-r-10"
|
|
||||||
export-file-name="galaxyProxy"
|
|
||||||
export-url="/galaxy/setting/export"
|
|
||||||
import-url="/galaxy/setting/import"
|
|
||||||
@afterImport="getTableData"
|
|
||||||
>
|
|
||||||
<template v-slot:before>
|
|
||||||
</template>
|
|
||||||
</top-tool-more-options>
|
|
||||||
</template>
|
|
||||||
<template v-slot:default>
|
|
||||||
<loading :loading="loading"></loading>
|
|
||||||
<galaxy-proxy-table
|
|
||||||
ref="dataTable"
|
|
||||||
:api="url"
|
|
||||||
:isNoData="isNoData"
|
|
||||||
:custom-table-title="tools.customTableTitle"
|
|
||||||
:height="mainTableHeight"
|
|
||||||
:table-data="tableData"
|
|
||||||
@delete="del"
|
|
||||||
@edit="edit"
|
|
||||||
@orderBy="tableDataSort"
|
|
||||||
@reload="getTableData"
|
|
||||||
@selectionChange="selectionChange"
|
|
||||||
@copy="copy"
|
|
||||||
@debug="debugRow"
|
|
||||||
></galaxy-proxy-table>
|
|
||||||
</template>
|
|
||||||
<!-- 分页组件 -->
|
|
||||||
<template #pagination>
|
|
||||||
<pagination ref="pagination" :page-obj="pageObj" :table-id="tableId" @pageNo='pageNo' @pageSize='pageSize'></pagination>
|
|
||||||
</template>
|
|
||||||
</cn-data-list>
|
|
||||||
<el-drawer
|
|
||||||
v-model="rightBox.show"
|
|
||||||
direction="rtl"
|
|
||||||
custom-class="common-right-box"
|
|
||||||
:size="700"
|
|
||||||
:with-header="false"
|
|
||||||
destroy-on-close>
|
|
||||||
<galaxy-proxy-box :object="object" @close="closeRightBox"></galaxy-proxy-box>
|
|
||||||
</el-drawer>
|
|
||||||
</div>
|
|
||||||
<galaxy-proxy-debug
|
|
||||||
v-model:show-debug="showDebug"
|
|
||||||
top="5vh"
|
|
||||||
:show-close="false"
|
|
||||||
:curGalaxyProxy="curGalaxyProxy"></galaxy-proxy-debug>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import cnDataList from '@/components/table/CnDataList'
|
|
||||||
import galaxyProxyBox from '@/components/rightBox/settings/GalaxyProxyBox'
|
|
||||||
import galaxyProxyTable from '@/components/table/administration/GalaxyProxyTable'
|
|
||||||
import dataListMixin from '@/mixins/data-list'
|
|
||||||
import { api } from '@/utils/api'
|
|
||||||
import axios from 'axios'
|
|
||||||
import TopToolMoreOptions from '@/components/common/popBox/TopToolMoreOptions'
|
|
||||||
import galaxyProxyDebug from '@/components/setting/GalaxyProxyDebug'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'GalaxyProxy',
|
|
||||||
components: {
|
|
||||||
cnDataList,
|
|
||||||
galaxyProxyBox,
|
|
||||||
galaxyProxyTable,
|
|
||||||
TopToolMoreOptions,
|
|
||||||
galaxyProxyDebug
|
|
||||||
},
|
|
||||||
mixins: [dataListMixin],
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
url: api.galaxyProxy,
|
|
||||||
tableId: 'galaxySettingTable', // 需要分页的table的id,用于记录每页数量
|
|
||||||
blankObject: { // 空白对象
|
|
||||||
name: ''
|
|
||||||
},
|
|
||||||
showDebug: false,
|
|
||||||
curGalaxyProxy: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
edit (u) {
|
|
||||||
axios.get(`${this.url}/${u.id}`).then(response => {
|
|
||||||
if (response.status === 200) {
|
|
||||||
const editObject = response.data.data
|
|
||||||
editObject.targetHeader || (editObject.targetHeader = '')
|
|
||||||
editObject.preHandle || (editObject.preHandle = '')
|
|
||||||
editObject.postHandle || (editObject.postHandle = '')
|
|
||||||
editObject.targetParam || (editObject.targetParam = '')
|
|
||||||
this.object = editObject
|
|
||||||
this.rightBox.show = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
debug (isTopDebug, u) {
|
|
||||||
if (!isTopDebug && u) {
|
|
||||||
this.curGalaxyProxy = JSON.parse(JSON.stringify(u))
|
|
||||||
}
|
|
||||||
this.showDebug = true
|
|
||||||
},
|
|
||||||
debugRow (u) {
|
|
||||||
this.debug(false, u)
|
|
||||||
},
|
|
||||||
clearCache () {
|
|
||||||
axios.put(`${this.url}/clearCache`).then(response => {
|
|
||||||
if (response.status === 200) {
|
|
||||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.success') })
|
|
||||||
} else {
|
|
||||||
this.$message.error(response.data.message)
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
this.$message.error(this.$t('tip.unknownError'))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
size="mini"
|
size="mini"
|
||||||
v-model="table.limit"
|
v-model="table.limit"
|
||||||
class="option__select select-topn"
|
class="option__select select-topn"
|
||||||
placeholder=""
|
placeholder=" "
|
||||||
popper-class="option-popper"
|
popper-class="option-popper"
|
||||||
@change="tableLimitChange"
|
@change="tableLimitChange"
|
||||||
>
|
>
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
size="mini"
|
size="mini"
|
||||||
v-model="copyOrderPieTable"
|
v-model="copyOrderPieTable"
|
||||||
class="option__select select-column"
|
class="option__select select-column"
|
||||||
placeholder=""
|
placeholder=" "
|
||||||
popper-class="option-popper"
|
popper-class="option-popper"
|
||||||
@change="orderPieTableChange"
|
@change="orderPieTableChange"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<el-select
|
<el-select
|
||||||
size="mini"
|
size="mini"
|
||||||
v-model="metric"
|
v-model="metric"
|
||||||
placeholder=""
|
placeholder=" "
|
||||||
popper-class="common-select"
|
popper-class="common-select"
|
||||||
v-if="showMetric"
|
v-if="showMetric"
|
||||||
:popper-append-to-body="false"
|
:popper-append-to-body="false"
|
||||||
@@ -104,7 +104,9 @@ export default {
|
|||||||
dnsRcodeMapData: [],
|
dnsRcodeMapData: [],
|
||||||
dnsQtypeMapData: [],
|
dnsQtypeMapData: [],
|
||||||
score: null,
|
score: null,
|
||||||
curTabState: curTabState
|
curTabState: curTabState,
|
||||||
|
performanceData: {},
|
||||||
|
scoreDataState: false // 评分数据是否加载完成
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -114,22 +116,32 @@ export default {
|
|||||||
// 显示顶部的Metric单位选项标识
|
// 显示顶部的Metric单位选项标识
|
||||||
showMetric () {
|
showMetric () {
|
||||||
return this.panelType === panelTypeAndRouteMapping.networkOverview || this.panelType === panelTypeAndRouteMapping.networkOverviewDrillDown
|
return this.panelType === panelTypeAndRouteMapping.networkOverview || this.panelType === panelTypeAndRouteMapping.networkOverviewDrillDown
|
||||||
|
},
|
||||||
|
scoreBaseState () {
|
||||||
|
return this.$store.getters.scoreBaseReady
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
// npmThirdLevelMenuScore: {
|
|
||||||
// deep: true,
|
|
||||||
// immediate: true,
|
|
||||||
// handler (n) {
|
|
||||||
// this.score = n
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
timeFilter: {
|
timeFilter: {
|
||||||
handler () {
|
handler () {
|
||||||
if (this.$route.path === '/panel/networkAppPerformance' && (this.lineQueryCondition || this.networkOverviewBeforeTab)) {
|
if (this.$route.path === '/panel/networkAppPerformance') {
|
||||||
this.scoreCalculation()
|
this.$store.commit('resetScoreBase')
|
||||||
|
this.queryScoreBase()
|
||||||
|
if (this.lineQueryCondition || this.networkOverviewBeforeTab) {
|
||||||
|
this.scoreCalculation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
scoreBaseState (n) {
|
||||||
|
if (n && this.scoreDataState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scoreDataState (n) {
|
||||||
|
if (n && this.scoreBaseState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted () {
|
async mounted () {
|
||||||
@@ -212,8 +224,14 @@ export default {
|
|||||||
return chart
|
return chart
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if (this.$route.path === '/panel/networkAppPerformance' && (this.lineQueryCondition || this.networkOverviewBeforeTab)) {
|
if (this.$route.path === '/panel/networkAppPerformance') {
|
||||||
this.scoreCalculation()
|
if (this.lineQueryCondition || this.networkOverviewBeforeTab) {
|
||||||
|
this.scoreCalculation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.$route.path === '/panel/networkAppPerformance' || this.$route.path === '/panel/linkMonitor') {
|
||||||
|
this.$store.commit('resetScoreBase')
|
||||||
|
this.queryScoreBase()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup (props) {
|
setup (props) {
|
||||||
@@ -396,6 +414,44 @@ export default {
|
|||||||
})
|
})
|
||||||
overwriteUrl(newUrl)
|
overwriteUrl(newUrl)
|
||||||
},
|
},
|
||||||
|
// 动态查询评分基准
|
||||||
|
queryScoreBase () {
|
||||||
|
const params = {
|
||||||
|
startTime: this.timeFilter.startTime,
|
||||||
|
endTime: this.timeFilter.endTime
|
||||||
|
}
|
||||||
|
const tcp = axios.get(api.npm.overview.tcpSessionDelay, { params: params })
|
||||||
|
const http = axios.get(api.npm.overview.httpResponseDelay, { params: params })
|
||||||
|
const ssl = axios.get(api.npm.overview.sslConDelay, { params: params })
|
||||||
|
const tcpPercent = axios.get(api.npm.overview.tcpLostlenPercent, { params: params })
|
||||||
|
const packetPercent = axios.get(api.npm.overview.packetRetransPercent, { params: params })
|
||||||
|
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
|
||||||
|
const scoreBase = {}
|
||||||
|
res.forEach((t, i) => {
|
||||||
|
if (t.status === 200) {
|
||||||
|
if (i === 0) {
|
||||||
|
scoreBase.establishLatencyMsP10 = _.get(t.data, 'data.result.establishLatencyMsP10', null)
|
||||||
|
scoreBase.establishLatencyMsP90 = _.get(t.data, 'data.result.establishLatencyMsP90', null)
|
||||||
|
} else if (i === 1) {
|
||||||
|
scoreBase.httpResponseLatencyP10 = _.get(t.data, 'data.result.httpResponseLatencyP10', null)
|
||||||
|
scoreBase.httpResponseLatencyP90 = _.get(t.data, 'data.result.httpResponseLatencyP90', null)
|
||||||
|
} else if (i === 2) {
|
||||||
|
scoreBase.sslConLatencyP10 = _.get(t.data, 'data.result.sslConLatencyP10', null)
|
||||||
|
scoreBase.sslConLatencyP90 = _.get(t.data, 'data.result.sslConLatencyP90', null)
|
||||||
|
} else if (i === 3) {
|
||||||
|
scoreBase.tcpLostlenPercentP10 = _.get(t.data, 'data.result.tcpLostlenPercentP10', null)
|
||||||
|
scoreBase.tcpLostlenPercentP90 = _.get(t.data, 'data.result.tcpLostlenPercentP90', null)
|
||||||
|
} else if (i === 4) {
|
||||||
|
scoreBase.pktRetransPercentP10 = _.get(t.data, 'data.result.pktRetransPercentP10', null)
|
||||||
|
scoreBase.pktRetransPercentP90 = _.get(t.data, 'data.result.pktRetransPercentP90', null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$store.commit('setScoreBase', scoreBase)
|
||||||
|
}).catch((e) => {
|
||||||
|
}).finally(() => {
|
||||||
|
})
|
||||||
|
},
|
||||||
scoreCalculation () {
|
scoreCalculation () {
|
||||||
let condition = ''
|
let condition = ''
|
||||||
let url = ''
|
let url = ''
|
||||||
@@ -443,18 +499,21 @@ export default {
|
|||||||
url = api.npm.overview.networkAnalysis
|
url = api.npm.overview.networkAnalysis
|
||||||
}
|
}
|
||||||
if ((type && condition) || type) {
|
if ((type && condition) || type) {
|
||||||
|
this.scoreDataState = false
|
||||||
|
this.performanceData = {}
|
||||||
params.type = params.type || type
|
params.type = params.type || type
|
||||||
axios.get(url, { params }).then(res => {
|
axios.get(url, { params }).then(res => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
const data = {
|
this.performanceData = {
|
||||||
establishLatencyMs: _.get(res, 'data.data.result.establishLatencyMsAvg', null),
|
establishLatencyMs: _.get(res, 'data.data.result.establishLatencyMsAvg', null),
|
||||||
httpResponseLatency: _.get(res, 'data.data.result.httpResponseLatencyAvg', null),
|
httpResponseLatency: _.get(res, 'data.data.result.httpResponseLatencyAvg', null),
|
||||||
sslConLatency: _.get(res, 'data.data.result.sslConLatencyAvg', null),
|
sslConLatency: _.get(res, 'data.data.result.sslConLatencyAvg', null),
|
||||||
tcpLostlenPercent: _.get(res, 'data.data.result.tcpLostlenPercentAvg', null),
|
tcpLostlenPercent: _.get(res, 'data.data.result.tcpLostlenPercentAvg', null),
|
||||||
pktRetransPercent: _.get(res, 'data.data.result.pktRetransPercentAvg', null)
|
pktRetransPercent: _.get(res, 'data.data.result.pktRetransPercentAvg', null)
|
||||||
}
|
}
|
||||||
this.score = computeScore(data)
|
|
||||||
}
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
this.scoreDataState = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -467,6 +526,9 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
window.open(href, '_blank')
|
window.open(href, '_blank')
|
||||||
|
},
|
||||||
|
handleScoreData () {
|
||||||
|
this.score = computeScore(this.performanceData, this.$store.getters.getScoreBase)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,12 +27,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="line-select line-header-right">
|
<div class="line-select line-header-right">
|
||||||
<div class="line-select-metric">
|
<!-- <div class="line-select-metric">
|
||||||
<span>{{$t('network.metric')}}:</span>
|
<span>{{$t('network.metric')}}:</span>
|
||||||
<div class="line-select__operation">
|
<div class="line-select__operation">
|
||||||
<el-select
|
<el-select
|
||||||
size="mini"
|
size="mini"
|
||||||
v-model="lineMetric"
|
v-model="lineMetric"
|
||||||
|
placeholder=" "
|
||||||
popper-class="common-select"
|
popper-class="common-select"
|
||||||
:popper-append-to-body="false"
|
:popper-append-to-body="false"
|
||||||
@change="metricSelectChange"
|
@change="metricSelectChange"
|
||||||
@@ -40,13 +41,14 @@
|
|||||||
<el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
<el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>-->
|
||||||
<div class="line-select-reference-line">
|
<div class="line-select-reference-line">
|
||||||
<span>{{$t('network.referenceLine')}}:</span>
|
<span>{{$t('network.referenceLine')}}:</span>
|
||||||
<div class="line-select__operation">
|
<div class="line-select__operation">
|
||||||
<el-select
|
<el-select
|
||||||
size="mini"
|
size="mini"
|
||||||
v-model="lineRefer"
|
v-model="lineRefer"
|
||||||
|
placeholder=" "
|
||||||
:disabled="!lineTab"
|
:disabled="!lineTab"
|
||||||
popper-class="common-select"
|
popper-class="common-select"
|
||||||
:popper-append-to-body="false"
|
:popper-append-to-body="false"
|
||||||
@@ -174,6 +176,9 @@ export default {
|
|||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
this.showError = false
|
this.showError = false
|
||||||
this.isNoData = res.data.data.result.length === 0
|
this.isNoData = res.data.data.result.length === 0
|
||||||
|
if (!active) {
|
||||||
|
this.tabs = _.cloneDeep(dataForDnsTrafficLine.tabs)
|
||||||
|
}
|
||||||
if (this.isNoData) {
|
if (this.isNoData) {
|
||||||
this.lineTab = ''
|
this.lineTab = ''
|
||||||
this.tabs = _.cloneDeep(dataForDnsTrafficLine.tabs)
|
this.tabs = _.cloneDeep(dataForDnsTrafficLine.tabs)
|
||||||
@@ -445,6 +450,7 @@ export default {
|
|||||||
this.legendSelectChange(e, 0)
|
this.legendSelectChange(e, 0)
|
||||||
})
|
})
|
||||||
this.tabs = tabs
|
this.tabs = tabs
|
||||||
|
this.lineRefer = 'Average'
|
||||||
this.echartsInit(this.tabs, true)
|
this.echartsInit(this.tabs, true)
|
||||||
} else {
|
} else {
|
||||||
const unit = 'bps'
|
const unit = 'bps'
|
||||||
@@ -464,7 +470,7 @@ export default {
|
|||||||
|
|
||||||
dnsData.forEach(e => {
|
dnsData.forEach(e => {
|
||||||
e.unitType = type
|
e.unitType = type
|
||||||
if (parseFloat(e.analysis.avg) === 0 || isNaN(parseFloat(e.analysis.avg))) {
|
if (parseFloat(e.analysis.max) === 0 || isNaN(parseFloat(e.analysis.max))) {
|
||||||
e.show = false
|
e.show = false
|
||||||
num += 1
|
num += 1
|
||||||
} else {
|
} else {
|
||||||
@@ -474,13 +480,18 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.lineTab === e.class) {
|
if (this.lineTab === e.class) {
|
||||||
if (parseFloat(e.analysis.avg) <= 0) {
|
if (parseFloat(e.analysis.max) <= 0) {
|
||||||
this.lineTab = ''
|
this.lineTab = ''
|
||||||
this.lineRefer = ''
|
this.lineRefer = ''
|
||||||
this.init()
|
// this.init() // 后续多关注
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const emptyData = dnsData.filter(d => parseFloat(d.analysis.max) === 0)
|
||||||
|
this.isNoData = emptyData.length === dnsData.length
|
||||||
|
if (this.isNoData) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
this.tabs = dnsData
|
this.tabs = dnsData
|
||||||
// 如果三者avg都为0时,至少保证total显示
|
// 如果三者avg都为0时,至少保证total显示
|
||||||
@@ -489,10 +500,10 @@ export default {
|
|||||||
let ingressAvg = 0
|
let ingressAvg = 0
|
||||||
let egressAvg = 0
|
let egressAvg = 0
|
||||||
if (ingressObj) {
|
if (ingressObj) {
|
||||||
ingressAvg = parseFloat(ingressObj.analysis.avg) || 0
|
ingressAvg = parseFloat(ingressObj.analysis.max) || 0
|
||||||
}
|
}
|
||||||
if (egressObj) {
|
if (egressObj) {
|
||||||
egressAvg = parseFloat(egressObj.analysis.avg) || 0
|
egressAvg = parseFloat(egressObj.analysis.max) || 0
|
||||||
}
|
}
|
||||||
if ((ingressAvg + egressAvg) === 0) {
|
if ((ingressAvg + egressAvg) === 0) {
|
||||||
const totalObj = dnsData.find(d => d.name === 'network.total')
|
const totalObj = dnsData.find(d => d.name === 'network.total')
|
||||||
|
|||||||
@@ -32,7 +32,13 @@
|
|||||||
</el-popover>
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
<div class="entity-tags" v-if="!hideTagArea">
|
<div class="entity-tags" v-if="!hideTagArea">
|
||||||
<div v-for="tag in levelTwoTags" :key="tag.value" class="entity-tag" :class="`entity-tag--level-two-${tag.type}`">{{tag.value}}</div>
|
<div v-for="tag in levelTwoTags"
|
||||||
|
:key="tag.value"
|
||||||
|
class="entity-tag"
|
||||||
|
:class="`entity-tag--level-two-${tag.type}`"
|
||||||
|
:style="getTagColor(tag.color)">
|
||||||
|
{{tag.value}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 分割线-->
|
<!-- 分割线-->
|
||||||
<div class="dividing-line"></div>
|
<div class="dividing-line"></div>
|
||||||
@@ -54,10 +60,11 @@ import {
|
|||||||
drillDownPanelTypeMapping,
|
drillDownPanelTypeMapping,
|
||||||
entityType,
|
entityType,
|
||||||
entityDetailTags,
|
entityDetailTags,
|
||||||
psiphon3IpType,
|
tagValueLabelMapping,
|
||||||
riskLevelMapping
|
riskLevelMapping,
|
||||||
|
entityDefaultColor
|
||||||
} from '@/utils/constants'
|
} from '@/utils/constants'
|
||||||
import { selectElementText, copySelectionText } from '@/utils/tools'
|
import { selectElementText, copySelectionText, getTagColor } from '@/utils/tools'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import i18n from '@/i18n'
|
import i18n from '@/i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
@@ -84,16 +91,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
tagValueHandler (k, k2, value) {
|
getTagColor,
|
||||||
if (k === 'psiphon3Ip') {
|
tagValueHandler (value) {
|
||||||
if (k2 === 'type') {
|
const find = tagValueLabelMapping.find(t => t.value === value)
|
||||||
const find = psiphon3IpType.find(t => t.value === value)
|
return find ? find.name : value
|
||||||
if (find) {
|
|
||||||
return find.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
},
|
},
|
||||||
getData () {
|
getData () {
|
||||||
this.toggleLoading(true)
|
this.toggleLoading(true)
|
||||||
@@ -114,13 +115,13 @@ export default {
|
|||||||
Object.keys(res.data[k]).forEach(k2 => {
|
Object.keys(res.data[k]).forEach(k2 => {
|
||||||
const find = entityDetailTags[this.entity.entityType].find(t => t.name === k2)
|
const find = entityDetailTags[this.entity.entityType].find(t => t.name === k2)
|
||||||
if (find) {
|
if (find) {
|
||||||
this.levelTwoTags.push({ key: k2, value: this.tagValueHandler(k, k2, res.data[k][k2]), type: find.type })
|
this.levelTwoTags.push({ key: k2, value: this.tagValueHandler(res.data[k][k2]), type: find.type })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (_.isArray(res.data.userDefinedTags)) {
|
if (_.isArray(res.data.userDefinedTags)) {
|
||||||
this.levelTwoTags = _.concat(this.levelTwoTags, res.data.userDefinedTags.map(tag => ({ value: tag.tagValue, type: 'normal' })))
|
this.levelTwoTags = _.concat(this.levelTwoTags, res.data.userDefinedTags.map(tag => ({ value: tag.tagValue, color: tag.knowledgeBase ? tag.knowledgeBase.color : entityDefaultColor })))
|
||||||
}
|
}
|
||||||
this.hideTagArea = _.isEmpty(this.levelTwoTags)
|
this.hideTagArea = _.isEmpty(this.levelTwoTags)
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
<el-select
|
<el-select
|
||||||
size="mini"
|
size="mini"
|
||||||
v-model="metric"
|
v-model="metric"
|
||||||
placeholder=""
|
placeholder=" "
|
||||||
popper-class="common-select"
|
popper-class="common-select"
|
||||||
:popper-append-to-body="false"
|
:popper-append-to-body="false"
|
||||||
@change="metricChange"
|
@change="metricChange"
|
||||||
@@ -66,6 +66,7 @@
|
|||||||
size="mini"
|
size="mini"
|
||||||
v-model="lineRefer"
|
v-model="lineRefer"
|
||||||
:disabled="!lineTab"
|
:disabled="!lineTab"
|
||||||
|
placeholder=" "
|
||||||
popper-class="common-select"
|
popper-class="common-select"
|
||||||
:popper-append-to-body="false"
|
:popper-append-to-body="false"
|
||||||
@change="referenceSelectChange"
|
@change="referenceSelectChange"
|
||||||
@@ -226,6 +227,9 @@ export default {
|
|||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
this.isNoData = res.data.result.length === 0
|
this.isNoData = res.data.result.length === 0
|
||||||
this.showError = false
|
this.showError = false
|
||||||
|
if (!active) {
|
||||||
|
this.tabs = _.cloneDeep(this.tabsTemplate)
|
||||||
|
}
|
||||||
if (this.isNoData) {
|
if (this.isNoData) {
|
||||||
this.lineTab = ''
|
this.lineTab = ''
|
||||||
this.tabs = _.cloneDeep(this.tabsTemplate)
|
this.tabs = _.cloneDeep(this.tabsTemplate)
|
||||||
@@ -497,7 +501,7 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data !== undefined && data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
newData.forEach((item) => {
|
newData.forEach((item) => {
|
||||||
item.type = getLineType(item.type)
|
item.type = getLineType(item.type)
|
||||||
if (item.type === val) {
|
if (item.type === val) {
|
||||||
@@ -510,6 +514,24 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
lineData.splice(0, 1)
|
lineData.splice(0, 1)
|
||||||
|
// TODO 下面的逻辑是判断total曲线的尾部数据,从尾往前数0值的个数,若个数大于0,所有曲线都从尾部去掉相同数量的点,最多4个
|
||||||
|
const totalData = lineData[0]
|
||||||
|
if (_.get(totalData, 'values', []).length > 4) {
|
||||||
|
let count = 0
|
||||||
|
for (let i = totalData.values.length - 1; i >= totalData.values.length - 4; i--) {
|
||||||
|
if (totalData.values[i].length > 1 && totalData.values[i][1] === 0) {
|
||||||
|
count++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count > 0) {
|
||||||
|
lineData.forEach(l => {
|
||||||
|
l.values.splice(l.values.length - count, count)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (val === 'Sessions/s') {
|
if (val === 'Sessions/s') {
|
||||||
const tabs = _.cloneDeep(this.tabsTemplate)
|
const tabs = _.cloneDeep(this.tabsTemplate)
|
||||||
lineData.forEach((d, i) => {
|
lineData.forEach((d, i) => {
|
||||||
@@ -527,6 +549,7 @@ export default {
|
|||||||
})
|
})
|
||||||
this.tabs = tabs
|
this.tabs = tabs
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
this.lineRefer = 'Average'
|
||||||
this.echartsInit(this.tabs, true)
|
this.echartsInit(this.tabs, true)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -544,7 +567,7 @@ export default {
|
|||||||
const self = this
|
const self = this
|
||||||
tabs.forEach(e => {
|
tabs.forEach(e => {
|
||||||
e.unitType = type
|
e.unitType = type
|
||||||
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
|
if (e.name !== 'network.total' && parseFloat(e.analysis.max) === 0) {
|
||||||
e.show = false
|
e.show = false
|
||||||
num += 1
|
num += 1
|
||||||
} else {
|
} else {
|
||||||
@@ -554,13 +577,18 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.lineTab === e.class) {
|
if (self.lineTab === e.class) {
|
||||||
if (parseFloat(e.analysis.avg) <= 0) {
|
if (parseFloat(e.analysis.max) <= 0) {
|
||||||
self.lineTab = ''
|
self.lineTab = ''
|
||||||
self.lineRefer = ''
|
self.lineRefer = ''
|
||||||
self.init()
|
// self.init() // 后续多测试关注
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const emptyData = tabs.filter(d => parseFloat(d.analysis.max) === 0)
|
||||||
|
this.isNoData = emptyData.length === tabs.length
|
||||||
|
if (this.isNoData) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
this.tabs = tabs
|
this.tabs = tabs
|
||||||
if (num === 5) {
|
if (num === 5) {
|
||||||
tabs[0].invertTab = false
|
tabs[0].invertTab = false
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
<security-event v-else-if="tab.name === entityDetailTabsName.securityEvent && 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" />
|
<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>
|
<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-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,24 +29,27 @@
|
|||||||
<script>
|
<script>
|
||||||
import chartMixin from '@/views/charts2/chart-mixin'
|
import chartMixin from '@/views/charts2/chart-mixin'
|
||||||
import i18n from '@/i18n'
|
import i18n from '@/i18n'
|
||||||
import { entityDetailTabsName, entityDetailTags, psiphon3IpType } from '@/utils/constants'
|
import { entityDetailTabsName, entityDetailTags } from '@/utils/constants'
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import InformationAggregation from '@/views/charts2/charts/entityDetail/tabs/InformationAggregation'
|
import InformationAggregation from '@/views/charts2/charts/entityDetail/tabs/InformationAggregation'
|
||||||
import DomainNameResolution from '@/views/charts2/charts/entityDetail/tabs/DomainNameResolution'
|
import DomainNameResolution from '@/views/charts2/charts/entityDetail/tabs/DomainNameResolution'
|
||||||
import SecurityEvent from '@/views/charts2/charts/entityDetail/tabs/SecurityEvent'
|
import SecurityEvent from '@/views/charts2/charts/entityDetail/tabs/SecurityEvent'
|
||||||
import PerformanceEvent from '@/views/charts2/charts/entityDetail/tabs/PerformanceEvent'
|
import PerformanceEvent from '@/views/charts2/charts/entityDetail/tabs/PerformanceEvent'
|
||||||
|
import BehaviorPattern from '@/views/charts2/charts/entityDetail/tabs/BehaviorPattern'
|
||||||
import OpenPort from '@/views/charts2/charts/entityDetail/tabs/OpenPort'
|
import OpenPort from '@/views/charts2/charts/entityDetail/tabs/OpenPort'
|
||||||
import DigitalCertificate from '@/views/charts2/charts/entityDetail/tabs/DigitalCertificate'
|
import DigitalCertificate from '@/views/charts2/charts/entityDetail/tabs/DigitalCertificate'
|
||||||
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { api } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
|
import { tagValueLabelMapping } from '../../../../utils/constants'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'EntityDetailTabs',
|
name: 'EntityDetailTabs',
|
||||||
mixins: [chartMixin],
|
mixins: [chartMixin],
|
||||||
components: {
|
components: {
|
||||||
PerformanceEvent,
|
PerformanceEvent,
|
||||||
|
BehaviorPattern,
|
||||||
SecurityEvent,
|
SecurityEvent,
|
||||||
InformationAggregation,
|
InformationAggregation,
|
||||||
DomainNameResolution,
|
DomainNameResolution,
|
||||||
@@ -90,6 +94,9 @@ export default {
|
|||||||
if (entityType !== 'app') {
|
if (entityType !== 'app') {
|
||||||
tabs.unshift({ name: entityDetailTabsName.informationAggregation, label: i18n.global.t('entities.informationAggregation'), icon: 'cn-icon cn-icon-information-aggregation', tag: 0 })
|
tabs.unshift({ name: entityDetailTabsName.informationAggregation, label: i18n.global.t('entities.informationAggregation'), icon: 'cn-icon cn-icon-information-aggregation', tag: 0 })
|
||||||
}
|
}
|
||||||
|
if (entityType === 'ip') {
|
||||||
|
tabs.push({ name: entityDetailTabsName.behaviorPattern, label: i18n.global.t('entities.behaviorPattern'), icon: 'cn-icon cn-icon-behavior', tag: 0 })
|
||||||
|
}
|
||||||
const activeTab = ref(tabs[0].name)
|
const activeTab = ref(tabs[0].name)
|
||||||
|
|
||||||
const { query } = useRoute()
|
const { query } = useRoute()
|
||||||
@@ -136,7 +143,7 @@ export default {
|
|||||||
Object.keys(r[k]).forEach(k2 => {
|
Object.keys(r[k]).forEach(k2 => {
|
||||||
const find = entityDetailTags[this.entity.entityType].find(t => t.name === k2)
|
const find = entityDetailTags[this.entity.entityType].find(t => t.name === k2)
|
||||||
if (find) {
|
if (find) {
|
||||||
aggregation.intelligenceContent.push({ key: k2, value: this.tagValueHandler(k, k2, r[k][k2]), type: find.type })
|
aggregation.intelligenceContent.push({ key: k2, value: this.tagValueHandler(r[k][k2]), type: find.type })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -171,7 +178,8 @@ export default {
|
|||||||
if (this.entity.entityType === 'ip') {
|
if (this.entity.entityType === 'ip') {
|
||||||
const appsOfIp = axios.get(api.entity.domainNameResolutionAboutAppsOfIp, { params: params })
|
const appsOfIp = axios.get(api.entity.domainNameResolutionAboutAppsOfIp, { params: params })
|
||||||
const domainsOfIp = axios.get(api.entity.domainNameResolutionAboutDomainsOfIp, { params: params })
|
const domainsOfIp = axios.get(api.entity.domainNameResolutionAboutDomainsOfIp, { params: params })
|
||||||
this.promiseData(appsOfIp, domainsOfIp)
|
const behaviorPattern = axios.get(api.entity.behaviorPattern, { params: params })
|
||||||
|
this.promiseData(appsOfIp, domainsOfIp, behaviorPattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.entity.entityType === 'domain') {
|
if (this.entity.entityType === 'domain') {
|
||||||
@@ -191,6 +199,18 @@ export default {
|
|||||||
const len1 = res[0].status === 200 ? res0.data.result.length : 0
|
const len1 = res[0].status === 200 ? res0.data.result.length : 0
|
||||||
const len2 = res[1].status === 200 ? res1.data.result.length : 0
|
const len2 = res[1].status === 200 ? res1.data.result.length : 0
|
||||||
this.initSetTag(entityDetailTabsName.relatedEntity, len1 + len2)
|
this.initSetTag(entityDetailTabsName.relatedEntity, len1 + len2)
|
||||||
|
const behaviorPatternData = res[2].status === 200 ? res[2].data.data.result : 0
|
||||||
|
let behaviorPatternLen = 0
|
||||||
|
if (behaviorPatternData && behaviorPatternData[0]) {
|
||||||
|
const dataObject = behaviorPatternData[0]
|
||||||
|
Object.keys(dataObject).forEach(key => {
|
||||||
|
const value = Number(dataObject[key]) ? Number(dataObject[key]) : 0
|
||||||
|
if (value !== 0) {
|
||||||
|
behaviorPatternLen++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.initSetTag(entityDetailTabsName.behaviorPattern, behaviorPatternLen)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'domain': {
|
case 'domain': {
|
||||||
@@ -251,16 +271,9 @@ export default {
|
|||||||
case 'app': return api.entity.openPortOfApp
|
case 'app': return api.entity.openPortOfApp
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tagValueHandler (k, k2, value) {
|
tagValueHandler (value) {
|
||||||
if (k === 'psiphon3Ip') {
|
const find = tagValueLabelMapping.find(t => t.value === value)
|
||||||
if (k2 === 'type') {
|
return find ? find.name : value
|
||||||
const find = psiphon3IpType.find(t => t.value === value)
|
|
||||||
if (find) {
|
|
||||||
return find.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeUnmount () {
|
beforeUnmount () {
|
||||||
|
|||||||
189
src/views/charts2/charts/entityDetail/tabs/BehaviorPattern.vue
Normal file
189
src/views/charts2/charts/entityDetail/tabs/BehaviorPattern.vue
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
<template>
|
||||||
|
<chart-error v-if="showError" :content="errorMsg" class="entity-detail-event-error"></chart-error>
|
||||||
|
<chart-no-data v-if="isNoData && !showError"></chart-no-data>
|
||||||
|
|
||||||
|
<div v-if="!isNoData && !showError" class="entity-detail-event-block" style="height: 100%;width: 100%;position: relative;">
|
||||||
|
<div class="behavior-pattern" >
|
||||||
|
<div class="behavior-pattern-legend" >
|
||||||
|
<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" >{{ 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>
|
||||||
|
<div class="chart-bottom-dot__right"></div>
|
||||||
|
<div class="chart-bottom-dot__left"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import { pieChartOption4 } from '@/views/charts2/charts/options/echartOption'
|
||||||
|
import { shallowRef } from 'vue'
|
||||||
|
import { entityDetailTabsName, chartColorForBehaviorPattern, unitTypes } from '@/utils/constants'
|
||||||
|
import unitConvert from '@/utils/unit-convert'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { api } from '@/utils/api'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import chartMixin from '@/views/charts2/chart-mixin'
|
||||||
|
import ChartError from '@/components/common/Error'
|
||||||
|
import { toUpperCaseByString, reverseSortBy } from '@/utils/tools'
|
||||||
|
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BehaviorPattern',
|
||||||
|
components: { ChartError, ChartNoData },
|
||||||
|
mixins: [chartMixin],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
showError: false,
|
||||||
|
errorMsg: '',
|
||||||
|
tableData: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup () {
|
||||||
|
const { query } = useRoute()
|
||||||
|
const entityType = query.entityType
|
||||||
|
const entityName = query.entityName
|
||||||
|
|
||||||
|
return {
|
||||||
|
entityType,
|
||||||
|
entityName,
|
||||||
|
myChart: shallowRef(null),
|
||||||
|
chartColorForBehaviorPattern,
|
||||||
|
unitTypes
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted () {
|
||||||
|
await this.initData()
|
||||||
|
this.toggleLoading(true)
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
this.toggleLoading(false)
|
||||||
|
clearInterval(timer)
|
||||||
|
}, 200)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
unitConvert,
|
||||||
|
toUpperCaseByString,
|
||||||
|
dateFormatByAppearance,
|
||||||
|
initEcharts () {
|
||||||
|
this.chartOption = pieChartOption4
|
||||||
|
this.chartOption.angleAxis.data = []
|
||||||
|
this.chartOption.series[0].data = []
|
||||||
|
this.tableData.forEach((item, index) => {
|
||||||
|
this.chartOption.angleAxis.data.push(item.name)
|
||||||
|
this.chartOption.series[0].data.push(item.value)
|
||||||
|
})
|
||||||
|
const len = this.tableData.length
|
||||||
|
const endIndex = len + 1
|
||||||
|
this.tableData.forEach((item, i) => {
|
||||||
|
if (i !== endIndex) {
|
||||||
|
this.chartOption.angleAxis.data.push(item.name + '2')
|
||||||
|
this.chartOption.series[0].data.push(0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const axisLabel = this.chartOption.angleAxis.axisLabel
|
||||||
|
this.chartOption.angleAxis.axisLabel = {
|
||||||
|
...axisLabel,
|
||||||
|
formatter: function (params, index) {
|
||||||
|
if (len > 15) {
|
||||||
|
if (index === 7) {
|
||||||
|
return params + '\n'
|
||||||
|
} else if (index === 8) {
|
||||||
|
return '\n' + params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index === endIndex) {
|
||||||
|
return params + '\n'
|
||||||
|
} else {
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const self = this
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (self.myChart) {
|
||||||
|
self.myChart.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
const dom = document.getElementById('entityIpRoseType')
|
||||||
|
if (dom) {
|
||||||
|
self.myChart = echarts.init(dom)
|
||||||
|
self.myChart.setOption(this.chartOption)
|
||||||
|
|
||||||
|
self.myChart.dispatchAction({
|
||||||
|
type: 'takeGlobalCursor',
|
||||||
|
key: 'brush',
|
||||||
|
brushOption: {
|
||||||
|
brushType: 'lineX',
|
||||||
|
xAxisIndex: 'all',
|
||||||
|
brushMode: 'single',
|
||||||
|
throttleType: 'debounce'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async initData () {
|
||||||
|
const params = {
|
||||||
|
resource: this.entityName
|
||||||
|
}
|
||||||
|
this.toggleLoading(true)
|
||||||
|
await axios.get(`${api.entity.behaviorPattern}`, { params: params }).then(response => {
|
||||||
|
const res = response.data
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
this.isNoData = res.data.result.length === 0
|
||||||
|
|
||||||
|
this.showError = false
|
||||||
|
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) {
|
||||||
|
sum = sum + value
|
||||||
|
this.tableData.push({
|
||||||
|
name: key,
|
||||||
|
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) {
|
||||||
|
this.isNoData = true
|
||||||
|
}
|
||||||
|
this.initEcharts()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.httpError(res)
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
this.httpError(e)
|
||||||
|
}).finally(() => {
|
||||||
|
this.toggleLoading(false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
httpError (e) {
|
||||||
|
this.isNoData = false
|
||||||
|
this.showError = true
|
||||||
|
this.errorMsg = this.errorMsgHandler(e)
|
||||||
|
this.$emit('checkTag', entityDetailTabsName.behaviorPattern, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
import chartMixin from '@/views/charts2/chart-mixin'
|
import chartMixin from '@/views/charts2/chart-mixin'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { api } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
import { entityDetailTabsName, entityDetailTags, psiphon3IpType } from '@/utils/constants'
|
import { entityDetailTabsName, entityDetailTags, tagValueLabelMapping } from '@/utils/constants'
|
||||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||||
import chartNoData from '@/views/charts/charts/ChartNoData'
|
import chartNoData from '@/views/charts/charts/ChartNoData'
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ export default {
|
|||||||
tagValueHandler (k, k2, value) {
|
tagValueHandler (k, k2, value) {
|
||||||
if (k === 'psiphon3Ip') {
|
if (k === 'psiphon3Ip') {
|
||||||
if (k2 === 'type') {
|
if (k2 === 'type') {
|
||||||
const find = psiphon3IpType.find(t => t.value === value)
|
const find = tagValueLabelMapping.find(t => t.value === value)
|
||||||
if (find) {
|
if (find) {
|
||||||
return find.name
|
return find.name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,12 +355,12 @@ export default {
|
|||||||
if (out < 0.0001 && out !== 0) {
|
if (out < 0.0001 && out !== 0) {
|
||||||
outUsage = '< 0.01%'
|
outUsage = '< 0.01%'
|
||||||
} else {
|
} else {
|
||||||
outUsage = JSON.stringify(parseFloat((out * 100).toFixed(2)))
|
outUsage = JSON.stringify(parseFloat(out * 100).toFixed(2))
|
||||||
}
|
}
|
||||||
if (_in < 0.0001 && _in !== 0) {
|
if (_in < 0.0001 && _in !== 0) {
|
||||||
inUsage = '< 0.01%'
|
inUsage = '< 0.01%'
|
||||||
} else {
|
} else {
|
||||||
inUsage = JSON.stringify(parseFloat((_in * 100).toFixed(2)))
|
inUsage = JSON.stringify(parseFloat(_in * 100).toFixed(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
length = outUsage.length + inUsage.length
|
length = outUsage.length + inUsage.length
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ export default {
|
|||||||
isLinkShowError: false, // 显示左侧链路报错标识
|
isLinkShowError: false, // 显示左侧链路报错标识
|
||||||
linkErrorMsg: '', // 左侧链路的报错信息
|
linkErrorMsg: '', // 左侧链路的报错信息
|
||||||
isNextShowError: false, // 显示右侧下一跳报错标识
|
isNextShowError: false, // 显示右侧下一跳报错标识
|
||||||
nextErrorMsg: '' // 右侧下一跳的报错信息
|
nextErrorMsg: '', // 右侧下一跳的报错信息
|
||||||
|
scoreDataState: false // 评分数据是否加载完成
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@@ -41,6 +42,23 @@ export default {
|
|||||||
handler () {
|
handler () {
|
||||||
this.init()
|
this.init()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
scoreBaseState (n) {
|
||||||
|
if (n && this.scoreDataState) {
|
||||||
|
this.handleScoreData(this.linkGridData)
|
||||||
|
this.handleScoreData(this.nextGridData)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scoreDataState (n) {
|
||||||
|
if (n && this.scoreBaseState) {
|
||||||
|
this.handleScoreData(this.linkGridData)
|
||||||
|
this.handleScoreData(this.nextGridData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
scoreBaseState () {
|
||||||
|
return this.$store.getters.scoreBaseReady
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
@@ -48,6 +66,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
init () {
|
init () {
|
||||||
|
this.scoreDataState = false
|
||||||
// 链路基本信息
|
// 链路基本信息
|
||||||
let linkInfo = localStorage.getItem(storageKey.linkInfo)
|
let linkInfo = localStorage.getItem(storageKey.linkInfo)
|
||||||
linkInfo = JSON.parse(linkInfo)
|
linkInfo = JSON.parse(linkInfo)
|
||||||
@@ -117,9 +136,9 @@ export default {
|
|||||||
d.usageMore90 = outUsage >= 0.9 || inUsage >= 0.9
|
d.usageMore90 = outUsage >= 0.9 || inUsage >= 0.9
|
||||||
// 计算npm分数
|
// 计算npm分数
|
||||||
// 分数低于3分,赋红点
|
// 分数低于3分,赋红点
|
||||||
d.score = this.localComputeScore(d)
|
// d.score = this.localComputeScore(d)
|
||||||
|
|
||||||
d.scoreLow3 = d.score < 3 || d.score === '-'
|
// d.scoreLow3 = d.score < 3 || d.score === '-'
|
||||||
|
|
||||||
const xAxis = inLink.linkId.split('Hundredgige').pop() - 1
|
const xAxis = inLink.linkId.split('Hundredgige').pop() - 1
|
||||||
const yAxis = outLink.linkId.split('Hundredgige').pop() - 1
|
const yAxis = outLink.linkId.split('Hundredgige').pop() - 1
|
||||||
@@ -210,9 +229,9 @@ export default {
|
|||||||
d.usageMore90 = outUsage >= 0.9 || inUsage >= 0.9
|
d.usageMore90 = outUsage >= 0.9 || inUsage >= 0.9
|
||||||
// 计算npm分数
|
// 计算npm分数
|
||||||
// 分数低于3分,赋红点
|
// 分数低于3分,赋红点
|
||||||
d.score = this.localComputeScore(d)
|
// d.score = this.localComputeScore(d)
|
||||||
|
|
||||||
d.scoreLow3 = d.score < 3 || d.score === '-'
|
// d.scoreLow3 = d.score < 3 || d.score === '-'
|
||||||
|
|
||||||
const xAxis = inLink.linkId
|
const xAxis = inLink.linkId
|
||||||
const yAxis = outLink.linkId
|
const yAxis = outLink.linkId
|
||||||
@@ -254,6 +273,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
|
this.scoreDataState = true
|
||||||
this.toggleLoading(false)
|
this.toggleLoading(false)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -282,6 +302,23 @@ export default {
|
|||||||
score = computeScore(dataScore)
|
score = computeScore(dataScore)
|
||||||
return score
|
return score
|
||||||
},
|
},
|
||||||
|
handleScoreData (data) {
|
||||||
|
data.forEach(d => {
|
||||||
|
if (d.out) {
|
||||||
|
d.out.forEach(t => {
|
||||||
|
const data = {
|
||||||
|
establishLatencyMs: t.establishLatencyMs,
|
||||||
|
httpResponseLatency: t.httpResponseLatency,
|
||||||
|
sslConLatency: t.sslConLatency,
|
||||||
|
tcpLostlenPercent: t.tcpLostlenPercent,
|
||||||
|
pktRetransPercent: t.pktRetransPercent
|
||||||
|
}
|
||||||
|
t.score = computeScore(data, this.$store.getters.getScoreBase)
|
||||||
|
t.scoreLow3 = t.score < 3 || t.score === '-'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 计算popover弹窗和右侧数据模块的宽度
|
* 计算popover弹窗和右侧数据模块的宽度
|
||||||
* 弹窗最小宽度为360px,右侧数据最小宽度为75px,右侧数据每大一位,popover弹窗宽度增加7px
|
* 弹窗最小宽度为360px,右侧数据最小宽度为75px,右侧数据每大一位,popover弹窗宽度增加7px
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
<el-select
|
<el-select
|
||||||
size="mini"
|
size="mini"
|
||||||
v-model="lineMetric"
|
v-model="lineMetric"
|
||||||
|
placeholder=" "
|
||||||
popper-class="common-select"
|
popper-class="common-select"
|
||||||
:popper-append-to-body="false"
|
:popper-append-to-body="false"
|
||||||
@change="metricSelectChange"
|
@change="metricSelectChange"
|
||||||
@@ -156,7 +157,7 @@ export default {
|
|||||||
endTime: getSecond(this.timeFilter.endTime)
|
endTime: getSecond(this.timeFilter.endTime)
|
||||||
}
|
}
|
||||||
if (this.queryCondition) {
|
if (this.queryCondition) {
|
||||||
const condition = this.queryCondition.toLowerCase().split(' or ')
|
const condition = this.queryCondition.split(' or ')
|
||||||
if (condition.length > 1) {
|
if (condition.length > 1) {
|
||||||
params.outParam = condition.find(c => c.indexOf('common_out_link_id') > -1 || c.indexOf('out_link_direction') > -1)
|
params.outParam = condition.find(c => c.indexOf('common_out_link_id') > -1 || c.indexOf('out_link_direction') > -1)
|
||||||
params.inParam = condition.find(c => c.indexOf('common_in_link_id') > -1 || c.indexOf('in_link_direction') > -1)
|
params.inParam = condition.find(c => c.indexOf('common_in_link_id') > -1 || c.indexOf('in_link_direction') > -1)
|
||||||
@@ -168,6 +169,9 @@ export default {
|
|||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
this.showError = false
|
this.showError = false
|
||||||
this.isNoData = res.data.result.length === 0
|
this.isNoData = res.data.result.length === 0
|
||||||
|
if (!active) {
|
||||||
|
this.tabs = dataForLinkTrafficLine.tabs
|
||||||
|
}
|
||||||
if (this.isNoData) {
|
if (this.isNoData) {
|
||||||
this.lineTab = ''
|
this.lineTab = ''
|
||||||
this.tabs = dataForLinkTrafficLine.tabs
|
this.tabs = dataForLinkTrafficLine.tabs
|
||||||
@@ -387,7 +391,7 @@ export default {
|
|||||||
let num = 0
|
let num = 0
|
||||||
linkData.forEach(e => {
|
linkData.forEach(e => {
|
||||||
e.unitType = type
|
e.unitType = type
|
||||||
if (parseFloat(e.analysis.avg) === 0 || isNaN(parseFloat(e.analysis.avg))) {
|
if (parseFloat(e.analysis.max) === 0 || isNaN(parseFloat(e.analysis.max))) {
|
||||||
e.show = false
|
e.show = false
|
||||||
num += 1
|
num += 1
|
||||||
} else {
|
} else {
|
||||||
@@ -397,13 +401,18 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.lineTab === e.class) {
|
if (this.lineTab === e.class) {
|
||||||
if (parseFloat(e.analysis.avg) <= 0) {
|
if (parseFloat(e.analysis.max) <= 0) {
|
||||||
this.lineTab = ''
|
this.lineTab = ''
|
||||||
this.lineRefer = ''
|
this.lineRefer = ''
|
||||||
this.init()
|
// this.init() // 暂时注掉,后续观察
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const emptyData = linkData.filter(d => parseFloat(d.analysis.max) === 0)
|
||||||
|
this.isNoData = emptyData.length === linkData.length
|
||||||
|
if (this.isNoData) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
this.tabs = linkData
|
this.tabs = linkData
|
||||||
// 如果三者avg都为0时,至少保证total显示
|
// 如果三者avg都为0时,至少保证total显示
|
||||||
const ingressObj = linkData.find(d => d.name === 'linkMonitor.ingress')
|
const ingressObj = linkData.find(d => d.name === 'linkMonitor.ingress')
|
||||||
@@ -411,10 +420,10 @@ export default {
|
|||||||
let ingressAvg = 0
|
let ingressAvg = 0
|
||||||
let egressAvg = 0
|
let egressAvg = 0
|
||||||
if (ingressObj) {
|
if (ingressObj) {
|
||||||
ingressAvg = parseFloat(ingressObj.analysis.avg) || 0
|
ingressAvg = parseFloat(ingressObj.analysis.max) || 0
|
||||||
}
|
}
|
||||||
if (egressObj) {
|
if (egressObj) {
|
||||||
egressAvg = parseFloat(egressObj.analysis.avg) || 0
|
egressAvg = parseFloat(egressObj.analysis.max) || 0
|
||||||
}
|
}
|
||||||
if ((ingressAvg + egressAvg) === 0) {
|
if ((ingressAvg + egressAvg) === 0) {
|
||||||
const totalObj = linkData.find(d => d.name === 'network.total')
|
const totalObj = linkData.find(d => d.name === 'network.total')
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export default {
|
|||||||
}
|
}
|
||||||
let url = ''
|
let url = ''
|
||||||
if (this.queryCondition) {
|
if (this.queryCondition) {
|
||||||
const condition = this.queryCondition.toLowerCase().split(' or ')
|
const condition = this.queryCondition.split(' or ')
|
||||||
if (condition.length > 1) {
|
if (condition.length > 1) {
|
||||||
if (n === 0) {
|
if (n === 0) {
|
||||||
params.q = condition.find(c => c.indexOf('common_in_link_id') > -1 || c.indexOf('in_link_direction') > -1)
|
params.q = condition.find(c => c.indexOf('common_in_link_id') > -1 || c.indexOf('in_link_direction') > -1)
|
||||||
|
|||||||
@@ -87,7 +87,14 @@ export default {
|
|||||||
bandWidth: 0,
|
bandWidth: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
showError: false,
|
showError: false,
|
||||||
errorMsg: ''
|
errorMsg: '',
|
||||||
|
scoreDataState: false,
|
||||||
|
performanceData: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
scoreBaseState () {
|
||||||
|
return this.$store.getters.scoreBaseReady
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -95,6 +102,16 @@ export default {
|
|||||||
handler (n) {
|
handler (n) {
|
||||||
this.linkTrafficData()
|
this.linkTrafficData()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
scoreBaseState (n) {
|
||||||
|
if (n && this.scoreDataState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scoreDataState (n) {
|
||||||
|
if (n && this.scoreBaseState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -103,8 +120,11 @@ export default {
|
|||||||
startTime: getSecond(this.timeFilter.startTime),
|
startTime: getSecond(this.timeFilter.startTime),
|
||||||
endTime: getSecond(this.timeFilter.endTime)
|
endTime: getSecond(this.timeFilter.endTime)
|
||||||
}
|
}
|
||||||
|
this.loading = true
|
||||||
|
this.performanceData = {}
|
||||||
|
this.scoreDataState = false
|
||||||
if (this.queryCondition) {
|
if (this.queryCondition) {
|
||||||
const condition = this.queryCondition.toLowerCase().split(' or ')
|
const condition = this.queryCondition.split(' or ')
|
||||||
if (condition.length > 1) {
|
if (condition.length > 1) {
|
||||||
// params.outParam = true
|
// params.outParam = true
|
||||||
params.outParam = condition.find(c => c.indexOf('common_out_link_id') > -1 || c.indexOf('out_link_direction') > -1)
|
params.outParam = condition.find(c => c.indexOf('common_out_link_id') > -1 || c.indexOf('out_link_direction') > -1)
|
||||||
@@ -142,7 +162,6 @@ export default {
|
|||||||
this.bandWidth = bandwidthAll
|
this.bandWidth = bandwidthAll
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.loading = true
|
|
||||||
axios.get(api.linkMonitor.networkAnalysis, { params: params }).then(response => {
|
axios.get(api.linkMonitor.networkAnalysis, { params: params }).then(response => {
|
||||||
const res = response.data
|
const res = response.data
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
@@ -152,7 +171,7 @@ export default {
|
|||||||
this.linkTrafficListData = {}
|
this.linkTrafficListData = {}
|
||||||
this.linkTrafficListData.npmScore = '-'
|
this.linkTrafficListData.npmScore = '-'
|
||||||
} else {
|
} else {
|
||||||
const data = {
|
this.performanceData = {
|
||||||
establishLatencyMs: _.get(res.data.result[0], 'establishLatencyMs', null),
|
establishLatencyMs: _.get(res.data.result[0], 'establishLatencyMs', null),
|
||||||
httpResponseLatency: _.get(res.data.result[0], 'httpResponseLatency', null),
|
httpResponseLatency: _.get(res.data.result[0], 'httpResponseLatency', null),
|
||||||
sslConLatency: _.get(res.data.result[0], 'sslConLatency', null),
|
sslConLatency: _.get(res.data.result[0], 'sslConLatency', null),
|
||||||
@@ -160,19 +179,24 @@ export default {
|
|||||||
pktRetransPercent: _.get(res.data.result[0], 'pktRetransPercent', null)
|
pktRetransPercent: _.get(res.data.result[0], 'pktRetransPercent', null)
|
||||||
}
|
}
|
||||||
this.linkTrafficListData = res.data.result[0]
|
this.linkTrafficListData = res.data.result[0]
|
||||||
this.linkTrafficListData.npmScore = computeScore(data)
|
// this.linkTrafficListData.npmScore = computeScore(data)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.showError = true
|
this.showError = true
|
||||||
this.errorMsg = res.message
|
this.errorMsg = res.message
|
||||||
}
|
}
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
this.showError = true
|
this.showError = true
|
||||||
this.errorMsg = e.message
|
this.errorMsg = e.message
|
||||||
this.isNoData = false
|
this.isNoData = false
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
this.scoreDataState = true
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
handleScoreData () {
|
||||||
|
this.linkTrafficListData.npmScore = computeScore(this.performanceData, this.$store.getters.getScoreBase)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
|||||||
@@ -1,994 +0,0 @@
|
|||||||
export default [
|
|
||||||
{
|
|
||||||
value: 'Afghanistan',
|
|
||||||
label: 'Afghanistan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Albania',
|
|
||||||
label: 'Albania'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Algeria',
|
|
||||||
label: 'Algeria'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'American Samoa',
|
|
||||||
label: 'American Samoa'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Andorra',
|
|
||||||
label: 'Andorra'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Angola',
|
|
||||||
label: 'Angola'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Anguilla',
|
|
||||||
label: 'Anguilla'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Antarctica',
|
|
||||||
label: 'Antarctica'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Antigua and Barbuda',
|
|
||||||
label: 'Antigua and Barbuda'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Argentina',
|
|
||||||
label: 'Argentina'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Armenia',
|
|
||||||
label: 'Armenia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Aruba',
|
|
||||||
label: 'Aruba'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Australia',
|
|
||||||
label: 'Australia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Austria',
|
|
||||||
label: 'Austria'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Azerbaijan',
|
|
||||||
label: 'Azerbaijan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Bahamas (the)',
|
|
||||||
label: 'Bahamas (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Bahrain',
|
|
||||||
label: 'Bahrain'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Bangladesh',
|
|
||||||
label: 'Bangladesh'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Barbados',
|
|
||||||
label: 'Barbados'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Belarus',
|
|
||||||
label: 'Belarus'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Belgium',
|
|
||||||
label: 'Belgium'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Belize',
|
|
||||||
label: 'Belize'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Benin',
|
|
||||||
label: 'Benin'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Bermuda',
|
|
||||||
label: 'Bermuda'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Åland Islands',
|
|
||||||
label: 'Åland Islands'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Bhutan',
|
|
||||||
label: 'Bhutan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Bolivia (Plurinational State of)',
|
|
||||||
label: 'Bolivia (Plurinational State of)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Bonaire, Sint Eustatius and Saba',
|
|
||||||
label: 'Bonaire, Sint Eustatius and Saba'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Bosnia and Herzegovina',
|
|
||||||
label: 'Bosnia and Herzegovina'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Botswana',
|
|
||||||
label: 'Botswana'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Bouvet Island',
|
|
||||||
label: 'Bouvet Island'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Brazil',
|
|
||||||
label: 'Brazil'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'British Indian Ocean Territory (the)',
|
|
||||||
label: 'British Indian Ocean Territory (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Brunei Darussalam',
|
|
||||||
label: 'Brunei Darussalam'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Bulgaria',
|
|
||||||
label: 'Bulgaria'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Burkina Faso',
|
|
||||||
label: 'Burkina Faso'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Burundi',
|
|
||||||
label: 'Burundi'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Cabo Verde',
|
|
||||||
label: 'Cabo Verde'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Cambodia',
|
|
||||||
label: 'Cambodia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Cameroon',
|
|
||||||
label: 'Cameroon'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Canada',
|
|
||||||
label: 'Canada'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Cayman Islands (the)',
|
|
||||||
label: 'Cayman Islands (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Central African Republic (the)',
|
|
||||||
label: 'Central African Republic (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Chad',
|
|
||||||
label: 'Chad'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Chile',
|
|
||||||
label: 'Chile'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'China',
|
|
||||||
label: 'China'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Christmas Island',
|
|
||||||
label: 'Christmas Island'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Cocos (Keeling) Islands (the)',
|
|
||||||
label: 'Cocos (Keeling) Islands (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Colombia',
|
|
||||||
label: 'Colombia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Comoros (the)',
|
|
||||||
label: 'Comoros (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Congo (the Democratic Republic of the)',
|
|
||||||
label: 'Congo (the Democratic Republic of the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Congo (the)',
|
|
||||||
label: 'Congo (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Cook Islands (the)',
|
|
||||||
label: 'Cook Islands (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Costa Rica',
|
|
||||||
label: 'Costa Rica'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Croatia',
|
|
||||||
label: 'Croatia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Cuba',
|
|
||||||
label: 'Cuba'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Curaçao',
|
|
||||||
label: 'Curaçao'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Cyprus',
|
|
||||||
label: 'Cyprus'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Czech Republic',
|
|
||||||
label: 'Czech Republic'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "Côte d'Ivoire",
|
|
||||||
label: "Côte d'Ivoire"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Denmark',
|
|
||||||
label: 'Denmark'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Djibouti',
|
|
||||||
label: 'Djibouti'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Dominica',
|
|
||||||
label: 'Dominica'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Dominican Republic (the)',
|
|
||||||
label: 'Dominican Republic (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Ecuador',
|
|
||||||
label: 'Ecuador'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Egypt',
|
|
||||||
label: 'Egypt'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'El Salvador',
|
|
||||||
label: 'El Salvador'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Equatorial Guinea',
|
|
||||||
label: 'Equatorial Guinea'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Eritrea',
|
|
||||||
label: 'Eritrea'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Estonia',
|
|
||||||
label: 'Estonia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Eswatini',
|
|
||||||
label: 'Eswatini'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Ethiopia',
|
|
||||||
label: 'Ethiopia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Falkland Islands (the) [Malvinas]',
|
|
||||||
label: 'Falkland Islands (the) [Malvinas]'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Faroe Islands (the)',
|
|
||||||
label: 'Faroe Islands (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Fiji',
|
|
||||||
label: 'Fiji'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Finland',
|
|
||||||
label: 'Finland'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'France',
|
|
||||||
label: 'France'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'French Guiana',
|
|
||||||
label: 'French Guiana'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'French Polynesia',
|
|
||||||
label: 'French Polynesia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'French Southern Territories (the)',
|
|
||||||
label: 'French Southern Territories (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Gabon',
|
|
||||||
label: 'Gabon'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Gambia (the)',
|
|
||||||
label: 'Gambia (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Georgia',
|
|
||||||
label: 'Georgia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Germany',
|
|
||||||
label: 'Germany'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Ghana',
|
|
||||||
label: 'Ghana'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Gibraltar',
|
|
||||||
label: 'Gibraltar'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Greece',
|
|
||||||
label: 'Greece'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Greenland',
|
|
||||||
label: 'Greenland'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Grenada',
|
|
||||||
label: 'Grenada'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Guadeloupe',
|
|
||||||
label: 'Guadeloupe'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Guam',
|
|
||||||
label: 'Guam'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Guatemala',
|
|
||||||
label: 'Guatemala'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Guernsey',
|
|
||||||
label: 'Guernsey'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Guinea',
|
|
||||||
label: 'Guinea'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Guinea-Bissau',
|
|
||||||
label: 'Guinea-Bissau'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Guyana',
|
|
||||||
label: 'Guyana'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Haiti',
|
|
||||||
label: 'Haiti'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Heard Island and McDonald Islands',
|
|
||||||
label: 'Heard Island and McDonald Islands'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Holy See (the)',
|
|
||||||
label: 'Holy See (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Honduras',
|
|
||||||
label: 'Honduras'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Hong Kong',
|
|
||||||
label: 'Hong Kong'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Hungary',
|
|
||||||
label: 'Hungary'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Iceland',
|
|
||||||
label: 'Iceland'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'India',
|
|
||||||
label: 'India'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Indonesia',
|
|
||||||
label: 'Indonesia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Iran (Islamic Republic of)',
|
|
||||||
label: 'Iran (Islamic Republic of)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Iraq',
|
|
||||||
label: 'Iraq'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Ireland',
|
|
||||||
label: 'Ireland'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Isle of Man',
|
|
||||||
label: 'Isle of Man'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Israel',
|
|
||||||
label: 'Israel'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Italy',
|
|
||||||
label: 'Italy'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Jamaica',
|
|
||||||
label: 'Jamaica'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Japan',
|
|
||||||
label: 'Japan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Jersey',
|
|
||||||
label: 'Jersey'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Jordan',
|
|
||||||
label: 'Jordan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Kazakhstan',
|
|
||||||
label: 'Kazakhstan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Kenya',
|
|
||||||
label: 'Kenya'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Kiribati',
|
|
||||||
label: 'Kiribati'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Korea',
|
|
||||||
label: 'Korea'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Kuwait',
|
|
||||||
label: 'Kuwait'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Kyrgyzstan',
|
|
||||||
label: 'Kyrgyzstan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "Lao People's Democratic Republic (the)",
|
|
||||||
label: "Lao People's Democratic Republic (the)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Latvia',
|
|
||||||
label: 'Latvia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Lebanon',
|
|
||||||
label: 'Lebanon'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Lesotho',
|
|
||||||
label: 'Lesotho'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Liberia',
|
|
||||||
label: 'Liberia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Libya',
|
|
||||||
label: 'Libya'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Liechtenstein',
|
|
||||||
label: 'Liechtenstein'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Lithuania',
|
|
||||||
label: 'Lithuania'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Luxembourg',
|
|
||||||
label: 'Luxembourg'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Macao',
|
|
||||||
label: 'Macao'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Madagascar',
|
|
||||||
label: 'Madagascar'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Malawi',
|
|
||||||
label: 'Malawi'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Malaysia',
|
|
||||||
label: 'Malaysia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Maldives',
|
|
||||||
label: 'Maldives'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Mali',
|
|
||||||
label: 'Mali'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Malta',
|
|
||||||
label: 'Malta'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Marshall Islands (the)',
|
|
||||||
label: 'Marshall Islands (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Martinique',
|
|
||||||
label: 'Martinique'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Mauritania',
|
|
||||||
label: 'Mauritania'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Mauritius',
|
|
||||||
label: 'Mauritius'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Mayotte',
|
|
||||||
label: 'Mayotte'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Mexico',
|
|
||||||
label: 'Mexico'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Micronesia (Federated States of)',
|
|
||||||
label: 'Micronesia (Federated States of)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Moldova (the Republic of)',
|
|
||||||
label: 'Moldova (the Republic of)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Monaco',
|
|
||||||
label: 'Monaco'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Mongolia',
|
|
||||||
label: 'Mongolia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Montenegro',
|
|
||||||
label: 'Montenegro'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Montserrat',
|
|
||||||
label: 'Montserrat'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Morocco',
|
|
||||||
label: 'Morocco'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Mozambique',
|
|
||||||
label: 'Mozambique'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Myanmar',
|
|
||||||
label: 'Myanmar'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Namibia',
|
|
||||||
label: 'Namibia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Nauru',
|
|
||||||
label: 'Nauru'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Nepal',
|
|
||||||
label: 'Nepal'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Netherlands',
|
|
||||||
label: 'Netherlands'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'New Caledonia',
|
|
||||||
label: 'New Caledonia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'New Zealand',
|
|
||||||
label: 'New Zealand'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Nicaragua',
|
|
||||||
label: 'Nicaragua'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Niger',
|
|
||||||
label: 'Niger'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Nigeria',
|
|
||||||
label: 'Nigeria'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Niue',
|
|
||||||
label: 'Niue'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Norfolk Island',
|
|
||||||
label: 'Norfolk Island'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'North Macedonia',
|
|
||||||
label: 'North Macedonia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Northern Mariana Islands (the)',
|
|
||||||
label: 'Northern Mariana Islands (the)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Norway',
|
|
||||||
label: 'Norway'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Oman',
|
|
||||||
label: 'Oman'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Pakistan',
|
|
||||||
label: 'Pakistan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Palau',
|
|
||||||
label: 'Palau'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Palestine, State of',
|
|
||||||
label: 'Palestine, State of'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Panama',
|
|
||||||
label: 'Panama'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Papua New Guinea',
|
|
||||||
label: 'Papua New Guinea'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Paraguay',
|
|
||||||
label: 'Paraguay'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Peru',
|
|
||||||
label: 'Peru'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Philippines',
|
|
||||||
label: 'Philippines'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Pitcairn',
|
|
||||||
label: 'Pitcairn'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Poland',
|
|
||||||
label: 'Poland'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Portugal',
|
|
||||||
label: 'Portugal'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Puerto Rico',
|
|
||||||
label: 'Puerto Rico'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Qatar',
|
|
||||||
label: 'Qatar'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Romania',
|
|
||||||
label: 'Romania'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Russian Federation',
|
|
||||||
label: 'Russian Federation'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Rwanda',
|
|
||||||
label: 'Rwanda'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Réunion',
|
|
||||||
label: 'Réunion'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Saint Barthélemy',
|
|
||||||
label: 'Saint Barthélemy'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Saint Helena, Ascension and Tristan da Cunha',
|
|
||||||
label: 'Saint Helena, Ascension and Tristan da Cunha'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Saint Kitts and Nevis',
|
|
||||||
label: 'Saint Kitts and Nevis'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Saint Lucia',
|
|
||||||
label: 'Saint Lucia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Saint Martin',
|
|
||||||
label: 'Saint Martin'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Saint Pierre and Miquelon',
|
|
||||||
label: 'Saint Pierre and Miquelon'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Saint Vincent and the Grenadines',
|
|
||||||
label: 'Saint Vincent and the Grenadines'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Samoa',
|
|
||||||
label: 'Samoa'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'San Marino',
|
|
||||||
label: 'San Marino'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Sao Tome and Principe',
|
|
||||||
label: 'Sao Tome and Principe'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Saudi Arabia',
|
|
||||||
label: 'Saudi Arabia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Senegal',
|
|
||||||
label: 'Senegal'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Serbia',
|
|
||||||
label: 'Serbia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Seychelles',
|
|
||||||
label: 'Seychelles'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Sierra Leone',
|
|
||||||
label: 'Sierra Leone'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Singapore',
|
|
||||||
label: 'Singapore'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Sint Maarten',
|
|
||||||
label: 'Sint Maarten'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Slovakia',
|
|
||||||
label: 'Slovakia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Slovenia',
|
|
||||||
label: 'Slovenia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Solomon Islands',
|
|
||||||
label: 'Solomon Islands'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Somalia',
|
|
||||||
label: 'Somalia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'South Africa',
|
|
||||||
label: 'South Africa'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'South Georgia and the South Sandwich Islands',
|
|
||||||
label: 'South Georgia and the South Sandwich Islands'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'South Sudan',
|
|
||||||
label: 'South Sudan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Spain',
|
|
||||||
label: 'Spain'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Sri Lanka',
|
|
||||||
label: 'Sri Lanka'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Sudan',
|
|
||||||
label: 'Sudan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Suriname',
|
|
||||||
label: 'Suriname'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Svalbard and Jan Mayen',
|
|
||||||
label: 'Svalbard and Jan Mayen'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Sweden',
|
|
||||||
label: 'Sweden'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Switzerland',
|
|
||||||
label: 'Switzerland'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Syrian Arab Republic',
|
|
||||||
label: 'Syrian Arab Republic'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Taiwan',
|
|
||||||
label: 'Taiwan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Tajikistan',
|
|
||||||
label: 'Tajikistan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Tanzania, the United Republic of',
|
|
||||||
label: 'Tanzania, the United Republic of'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Thailand',
|
|
||||||
label: 'Thailand'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Timor-Leste',
|
|
||||||
label: 'Timor-Leste'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Togo',
|
|
||||||
label: 'Togo'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Tokelau',
|
|
||||||
label: 'Tokelau'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Tonga',
|
|
||||||
label: 'Tonga'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Trinidad and Tobago',
|
|
||||||
label: 'Trinidad and Tobago'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Tunisia',
|
|
||||||
label: 'Tunisia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Turkey',
|
|
||||||
label: 'Turkey'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Turkmenistan',
|
|
||||||
label: 'Turkmenistan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Turks and Caicos Islands',
|
|
||||||
label: 'Turks and Caicos Islands'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Tuvalu',
|
|
||||||
label: 'Tuvalu'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Uganda',
|
|
||||||
label: 'Uganda'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Ukraine',
|
|
||||||
label: 'Ukraine'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'United Arab Emirates',
|
|
||||||
label: 'United Arab Emirates'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'United Kingdom of Great Britain and Northern Ireland',
|
|
||||||
label: 'United Kingdom of Great Britain and Northern Ireland'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'United States Minor Outlying Islands',
|
|
||||||
label: 'United States Minor Outlying Islands'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'United States',
|
|
||||||
label: 'United States'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Uruguay',
|
|
||||||
label: 'Uruguay'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Uzbekistan',
|
|
||||||
label: 'Uzbekistan'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Vanuatu',
|
|
||||||
label: 'Vanuatu'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Venezuela (Bolivarian Republic of)',
|
|
||||||
label: 'Venezuela (Bolivarian Republic of)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Viet Nam',
|
|
||||||
label: 'Viet Nam'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Virgin Islands (British)',
|
|
||||||
label: 'Virgin Islands (British)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Virgin Islands (U.S.)',
|
|
||||||
label: 'Virgin Islands (U.S.)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Wallis and Futuna',
|
|
||||||
label: 'Wallis and Futuna'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Western Sahara*',
|
|
||||||
label: 'Western Sahara*'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Yemen',
|
|
||||||
label: 'Yemen'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Zambia',
|
|
||||||
label: 'Zambia'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'Zimbabwe',
|
|
||||||
label: 'Zimbabwe'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
size="mini"
|
size="mini"
|
||||||
v-model="lineRefer"
|
v-model="lineRefer"
|
||||||
:disabled="!lineTab"
|
:disabled="!lineTab"
|
||||||
|
placeholder=" "
|
||||||
popper-class="common-select"
|
popper-class="common-select"
|
||||||
:popper-append-to-body="false"
|
:popper-append-to-body="false"
|
||||||
@change="referenceSelectChange"
|
@change="referenceSelectChange"
|
||||||
@@ -192,6 +193,9 @@ export default {
|
|||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
this.isNoData = res.data.result.length === 0
|
this.isNoData = res.data.result.length === 0
|
||||||
this.showError = false
|
this.showError = false
|
||||||
|
if (!active) {
|
||||||
|
this.tabs = _.cloneDeep(this.tabsTemplate)
|
||||||
|
}
|
||||||
if (this.isNoData) {
|
if (this.isNoData) {
|
||||||
this.lineTab = ''
|
this.lineTab = ''
|
||||||
this.tabs = _.cloneDeep(this.tabsTemplate)
|
this.tabs = _.cloneDeep(this.tabsTemplate)
|
||||||
@@ -464,8 +468,7 @@ export default {
|
|||||||
newData.push(obj)
|
newData.push(obj)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (data && data.length > 0) {
|
||||||
if (data !== undefined && data.length > 0) {
|
|
||||||
newData.forEach((item) => {
|
newData.forEach((item) => {
|
||||||
item.type = getLineType(item.type)
|
item.type = getLineType(item.type)
|
||||||
if (item.type === val) {
|
if (item.type === val) {
|
||||||
@@ -478,6 +481,24 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
lineData.splice(0, 1)
|
lineData.splice(0, 1)
|
||||||
|
// TODO 下面的逻辑是判断total曲线的尾部数据,从尾往前数0值的个数,若个数大于0,所有曲线都从尾部去掉相同数量的点,最多4个
|
||||||
|
const totalData = lineData[0]
|
||||||
|
if (_.get(totalData, 'values', []).length > 4) {
|
||||||
|
let count = 0
|
||||||
|
for (let i = totalData.values.length - 1; i >= totalData.values.length - 4; i--) {
|
||||||
|
if (totalData.values[i].length > 1 && totalData.values[i][1] === 0) {
|
||||||
|
count++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count > 0) {
|
||||||
|
lineData.forEach(l => {
|
||||||
|
l.values.splice(l.values.length - count, count)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (val === 'Sessions/s') {
|
if (val === 'Sessions/s') {
|
||||||
const tabs = _.cloneDeep(this.tabsTemplate)
|
const tabs = _.cloneDeep(this.tabsTemplate)
|
||||||
lineData.forEach((d, i) => {
|
lineData.forEach((d, i) => {
|
||||||
@@ -495,6 +516,7 @@ export default {
|
|||||||
})
|
})
|
||||||
this.tabs = tabs
|
this.tabs = tabs
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
this.lineRefer = 'Average'
|
||||||
this.echartsInit(this.tabs, true)
|
this.echartsInit(this.tabs, true)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -512,7 +534,7 @@ export default {
|
|||||||
const self = this
|
const self = this
|
||||||
tabs.forEach(e => {
|
tabs.forEach(e => {
|
||||||
e.unitType = type
|
e.unitType = type
|
||||||
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
|
if (e.name !== 'network.total' && parseFloat(e.analysis.max) === 0) {
|
||||||
e.show = false
|
e.show = false
|
||||||
num += 1
|
num += 1
|
||||||
} else {
|
} else {
|
||||||
@@ -522,13 +544,18 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.lineTab === e.class) {
|
if (self.lineTab === e.class) {
|
||||||
if (parseFloat(e.analysis.avg) <= 0) {
|
if (parseFloat(e.analysis.max) <= 0) {
|
||||||
self.lineTab = ''
|
self.lineTab = ''
|
||||||
self.lineRefer = ''
|
self.lineRefer = ''
|
||||||
self.init()
|
// self.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const emptyData = tabs.filter(d => parseFloat(d.analysis.max) === 0)
|
||||||
|
this.isNoData = emptyData.length === tabs.length
|
||||||
|
if (this.isNoData) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
this.tabs = tabs
|
this.tabs = tabs
|
||||||
if (num === 5) {
|
if (num === 5) {
|
||||||
tabs[0].invertTab = false
|
tabs[0].invertTab = false
|
||||||
|
|||||||
@@ -379,12 +379,25 @@ export default {
|
|||||||
timeFilter: {
|
timeFilter: {
|
||||||
handler (n) {
|
handler (n) {
|
||||||
const queryParams = this.getQueryParams()
|
const queryParams = this.getQueryParams()
|
||||||
this.changeUrlTabState()
|
|
||||||
this.getChartData(queryParams)
|
this.getChartData(queryParams)
|
||||||
|
this.changeUrlTabState()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
metric (n) {
|
metric (n) {
|
||||||
this.changeMetric()
|
this.changeMetric()
|
||||||
|
},
|
||||||
|
scoreBaseState (n) {
|
||||||
|
if (n && Object.keys(_.get(this.tableData, '[0].scoreGroup', {})).length >= 5) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tableData: {
|
||||||
|
deep: true,
|
||||||
|
handler (n) {
|
||||||
|
if (Object.keys(_.get(n, '[0].scoreGroup', {})).length >= 5 && this.scoreBaseState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -399,6 +412,9 @@ export default {
|
|||||||
className = 'tab-table tab-table__no-bottom'
|
className = 'tab-table tab-table__no-bottom'
|
||||||
}
|
}
|
||||||
return className
|
return className
|
||||||
|
},
|
||||||
|
scoreBaseState () {
|
||||||
|
return this.$store.getters.scoreBaseReady
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mixins: [chartMixin],
|
mixins: [chartMixin],
|
||||||
@@ -468,12 +484,12 @@ export default {
|
|||||||
return excludeName.indexOf(title.name) > -1 ? false : 'custom'
|
return excludeName.indexOf(title.name) > -1 ? false : 'custom'
|
||||||
},
|
},
|
||||||
searchColumnWidth (columnType) {
|
searchColumnWidth (columnType) {
|
||||||
let checkedGroup = this.customTableTitles.filter(item => item.checked)
|
const checkedGroup = this.customTableTitles.filter(item => item.checked)
|
||||||
let checkedNum = checkedGroup.length
|
const checkedNum = checkedGroup.length
|
||||||
if (columnType === 'dillDown') {
|
if (columnType === 'dillDown') {
|
||||||
if(checkedNum === 1){
|
if (checkedNum === 1) {
|
||||||
return 'auto'
|
return 'auto'
|
||||||
}else if(checkedNum > 1){
|
} else if (checkedNum > 1) {
|
||||||
return '217px'
|
return '217px'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -501,7 +517,7 @@ export default {
|
|||||||
name: this.dropDownValue ? this.dropDownValue : ''
|
name: this.dropDownValue ? this.dropDownValue : ''
|
||||||
}
|
}
|
||||||
let url = curTableInCode.url.drilldownList
|
let url = curTableInCode.url.drilldownList
|
||||||
if(this.isDrilldown() || this.tableType === fromRoute.linkMonitor){
|
if (this.isDrilldown() || this.tableType === fromRoute.linkMonitor) {
|
||||||
url = curTableInCode.url.relationTabDrilldownList
|
url = curTableInCode.url.relationTabDrilldownList
|
||||||
const condition = this.getQueryCondition()
|
const condition = this.getQueryCondition()
|
||||||
if (condition) {
|
if (condition) {
|
||||||
@@ -601,8 +617,8 @@ export default {
|
|||||||
this.curPageNum = 1
|
this.curPageNum = 1
|
||||||
this.initDropdownList(prop)
|
this.initDropdownList(prop)
|
||||||
},
|
},
|
||||||
scrollList (prop,tabProp) {
|
scrollList (prop, tabProp) {
|
||||||
const obj = document.getElementById('tabSearchSelectDropdown'+tabProp)
|
const obj = document.getElementById('tabSearchSelectDropdown' + tabProp)
|
||||||
if ((obj.scrollTop + obj.clientHeight === obj.scrollHeight) && obj.scrollHeight !== 0) {
|
if ((obj.scrollTop + obj.clientHeight === obj.scrollHeight) && obj.scrollHeight !== 0) {
|
||||||
this.initDropdownList(prop)
|
this.initDropdownList(prop)
|
||||||
}
|
}
|
||||||
@@ -1038,12 +1054,12 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
item.scoreGroup[self.columnNameGroup[tableColumn.prop]] = 0
|
item.scoreGroup[self.columnNameGroup[tableColumn.prop]] = 0
|
||||||
}
|
}
|
||||||
if (Object.keys(item.scoreGroup).length >= 5) {
|
/* if (Object.keys(item.scoreGroup).length >= 5) {
|
||||||
item.score = computeScore(item.scoreGroup)
|
item.score = computeScore(item.scoreGroup)
|
||||||
if (!_.isNumber(item.score)) {
|
if (!_.isNumber(item.score)) {
|
||||||
item.score = '-'
|
item.score = '-'
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
tableColumn.showError = true
|
tableColumn.showError = true
|
||||||
@@ -2223,6 +2239,18 @@ export default {
|
|||||||
this.orderBy = 'sessions'
|
this.orderBy = 'sessions'
|
||||||
this.metricUnit = 'sessions'
|
this.metricUnit = 'sessions'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
handleScoreData () {
|
||||||
|
this.tableData.forEach(t => {
|
||||||
|
const data = {
|
||||||
|
establishLatencyMs: t.scoreGroup ? t.scoreGroup.establishLatencyMs : null,
|
||||||
|
httpResponseLatency: t.scoreGroup ? t.scoreGroup.httpResponseLatency : null,
|
||||||
|
sslConLatency: t.scoreGroup ? t.scoreGroup.sslConLatency : null,
|
||||||
|
tcpLostlenPercent: t.scoreGroup ? t.scoreGroup.tcpLostlenPercent : null,
|
||||||
|
pktRetransPercent: t.scoreGroup ? t.scoreGroup.pktRetransPercent : null
|
||||||
|
}
|
||||||
|
t.score = computeScore(data, this.$store.getters.getScoreBase)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted () {
|
async mounted () {
|
||||||
|
|||||||
@@ -172,7 +172,8 @@ export default {
|
|||||||
curTabState: curTabState,
|
curTabState: curTabState,
|
||||||
urlChangeParams: {},
|
urlChangeParams: {},
|
||||||
showError: false,
|
showError: false,
|
||||||
errorMsg: ''
|
errorMsg: '',
|
||||||
|
scoreDataState: false // 评分数据是否加载完成
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@@ -185,6 +186,21 @@ export default {
|
|||||||
handler () {
|
handler () {
|
||||||
this.init()
|
this.init()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
scoreBaseState (n) {
|
||||||
|
if (n && this.scoreDataState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scoreDataState (n) {
|
||||||
|
if (n && this.scoreBaseState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
scoreBaseState () {
|
||||||
|
return this.$store.getters.scoreBaseReady
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -197,6 +213,7 @@ export default {
|
|||||||
const currentTrafficRequest = axios.get(api.npm.overview.appTrafficAnalysis, { params: { ...params, cycle: 0 } })
|
const currentTrafficRequest = axios.get(api.npm.overview.appTrafficAnalysis, { params: { ...params, cycle: 0 } })
|
||||||
const lastCycleTrafficRequest = axios.get(api.npm.overview.appTrafficAnalysis, { params: { ...params, cycle: 1 } })
|
const lastCycleTrafficRequest = axios.get(api.npm.overview.appTrafficAnalysis, { params: { ...params, cycle: 1 } })
|
||||||
this.toggleLoading(true)
|
this.toggleLoading(true)
|
||||||
|
this.scoreDataState = false
|
||||||
Promise.all([currentTrafficRequest, lastCycleTrafficRequest]).then(res => {
|
Promise.all([currentTrafficRequest, lastCycleTrafficRequest]).then(res => {
|
||||||
if (res[0].status === 200 && res[1].status === 200) {
|
if (res[0].status === 200 && res[1].status === 200) {
|
||||||
this.showError = false
|
this.showError = false
|
||||||
@@ -239,6 +256,9 @@ export default {
|
|||||||
t[keyPre[i] + 'Score'] = r.data.data.result.find(d => d.appSubcategory === t.appSubcategory)
|
t[keyPre[i] + 'Score'] = r.data.data.result.find(d => d.appSubcategory === t.appSubcategory)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
tableData.forEach(t => {
|
||||||
|
t[keyPre[i] + 'Score'] = null
|
||||||
|
})
|
||||||
this.showError = true
|
this.showError = true
|
||||||
msg = msg + ',' + r.data.data.message
|
msg = msg + ',' + r.data.data.message
|
||||||
if (msg.indexOf(',') === 0) {
|
if (msg.indexOf(',') === 0) {
|
||||||
@@ -250,7 +270,7 @@ export default {
|
|||||||
this.errorMsg = msg
|
this.errorMsg = msg
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
tableData.forEach(t => {
|
/* tableData.forEach(t => {
|
||||||
const data = {
|
const data = {
|
||||||
establishLatencyMs: t.tcpScore ? t.tcpScore.establishLatencyMs : null,
|
establishLatencyMs: t.tcpScore ? t.tcpScore.establishLatencyMs : null,
|
||||||
httpResponseLatency: t.httpScore ? t.httpScore.httpResponseLatency : null,
|
httpResponseLatency: t.httpScore ? t.httpScore.httpResponseLatency : null,
|
||||||
@@ -259,10 +279,11 @@ export default {
|
|||||||
pktRetransPercent: t.packetRetransScore ? t.packetRetransScore.pktRetransPercent : null
|
pktRetransPercent: t.packetRetransScore ? t.packetRetransScore.pktRetransPercent : null
|
||||||
}
|
}
|
||||||
t.score = computeScore(data)
|
t.score = computeScore(data)
|
||||||
})
|
}) */
|
||||||
this.tableData = tableData
|
this.tableData = tableData
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.toggleLoading(false)
|
this.toggleLoading(false)
|
||||||
|
this.scoreDataState = true
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.tableData = []
|
this.tableData = []
|
||||||
@@ -382,6 +403,18 @@ export default {
|
|||||||
overwriteUrl(newUrl)
|
overwriteUrl(newUrl)
|
||||||
}
|
}
|
||||||
this.urlChangeParams = {}
|
this.urlChangeParams = {}
|
||||||
|
},
|
||||||
|
handleScoreData () {
|
||||||
|
this.tableData.forEach(t => {
|
||||||
|
const data = {
|
||||||
|
establishLatencyMs: t.tcpScore ? t.tcpScore.establishLatencyMs : null,
|
||||||
|
httpResponseLatency: t.httpScore ? t.httpScore.httpResponseLatency : null,
|
||||||
|
sslConLatency: t.sslScore ? t.sslScore.sslConLatency : null,
|
||||||
|
tcpLostlenPercent: t.tcpLostScore ? t.tcpLostScore.tcpLostlenPercent : null,
|
||||||
|
pktRetransPercent: t.packetRetransScore ? t.packetRetransScore.pktRetransPercent : null
|
||||||
|
}
|
||||||
|
t.score = computeScore(data, this.$store.getters.getScoreBase)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="npm-header-body" v-for="(item, index) in chartData" :key=index>
|
<div class="npm-header-body" v-for="(item, index) in chartData" :key=index>
|
||||||
<div class="npm-header-body-severity">
|
<div class="npm-header-body-severity">
|
||||||
<div class="npm-header-body-severity-icon" :class="item.eventSeverity" :test-id="`icon${index}`"></div>
|
<div class="npm-header-body-severity-icon" :class="item.eventSeverity" :test-id="`icon${index}`"></div>
|
||||||
<div class="npm-header-body-severity-value" :test-id="`severity${index}`">{{item.eventSeverity}}</div>
|
<div class="npm-header-body-severity-value" :test-id="`severity${index}`">{{ $t(item.eventSeverity) }}</div>
|
||||||
</div>
|
</div>
|
||||||
<chart-error v-if="showError" tooltip :content="errorMsg" />
|
<chart-error v-if="showError" tooltip :content="errorMsg" />
|
||||||
<div v-else class="npm-header-body-total" :test-id="`total${index}`">{{item.count}}</div>
|
<div v-else class="npm-header-body-total" :test-id="`total${index}`">{{item.count}}</div>
|
||||||
@@ -45,7 +45,7 @@ export default {
|
|||||||
endTime: this.timeFilter && this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : '',
|
endTime: this.timeFilter && this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : '',
|
||||||
type: this.type
|
type: this.type
|
||||||
}
|
}
|
||||||
/*this.toggleLoading(true)
|
/* this.toggleLoading(true)
|
||||||
axios.get(api.npm.events.list, { params: params }).then(response => {
|
axios.get(api.npm.events.list, { params: params }).then(response => {
|
||||||
const res = response.data
|
const res = response.data
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
@@ -69,7 +69,7 @@ export default {
|
|||||||
this.errorMsg = this.errorMsgHandler(e)
|
this.errorMsg = this.errorMsgHandler(e)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.toggleLoading(false)
|
this.toggleLoading(false)
|
||||||
})*/
|
}) */
|
||||||
this.toggleLoading(false)
|
this.toggleLoading(false)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,21 +43,38 @@ export default {
|
|||||||
trafficDirection: 'Server',
|
trafficDirection: 'Server',
|
||||||
curTabState: curTabState,
|
curTabState: curTabState,
|
||||||
showError: false,
|
showError: false,
|
||||||
errorMsg: ''
|
errorMsg: '',
|
||||||
|
scoreDataState: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mixins: [chartMixin],
|
mixins: [chartMixin],
|
||||||
|
computed: {
|
||||||
|
scoreBaseState () {
|
||||||
|
return this.$store.getters.scoreBaseReady
|
||||||
|
}
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
timeFilter: {
|
timeFilter: {
|
||||||
handler () {
|
handler () {
|
||||||
this.loadAm4ChartMap(this.polygonSeries, this.worldImageSeries)
|
this.loadAm4ChartMap(this.polygonSeries, this.worldImageSeries)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
scoreBaseState (n) {
|
||||||
|
if (n && this.scoreDataState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scoreDataState (n) {
|
||||||
|
if (n && this.scoreBaseState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async initMap () {
|
async initMap () {
|
||||||
// 初始化插件
|
// 初始化插件
|
||||||
this.toggleLoading(true)
|
this.toggleLoading(true)
|
||||||
|
this.scoreDataState = false // 重置评分数据状态
|
||||||
const geoData = await getGeoData(storageKey.iso36112WorldLow)
|
const geoData = await getGeoData(storageKey.iso36112WorldLow)
|
||||||
const chart = am4Core.create('npmDrillDownMap', am4Maps.MapChart)
|
const chart = am4Core.create('npmDrillDownMap', am4Maps.MapChart)
|
||||||
chart.geodata = geoData
|
chart.geodata = geoData
|
||||||
@@ -81,6 +98,7 @@ export default {
|
|||||||
// 清除数据
|
// 清除数据
|
||||||
// polygonSeries.data.splice(0)
|
// polygonSeries.data.splice(0)
|
||||||
this.toggleLoading(true)
|
this.toggleLoading(true)
|
||||||
|
this.scoreDataState = false // 重置评分数据状态
|
||||||
// 清除legend
|
// 清除legend
|
||||||
this.myChart.children.each((s, i) => {
|
this.myChart.children.each((s, i) => {
|
||||||
if (s && s.className !== 'Container') {
|
if (s && s.className !== 'Container') {
|
||||||
@@ -140,10 +158,11 @@ export default {
|
|||||||
tcpLostlenPercent: valueToRangeValue(data.tcpLostlenPercent, unitTypes.percent).join(' '),
|
tcpLostlenPercent: valueToRangeValue(data.tcpLostlenPercent, unitTypes.percent).join(' '),
|
||||||
pktRetransPercent: valueToRangeValue(data.pktRetransPercent, unitTypes.percent).join(' ')
|
pktRetransPercent: valueToRangeValue(data.pktRetransPercent, unitTypes.percent).join(' ')
|
||||||
}
|
}
|
||||||
t.tooltip.data.score = computeScore(data)
|
t.performanceData = data
|
||||||
|
/* t.tooltip.data.score = computeScore(data)
|
||||||
if (t.tooltip.data.score === '-') {
|
if (t.tooltip.data.score === '-') {
|
||||||
t.tooltip.data.score = ''
|
t.tooltip.data.score = ''
|
||||||
}
|
} */
|
||||||
t.tooltip.data.total = valueToRangeValue(t.totalBitsRate, unitTypes.bps).join(' ')
|
t.tooltip.data.total = valueToRangeValue(t.totalBitsRate, unitTypes.bps).join(' ')
|
||||||
t.tooltip.data.inbound = valueToRangeValue(t.inboundBitsRate, unitTypes.bps).join(' ')
|
t.tooltip.data.inbound = valueToRangeValue(t.inboundBitsRate, unitTypes.bps).join(' ')
|
||||||
t.tooltip.data.outbound = valueToRangeValue(t.outboundBitsRate, unitTypes.bps).join(' ')
|
t.tooltip.data.outbound = valueToRangeValue(t.outboundBitsRate, unitTypes.bps).join(' ')
|
||||||
@@ -161,6 +180,7 @@ export default {
|
|||||||
sslConLatency: this.$t('networkAppPerformance.sslResponseLatency')
|
sslConLatency: this.$t('networkAppPerformance.sslResponseLatency')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.scoreDataState = true
|
||||||
this.loadMarkerData(imageSeries, mapData)
|
this.loadMarkerData(imageSeries, mapData)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -180,14 +200,10 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
loadMarkerData (imageSeries, data) {
|
loadMarkerData (imageSeries, data) {
|
||||||
const _data = data.filter(d => d.tooltip.data.score || d.tooltip.data.score === 0)
|
imageSeries.data = data.map(r => ({
|
||||||
imageSeries.data = _data.map(r => ({
|
|
||||||
...r,
|
...r,
|
||||||
score: r.tooltip.data.score,
|
|
||||||
name: r.superAdminArea || r.countryRegion,
|
name: r.superAdminArea || r.countryRegion,
|
||||||
id: r.serverId,
|
id: r.serverId
|
||||||
color: this.scoreColor(r.tooltip.data.score),
|
|
||||||
border: this.scoreColor(r.tooltip.data.score)
|
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
scoreColor (score) {
|
scoreColor (score) {
|
||||||
@@ -281,6 +297,9 @@ export default {
|
|||||||
imageTemplate.adapter.add('longitude', function (longitude, target) {
|
imageTemplate.adapter.add('longitude', function (longitude, target) {
|
||||||
const polygon = polygonSeries.getPolygonById(target.dataItem.dataContext.id)
|
const polygon = polygonSeries.getPolygonById(target.dataItem.dataContext.id)
|
||||||
if (polygon) {
|
if (polygon) {
|
||||||
|
if (target.dataItem.dataContext.id === 'RU') {
|
||||||
|
return 90
|
||||||
|
}
|
||||||
return polygon.visualLongitude
|
return polygon.visualLongitude
|
||||||
}
|
}
|
||||||
return longitude
|
return longitude
|
||||||
@@ -307,6 +326,22 @@ export default {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return imageSeries
|
return imageSeries
|
||||||
|
},
|
||||||
|
handleScoreData () {
|
||||||
|
const imageSeries = this.location ? this.countryImageSeries : this.worldImageSeries
|
||||||
|
imageSeries.data = imageSeries.data.map(d => {
|
||||||
|
let score = computeScore(d.performanceData, this.$store.getters.getScoreBase)
|
||||||
|
if (score === '-') {
|
||||||
|
score = ''
|
||||||
|
}
|
||||||
|
d.tooltip.data.score = score
|
||||||
|
return {
|
||||||
|
...d,
|
||||||
|
score,
|
||||||
|
color: this.scoreColor(score),
|
||||||
|
border: this.scoreColor(score)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
|||||||
@@ -324,9 +324,15 @@ export default {
|
|||||||
case 5:
|
case 5:
|
||||||
return api.npm.location.packetsRetrains
|
return api.npm.location.packetsRetrains
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
initI18n () {
|
||||||
|
dataForNpmLine.chartOptionLineData.forEach(item => {
|
||||||
|
item.legend = this.$t(item.legend)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
this.initI18n()
|
||||||
if (this.chart) {
|
if (this.chart) {
|
||||||
this.chartData = _.cloneDeep(this.chart)
|
this.chartData = _.cloneDeep(this.chart)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
v-model="trafficDirection"
|
v-model="trafficDirection"
|
||||||
class="map-select map-select__direction"
|
class="map-select map-select__direction"
|
||||||
popper-class="map-select-down"
|
popper-class="map-select-down"
|
||||||
|
placeholder=" "
|
||||||
:popper-append-to-body="false"
|
:popper-append-to-body="false"
|
||||||
>
|
>
|
||||||
<el-option value="Server">Server</el-option>
|
<el-option value="Server">Server</el-option>
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
:popper-append-to-body="false"
|
:popper-append-to-body="false"
|
||||||
>
|
>
|
||||||
<template #prefix><i class="cn-icon cn-icon-location" style="color: #575757;"></i></template>
|
<template #prefix><i class="cn-icon cn-icon-location" style="color: #575757;"></i></template>
|
||||||
<el-option v-for="(country, index) in locationOptions" :key="index" :value="country.value">{{country.label}}</el-option>
|
<el-option v-for="country in showLocationOptions" :key="country" :value="country">{{country}}</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="map-legend">
|
<div class="map-legend">
|
||||||
@@ -50,8 +51,7 @@ import { shallowRef } from 'vue'
|
|||||||
import * as am4Core from '@amcharts/amcharts4/core'
|
import * as am4Core from '@amcharts/amcharts4/core'
|
||||||
import * as am4Maps from '@amcharts/amcharts4/maps'
|
import * as am4Maps from '@amcharts/amcharts4/maps'
|
||||||
import { computeScore, getGeoData } from '@/utils/tools'
|
import { computeScore, getGeoData } from '@/utils/tools'
|
||||||
import { countryNameIdMapping, storageKey, unitTypes } from '@/utils/constants'
|
import { countryNameIdMapping, storageKey, unitTypes, iso36112 } from '@/utils/constants'
|
||||||
import locationOptions from '@/views/charts2/charts/locationOptions'
|
|
||||||
import { valueToRangeValue } from '@/utils/unit-convert'
|
import { valueToRangeValue } from '@/utils/unit-convert'
|
||||||
import { getSecond } from '@/utils/date-util'
|
import { getSecond } from '@/utils/date-util'
|
||||||
import { api } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
@@ -65,7 +65,7 @@ export default {
|
|||||||
components: { ChartError },
|
components: { ChartError },
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
locationOptions,
|
showLocationOptions: [],
|
||||||
myChart: null,
|
myChart: null,
|
||||||
polygonSeries: null,
|
polygonSeries: null,
|
||||||
countrySeries: null,
|
countrySeries: null,
|
||||||
@@ -75,14 +75,21 @@ export default {
|
|||||||
trafficDirection: 'Server',
|
trafficDirection: 'Server',
|
||||||
location: '',
|
location: '',
|
||||||
showError: false,
|
showError: false,
|
||||||
errorMsg: ''
|
errorMsg: '',
|
||||||
|
scoreDataState: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mixins: [chartMixin],
|
mixins: [chartMixin],
|
||||||
|
computed: {
|
||||||
|
scoreBaseState () {
|
||||||
|
return this.$store.getters.scoreBaseReady
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async initMap () {
|
async initMap () {
|
||||||
// 初始化插件
|
// 初始化插件
|
||||||
this.toggleLoading(true)
|
this.toggleLoading(true)
|
||||||
|
this.scoreDataState = false // 重置评分数据状态
|
||||||
const geoData = await getGeoData(storageKey.iso36112WorldLow)
|
const geoData = await getGeoData(storageKey.iso36112WorldLow)
|
||||||
const chart = am4Core.create('npmMap', am4Maps.MapChart)
|
const chart = am4Core.create('npmMap', am4Maps.MapChart)
|
||||||
chart.geodata = geoData
|
chart.geodata = geoData
|
||||||
@@ -101,14 +108,13 @@ export default {
|
|||||||
this.worldImageSeries.mapImages.template.events.on('hit', async ev => {
|
this.worldImageSeries.mapImages.template.events.on('hit', async ev => {
|
||||||
this.$store.commit('setNpmLocationCountry', ev.target.dataItem.dataContext.name)
|
this.$store.commit('setNpmLocationCountry', ev.target.dataItem.dataContext.name)
|
||||||
this.location = ev.target.dataItem.dataContext.name
|
this.location = ev.target.dataItem.dataContext.name
|
||||||
const countryId = ev.target.dataItem.dataContext.id
|
|
||||||
ev.target.isHover = false
|
ev.target.isHover = false
|
||||||
await this.drill(countryId)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
loadAm4ChartMap (polygonSeries, imageSeries) {
|
loadAm4ChartMap (polygonSeries, imageSeries) {
|
||||||
try {
|
try {
|
||||||
this.toggleLoading(true)
|
this.toggleLoading(true)
|
||||||
|
this.scoreDataState = false // 重置评分数据状态
|
||||||
// 清除legend
|
// 清除legend
|
||||||
this.myChart.children.each((s, i) => {
|
this.myChart.children.each((s, i) => {
|
||||||
if (s && s.className !== 'Container') {
|
if (s && s.className !== 'Container') {
|
||||||
@@ -172,10 +178,11 @@ export default {
|
|||||||
tcpLostlenPercent: valueToRangeValue(data.tcpLostlenPercent, unitTypes.percent).join(' '),
|
tcpLostlenPercent: valueToRangeValue(data.tcpLostlenPercent, unitTypes.percent).join(' '),
|
||||||
pktRetransPercent: valueToRangeValue(data.pktRetransPercent, unitTypes.percent).join(' ')
|
pktRetransPercent: valueToRangeValue(data.pktRetransPercent, unitTypes.percent).join(' ')
|
||||||
}
|
}
|
||||||
t.tooltip.data.score = computeScore(data)
|
t.performanceData = data
|
||||||
|
/* t.tooltip.data.score = computeScore(data)
|
||||||
if (t.tooltip.data.score === '-') {
|
if (t.tooltip.data.score === '-') {
|
||||||
t.tooltip.data.score = ''
|
t.tooltip.data.score = ''
|
||||||
}
|
} */
|
||||||
t.tooltip.data.total = valueToRangeValue(t.totalBitsRate, unitTypes.bps).join(' ')
|
t.tooltip.data.total = valueToRangeValue(t.totalBitsRate, unitTypes.bps).join(' ')
|
||||||
t.tooltip.data.inbound = valueToRangeValue(t.inboundBitsRate, unitTypes.bps).join(' ')
|
t.tooltip.data.inbound = valueToRangeValue(t.inboundBitsRate, unitTypes.bps).join(' ')
|
||||||
t.tooltip.data.outbound = valueToRangeValue(t.outboundBitsRate, unitTypes.bps).join(' ')
|
t.tooltip.data.outbound = valueToRangeValue(t.outboundBitsRate, unitTypes.bps).join(' ')
|
||||||
@@ -193,6 +200,7 @@ export default {
|
|||||||
sslConLatency: this.$t('networkAppPerformance.sslResponseLatency')
|
sslConLatency: this.$t('networkAppPerformance.sslResponseLatency')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.scoreDataState = true
|
||||||
this.loadMarkerData(imageSeries, mapData)
|
this.loadMarkerData(imageSeries, mapData)
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
this.showError = true
|
this.showError = true
|
||||||
@@ -219,15 +227,18 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
loadMarkerData (imageSeries, data) {
|
loadMarkerData (imageSeries, data) {
|
||||||
const _data = data.filter(d => d.tooltip.data.score || d.tooltip.data.score === 0)
|
imageSeries.data = data.map(r => ({
|
||||||
imageSeries.data = _data.map(r => ({
|
|
||||||
...r,
|
...r,
|
||||||
score: r.tooltip.data.score,
|
|
||||||
name: r.superAdminArea || r.countryRegion,
|
name: r.superAdminArea || r.countryRegion,
|
||||||
id: r.serverId,
|
id: r.serverId
|
||||||
color: this.scoreColor(r.tooltip.data.score),
|
|
||||||
border: this.scoreColor(r.tooltip.data.score)
|
|
||||||
}))
|
}))
|
||||||
|
if (!this.location) {
|
||||||
|
this.filterLocationOptions(data)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
filterLocationOptions (data) {
|
||||||
|
const showLocationOptions = Object.keys(countryNameIdMapping).filter(c => data.some(d => d.countryRegion === c))
|
||||||
|
this.showLocationOptions = Array.from(new Set(showLocationOptions))
|
||||||
},
|
},
|
||||||
scoreColor (score) {
|
scoreColor (score) {
|
||||||
if (score >= 0 && score <= 2) {
|
if (score >= 0 && score <= 2) {
|
||||||
@@ -320,6 +331,9 @@ export default {
|
|||||||
imageTemplate.adapter.add('longitude', function (longitude, target) {
|
imageTemplate.adapter.add('longitude', function (longitude, target) {
|
||||||
const polygon = polygonSeries.getPolygonById(target.dataItem.dataContext.id)
|
const polygon = polygonSeries.getPolygonById(target.dataItem.dataContext.id)
|
||||||
if (polygon) {
|
if (polygon) {
|
||||||
|
if (target.dataItem.dataContext.id === 'RU') {
|
||||||
|
return 90
|
||||||
|
}
|
||||||
return polygon.visualLongitude
|
return polygon.visualLongitude
|
||||||
}
|
}
|
||||||
return longitude
|
return longitude
|
||||||
@@ -352,34 +366,55 @@ export default {
|
|||||||
if (countryId) {
|
if (countryId) {
|
||||||
const targetMapObject = this.polygonSeries.getPolygonById(countryId)
|
const targetMapObject = this.polygonSeries.getPolygonById(countryId)
|
||||||
targetMapObject.series.chart.zoomToMapObject(targetMapObject)
|
targetMapObject.series.chart.zoomToMapObject(targetMapObject)
|
||||||
const geoData = await getGeoData(countryId)
|
if (iso36112[countryId]) {
|
||||||
if (geoData) {
|
const geoData = await getGeoData(countryId)
|
||||||
if (!this.countrySeries) {
|
if (geoData) {
|
||||||
this.countrySeries = this.polygonSeriesFactory()
|
if (!this.countrySeries) {
|
||||||
}
|
this.countrySeries = this.polygonSeriesFactory()
|
||||||
if (!this.countryImageSeries) {
|
}
|
||||||
this.countryImageSeries = this.imageSeriesFactory('score', this.countrySeries)
|
if (!this.countryImageSeries) {
|
||||||
}
|
this.countryImageSeries = this.imageSeriesFactory('score', this.countrySeries)
|
||||||
this.countrySeries.geodata = geoData
|
}
|
||||||
this.polygonSeries.hide()
|
this.countrySeries.geodata = geoData
|
||||||
this.worldImageSeries.hide()
|
this.polygonSeries.hide()
|
||||||
this.countrySeries.show()
|
this.worldImageSeries.hide()
|
||||||
this.countryImageSeries.show()
|
this.countrySeries.show()
|
||||||
|
this.countryImageSeries.show()
|
||||||
|
|
||||||
await this.$nextTick(() => {
|
await this.$nextTick(() => {
|
||||||
this.loadAm4ChartMap(this.countrySeries, this.countryImageSeries)
|
this.loadAm4ChartMap(this.countrySeries, this.countryImageSeries)
|
||||||
})
|
})
|
||||||
} else if (!num || num < 3) {
|
} else if (!num || num < 3) {
|
||||||
// 多次测试,最多2次查询不到数据
|
// 多次测试,最多2次查询不到数据
|
||||||
if (!num) {
|
if (!num) {
|
||||||
num = 0
|
num = 0
|
||||||
|
}
|
||||||
|
num++
|
||||||
|
await this.drill(countryId, num)
|
||||||
|
} else {
|
||||||
|
this.$message.warning(this.$t('tip.noDetailMap'))
|
||||||
}
|
}
|
||||||
num++
|
|
||||||
await this.drill(countryId, num)
|
|
||||||
} else {
|
} else {
|
||||||
this.$message.warning(this.$t('tip.noDetailMap'))
|
this.$message.warning(this.$t('tip.noDetailMap'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
handleScoreData () {
|
||||||
|
const imageSeries = this.location ? this.countryImageSeries : this.worldImageSeries
|
||||||
|
imageSeries.data = imageSeries.data.map(d => {
|
||||||
|
let score = computeScore(d.performanceData, this.$store.getters.getScoreBase)
|
||||||
|
if (score === '-') {
|
||||||
|
score = ''
|
||||||
|
}
|
||||||
|
d.tooltip.data.score = score
|
||||||
|
return {
|
||||||
|
...d,
|
||||||
|
score,
|
||||||
|
color: this.scoreColor(score),
|
||||||
|
border: this.scoreColor(score)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// this.myChart.invalidateData()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -419,6 +454,16 @@ export default {
|
|||||||
this.loadAm4ChartMap(this.polygonSeries, this.worldImageSeries)
|
this.loadAm4ChartMap(this.polygonSeries, this.worldImageSeries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
scoreBaseState (n) {
|
||||||
|
if (n && this.scoreDataState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scoreDataState (n) {
|
||||||
|
if (n && this.scoreBaseState) {
|
||||||
|
this.handleScoreData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<el-select
|
<el-select
|
||||||
size="mini"
|
size="mini"
|
||||||
v-model="metricFilter"
|
v-model="metricFilter"
|
||||||
placeholder=""
|
placeholder=" "
|
||||||
popper-class="common-select"
|
popper-class="common-select"
|
||||||
:popper-append-to-body="false"
|
:popper-append-to-body="false"
|
||||||
@change="metricChange"
|
@change="metricChange"
|
||||||
@@ -458,9 +458,21 @@ export default {
|
|||||||
}
|
}
|
||||||
this.$store.commit('setRangeEchartsData', rangeObj)
|
this.$store.commit('setRangeEchartsData', rangeObj)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
initI18n () {
|
||||||
|
dataForNpmTrafficLine.tabs.forEach(item => {
|
||||||
|
item.name = this.$t(item.name)
|
||||||
|
})
|
||||||
|
dataForNpmTrafficLine.npmQuantity.forEach(item => {
|
||||||
|
item.name = this.$t(item.name)
|
||||||
|
})
|
||||||
|
dataForNpmTrafficLine.metricOptions.forEach(item => {
|
||||||
|
item.label = this.$t(item.label)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
this.initI18n()
|
||||||
if (this.chart) {
|
if (this.chart) {
|
||||||
this.chartData = _.cloneDeep(this.chart)
|
this.chartData = _.cloneDeep(this.chart)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ import {
|
|||||||
chartColor3,
|
chartColor3,
|
||||||
chartColor5,
|
chartColor5,
|
||||||
chartColor6,
|
chartColor6,
|
||||||
|
chartColorForBehaviorPattern,
|
||||||
unitTypes
|
unitTypes
|
||||||
} from '@/utils/constants'
|
} from '@/utils/constants'
|
||||||
import unitConvert, { valueToRangeValue } from '@/utils/unit-convert'
|
import unitConvert from '@/utils/unit-convert'
|
||||||
import { axisFormatter } from '@/views/charts/charts/tools'
|
import { axisFormatter } from '@/views/charts/charts/tools'
|
||||||
import { xAxisTimeFormatter, xAxisTimeRich } from '@/utils/date-util'
|
import { xAxisTimeFormatter, xAxisTimeRich } from '@/utils/date-util'
|
||||||
|
|
||||||
@@ -156,6 +157,111 @@ export const pieChartOption3 = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const pieChartOption4 = {
|
||||||
|
color: chartColorForBehaviorPattern,
|
||||||
|
polar: {
|
||||||
|
radius: [30, 225],
|
||||||
|
center: ['400px', '100%']// 为了显示出来半圆底部左侧的边
|
||||||
|
},
|
||||||
|
radiusAxis: {
|
||||||
|
min: 0,
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#d3d3d3',
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#d3d3d3',
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
angleAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: [], // 'a', 'b', 'c', 'd','aa', 'ab', 'ac', 'ad','a', 'b', 'c', 'd','aa', 'ab', 'ac', 'ad'
|
||||||
|
startAngle: 180,
|
||||||
|
// splitNumber: 30,
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
show: true,
|
||||||
|
// alignWithLabel:true,//可以保证刻度线和标签对齐
|
||||||
|
interval: 0, // 强制显示所有标签
|
||||||
|
// hideOverlap:true//从 v5.2.0 开始支持
|
||||||
|
formatter: function (params, index) {
|
||||||
|
if (index === 7) {
|
||||||
|
return params + '\n'
|
||||||
|
} else if (index === 8) {
|
||||||
|
return '\n' + params
|
||||||
|
} else if (index === 15) {
|
||||||
|
return params + '\n'
|
||||||
|
} else {
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
alignWithLabel: true,
|
||||||
|
interval: 0,
|
||||||
|
length: 5
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: ['#e2e5ec'],
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
formatter: function (item) {
|
||||||
|
let str = '<div style="display:flex;flex-direction: row;align-items: center;">'
|
||||||
|
str += '<div style="width: 8px;\n' +
|
||||||
|
' height: 8px;\n' +
|
||||||
|
' margin: 3px 8px 0 0;\n' +
|
||||||
|
' border-radius: 1px;;background:'
|
||||||
|
str += item.color
|
||||||
|
str += ';"></div>'
|
||||||
|
str += item.name + ': ' + unitConvert(item.value, unitTypes.number).join('')
|
||||||
|
str += '</div>'
|
||||||
|
str += '</div>'
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
type: 'bar',
|
||||||
|
data: [], // 8,7,6,5,4,3,2,1,0,0,0,0,0,0,0,0
|
||||||
|
coordinateSystem: 'polar',
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: function (params) {
|
||||||
|
return chartColorForBehaviorPattern[params.dataIndex]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
position: 'middle',
|
||||||
|
formatter: '{b}: {c}'
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
animation: false
|
||||||
|
}
|
||||||
|
|
||||||
export const stackedLineChartOption = {
|
export const stackedLineChartOption = {
|
||||||
color: chartColor3,
|
color: chartColor3,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="detection-filter-case">
|
<div class="detection-filter-case">
|
||||||
<div class="no-data" v-if="isNoData">{{ $t('npm.noData') }}</div>
|
|
||||||
|
|
||||||
<div class="new-detection-filter-title">{{$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">
|
<template v-for="(filter, index) in filterData" :key="index">
|
||||||
<div class="detection-filter" v-show="filter.data.length > 0">
|
<div class="detection-filter" v-show="filter.data.length > 0">
|
||||||
<div class="filter__header" @click="filter.collapse = !filter.collapse">
|
<div class="filter__header" @click="filter.collapse = !filter.collapse">
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
<loading :loading="loading"></loading>
|
<loading :loading="loading"></loading>
|
||||||
<div class="detection-list__content">
|
<div class="detection-list__content">
|
||||||
<div class="detection-list--list">
|
<div class="detection-list--list">
|
||||||
<div class="no-data" v-if="noData">{{ $t('npm.noData') }}</div>
|
<div class="no-data" v-if="myListData.length===0">{{ $t('npm.noData') }}</div>
|
||||||
<div v-if="!isCollapse" @click="collapse" class="cn-detection__shadow new-cn-detection__shadow"></div>
|
<div v-if="!isCollapse" @click="collapse" class="cn-detection__shadow new-cn-detection__shadow"></div>
|
||||||
<detection-row
|
<detection-row
|
||||||
style="margin-bottom: 10px"
|
style="margin-bottom: 10px"
|
||||||
class="detection-border"
|
class="detection-border"
|
||||||
v-for="(data, index) in listData"
|
v-for="(data, index) in myListData"
|
||||||
:detection="data"
|
:detection="data"
|
||||||
:page-type="pageType"
|
:page-type="pageType"
|
||||||
:timeFilter="timeFilter"
|
:timeFilter="timeFilter"
|
||||||
@@ -26,6 +26,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import DetectionRow from '@/views/detections/DetectionRow'
|
import DetectionRow from '@/views/detections/DetectionRow'
|
||||||
import Loading from '@/components/common/Loading'
|
import Loading from '@/components/common/Loading'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { api } from '@/utils/api'
|
||||||
export default {
|
export default {
|
||||||
name: 'DetectionList',
|
name: 'DetectionList',
|
||||||
components: {
|
components: {
|
||||||
@@ -49,7 +51,8 @@ export default {
|
|||||||
collapseIndex: 0,
|
collapseIndex: 0,
|
||||||
tableId: 'detectionList',
|
tableId: 'detectionList',
|
||||||
listDataCopy: [],
|
listDataCopy: [],
|
||||||
noData: false
|
noData: true,
|
||||||
|
myListData: [] // listData的克隆,避免因为修改listData里的malWareName而触发watch监听
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
@@ -60,6 +63,25 @@ export default {
|
|||||||
window.removeEventListener('mousewheel', this.handleScroll)
|
window.removeEventListener('mousewheel', this.handleScroll)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
initData () {
|
||||||
|
this.myListData = []
|
||||||
|
this.listData.forEach((item, i) => {
|
||||||
|
this.myListData.push(this.$_.cloneDeep(item))
|
||||||
|
if (item.eventInfoObj && item.isBuiltin == 1) {
|
||||||
|
axios.get(`${api.detection.securityEvent.detail}/${item.eventInfoObj.ioc_type.toLowerCase()}?resource=${item.eventInfoObj.ioc_value}`).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
if (item.eventType === 'Anonymity') {
|
||||||
|
this.myListData[i].darkweb = this.$_.get(res, 'data.data.darkweb', {}) || {}
|
||||||
|
} else if (item.eventType === 'Command and Control') {
|
||||||
|
this.myListData[i].malware = this.$_.get(res, 'data.data.malware', {}) || {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
switchCollapse (isCollapse, index) {
|
switchCollapse (isCollapse, index) {
|
||||||
this.isCollapse = isCollapse
|
this.isCollapse = isCollapse
|
||||||
this.collapseIndex = index
|
this.collapseIndex = index
|
||||||
@@ -84,15 +106,18 @@ export default {
|
|||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
listData: {
|
listData: {
|
||||||
|
immediate: true,
|
||||||
deep: true,
|
deep: true,
|
||||||
handler (n) {
|
handler (n) {
|
||||||
if (!n || n.length === 0) {
|
if (!n || n.length === 0) {
|
||||||
this.timeout = setTimeout(() => {
|
this.timeout = setTimeout(() => {
|
||||||
this.noData = true
|
this.noData = true
|
||||||
|
this.myListData = []
|
||||||
}, 500)
|
}, 500)
|
||||||
} else {
|
} else {
|
||||||
clearTimeout(this.timeout)
|
clearTimeout(this.timeout)
|
||||||
this.noData = false
|
this.noData = false
|
||||||
|
this.initData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,19 +9,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cn-detection__case">
|
<div class="cn-detection__case">
|
||||||
<div class="cn-detection__icon" :style="`background-color: ${eventSeverityColor[detection.eventSecurity]}`"></div>
|
<div class="cn-detection__icon" :style="`background-color: ${eventSeverityColor[detection.severity]}`"></div>
|
||||||
<div class="cn-detection__row">
|
<div class="cn-detection__row">
|
||||||
<div class="cn-detection__header" v-if="pageType === detectionPageType.securityEvent">
|
<div class="cn-detection__header" v-if="pageType === detectionPageType.securityEvent">
|
||||||
<span
|
<span
|
||||||
class="detection-event-severity-color-block"
|
class="detection-event-severity-color-block"
|
||||||
:style="`background-color: ${eventSeverityColor[detection.eventSeverity]}`">
|
:style="`background-color: ${eventSeverityColor[detection.eventSeverity]}`">
|
||||||
</span>
|
</span>
|
||||||
<span class="detection-event-severity-block">{{ detection.securityType || '-' }}</span>
|
<span class="detection-event-severity-block">{{ detection.eventName || '-' }}</span>
|
||||||
<i class="cn-icon cn-icon-attacker" ></i>{{detection.offenderIp || '-'}}
|
<i class="cn-icon cn-icon-attacker detection-list-icon" ></i>{{detection.offenderIp || '-'}}
|
||||||
<div v-if="detection.domain" class="domain">{{detection.domain}}</div>
|
<div v-if="detection.domain" class="domain">{{detection.domain}}</div>
|
||||||
<span class="line">-------</span>
|
<span class="line">-------</span>
|
||||||
<span class="circle"></span>
|
<span class="circle"></span>
|
||||||
<i class="cn-icon cn-icon-attacked" ></i>{{detection.victimIp || '-'}}
|
<i class="cn-icon cn-icon-attacked detection-list-icon" ></i>{{detection.victimIp || '-'}}
|
||||||
</div>
|
</div>
|
||||||
<div class="cn-detection__header" v-else-if="pageType === detectionPageType.performanceEvent">
|
<div class="cn-detection__header" v-else-if="pageType === detectionPageType.performanceEvent">
|
||||||
<div class="cn-entity__icon"><i :class="iconClass"></i></div>
|
<div class="cn-entity__icon"><i :class="iconClass"></i></div>
|
||||||
@@ -30,10 +30,10 @@
|
|||||||
<div class="cn-detection__body">
|
<div class="cn-detection__body">
|
||||||
<div class="body__basic-info">
|
<div class="body__basic-info">
|
||||||
<div class="basic-info">
|
<div class="basic-info">
|
||||||
<div class="basic-info__item" v-if="detection.eventSecurity">
|
<div class="basic-info__item" v-if="detection.severity">
|
||||||
<i class="cn-icon cn-icon-severity-level"></i>
|
<i class="cn-icon cn-icon-severity-level"></i>
|
||||||
<span>{{$t('detection.list.security')}} : </span>
|
<span>{{$t('detection.list.security')}} : </span>
|
||||||
<span>{{detection.eventSecurity || '-'}}</span>
|
<span>{{detection.severity || '-'}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-info__item" v-if="detection.eventSeverity">
|
<div class="basic-info__item" v-if="detection.eventSeverity">
|
||||||
<i class="cn-icon cn-icon-severity-level"></i>
|
<i class="cn-icon cn-icon-severity-level"></i>
|
||||||
@@ -45,15 +45,15 @@
|
|||||||
<span>{{$t('detections.eventType')}} : </span>
|
<span>{{$t('detections.eventType')}} : </span>
|
||||||
<span>{{detection.eventType || '-'}}</span>
|
<span>{{detection.eventType || '-'}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-info__item" v-if="detection.malwareName">
|
<div class="basic-info__item" v-if="detection.malware">
|
||||||
<i class="cn-icon cn-icon-trojan"></i>
|
<i class="cn-icon cn-icon-trojan"></i>
|
||||||
<span>{{$t('detection.list.malwareName')}} : </span>
|
<span>{{$t('detection.list.malwareName')}} : </span>
|
||||||
<span>{{detection.malwareName || '-'}}</span>
|
<span>{{ $_.get(detection, 'malware.malwareName', '-') || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-info__item" v-if="detection.cryptominingPool">
|
<div class="basic-info__item" v-if="detection.darkweb">
|
||||||
<i class="cn-icon cn-icon-mining-pool"></i>
|
<i class="cn-icon cn-icon-trojan"></i>
|
||||||
<span>{{$t('detection.list.cryptominingPool')}} : </span>
|
<span>{{$t('detection.nodeType')}} : </span>
|
||||||
<span>{{detection.cryptominingPool || '-'}}</span>
|
<span>{{ $_.get(detection, 'darkweb.nodeType', '-') || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-time2"></i>
|
<i class="cn-icon cn-icon-time2"></i>
|
||||||
@@ -63,9 +63,11 @@
|
|||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-duration"></i>
|
<i class="cn-icon cn-icon-duration"></i>
|
||||||
<span>{{$t('overall.duration')}} : </span>
|
<span>{{$t('overall.duration')}} : </span>
|
||||||
<span style="display: inline-block;height: 6px;width: 6px;border-radius: 50%;margin-right: 8px;"
|
<span>
|
||||||
:style="pointColor(detection)"></span>
|
{{ detection.matchTimes || '-'}} {{ $t('detection.list.times') }} /
|
||||||
<span>{{unitConvert(detection.durationMs, 'time', null, null, 0).join(' ') || '-'}}</span>
|
{{unitConvert(parseInt(detection.durationS), 'time', 's', null, 0).join(' ') || '-'}}
|
||||||
|
</span>
|
||||||
|
<div v-if="parseInt(detection.status) === 0" class="margin-l-10 detection-row-active">{{$t('detections.active')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -108,7 +110,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { eventSeverityColor, detectionPageType, entityType } from '@/utils/constants'
|
import { eventSeverityColor, detectionPageType, entityType } from '@/utils/constants'
|
||||||
import { getMillisecond } from '@/utils/date-util'
|
import { getMillisecond, dateFormatByAppearance } from '@/utils/date-util'
|
||||||
import unitConvert from '@/utils/unit-convert'
|
import unitConvert from '@/utils/unit-convert'
|
||||||
import DetectionSecurityEventOverview from '@/views/detections/overview/DetectionSecurityEventOverview'
|
import DetectionSecurityEventOverview from '@/views/detections/overview/DetectionSecurityEventOverview'
|
||||||
import DetectionPerformanceEventIpOverview from '@/views/detections/overview/DetectionPerformanceEventIpOverview'
|
import DetectionPerformanceEventIpOverview from '@/views/detections/overview/DetectionPerformanceEventIpOverview'
|
||||||
@@ -174,9 +176,19 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
isCollapse (newVal) {
|
||||||
|
const newQuery = this.$route.query
|
||||||
|
if (newVal && newQuery.eventId) {
|
||||||
|
delete newQuery.eventId
|
||||||
|
this.reloadUrl(newQuery, 'cleanOldParams')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
unitConvert,
|
unitConvert,
|
||||||
getMillisecond,
|
getMillisecond,
|
||||||
|
dateFormatByAppearance,
|
||||||
/* 切换折叠状态 */
|
/* 切换折叠状态 */
|
||||||
switchCollapse () {
|
switchCollapse () {
|
||||||
this.isCollapse = !this.isCollapse
|
this.isCollapse = !this.isCollapse
|
||||||
@@ -235,3 +247,17 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.detection-row-active {
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 0 7px;
|
||||||
|
background: #E9EFE1;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-family: NotoSansHans-Medium;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #7E9F54;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -5,23 +5,26 @@
|
|||||||
<advanced-search
|
<advanced-search
|
||||||
ref="search"
|
ref="search"
|
||||||
:column-list="columnList[pageType]"
|
:column-list="columnList[pageType]"
|
||||||
:operator-list="operatorList"
|
|
||||||
:connection-list="connectionList"
|
:connection-list="connectionList"
|
||||||
:full-text="false"
|
:default-mode="defaultMode"
|
||||||
class="advanced-search--show-list"
|
class="advanced-search--show-list"
|
||||||
|
:full-text="true"
|
||||||
|
:show-list="showList"
|
||||||
@search="search"
|
@search="search"
|
||||||
></advanced-search>
|
></advanced-search>
|
||||||
</div>
|
</div>
|
||||||
<div class="search-symbol-inline">
|
<!-- <div class="search-symbol-inline">-->
|
||||||
<i class="cn-icon cn-icon-help"></i>
|
<!-- <i class="cn-icon cn-icon-help"></i>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AdvancedSearch from '@/components/advancedSearch/Index'
|
import AdvancedSearch from '@/components/advancedSearch/Index'
|
||||||
import { humpToLine } from '@/utils/tools'
|
import { schemaDetectionSecurity } from '@/utils/static-data'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { ref } from 'vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'DetectionSearch',
|
name: 'DetectionSearch',
|
||||||
props: {
|
props: {
|
||||||
@@ -33,74 +36,7 @@ export default {
|
|||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
columnList: {
|
columnList: {
|
||||||
securityEvent: [
|
securityEvent: schemaDetectionSecurity,
|
||||||
{
|
|
||||||
name: 'event_severity',
|
|
||||||
type: 'string',
|
|
||||||
// label: 'Event severity',
|
|
||||||
label: 'event_severity',
|
|
||||||
doc: {
|
|
||||||
constraints: {
|
|
||||||
operator_functions: '=,in'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'security_type',
|
|
||||||
type: 'string',
|
|
||||||
// label: 'Security type',
|
|
||||||
label: 'security_type',
|
|
||||||
doc: {
|
|
||||||
constraints: {
|
|
||||||
operator_functions: '=,in'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'victim_ip',
|
|
||||||
type: 'string',
|
|
||||||
// label: 'Victim IP'
|
|
||||||
label: 'victim_ip',
|
|
||||||
doc: {
|
|
||||||
constraints: {
|
|
||||||
operator_functions: '=,in'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'victim_location_country',
|
|
||||||
type: 'string',
|
|
||||||
// label: 'Victim location'
|
|
||||||
label: 'victim_location_country',
|
|
||||||
doc: {
|
|
||||||
constraints: {
|
|
||||||
operator_functions: '=,in'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'offender_ip',
|
|
||||||
type: 'string',
|
|
||||||
// label: 'Offender IP'
|
|
||||||
label: 'offender_ip',
|
|
||||||
doc: {
|
|
||||||
constraints: {
|
|
||||||
operator_functions: '=,in'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'offender_location_country',
|
|
||||||
type: 'string',
|
|
||||||
// label: 'Offender location'
|
|
||||||
label: 'offender_location_country',
|
|
||||||
doc: {
|
|
||||||
constraints: {
|
|
||||||
operator_functions: '=,in'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
performanceEvent: [
|
performanceEvent: [
|
||||||
{
|
{
|
||||||
name: 'event_severity',
|
name: 'event_severity',
|
||||||
@@ -113,17 +49,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'event_type',
|
|
||||||
type: 'string',
|
|
||||||
// label: 'Event type'
|
|
||||||
label: 'event_type',
|
|
||||||
doc: {
|
|
||||||
constraints: {
|
|
||||||
operator_functions: '=,in'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'app_name',
|
name: 'app_name',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@@ -169,10 +94,19 @@ export default {
|
|||||||
value: 'OR',
|
value: 'OR',
|
||||||
label: 'OR'
|
label: 'OR'
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
showList: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['search'],
|
emits: ['search'],
|
||||||
|
setup () {
|
||||||
|
// 根据地址栏添加mode,即text和tag模式,默认text
|
||||||
|
const { query } = useRoute()
|
||||||
|
const defaultMode = ref(query.mode || 'text')
|
||||||
|
return {
|
||||||
|
defaultMode
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/* search (metaList, formatSql) {
|
/* search (metaList, formatSql) {
|
||||||
let sql = formatSql
|
let sql = formatSql
|
||||||
@@ -196,7 +130,7 @@ export default {
|
|||||||
if (params.oldValue.length === 0 && params.newValue.length === 1) {
|
if (params.oldValue.length === 0 && params.newValue.length === 1) {
|
||||||
// 1.参数值数量从0到1,直接addParams
|
// 1.参数值数量从0到1,直接addParams
|
||||||
const p = {
|
const p = {
|
||||||
column: humpToLine(params.column),
|
column: params.column,
|
||||||
operator: '=',
|
operator: '=',
|
||||||
value: params.newValue
|
value: params.newValue
|
||||||
}
|
}
|
||||||
@@ -204,7 +138,7 @@ export default {
|
|||||||
} else if (params.oldValue.length === 1 && params.newValue.length === 0) {
|
} else if (params.oldValue.length === 1 && params.newValue.length === 0) {
|
||||||
// 2.参数值数量从1到0,直接removeParams
|
// 2.参数值数量从1到0,直接removeParams
|
||||||
const p = {
|
const p = {
|
||||||
column: humpToLine(params.column),
|
column: params.column,
|
||||||
operator: '=',
|
operator: '=',
|
||||||
value: params.oldValue
|
value: params.oldValue
|
||||||
}
|
}
|
||||||
@@ -212,12 +146,12 @@ export default {
|
|||||||
} else if (params.oldValue.length === 2 && params.newValue.length === 1) {
|
} else if (params.oldValue.length === 2 && params.newValue.length === 1) {
|
||||||
// 3.参数值数量从多到1,operator由'in'改为'='
|
// 3.参数值数量从多到1,operator由'in'改为'='
|
||||||
const oldParam = {
|
const oldParam = {
|
||||||
column: humpToLine(params.column),
|
column: params.column,
|
||||||
operator: 'IN',
|
operator: 'IN',
|
||||||
value: params.oldValue
|
value: params.oldValue
|
||||||
}
|
}
|
||||||
const newParam = {
|
const newParam = {
|
||||||
column: humpToLine(params.column),
|
column: params.column,
|
||||||
operator: '=',
|
operator: '=',
|
||||||
value: params.newValue
|
value: params.newValue
|
||||||
}
|
}
|
||||||
@@ -225,12 +159,12 @@ export default {
|
|||||||
} else if (params.oldValue.length === 1 && params.newValue.length === 2) {
|
} else if (params.oldValue.length === 1 && params.newValue.length === 2) {
|
||||||
// 4.参数值数量从1到多, operator由'='改为'in'
|
// 4.参数值数量从1到多, operator由'='改为'in'
|
||||||
const oldParam = {
|
const oldParam = {
|
||||||
column: humpToLine(params.column),
|
column: params.column,
|
||||||
operator: '=',
|
operator: '=',
|
||||||
value: params.oldValue
|
value: params.oldValue
|
||||||
}
|
}
|
||||||
const newParam = {
|
const newParam = {
|
||||||
column: humpToLine(params.column),
|
column: params.column,
|
||||||
operator: 'IN',
|
operator: 'IN',
|
||||||
value: params.newValue
|
value: params.newValue
|
||||||
}
|
}
|
||||||
@@ -238,12 +172,12 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
// 5.参数值数量从多到多,加1或者减1
|
// 5.参数值数量从多到多,加1或者减1
|
||||||
const oldParam = {
|
const oldParam = {
|
||||||
column: humpToLine(params.column),
|
column: params.column,
|
||||||
operator: 'IN',
|
operator: 'IN',
|
||||||
value: params.oldValue
|
value: params.oldValue
|
||||||
}
|
}
|
||||||
const newParam = {
|
const newParam = {
|
||||||
column: humpToLine(params.column),
|
column: params.column,
|
||||||
operator: 'IN',
|
operator: 'IN',
|
||||||
value: params.newValue
|
value: params.newValue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="entity-explorer entity-explorer--show-list">
|
<div class="entity-explorer entity-explorer--show-list detections">
|
||||||
<!-- 顶部工具栏,在列表页显示 -->
|
<!-- 顶部工具栏,在列表页显示 -->
|
||||||
<div class="explorer-top-tools explorer-detection-top-tools">
|
<div class="explorer-top-tools explorer-detection-top-tools">
|
||||||
<div class="explorer-top-tools-title">{{$t('overall.detections')}}</div>
|
<div class="explorer-top-tools-title">{{$t('overall.detections')}}</div>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
@search="search"
|
@search="search"
|
||||||
></detection-search>
|
></detection-search>
|
||||||
<!-- 内容区 -->
|
<!-- 内容区 -->
|
||||||
<div class="explorer-container" style="height: calc(100% - 20px);flex-direction: column">
|
<div class="detections__container">
|
||||||
<loading :loading="loading"></loading>
|
<loading :loading="loading"></loading>
|
||||||
<template v-if="isEventSeverityNoData">
|
<template v-if="isEventSeverityNoData">
|
||||||
<div class="no-data detection__event-severity-bar" >{{ $t('npm.noData') }}</div>
|
<div class="no-data detection__event-severity-bar" >{{ $t('npm.noData') }}</div>
|
||||||
@@ -54,39 +54,36 @@
|
|||||||
<div class="detection__list-statistics detection-border">
|
<div class="detection__list-statistics detection-border">
|
||||||
<div class="statistics__severity">
|
<div class="statistics__severity">
|
||||||
<div class="chart-header">
|
<div class="chart-header">
|
||||||
<div class="chart-header__title">{{$t('detection.severity')}}</div>
|
<div class="chart-header__title">{{$t('detections.severity')}}</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="isStatisticsSeverityNoData">
|
<template v-if="isStatisticsSeverityNoData">
|
||||||
<div class="no-data chart-content" >{{ $t('npm.noData') }}</div>
|
<div class="no-data chart-content" >{{ $t('npm.noData') }}</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="chart-content" :id="`eventSeverityPie${pageType}`">
|
<div class="chart-content" :id="`eventSeverityPie${pageType}`"></div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="statistics__category">
|
<div class="statistics__category">
|
||||||
<div class="chart-header">
|
<div class="chart-header">
|
||||||
<div class="chart-header__title">{{$t('detection.categoryProportion')}}</div>
|
<div class="chart-header__title">{{$t('detections.eventType')}}</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="isStatisticsCategoryNoData">
|
<template v-if="isStatisticsCategoryNoData">
|
||||||
<div class="no-data chart-content" >{{ $t('npm.noData') }}</div>
|
<div class="no-data chart-content" >{{ $t('npm.noData') }}</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="chart-content" :id="`detectionCategoryPer${pageType}`">
|
<div class="chart-content" :id="`detectionCategoryPer${pageType}`"></div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="statistics__active-attack">
|
<div class="statistics__active-attack">
|
||||||
<div class="chart-header">
|
<div class="chart-header">
|
||||||
<div class="chart-header__title">{{pageType === detectionPageType.securityEvent ? $t('detection.activeAttacker') : $t('detections.activeEntity')}}</div>
|
<div class="chart-header__title">{{pageType === detectionPageType.securityEvent ? $t('detection.activeOffender') : $t('detections.activeEntity')}}</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="isStatisticsActiveAttackNoData">
|
<template v-if="isStatisticsActiveAttackNoData">
|
||||||
<div class="no-data chart-content" >{{ $t('npm.noData') }}</div>
|
<div class="no-data chart-content" >{{ $t('npm.noData') }}</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="chart-content" style="padding-left: 5px;" :id="`detectionActiveAttacker${pageType}`">
|
<div class="chart-content" style="padding-left: 5px;" :id="`detectionActiveAttacker${pageType}`"></div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -124,7 +121,7 @@ import DetectionFilter from '@/views/detections/DetectionFilter'
|
|||||||
import DetectionList from '@/views/detections/DetectionList'
|
import DetectionList from '@/views/detections/DetectionList'
|
||||||
import Pagination from '@/components/common/Pagination'
|
import Pagination from '@/components/common/Pagination'
|
||||||
import { defaultPageSize, detectionPageType } from '@/utils/constants'
|
import { defaultPageSize, detectionPageType } from '@/utils/constants'
|
||||||
import { getNowTime, getSecond, toTime } from '@/utils/date-util'
|
import { getNowTime, getSecond, getMillisecond } from '@/utils/date-util'
|
||||||
import { ref, shallowRef } from 'vue'
|
import { ref, shallowRef } from 'vue'
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import {
|
import {
|
||||||
@@ -134,12 +131,13 @@ import {
|
|||||||
multipleBarOption,
|
multipleBarOption,
|
||||||
pieForSeverity
|
pieForSeverity
|
||||||
} from '@/views/detections/options/detectionOptions'
|
} from '@/views/detections/options/detectionOptions'
|
||||||
import { api, getData } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { extensionEchartY, reverseSortBy } from '@/utils/tools'
|
import { urlParamsHandler, overwriteUrl, extensionEchartY, reverseSortBy } from '@/utils/tools'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import Loading from '@/components/common/Loading'
|
import Loading from '@/components/common/Loading'
|
||||||
import ChartTabs from '@/components/common/ChartTabs'
|
import ChartTabs from '@/components/common/ChartTabs'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Index',
|
name: 'Index',
|
||||||
@@ -160,18 +158,18 @@ export default {
|
|||||||
i18n: 'entities.securityEvents',
|
i18n: 'entities.securityEvents',
|
||||||
path: '/detection/securityEvent',
|
path: '/detection/securityEvent',
|
||||||
icon: 'cn-icon cn-icon-a-SecurityEvent'
|
icon: 'cn-icon cn-icon-a-SecurityEvent'
|
||||||
},
|
}
|
||||||
// {
|
// {
|
||||||
// i18n: 'entities.regulatoryRiskEvents',
|
// i18n: 'entities.regulatoryRiskEvents',
|
||||||
// path: '/detection/securityEvent',
|
// path: '/detection/securityEvent',
|
||||||
// icon: 'cn-icon cn-icon-a-RegulatoryRiskEvent',
|
// icon: 'cn-icon cn-icon-a-RegulatoryRiskEvent',
|
||||||
// disable: true
|
// disable: true
|
||||||
// },
|
// },
|
||||||
{
|
// {
|
||||||
i18n: 'overall.performanceEvents',
|
// i18n: 'overall.performanceEvents',
|
||||||
path: '/detection/performanceEvent',
|
// path: '/detection/performanceEvent',
|
||||||
icon: 'cn-icon cn-icon-a-PerformanceEvent'
|
// icon: 'cn-icon cn-icon-a-PerformanceEvent'
|
||||||
}
|
// }
|
||||||
],
|
],
|
||||||
chartInit: [],
|
chartInit: [],
|
||||||
pageObj: {
|
pageObj: {
|
||||||
@@ -185,61 +183,73 @@ export default {
|
|||||||
filterData: {
|
filterData: {
|
||||||
securityEvent: [
|
securityEvent: [
|
||||||
{
|
{
|
||||||
title: this.$t('detections.eventSeverity'),
|
title: this.$t('overall.status'),
|
||||||
column: 'eventSeverity',
|
column: 'status',
|
||||||
|
topColumn: 'status',
|
||||||
collapse: false,
|
collapse: false,
|
||||||
value: [], // value之间是or的关系
|
value: [], // value之间是or的关系
|
||||||
data: [] // 从接口动态获取,本项在获得数据后需要特殊处理左边框颜色
|
data: [] // 从接口动态获取,本项在获得数据后需要特殊处理左边框颜色
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: this.$t('detections.securityType'),
|
title: this.$t('detections.severity'),
|
||||||
column: 'securityType',
|
column: 'severity',
|
||||||
|
topColumn: 'severity',
|
||||||
|
collapse: false,
|
||||||
|
value: [], // value之间是or的关系
|
||||||
|
data: [] // 从接口动态获取,本项在获得数据后需要特殊处理左边框颜色
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('detections.eventType'),
|
||||||
|
column: 'eventType',
|
||||||
|
topColumn: 'event_type',
|
||||||
collapse: false,
|
collapse: false,
|
||||||
value: [],
|
value: [],
|
||||||
data: [] // 从接口动态获取
|
data: [] // 从接口动态获取
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: this.$t('detections.victimIp'),
|
title: this.$t('detections.victimIp'),
|
||||||
column: 'victimIp',
|
column: 'victimIP',
|
||||||
|
topColumn: 'victim_ip',
|
||||||
collapse: false,
|
collapse: false,
|
||||||
value: [],
|
value: [],
|
||||||
showMore: true,
|
showMore: true,
|
||||||
showIndex: 9,
|
showIndex: 9,
|
||||||
data: [] // 从接口动态获取
|
data: [] // 从接口动态获取
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
title: this.$t('detections.victimLocation'),
|
// title: this.$t('detections.victimLocation'),
|
||||||
column: 'victimLocationCountry',
|
// column: 'victimLocationCountry',
|
||||||
collapse: false,
|
// collapse: false,
|
||||||
value: [],
|
// value: [],
|
||||||
showMore: false,
|
// showMore: false,
|
||||||
showIndex: 9,
|
// showIndex: 9,
|
||||||
data: [
|
// data: [
|
||||||
{
|
// {
|
||||||
label: 'China',
|
// label: 'China',
|
||||||
value: 'china',
|
// value: 'china',
|
||||||
count: 50
|
// count: 50
|
||||||
}
|
// }
|
||||||
] // 从接口动态获取
|
// ] // 从接口动态获取
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
title: this.$t('detections.offenderIp'),
|
title: this.$t('detections.offenderIp'),
|
||||||
column: 'offenderIp',
|
column: 'offenderIP',
|
||||||
collapse: false,
|
topColumn: 'offender_ip',
|
||||||
value: [],
|
|
||||||
showMore: false,
|
|
||||||
showIndex: 9,
|
|
||||||
data: [] // 从接口动态获取
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.$t('detections.offenderLocation'),
|
|
||||||
column: 'offenderLocationCountry',
|
|
||||||
collapse: false,
|
collapse: false,
|
||||||
value: [],
|
value: [],
|
||||||
showMore: false,
|
showMore: false,
|
||||||
showIndex: 9,
|
showIndex: 9,
|
||||||
data: [] // 从接口动态获取
|
data: [] // 从接口动态获取
|
||||||
}
|
}
|
||||||
|
// {
|
||||||
|
// title: this.$t('detections.offenderLocation'),
|
||||||
|
// column: 'offenderLocationCountry',
|
||||||
|
// collapse: false,
|
||||||
|
// value: [],
|
||||||
|
// showMore: false,
|
||||||
|
// showIndex: 9,
|
||||||
|
// data: [] // 从接口动态获取
|
||||||
|
// }
|
||||||
],
|
],
|
||||||
performanceEvent: [
|
performanceEvent: [
|
||||||
{
|
{
|
||||||
@@ -275,24 +285,47 @@ export default {
|
|||||||
isStatisticsCategoryNoData: false,
|
isStatisticsCategoryNoData: false,
|
||||||
isStatisticsActiveAttackNoData: false,
|
isStatisticsActiveAttackNoData: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
oldActiveEntitySearchValue: ''
|
oldActiveEntitySearchValue: '',
|
||||||
|
initFlag: true // 初始化标识,初始化时保证mounted执行
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 初始化顶部大柱状图
|
initStatusData (params) {
|
||||||
|
axios.get(api.detection[this.pageType].statusStatistics, { params }).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const data = res.data.data.result
|
||||||
|
this.filterData[this.pageType][0].data = data.map(r => {
|
||||||
|
let label = ''
|
||||||
|
if (r.status === '0') {
|
||||||
|
label = this.$t('detections.active')
|
||||||
|
} else if (r.status === '1') {
|
||||||
|
label = this.$t('detections.ended')
|
||||||
|
}
|
||||||
|
return { label, value: r.status, count: r.count }
|
||||||
|
})
|
||||||
|
this.isCheckFilterByQ(params, 0)
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
this.filterData[this.pageType][0].data = []
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/** 初始化顶部大柱状图 */
|
||||||
initEventSeverityTrendData (params) {
|
initEventSeverityTrendData (params) {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
/* getData(api.detection[this.pageType].eventSeverityTrend, params).then(data => {
|
axios.get(api.detection[this.pageType].timeDistribution, { params }).then(res => {
|
||||||
|
const data = res.data.data.result
|
||||||
this.eventSeverityData = data
|
this.eventSeverityData = data
|
||||||
if (!this.$_.isEmpty(data)) {
|
if (!this.$_.isEmpty(data)) {
|
||||||
const dataMap = new Map()
|
const dataMap = new Map()
|
||||||
data.forEach(item => {
|
data.forEach(item => {
|
||||||
if (item.eventSeverity) {
|
if (item.severity) {
|
||||||
if (!dataMap.has(item.eventSeverity)) {
|
if (!dataMap.has(item.severity)) {
|
||||||
const count = [[toTime(item.statTime), item.count]]
|
const count = [[getMillisecond(parseFloat(item.statTime)), item.count]]
|
||||||
dataMap.set(item.eventSeverity, count)
|
dataMap.set(item.severity, count)
|
||||||
} else {
|
} else {
|
||||||
dataMap.get(item.eventSeverity).push([toTime(item.statTime), item.count])
|
dataMap.get(item.severity).push([getMillisecond(parseFloat(item.statTime)), item.count])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -331,12 +364,6 @@ export default {
|
|||||||
serie.data = seriesData
|
serie.data = seriesData
|
||||||
})
|
})
|
||||||
|
|
||||||
// eventSeverityTrendOption.xAxis.data = dataMap.get('info').map(v => rTime(v[0]))
|
|
||||||
|
|
||||||
eventSeverityTrendOption.xAxis = [{
|
|
||||||
type: 'time',
|
|
||||||
splitNumber: 8
|
|
||||||
}]
|
|
||||||
let detectionChart = echarts.getInstanceByDom(chartDom)
|
let detectionChart = echarts.getInstanceByDom(chartDom)
|
||||||
if (detectionChart) {
|
if (detectionChart) {
|
||||||
echarts.dispose(detectionChart)
|
echarts.dispose(detectionChart)
|
||||||
@@ -348,32 +375,26 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
// this.isEventSeverityNoData = true
|
// this.isEventSeverityNoData = true
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(e => {
|
||||||
console.log(error)
|
console.error(e)
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
}) */
|
})
|
||||||
const timer = setTimeout(() => {
|
|
||||||
this.loading = false
|
|
||||||
this.isEventSeverityNoData = true
|
|
||||||
this.isStatisticsCategoryNoData = true
|
|
||||||
this.isStatisticsSeverityNoData = true
|
|
||||||
this.isStatisticsActiveAttackNoData = true
|
|
||||||
clearTimeout(timer)
|
|
||||||
}, 150)
|
|
||||||
},
|
},
|
||||||
|
/** 初始化左侧事件严重等级和第一个小饼图 */
|
||||||
// 初始化左侧事件严重等级和小饼图
|
|
||||||
initEventSeverityData (params) {
|
initEventSeverityData (params) {
|
||||||
getData(api.detection[this.pageType].eventSeverity, params).then(data => {
|
axios.get(api.detection[this.pageType].severityStatistics, { params }).then(res => {
|
||||||
|
const data = res.data.data.result
|
||||||
this.statisticsSeverityData = data
|
this.statisticsSeverityData = data
|
||||||
if (!this.$_.isEmpty(data)) {
|
if (!this.$_.isEmpty(data)) {
|
||||||
this.filterData[this.pageType][0].data = data.map(r => ({ label: r.eventSeverity, value: r.eventSeverity, count: r.count }))
|
this.filterData[this.pageType][1].data = data.map(r => ({ label: r.severity, value: r.severity, count: r.count }))
|
||||||
|
this.isCheckFilterByQ(params, 1)
|
||||||
const eventSeverityOption = this.$_.cloneDeep(pieForSeverity)
|
const eventSeverityOption = this.$_.cloneDeep(pieForSeverity)
|
||||||
eventSeverityOption.series[0].data = data.map(d => {
|
eventSeverityOption.series[0].data = data.map(d => {
|
||||||
return { value: d.count, name: d.eventSeverity, itemStyle: { color: getSeverityColor(d.eventSeverity) } }
|
return { value: d.count, name: d.severity, itemStyle: { color: getSeverityColor(d.severity) } }
|
||||||
})
|
})
|
||||||
const chartDom = document.getElementById(`eventSeverityPie${this.pageType}`)
|
const chartDom = document.getElementById(`eventSeverityPie${this.pageType}`)
|
||||||
let detectionChart = echarts.getInstanceByDom(chartDom)
|
let detectionChart = echarts.getInstanceByDom(chartDom)
|
||||||
@@ -389,19 +410,22 @@ export default {
|
|||||||
if (this.pageType === 'performanceEvent') {
|
if (this.pageType === 'performanceEvent') {
|
||||||
vm.filterData.performanceEvent[0].value = vm.triggerFilterDataValue(vm.filterData.performanceEvent[0].value, e.data.name)
|
vm.filterData.performanceEvent[0].value = vm.triggerFilterDataValue(vm.filterData.performanceEvent[0].value, e.data.name)
|
||||||
} else if (this.pageType === 'securityEvent') {
|
} else if (this.pageType === 'securityEvent') {
|
||||||
vm.filterData.securityEvent[0].value = vm.triggerFilterDataValue(vm.filterData.securityEvent[0].value, e.data.name)
|
vm.filterData.securityEvent[1].value = vm.triggerFilterDataValue(vm.filterData.securityEvent[1].value, e.data.name)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(e => {
|
||||||
console.log(error)
|
console.error(e)
|
||||||
|
this.filterData[this.pageType][1].data = []
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
initEventTypeData (params) {
|
initEventTypeData (params) {
|
||||||
getData(api.detection[this.pageType].eventType, params).then(data => {
|
axios.get(api.detection[this.pageType].eventType, { params }).then(res => {
|
||||||
|
const data = res.data.data.result
|
||||||
this.statisticsCategoryData = data
|
this.statisticsCategoryData = data
|
||||||
if (!this.$_.isEmpty(data)) {
|
if (!this.$_.isEmpty(data)) {
|
||||||
this.filterData[this.pageType][1].data = data.map(r => ({
|
this.filterData[this.pageType][2].data = data.map(r => ({
|
||||||
label: r.eventType,
|
label: r.eventType,
|
||||||
value: r.eventType,
|
value: r.eventType,
|
||||||
count: r.count
|
count: r.count
|
||||||
@@ -425,19 +449,24 @@ export default {
|
|||||||
vm.filterData.performanceEvent[1].value = vm.triggerFilterDataValue(vm.filterData.performanceEvent[1].value, e.data.name)
|
vm.filterData.performanceEvent[1].value = vm.triggerFilterDataValue(vm.filterData.performanceEvent[1].value, e.data.name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(e => {
|
||||||
console.log(error)
|
console.error(e)
|
||||||
|
this.filterData[this.pageType][2].data = []
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
/** 第二个饼图和左侧filter的eventType */
|
||||||
initSecurityTypeData (params) {
|
initSecurityTypeData (params) {
|
||||||
getData(api.detection[this.pageType].securityType, params).then(data => {
|
axios.get(api.detection[this.pageType].eventTypeStatistics, { params }).then(res => {
|
||||||
|
const data = res.data.data.result
|
||||||
this.statisticsCategoryData = data
|
this.statisticsCategoryData = data
|
||||||
if (!this.$_.isEmpty(data)) {
|
if (!this.$_.isEmpty(data)) {
|
||||||
this.filterData[this.pageType][1].data = data.map(r => ({
|
this.filterData[this.pageType][2].data = data.map(r => ({
|
||||||
label: r.securityType,
|
label: r.eventType,
|
||||||
value: r.securityType,
|
value: r.eventType,
|
||||||
count: r.count
|
count: r.count
|
||||||
}))
|
}))
|
||||||
|
this.isCheckFilterByQ(params, 2)
|
||||||
const chartDom = document.getElementById(`detectionCategoryPer${this.pageType}`)
|
const chartDom = document.getElementById(`detectionCategoryPer${this.pageType}`)
|
||||||
let detectionChart = echarts.getInstanceByDom(chartDom)
|
let detectionChart = echarts.getInstanceByDom(chartDom)
|
||||||
if (detectionChart) {
|
if (detectionChart) {
|
||||||
@@ -447,22 +476,26 @@ export default {
|
|||||||
this.chartInit.push(shallowRef(detectionChart))
|
this.chartInit.push(shallowRef(detectionChart))
|
||||||
const securityTypeOption = this.$_.cloneDeep(pieForSeverity)
|
const securityTypeOption = this.$_.cloneDeep(pieForSeverity)
|
||||||
securityTypeOption.series[0].data = data.map(d => {
|
securityTypeOption.series[0].data = data.map(d => {
|
||||||
return { value: d.count, name: d.securityType, itemStyle: { color: getAttackColor(d.securityType) } }
|
return { value: d.count, name: d.eventType, itemStyle: { color: getAttackColor(d.eventType) } }
|
||||||
})
|
})
|
||||||
detectionChart.setOption(securityTypeOption)
|
detectionChart.setOption(securityTypeOption)
|
||||||
|
|
||||||
const vm = this
|
const vm = this
|
||||||
detectionChart.off('click')
|
detectionChart.off('click')
|
||||||
detectionChart.on('click', e => {
|
detectionChart.on('click', e => {
|
||||||
vm.filterData.securityEvent[1].value = vm.triggerFilterDataValue(vm.filterData.securityEvent[1].value, e.data.name)
|
vm.filterData.securityEvent[2].value = vm.triggerFilterDataValue(vm.filterData.securityEvent[2].value, e.data.name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(e => {
|
||||||
console.log(error)
|
console.error(e)
|
||||||
|
this.filterData[this.pageType][2].data = []
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
/** 横向柱状图和左侧filter的offenderIp */
|
||||||
initOffenderIpData (params) {
|
initOffenderIpData (params) {
|
||||||
getData(api.detection[this.pageType].offenderIp, params).then(data => {
|
axios.get(api.detection[this.pageType].offenderIpStatistics, { params }).then(res => {
|
||||||
|
let data = res.data.data.result
|
||||||
this.statisticsActiveAttackData = data
|
this.statisticsActiveAttackData = data
|
||||||
if (!this.$_.isEmpty(data)) {
|
if (!this.$_.isEmpty(data)) {
|
||||||
this.filterData[this.pageType][4].data = data.map(r => ({
|
this.filterData[this.pageType][4].data = data.map(r => ({
|
||||||
@@ -470,6 +503,7 @@ export default {
|
|||||||
value: r.offenderIp,
|
value: r.offenderIp,
|
||||||
count: r.count
|
count: r.count
|
||||||
}))
|
}))
|
||||||
|
this.isCheckFilterByQ(params, 4)
|
||||||
const { showMore, showIndex } = 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].showMore = showMore
|
||||||
this.filterData[this.pageType][4].showIndex = showIndex
|
this.filterData[this.pageType][4].showIndex = showIndex
|
||||||
@@ -495,43 +529,34 @@ export default {
|
|||||||
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(error => {
|
}).catch(e => {
|
||||||
console.log(error)
|
console.error(e)
|
||||||
|
this.filterData[this.pageType][4].data = []
|
||||||
|
this.filterData[this.pageType][4].showMore = false
|
||||||
|
this.filterData[this.pageType][4].showIndex = 9
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
initVictimIpData (params) {
|
initVictimIpData (params) {
|
||||||
getData(api.detection[this.pageType].victimIp, params).then(data => {
|
axios.get(api.detection[this.pageType].victimIpStatistics, { params }).then(res => {
|
||||||
this.filterData[this.pageType][2].data = data.map(r => ({ label: r.victimIp, value: r.victimIp, count: r.count }))
|
const data = res.data.data.result
|
||||||
const { showMore, showIndex } = this.computeFilterPage(this.filterData[this.pageType][2].data)
|
this.filterData[this.pageType][3].data = data.map(r => ({ label: r.victimIp, value: r.victimIp, count: r.count }))
|
||||||
this.filterData[this.pageType][2].showMore = showMore
|
this.isCheckFilterByQ(params, 3)
|
||||||
this.filterData[this.pageType][2].showIndex = showIndex
|
|
||||||
}).catch(error => {
|
|
||||||
console.log(error)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
initVictimLocationData (params) {
|
|
||||||
getData(api.detection[this.pageType].victimLocation, params).then(data => {
|
|
||||||
this.filterData[this.pageType][3].data = data.map(r => ({ label: r.victimLocationCountry, value: r.victimLocationCountry, count: r.count }))
|
|
||||||
const { showMore, showIndex } = 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].showMore = showMore
|
||||||
this.filterData[this.pageType][3].showIndex = showIndex
|
this.filterData[this.pageType][3].showIndex = showIndex
|
||||||
}).catch(error => {
|
}).catch(e => {
|
||||||
console.log(error)
|
console.error(e)
|
||||||
})
|
this.filterData[this.pageType][3].data = []
|
||||||
},
|
this.filterData[this.pageType][3].showMore = false
|
||||||
initOffenderLocationData (params) {
|
this.filterData[this.pageType][3].showIndex = 9
|
||||||
getData(api.detection[this.pageType].offenderLocation, params).then(data => {
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
this.filterData[this.pageType][5].data = data.map(r => ({ label: r.offenderLocationCountry, value: r.offenderLocationCountry, count: r.count }))
|
|
||||||
const { showMore, showIndex } = this.computeFilterPage(this.filterData[this.pageType][5].data)
|
|
||||||
this.filterData[this.pageType][5].showMore = showMore
|
|
||||||
this.filterData[this.pageType][5].showIndex = showIndex
|
|
||||||
}).catch(error => {
|
|
||||||
console.log(error)
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
initActiveEntity (params) {
|
initActiveEntity (params) {
|
||||||
getData(api.detection[this.pageType].activeEntity, params).then(data => {
|
axios.get(api.detection[this.pageType].activeEntity, { params }).then(res => {
|
||||||
|
let data = res.data.data.result
|
||||||
this.statisticsActiveAttackData = data
|
this.statisticsActiveAttackData = data
|
||||||
if (!this.$_.isEmpty(data)) {
|
if (!this.$_.isEmpty(data)) {
|
||||||
const chartDom = document.getElementById(`detectionActiveAttacker${this.pageType}`)
|
const chartDom = document.getElementById(`detectionActiveAttacker${this.pageType}`)
|
||||||
@@ -591,7 +616,7 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.log(error)
|
console.error(error)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
triggerFilterDataValue (array, value) {
|
triggerFilterDataValue (array, value) {
|
||||||
@@ -610,34 +635,49 @@ export default {
|
|||||||
showIndex: 9
|
showIndex: 9
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
queryList () {
|
queryList (q) {
|
||||||
const params = {
|
const params = {
|
||||||
startTime: getSecond(this.timeFilter.startTime),
|
startTime: getSecond(this.timeFilter.startTime),
|
||||||
endTime: getSecond(this.timeFilter.endTime),
|
endTime: getSecond(this.timeFilter.endTime),
|
||||||
q: this.q,
|
resource: q,
|
||||||
pageSize: this.pageObj.pageSize,
|
pageSize: this.pageObj.pageSize,
|
||||||
pageNo: this.pageObj.pageNo
|
pageNo: this.pageObj.pageNo
|
||||||
}
|
}
|
||||||
/* axios.get(api.detection[this.pageType].listBasic, { params }).then(response => {
|
axios.get(api.detection[this.pageType].securityList, { params }).then(response => {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
this.listData = response.data.data.result
|
const data = response.data.data.result
|
||||||
|
if (data.length > 0) {
|
||||||
|
data.forEach(item => {
|
||||||
|
item.eventInfoObj = JSON.parse(item.eventInfo)
|
||||||
|
item.startTime = parseFloat(item.startTime)
|
||||||
|
})
|
||||||
|
this.listData = data
|
||||||
|
} else {
|
||||||
|
this.listData = []
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.listData = []
|
this.listData = []
|
||||||
console.error(response.data.message)
|
console.error(response.data.message)
|
||||||
this.$message.error(response.data.message)
|
this.$message.error(response.data.message)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
getData(api.detection[this.pageType].listCount, params).then(data => {
|
axios.get(api.detection[this.pageType].securityCount, { params }).then(res => {
|
||||||
this.pageObj.total = data
|
this.pageObj.total = parseInt(this.$_.get(res, 'data.data.result', 0))
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.log(error)
|
console.error(error)
|
||||||
}) */
|
})
|
||||||
},
|
},
|
||||||
timeRefreshChange () {
|
timeRefreshChange () {
|
||||||
this.initNoData()
|
// 不是自选时间
|
||||||
if (!this.$refs.dateTimeRange.isCustom) {
|
if (this.$refs.dateTimeRange) {
|
||||||
const value = this.timeFilter.dateRangeValue
|
if (!this.$refs.dateTimeRange.isCustom) {
|
||||||
this.$refs.dateTimeRange.quickChange(value)
|
const value = this.timeFilter.dateRangeValue
|
||||||
|
this.$refs.dateTimeRange.quickChange(value)
|
||||||
|
} else {
|
||||||
|
this.timeFilter = JSON.parse(JSON.stringify(this.timeFilter))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.timeFilter = JSON.parse(JSON.stringify(this.timeFilter))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
initNoData () {
|
initNoData () {
|
||||||
@@ -646,9 +686,16 @@ export default {
|
|||||||
this.isStatisticsCategoryNoData = false
|
this.isStatisticsCategoryNoData = false
|
||||||
this.isStatisticsActiveAttackNoData = false
|
this.isStatisticsActiveAttackNoData = false
|
||||||
},
|
},
|
||||||
reload (s, e, v) {
|
reload (startTime, endTime, dateRangeValue) {
|
||||||
this.initNoData()
|
this.initNoData()
|
||||||
this.dateTimeRangeChange(s, e, v)
|
this.dateTimeRangeChange(startTime, endTime, dateRangeValue)
|
||||||
|
const { query } = this.$route
|
||||||
|
const newUrl = urlParamsHandler(window.location.href, query, {
|
||||||
|
startTime: this.timeFilter.startTime,
|
||||||
|
endTime: this.timeFilter.endTime,
|
||||||
|
range: dateRangeValue.value
|
||||||
|
})
|
||||||
|
overwriteUrl(newUrl)
|
||||||
},
|
},
|
||||||
// methods
|
// methods
|
||||||
dateTimeRangeChange (s, e, v) {
|
dateTimeRangeChange (s, e, v) {
|
||||||
@@ -674,8 +721,26 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.pageObj.resetPageNo = true
|
this.pageObj.resetPageNo = true
|
||||||
}
|
}
|
||||||
this.queryFilter()
|
// 参数q,避免切换页码时,地址栏参数q为空
|
||||||
this.queryList()
|
let urlQ = ''
|
||||||
|
if (param && param.str) {
|
||||||
|
// urlQ = encodeURI(param.str)
|
||||||
|
urlQ = param.str
|
||||||
|
} else if (this.q) {
|
||||||
|
// urlQ = encodeURI(this.q)
|
||||||
|
urlQ = this.q
|
||||||
|
}
|
||||||
|
const mode = this.$route.query.mode || 'text'
|
||||||
|
const newUrl = urlParamsHandler(window.location.href, this.$route.query, {
|
||||||
|
startTime: this.timeFilter.startTime,
|
||||||
|
endTime: this.timeFilter.endTime,
|
||||||
|
range: this.timeFilter.dateRangeValue,
|
||||||
|
q: urlQ,
|
||||||
|
mode: mode
|
||||||
|
})
|
||||||
|
overwriteUrl(newUrl)
|
||||||
|
this.queryFilter(urlQ)
|
||||||
|
this.queryList(urlQ)
|
||||||
},
|
},
|
||||||
resetFilterData () {
|
resetFilterData () {
|
||||||
this.filterData.securityEvent.forEach(d => {
|
this.filterData.securityEvent.forEach(d => {
|
||||||
@@ -685,25 +750,23 @@ export default {
|
|||||||
d.data = []
|
d.data = []
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
queryFilter () {
|
queryFilter (q) {
|
||||||
this.resetFilterData()
|
this.resetFilterData()
|
||||||
const params = {
|
const params = {
|
||||||
startTime: getSecond(this.timeFilter.startTime),
|
startTime: getSecond(this.timeFilter.startTime),
|
||||||
endTime: getSecond(this.timeFilter.endTime),
|
endTime: getSecond(this.timeFilter.endTime),
|
||||||
q: this.q
|
resource: q
|
||||||
}
|
}
|
||||||
this.listData = []
|
this.initStatusData(params)
|
||||||
this.initEventSeverityTrendData(params)
|
this.initEventSeverityTrendData(params)
|
||||||
// this.initEventSeverityData(params)
|
this.initEventSeverityData(params)
|
||||||
if (this.pageType === detectionPageType.securityEvent) {
|
if (this.pageType === detectionPageType.securityEvent) {
|
||||||
// this.initOffenderIpData(params)
|
this.initOffenderIpData(params)
|
||||||
// this.initOffenderLocationData(params)
|
this.initVictimIpData(params)
|
||||||
// this.initVictimIpData(params)
|
this.initSecurityTypeData(params)
|
||||||
// this.initVictimLocationData(params)
|
|
||||||
// this.initSecurityTypeData(params)
|
|
||||||
} else if (this.pageType === detectionPageType.performanceEvent) {
|
} else if (this.pageType === detectionPageType.performanceEvent) {
|
||||||
// this.initActiveEntity(params)
|
this.initActiveEntity(params)
|
||||||
// this.initEventTypeData(params)
|
this.initEventTypeData(params)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pageSize (val) {
|
pageSize (val) {
|
||||||
@@ -713,7 +776,11 @@ export default {
|
|||||||
pageNo (val) {
|
pageNo (val) {
|
||||||
this.pageObj.pageNo = val || 1
|
this.pageObj.pageNo = val || 1
|
||||||
this.pageObj.resetPageNo = false
|
this.pageObj.resetPageNo = false
|
||||||
this.search(this.metaList, this.q)
|
// 初始化时,mounted和pageNo都会调用列表接口,且pageNo先执行,
|
||||||
|
// 初始化保证mounted执行,后续pageNo变动则不影响接口调用
|
||||||
|
if (!this.initFlag) {
|
||||||
|
this.search(this.metaList, this.q)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 点击上一页箭头
|
// 点击上一页箭头
|
||||||
prev () {
|
prev () {
|
||||||
@@ -739,16 +806,48 @@ export default {
|
|||||||
},
|
},
|
||||||
jumpNewDetetion () {
|
jumpNewDetetion () {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: '/detectionsNew',
|
path: '/detectionPolicy',
|
||||||
query: {
|
query: {
|
||||||
t: +new Date()
|
t: +new Date()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
isCheckFilterByQ (params, index) {
|
||||||
|
if (params.resource) {
|
||||||
|
let obj
|
||||||
|
if (index === 0) {
|
||||||
|
obj = this.filterData[this.pageType][index].data.find(d => params.resource.indexOf(d.value) > -1 && params.resource.indexOf('status') > -1)
|
||||||
|
} else {
|
||||||
|
obj = this.filterData[this.pageType][index].data.find(d => params.resource.indexOf(d.value) > -1)
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.queryFilter()
|
let { q } = this.$route.query
|
||||||
this.queryList()
|
|
||||||
|
// 如果地址栏有listMode,即列表页,并非首页,则开始搜索
|
||||||
|
if (q) {
|
||||||
|
// %位置为0是输入中文时能解码,%20,25%分别是空格和%的情况
|
||||||
|
if (q && (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1)) {
|
||||||
|
q = decodeURI(q)
|
||||||
|
}
|
||||||
|
// %位置不为0,即内容包含非英文时
|
||||||
|
const str1 = q.substring(q.indexOf('%'), q.indexOf('%') + 3)
|
||||||
|
if (q && q.indexOf('%') > 0 && (str1 !== '%20' || str1 === '%25')) {
|
||||||
|
q = decodeURI(q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.queryFilter(q)
|
||||||
|
this.initFlag = false
|
||||||
|
this.queryList(q)
|
||||||
this.debounceFunc = this.$_.debounce(this.resize, 300)
|
this.debounceFunc = this.$_.debounce(this.resize, 300)
|
||||||
window.addEventListener('resize', this.debounceFunc)
|
window.addEventListener('resize', this.debounceFunc)
|
||||||
},
|
},
|
||||||
@@ -821,37 +920,61 @@ export default {
|
|||||||
'filterData.securityEvent.0.value': {
|
'filterData.securityEvent.0.value': {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler (n, o) {
|
handler (n, o) {
|
||||||
this.$refs.search.changeParams({ column: this.filterData.securityEvent[0].column, oldValue: o, newValue: n })
|
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': {
|
'filterData.securityEvent.1.value': {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler (n, o) {
|
handler (n, o) {
|
||||||
this.$refs.search.changeParams({ column: this.filterData.securityEvent[1].column, oldValue: o, newValue: n })
|
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': {
|
'filterData.securityEvent.2.value': {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler (n, o) {
|
handler (n, o) {
|
||||||
this.$refs.search.changeParams({ column: this.filterData.securityEvent[2].column, oldValue: o, newValue: n })
|
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': {
|
'filterData.securityEvent.3.value': {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler (n, o) {
|
handler (n, o) {
|
||||||
this.$refs.search.changeParams({ column: this.filterData.securityEvent[3].column, oldValue: o, newValue: n })
|
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': {
|
'filterData.securityEvent.4.value': {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler (n, o) {
|
handler (n, o) {
|
||||||
this.$refs.search.changeParams({ column: this.filterData.securityEvent[4].column, oldValue: o, newValue: n })
|
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': {
|
'filterData.securityEvent.5.value': {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler (n, o) {
|
handler (n, o) {
|
||||||
this.$refs.search.changeParams({ column: this.filterData.securityEvent[5].column, oldValue: o, newValue: n })
|
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': {
|
'filterData.performanceEvent.0.value': {
|
||||||
@@ -871,12 +994,37 @@ export default {
|
|||||||
window.removeEventListener('resize', this.debounceFunc)
|
window.removeEventListener('resize', this.debounceFunc)
|
||||||
},
|
},
|
||||||
setup () {
|
setup () {
|
||||||
const { params } = useRoute()
|
const store = useStore()
|
||||||
const pageType = params.typeName
|
let { params, query, path } = useRoute()
|
||||||
const dateRangeValue = 60
|
// 获取路由跳转过的历史状态,赋值给当前界面,起到保留状态的作用,如浏览器的回退前进等
|
||||||
const { startTime, endTime } = getNowTime(dateRangeValue)
|
const routerObj = store.getters.getRouterHistoryList.find(item => item.t === query.t)
|
||||||
const timeFilter = ref({ startTime, endTime, dateRangeValue })
|
if (routerObj) {
|
||||||
|
params = routerObj.params
|
||||||
|
query = routerObj.query
|
||||||
|
path = routerObj.path
|
||||||
|
|
||||||
|
// 如果当前界面之前载入过,获取状态后更新地址栏,以便后续的赋值操作
|
||||||
|
const newUrl = urlParamsHandler(window.location.href, useRoute().query, query)
|
||||||
|
overwriteUrl(newUrl)
|
||||||
|
}
|
||||||
|
const pageType = params.typeName
|
||||||
|
// 获取url携带的range、startTime、endTime
|
||||||
|
const rangeParam = query.range
|
||||||
|
const startTimeParam = query.startTime
|
||||||
|
const endTimeParam = query.endTime
|
||||||
|
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
|
||||||
|
const timeFilter = ref({ dateRangeValue })
|
||||||
|
if (!startTimeParam || !endTimeParam) {
|
||||||
|
const { startTime, endTime } = getNowTime(60)
|
||||||
|
timeFilter.value.startTime = getSecond(startTime)
|
||||||
|
timeFilter.value.endTime = getSecond(endTime)
|
||||||
|
// 如果没有时间参数,就将参数写入url
|
||||||
|
const newUrl = urlParamsHandler(window.location.href, useRoute().query, { startTime: timeFilter.value.startTime, endTime: timeFilter.value.endTime, range: dateRangeValue })
|
||||||
|
overwriteUrl(newUrl)
|
||||||
|
} else {
|
||||||
|
timeFilter.value.startTime = parseInt(startTimeParam)
|
||||||
|
timeFilter.value.endTime = parseInt(endTimeParam)
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
timeFilter,
|
timeFilter,
|
||||||
pageType
|
pageType
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="detection">
|
<div class="detection">
|
||||||
<div class="detection-title">
|
<div class="detection-title">
|
||||||
<span>{{ $t('overall.detections') }}</span>
|
<span>{{ $t('overall.policies') }}</span>
|
||||||
<span class="detection-title-label">
|
<span class="detection-title-label">
|
||||||
60 polices created(200 max) | 32 polices enabled(100 max)
|
{{ $t('detection.policesCreated', { total: policyTotal }) }} | {{ $t('detection.policesEnabled', { enabled: policyEnabledNum }) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="detection-content">
|
<div class="detection-content">
|
||||||
<div class="detection-filter">
|
<div class="detection-filter">
|
||||||
<detection-filter></detection-filter>
|
<detection-filter @filterParams="getFilterParams" @policyTotal="getPolicyTotal" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="detection-block">
|
<div class="detection-block">
|
||||||
<detection-tools
|
<detection-tools
|
||||||
@delete="toDelete"
|
@delete="toDelete"
|
||||||
@create="onCreate"
|
@create="onCreate"
|
||||||
|
@edit="onEdit"
|
||||||
@search="onSearch"
|
@search="onSearch"
|
||||||
|
:disableEdit="disableEdit"
|
||||||
:disableDelete="disableDelete"/>
|
:disableDelete="disableDelete"/>
|
||||||
|
|
||||||
<div class="detection-table" style="position: relative">
|
<div class="detection-table" style="position: relative">
|
||||||
@@ -32,7 +34,6 @@
|
|||||||
:all-count="18"
|
:all-count="18"
|
||||||
@selectionChange="selectionChange"
|
@selectionChange="selectionChange"
|
||||||
@reload="reloadRowList"
|
@reload="reloadRowList"
|
||||||
@toggleLoading="toggleLoading"
|
|
||||||
@rowDoubleClick="onRowDoubleClick"
|
@rowDoubleClick="onRowDoubleClick"
|
||||||
></detection-table>
|
></detection-table>
|
||||||
</div>
|
</div>
|
||||||
@@ -61,10 +62,8 @@
|
|||||||
cell-style="padding:4px 0px;font-size: 12px;color: #353636;font-weight: 400;"
|
cell-style="padding:4px 0px;font-size: 12px;color: #353636;font-weight: 400;"
|
||||||
header-cell-style="padding:4px 0px;background: #F5F8FA;font-size: 12px;color: #353636;font-weight: 500;">
|
header-cell-style="padding:4px 0px;background: #F5F8FA;font-size: 12px;color: #353636;font-weight: 500;">
|
||||||
<el-table-column :resizable="false" align="center" type="selection" width="50"></el-table-column>
|
<el-table-column :resizable="false" align="center" type="selection" width="50"></el-table-column>
|
||||||
<el-table-column property="ruleId" label="ID" width="70"></el-table-column>
|
<el-table-column property="ruleId" label="ID" width="150"></el-table-column>
|
||||||
<el-table-column property="name" label="Name"></el-table-column>
|
<el-table-column property="name" label="Name"></el-table-column>
|
||||||
<el-table-column property="category" label="Category" width="100" :formatter="categoryFormat"></el-table-column>
|
|
||||||
<el-table-column property="function" label="Function" width="110" :formatter="sourceFormat"></el-table-column>
|
|
||||||
</el-table>
|
</el-table>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
@@ -83,12 +82,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DetectionFilter from '@/views/detectionsNew/DetectionFilter'
|
import DetectionFilter from '@/views/detections/detectionPolicies/PolicyFilter'
|
||||||
import DetectionTools from '@/views/detectionsNew/DetectionTools'
|
import DetectionTools from '@/views/detections/detectionPolicies/PolicyTools'
|
||||||
import DetectionTable from '@/views/detectionsNew/DetectionTable'
|
import DetectionTable from '@/views/detections/detectionPolicies/PolicyTable'
|
||||||
import { api } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
import dataListMixin from '@/mixins/data-list'
|
import dataListMixin from '@/mixins/data-list'
|
||||||
import DetectionDrawer from '@/views/detectionsNew/DetectionDrawer'
|
import DetectionDrawer from '@/views/detections/detectionPolicies/PolicyDrawer'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Index',
|
name: 'Index',
|
||||||
@@ -101,8 +101,8 @@ export default {
|
|||||||
mixins: [dataListMixin],
|
mixins: [dataListMixin],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
// url: api.detection.list,
|
url: api.detection.list,
|
||||||
url: api.knowledgeBase,
|
// url: api.knowledgeBase,
|
||||||
listUrl: api.detection.list,
|
listUrl: api.detection.list,
|
||||||
tableId: 'detectionTable',
|
tableId: 'detectionTable',
|
||||||
isNoData: false,
|
isNoData: false,
|
||||||
@@ -110,42 +110,52 @@ export default {
|
|||||||
isSelectedStatus: false,
|
isSelectedStatus: false,
|
||||||
batchDeleteObjs: [], // 待删除列表
|
batchDeleteObjs: [], // 待删除列表
|
||||||
secondBatchDeleteObjs: [],
|
secondBatchDeleteObjs: [],
|
||||||
|
disableEdit: true,
|
||||||
disableDelete: true,
|
disableDelete: true,
|
||||||
showConfirmDialog: false,
|
showConfirmDialog: false,
|
||||||
delItemList: [],
|
delItemList: [],
|
||||||
showDrawer: false,
|
showDrawer: false,
|
||||||
drawerInfo: {}
|
drawerInfo: {},
|
||||||
|
filterParams: {},
|
||||||
|
policyTotal: 0,
|
||||||
|
policyEnabledNum: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onSearch () {
|
onSearch (keyWord) {
|
||||||
// todo 暂时禁用,后续再开发时解禁
|
this.filterParams = {
|
||||||
// const params = {
|
...this.filterParams,
|
||||||
// ...this.filterParams,
|
name: keyWord
|
||||||
// name: this.keyWord
|
}
|
||||||
// }
|
this.search(this.filterParams, 'detection')
|
||||||
// this.clearList()
|
|
||||||
// this.search(params)
|
|
||||||
// this.$refs.knowledgeFilter.reloadFilter(this.checkedCategoryIds, this.checkedStatusIds)
|
|
||||||
},
|
},
|
||||||
toDelete (data) {
|
toDelete (data) {
|
||||||
// todo 暂时禁用,后续再开发时解禁
|
if (data && data.ruleId) {
|
||||||
// if (data && data.ruleId) {
|
this.secondBatchDeleteObjs = []
|
||||||
// this.secondBatchDeleteObjs = []
|
this.batchDeleteObjs = []
|
||||||
// this.batchDeleteObjs = []
|
this.secondBatchDeleteObjs.push(data)
|
||||||
// this.secondBatchDeleteObjs.push(data)
|
this.batchDeleteObjs.push(data)
|
||||||
// this.batchDeleteObjs.push(data)
|
}
|
||||||
// }
|
this.showDelDialog()
|
||||||
// this.showDelDialog()
|
|
||||||
},
|
},
|
||||||
onCreate () {
|
onCreate () {
|
||||||
// todo 暂时禁用,后续再开发时解禁
|
this.$router.push({
|
||||||
// this.$router.push({
|
path: '/detectionPolicy/create',
|
||||||
// path: '/detection/policies/create',
|
query: {
|
||||||
// query: {
|
t: +new Date()
|
||||||
// t: +new Date()
|
}
|
||||||
// }
|
})
|
||||||
// })
|
},
|
||||||
|
onEdit () {
|
||||||
|
const pageNo = this.$router.currentRoute.value.query.pageNo
|
||||||
|
this.$router.push({
|
||||||
|
path: '/detectionPolicy/edit',
|
||||||
|
query: {
|
||||||
|
t: +new Date(),
|
||||||
|
pageNoForTable: pageNo || 1,
|
||||||
|
id: this.batchDeleteObjs[0].ruleId
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
selectionChange (objs) {
|
selectionChange (objs) {
|
||||||
this.batchDeleteObjs = []
|
this.batchDeleteObjs = []
|
||||||
@@ -161,8 +171,6 @@ export default {
|
|||||||
reloadRowList () {
|
reloadRowList () {
|
||||||
this.getTableData()
|
this.getTableData()
|
||||||
},
|
},
|
||||||
toggleLoading () {
|
|
||||||
},
|
|
||||||
showDelDialog () {
|
showDelDialog () {
|
||||||
this.showConfirmDialog = true
|
this.showConfirmDialog = true
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
@@ -177,16 +185,6 @@ export default {
|
|||||||
secondSelectionChange (objs) {
|
secondSelectionChange (objs) {
|
||||||
this.secondBatchDeleteObjs = objs
|
this.secondBatchDeleteObjs = objs
|
||||||
},
|
},
|
||||||
categoryFormat (row, column) {
|
|
||||||
// const category = row.category
|
|
||||||
// const t = knowledgeBaseCategory.find(t => t.value === category)
|
|
||||||
// return t ? t.name : category
|
|
||||||
},
|
|
||||||
sourceFormat (row, column) {
|
|
||||||
// const source = row.source
|
|
||||||
// const t = knowledgeBaseSource.find(t => t.value === source)
|
|
||||||
// return t ? t.name : source
|
|
||||||
},
|
|
||||||
submit () {
|
submit () {
|
||||||
this.delBatchDetection()
|
this.delBatchDetection()
|
||||||
this.showConfirmDialog = false
|
this.showConfirmDialog = false
|
||||||
@@ -205,40 +203,64 @@ export default {
|
|||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// todo 调用接口删除
|
this.toggleLoading(true)
|
||||||
// this.toggleLoading(true)
|
axios.delete(api.detection.delete + '?ruleIds=' + ids).then(response => {
|
||||||
// axios.delete(api.detection.delete + '?ruleIds=' + ids).then(response => {
|
if (response.status === 200) {
|
||||||
// if (response.status === 200) {
|
this.delFlag = true
|
||||||
// this.delFlag = true
|
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') })
|
||||||
// this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') })
|
this.secondBatchDeleteObjs.forEach((item) => {
|
||||||
// this.secondBatchDeleteObjs.forEach((item) => {
|
this.$refs.delDataTable.toggleRowSelection(item, false)
|
||||||
// this.$refs.delDataTable.toggleRowSelection(item, false)
|
})
|
||||||
// })
|
this.secondBatchDeleteObjs = []
|
||||||
// this.$refs.knowledgeFilter.reloadFilter()
|
this.batchDeleteObjs = []
|
||||||
// this.secondBatchDeleteObjs = []
|
delete this.searchLabel.category
|
||||||
// this.batchDeleteObjs = []
|
delete this.searchLabel.source
|
||||||
// delete this.searchLabel.category
|
this.getTableData()
|
||||||
// delete this.searchLabel.source
|
} else {
|
||||||
// this.getTableData()
|
this.$message.error(response.data.message)
|
||||||
// } else {
|
}
|
||||||
// this.$message.error(response.data.message)
|
}).finally(() => {
|
||||||
// }
|
this.toggleLoading(false)
|
||||||
// }).finally(() => {
|
if (this.isSelectedStatus) {
|
||||||
// this.toggleLoading(false)
|
this.isSelectedStatus = false
|
||||||
// if (this.isSelectedStatus != undefined) {
|
this.disableDelete = true
|
||||||
// this.isSelectedStatus = false
|
this.secondBatchDeleteObjs = []
|
||||||
// this.disableDelete = true
|
this.batchDeleteObjs = []
|
||||||
// this.secondBatchDeleteObjs = []
|
this.showConfirmDialog = false
|
||||||
// this.batchDeleteObjs = []
|
}
|
||||||
// this.showConfirmDialog = false
|
})
|
||||||
// }
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRowDoubleClick (data) {
|
onRowDoubleClick (data) {
|
||||||
// todo 暂时禁用,后续再开发时解禁
|
this.showDrawer = true
|
||||||
// this.showDrawer = true
|
this.drawerInfo = data
|
||||||
// this.drawerInfo = data
|
},
|
||||||
|
getFilterParams (params) {
|
||||||
|
const delList = []
|
||||||
|
if (params.status) {
|
||||||
|
this.filterParams.status = params.status
|
||||||
|
} else {
|
||||||
|
delete this.filterParams.status
|
||||||
|
delList.push('status')
|
||||||
|
}
|
||||||
|
if (params.category) {
|
||||||
|
this.filterParams.category = params.category
|
||||||
|
} else {
|
||||||
|
delete this.filterParams.category
|
||||||
|
delList.push('category')
|
||||||
|
}
|
||||||
|
if (params.eventType) {
|
||||||
|
this.filterParams.eventType = params.eventType
|
||||||
|
} else {
|
||||||
|
delete this.filterParams.eventType
|
||||||
|
delList.push('eventType')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.search(this.filterParams, 'detection', delList)
|
||||||
|
},
|
||||||
|
getPolicyTotal (total, enabledNum) {
|
||||||
|
this.policyTotal = total
|
||||||
|
this.policyEnabledNum = enabledNum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
252
src/views/detections/detectionPolicies/PolicyDrawer.vue
Normal file
252
src/views/detections/detectionPolicies/PolicyDrawer.vue
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
<template>
|
||||||
|
<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">ID: {{ drawerInfo.ruleId }}</div>
|
||||||
|
<div :class="`detection-tag-status${drawerInfo.status}`">
|
||||||
|
{{ $t(switchStatus(drawerInfo.status)) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-basic-function">
|
||||||
|
<div class="detection-drawer-title">{{ $t('overall.name') }}</div>
|
||||||
|
<div class="basic-function-value">{{ $_.get(detailData, 'name', '-') || '-'}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-basic-function">
|
||||||
|
<div class="detection-drawer-title">{{ $t('overall.type') }}</div>
|
||||||
|
<div class="basic-function-value">{{ $_.get(detailData, 'eventType', '-') || '-'}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-basic-description">
|
||||||
|
<div class="detection-drawer-title">{{ $t('config.dataSet.description') }}</div>
|
||||||
|
<div class="basic-description-value">{{ $_.get(detailData, 'description', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detection-drawer-collapse">
|
||||||
|
<el-collapse v-model="activeRule">
|
||||||
|
<el-collapse-item :title="$t('detection.ruleDefinition')" name="rule">
|
||||||
|
<div class="drawer-collapse-content">
|
||||||
|
|
||||||
|
<div class="drawer-basic-function">
|
||||||
|
<div class="detection-drawer-title">{{ $t('config.user.source') }}</div>
|
||||||
|
<div class="basic-function-value">{{ changeCategory(detailData.category) }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="detailData.ruleType==='indicator_match'">
|
||||||
|
<div class="drawer-basic-function">
|
||||||
|
<div class="detection-drawer-title">{{ $t('detection.library') }}</div>
|
||||||
|
<span class="basic-function-value">{{ $_.get(detailData, 'ruleConfigObj.knowledgeBase.name', '-') || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-basic-function">
|
||||||
|
<div class="detection-drawer-title">{{ $t('detection.level') }}</div>
|
||||||
|
<div class="detection-drawer-title">
|
||||||
|
<div class="detection__icon" :style="`background-color: ${eventSeverityColor[detailData.ruleConfigObj.level]}`"></div>
|
||||||
|
<div class="basic-function-value">{{ changeSecurityLevel(detailData.ruleConfigObj) }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<div class="drawer-basic-function">
|
||||||
|
<div class="detection-drawer-title">{{ $t('detection.create.dimensions') }}</div>
|
||||||
|
<span class="detection-tag-blue">{{ detailData.dimensions }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-basic-function">
|
||||||
|
<div class="detection-drawer-title">{{ $t('detections.filters') }}</div>
|
||||||
|
<span class="detection-tag-blue">Source Port</span>
|
||||||
|
<span style="margin: 0 6px;">{{ $t('detections.equal') }}</span><span>19890</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-basic-function" v-for="item in severityList" :key="item.severity"
|
||||||
|
style="padding-bottom: 0">
|
||||||
|
<div class="detection-drawer-title">
|
||||||
|
<div class="detection__icon" :style="`background-color: ${eventSeverityColor[item.severity]}`"></div>
|
||||||
|
<div>{{ toUpperCaseByString(item.severity) }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="detection-drawer-title">{{ $t('detections.conditions') }}</div>
|
||||||
|
<div>
|
||||||
|
<div class="detection-tag-gray margin-r-10">> 60 Kpackets/s</div>
|
||||||
|
<div class="detection-tag-gray">> 50 Unique Src IPs</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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-trigger">
|
||||||
|
Triggered when conditions occur at least
|
||||||
|
<span style="color: #046ECA">
|
||||||
|
{{ atLeast }} {{ times }}
|
||||||
|
</span> in
|
||||||
|
<span style="color: #046ECA">
|
||||||
|
{{ getNumberFromStr($_.get(detailData, 'ruleTriggerObj.interval', '0')) || '-' }}
|
||||||
|
{{ $_.get(detailData, 'ruleTriggerObj.intervalVal', '-') || '-' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-basic-function">
|
||||||
|
<div class="detection-drawer-title">{{ $t('detection.evaluationFrequency') }}</div>
|
||||||
|
<div class="drawer-trigger-minutes">
|
||||||
|
{{ getNumberFromStr($_.get(detailData, 'ruleTriggerObj.resetInterval', '0')) || '-' }}
|
||||||
|
{{ $_.get(detailData, 'ruleTriggerObj.intervalVal', '-') || '-' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="drawer-collapse-content" v-if="language==='cn'">
|
||||||
|
<div class="drawer-collapse-trigger">
|
||||||
|
当条件为
|
||||||
|
<span style="color: #046ECA">
|
||||||
|
{{ getNumberFromStr($_.get(detailData, 'ruleTriggerObj.interval', '0')) || '-' }}
|
||||||
|
{{ changeValueToLabel(detailData.ruleTriggerObj) }}
|
||||||
|
</span>内至少出现
|
||||||
|
<span style="color: #046ECA">
|
||||||
|
{{ $_.get(detailData, 'ruleTriggerObj.atLeast', '-') || '-' }} 次
|
||||||
|
</span>时触发
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-basic-function">
|
||||||
|
<div class="detection-drawer-title">评估频率</div>
|
||||||
|
<div class="drawer-trigger-minutes">
|
||||||
|
{{ getNumberFromStr($_.get(detailData, 'ruleTriggerObj.resetInterval', '0')) || '-' }}
|
||||||
|
{{ changeValueToLabel(detailData.ruleTriggerObj) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { switchStatus, toUpperCaseByString } from '@/utils/tools'
|
||||||
|
import { detectionUnitList, eventSeverityColor, securityLevel, storageKey } from '@/utils/constants'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { api } from '@/utils/api'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DetectionDrawer',
|
||||||
|
props: {
|
||||||
|
drawerInfo: {
|
||||||
|
type: Object
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
activeRule: 'rule',
|
||||||
|
activeTrigger: 'trigger',
|
||||||
|
detailData: {},
|
||||||
|
eventSeverityColor,
|
||||||
|
severityList: [],
|
||||||
|
language: 'en',
|
||||||
|
atLeast: 0,
|
||||||
|
times: 'time'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
drawerInfo: {
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
handler (n) {
|
||||||
|
if (n) {
|
||||||
|
this.getDetailData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.language = localStorage.getItem(storageKey.language) || 'en'
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
switchStatus,
|
||||||
|
toUpperCaseByString,
|
||||||
|
getDetailData () {
|
||||||
|
this.severityList = [
|
||||||
|
{
|
||||||
|
severity: 'critical',
|
||||||
|
list: ['> 60 Kpackets/s', '> 50 Unique Src IPs']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
severity: 'high',
|
||||||
|
list: ['> 20 Kpackets/s', '> 50 Unique Src IPs']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
axios.get(`${api.detection.detail}/${this.drawerInfo.ruleId}`).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.detailData = res.data.data
|
||||||
|
this.atLeast = this.$_.get(this.detailData, 'ruleTriggerObj.atLeast', '-')
|
||||||
|
if (!isNaN(this.atLeast) && this.atLeast > 1) {
|
||||||
|
this.times = 'times'
|
||||||
|
} else {
|
||||||
|
this.times = 'time'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getNumberFromStr (str) {
|
||||||
|
return str.match(/\d+(\.\d+)?/g)[0]
|
||||||
|
},
|
||||||
|
changeCategory (value) {
|
||||||
|
if (value) {
|
||||||
|
const obj = detectionUnitList.categoryList.find(d => d.value === value)
|
||||||
|
let label = value
|
||||||
|
if (obj) {
|
||||||
|
label = this.$t(obj.label)
|
||||||
|
}
|
||||||
|
return label
|
||||||
|
} else {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeSecurityLevel (config) {
|
||||||
|
if (config) {
|
||||||
|
if (config.level) {
|
||||||
|
const obj = securityLevel.find(d => d.value === config.level)
|
||||||
|
let label = config.level
|
||||||
|
if (obj) {
|
||||||
|
label = this.$t(obj.label)
|
||||||
|
}
|
||||||
|
return label
|
||||||
|
} else {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeValueToLabel (config) {
|
||||||
|
if (config) {
|
||||||
|
if (config.intervalVal) {
|
||||||
|
const obj = detectionUnitList.intervalListCN.find(d => d.value === config.intervalVal)
|
||||||
|
let label = config.intervalVal
|
||||||
|
if (obj) {
|
||||||
|
label = this.$t(obj.label)
|
||||||
|
}
|
||||||
|
return label
|
||||||
|
} else {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
</style>
|
||||||
128
src/views/detections/detectionPolicies/PolicyFilter.vue
Normal file
128
src/views/detections/detectionPolicies/PolicyFilter.vue
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="new-detection-filter-title">
|
||||||
|
{{ $t('detections.filters') }}
|
||||||
|
</div>
|
||||||
|
<div class="new-detection-filter-content">
|
||||||
|
<div>
|
||||||
|
<div class="new-filter-content-title">{{ $t('overall.status') }}</div>
|
||||||
|
<div class="new-filter-content-content">
|
||||||
|
<el-checkbox-group v-model="checkStatus" @change="onChangeCategory" style="display: flex;flex-direction: column">
|
||||||
|
<el-checkbox v-for="item in statusList" :key="item.name" class="new-filter-content-checkbox" :label="item.status">
|
||||||
|
<div>{{ item.name }}</div>
|
||||||
|
</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="new-filter-content-title">{{ $t('overall.category') }}</div>
|
||||||
|
<div class="new-filter-content-content">
|
||||||
|
<el-checkbox-group v-model="checkCategory" @change="onChangeCategory">
|
||||||
|
<el-checkbox v-for="item in categoryList" :key="item.name" class="new-filter-content-checkbox" :label="item.name">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="new-filter-content-title">{{ $t('overall.type') }}</div>
|
||||||
|
<div class="new-filter-content-content">
|
||||||
|
<el-checkbox-group v-model="checkEventType" @change="onChangeCategory" style="display: flex;flex-direction: column">
|
||||||
|
<el-checkbox v-for="item in eventTypeList" :key="item.name" class="new-filter-content-checkbox" :label="item.name">
|
||||||
|
{{ item.name }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
import { api } from '@/utils/api'
|
||||||
|
import { switchStatus } from '@/utils/tools'
|
||||||
|
import { detectionUnitList } from '@/utils/constants'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DetectionFilter',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
statusList: [], // 状态列表数据
|
||||||
|
categoryList: [], // 类别列表
|
||||||
|
eventTypeList: [], // 事件类型列表
|
||||||
|
checkStatus: [], // checkbox选择的状态列表
|
||||||
|
checkCategory: [], // checkbox选择的类别
|
||||||
|
checkEventType: [], // checkbox选择的事件类型
|
||||||
|
policyTotal: 0, // 策略总条数,与筛选条件无关
|
||||||
|
policyEnabledNum: 0 // 策略中状态为enabled的数量
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.getFilterData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getFilterData () {
|
||||||
|
axios.get(api.detection.statistics).then(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
const data = response.data.data
|
||||||
|
if (data.statusList) {
|
||||||
|
data.statusList.forEach(item => {
|
||||||
|
this.policyTotal += item.count
|
||||||
|
if (item.status === 1) {
|
||||||
|
this.policyEnabledNum = item.count
|
||||||
|
}
|
||||||
|
this.statusList.push({ status: item.status, name: this.$t(switchStatus(item.status)) })
|
||||||
|
})
|
||||||
|
this.$emit('policyTotal', this.policyTotal, this.policyEnabledNum)
|
||||||
|
} else {
|
||||||
|
this.statusList = []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.categoryList) {
|
||||||
|
this.categoryList = []
|
||||||
|
data.categoryList.forEach(item => {
|
||||||
|
const obj = detectionUnitList.categoryList.find(d => d.value === item.name)
|
||||||
|
if (obj) {
|
||||||
|
this.categoryList.push({ ...item, label: this.$t(obj.label) })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.categoryList = []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.eventTypeList) {
|
||||||
|
this.eventTypeList = data.eventTypeList
|
||||||
|
} else {
|
||||||
|
this.eventTypeList = []
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error(response.data)
|
||||||
|
}
|
||||||
|
}).catch((e) => {
|
||||||
|
console.error(e)
|
||||||
|
this.statusList = []
|
||||||
|
this.categoryList = []
|
||||||
|
this.eventTypeList = []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onChangeCategory () {
|
||||||
|
const obj = {}
|
||||||
|
if (this.checkStatus.length === 1) {
|
||||||
|
obj.status = this.checkStatus.join(',')
|
||||||
|
} else {
|
||||||
|
delete obj.status
|
||||||
|
}
|
||||||
|
if (this.checkCategory.length > 0) {
|
||||||
|
obj.category = this.checkCategory.join(',')
|
||||||
|
}
|
||||||
|
if (this.checkEventType.length > 0) {
|
||||||
|
obj.eventType = this.checkEventType.join(',')
|
||||||
|
}
|
||||||
|
this.$emit('filterParams', obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
497
src/views/detections/detectionPolicies/PolicyForm.vue
Normal file
497
src/views/detections/detectionPolicies/PolicyForm.vue
Normal file
@@ -0,0 +1,497 @@
|
|||||||
|
<template>
|
||||||
|
<div class="detection-form">
|
||||||
|
<loading :loading="myLoading"></loading>
|
||||||
|
|
||||||
|
<div class="detection-form-header">
|
||||||
|
{{ ruleId ? $t('detection.editEventPolicies') : $t('detection.createEventPolicies') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--第一步:General Settings-->
|
||||||
|
<div class="detection-form-content">
|
||||||
|
<div class="detection-form-collapse">
|
||||||
|
<el-collapse v-model="activeNames">
|
||||||
|
<el-collapse-item name="1">
|
||||||
|
<template #title>
|
||||||
|
<div class="form-collapse-header">
|
||||||
|
<div :class="activeNames[0]==='1' ? 'form-collapse-header-no-active' : 'form-collapse-header-no'">1</div>
|
||||||
|
<div class="form-collapse-header-title">{{ $t('detection.create.generalSettings') }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="form-collapse-content">
|
||||||
|
<general-settings ref="form" :editObj="editObj" :isComplete="isComplete" @setSettingForm="getFormSetting" />
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--第二步:Rule Definition-->
|
||||||
|
<div class="detection-form-collapse">
|
||||||
|
<el-collapse v-model="activeNames" style="position: relative;">
|
||||||
|
<el-collapse-item name="2">
|
||||||
|
<template #title>
|
||||||
|
<div class="form-collapse-header">
|
||||||
|
<div :class="activeNames[0]==='2' ? 'form-collapse-header-no-active' : 'form-collapse-header-no'">2</div>
|
||||||
|
<div class="form-collapse-header-title">{{ $t('detection.create.ruleDefinition') }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="form-collapse-content">
|
||||||
|
<rule-definition :settingObj="settingObj" :editObj="editObj" :isComplete="isComplete" @setRuleObj="getRuleObj" />
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--第三步:Trigger-->
|
||||||
|
<div class="detection-form-collapse">
|
||||||
|
<el-collapse v-model="activeNames">
|
||||||
|
<el-collapse-item name="3">
|
||||||
|
<template #title>
|
||||||
|
<div class="form-collapse-header">
|
||||||
|
<div :class="activeNames[0]==='3' ? 'form-collapse-header-no-active' : 'form-collapse-header-no'">3</div>
|
||||||
|
<div class="form-collapse-header-title">{{ $t('detection.create.trigger') }}</div>
|
||||||
|
</div>
|
||||||
|
</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">
|
||||||
|
<div class="trigger-block-item margin-b-10">
|
||||||
|
<div>At least</div>
|
||||||
|
<el-form-item prop="atLeast">
|
||||||
|
<el-input size="mini" maxlength="5" v-model="triggerObj.atLeast" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<div>times within</div>
|
||||||
|
|
||||||
|
<el-form-item prop="interval" class="policy-form-item">
|
||||||
|
<el-input size="mini" maxlength="5" v-model="triggerObj.interval" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item prop="intervalVal">
|
||||||
|
<el-select v-model="triggerObj.intervalVal" class="form-trigger__select" placeholder=" " size="mini">
|
||||||
|
<el-option
|
||||||
|
v-for="item in intervalList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="trigger-block-item">
|
||||||
|
<div>With the counter resetting after no activity for</div>
|
||||||
|
<el-form-item prop="resetInterval" class="policy-form-item">
|
||||||
|
<el-input size="mini" maxlength="5" v-model="triggerObj.resetInterval" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="resetIntervalVal">
|
||||||
|
<el-select v-model="triggerObj.resetIntervalVal" class="form-trigger__select" placeholder=" " size="mini">
|
||||||
|
<el-option
|
||||||
|
v-for="item in intervalList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
<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">
|
||||||
|
<el-input size="mini" maxlength="5" v-model="triggerObj.interval" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item prop="intervalVal">
|
||||||
|
<el-select v-model="triggerObj.intervalVal" class="form-trigger__select" placeholder=" " size="mini">
|
||||||
|
<el-option
|
||||||
|
v-for="item in intervalList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
内至少发生
|
||||||
|
<el-form-item prop="atLeast">
|
||||||
|
<el-input size="mini" maxlength="5" v-model="triggerObj.atLeast" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
次
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="trigger-block-item">
|
||||||
|
若连续
|
||||||
|
<el-form-item prop="resetInterval">
|
||||||
|
<el-input size="mini" maxlength="5" v-model="triggerObj.resetInterval" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="resetIntervalVal">
|
||||||
|
<el-select v-model="triggerObj.resetIntervalVal" class="form-trigger__select" placeholder=" " size="mini">
|
||||||
|
<el-option
|
||||||
|
v-for="item in intervalList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
不活跃将重置计数
|
||||||
|
</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>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import GeneralSettings from '@/components/table/detection/GeneralSettings'
|
||||||
|
import RuleDefinition from '@/components/table/detection/RuleDefinition'
|
||||||
|
import { api } from '@/utils/api'
|
||||||
|
import axios from 'axios'
|
||||||
|
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 } from '@/utils/constants'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DetectionForm',
|
||||||
|
data () {
|
||||||
|
const intervalValidator = (rule, value, callback) => {
|
||||||
|
const obj = this.handleIntervalByDateType(rule, value, this.triggerObj.intervalVal)
|
||||||
|
if (!obj.flag && obj.msg) {
|
||||||
|
callback(new Error(obj.msg))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const intervalValValidator = (rule, value, callback) => {
|
||||||
|
const obj = this.handleIntervalByDateType(rule, this.triggerObj.intervalVal, value)
|
||||||
|
if (!obj.flag && obj.msg) {
|
||||||
|
this.$refs.form3.validateField('interval')
|
||||||
|
callback()
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const resetIntervalValidator = (rule, value, callback) => {
|
||||||
|
const obj = this.handleIntervalByDateType(rule, value, this.triggerObj.resetIntervalVal)
|
||||||
|
if (!obj.flag && obj.msg) {
|
||||||
|
callback(new Error(obj.msg))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const resetIntervalValValidator = (rule, value, callback) => {
|
||||||
|
const obj = this.handleIntervalByDateType(rule, this.triggerObj.resetIntervalVal, value)
|
||||||
|
if (!obj.flag && obj.msg) {
|
||||||
|
this.$refs.form3.validateField('resetInterval')
|
||||||
|
callback()
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
activeNames: ['1'],
|
||||||
|
rules: {
|
||||||
|
atLeast: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: this.$t('validate.required'),
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
interval: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: this.$t('validate.required'),
|
||||||
|
trigger: 'blur'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: intervalValidator,
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
intervalVal: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: this.$t('validate.required'),
|
||||||
|
trigger: 'change'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: intervalValValidator,
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
resetInterval: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: this.$t('validate.required'),
|
||||||
|
trigger: 'blur'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: resetIntervalValidator,
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
resetIntervalVal: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: this.$t('validate.required'),
|
||||||
|
trigger: 'change'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: resetIntervalValValidator,
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
intervalList: [],
|
||||||
|
editObj: {},
|
||||||
|
isComplete: true, // 参数完整标识,默认完整(照顾编辑模式),false即不完整
|
||||||
|
language: 'en'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
GeneralSettings,
|
||||||
|
RuleDefinition,
|
||||||
|
Loading
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.language = localStorage.getItem(storageKey.language) || 'en'
|
||||||
|
if (this.language === 'en') {
|
||||||
|
this.intervalList = detectionUnitList.intervalList
|
||||||
|
} else if (this.language === 'cn') {
|
||||||
|
this.intervalList = detectionUnitList.intervalListCN
|
||||||
|
}
|
||||||
|
this.getDetailInfo()
|
||||||
|
},
|
||||||
|
setup () {
|
||||||
|
const { query } = useRoute()
|
||||||
|
const ruleId = ref(query.id || '')
|
||||||
|
const pageNoForTable = ref(query.pageNoForTable || 1)
|
||||||
|
const myLoading = ref(!!ruleId.value)
|
||||||
|
// General Settings,即第一步的form表单信息
|
||||||
|
const settingObj = ref({})
|
||||||
|
// 第二步的form表单信息
|
||||||
|
const ruleObj = ref({})
|
||||||
|
// 第三步的form表单信息
|
||||||
|
const triggerObj = ref({
|
||||||
|
atLeast: '',
|
||||||
|
interval: '',
|
||||||
|
intervalVal: '',
|
||||||
|
resetInterval: '',
|
||||||
|
resetIntervalVal: '',
|
||||||
|
finishFlag: false
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
ruleId,
|
||||||
|
myLoading,
|
||||||
|
pageNoForTable,
|
||||||
|
settingObj,
|
||||||
|
ruleObj,
|
||||||
|
triggerObj
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** 编辑时获取详情 */
|
||||||
|
getDetailInfo () {
|
||||||
|
if (this.ruleId) {
|
||||||
|
axios.get(`${api.detection.detail}/${this.ruleId}`).then(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
if (!response.data.data) {
|
||||||
|
throw new Error('No data found, id: ' + this.ruleId)
|
||||||
|
}
|
||||||
|
this.myLoading = false
|
||||||
|
this.editObj = { ...response.data.data, ruleId: this.ruleId }
|
||||||
|
this.settingObj = this.$_.cloneDeep(this.editObj)
|
||||||
|
this.settingObj.editFlag = false
|
||||||
|
this.settingObj.saveFlag = true
|
||||||
|
this.ruleObj = this.$_.cloneDeep(this.editObj.ruleConfigObj)
|
||||||
|
this.triggerObj = this.$_.cloneDeep(this.editObj.ruleTriggerObj)
|
||||||
|
this.triggerObj.intervalVal = getTimeByDurations(this.triggerObj.interval).type
|
||||||
|
this.triggerObj.interval = getTimeByDurations(this.triggerObj.interval).value
|
||||||
|
this.triggerObj.resetIntervalVal = getTimeByDurations(this.triggerObj.resetInterval).type
|
||||||
|
this.triggerObj.resetInterval = getTimeByDurations(this.triggerObj.resetInterval).value
|
||||||
|
this.activeNames = ['1', '2', '3']
|
||||||
|
} else {
|
||||||
|
console.error(response.data)
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
|
this.$router.push({
|
||||||
|
path: '/detectionPolicy',
|
||||||
|
query: {
|
||||||
|
pageNo: this.pageNoForTable ? Number(this.pageNoForTable) : 1,
|
||||||
|
t: +new Date()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 获取General Settings折叠板form数据 */
|
||||||
|
getFormSetting (data) {
|
||||||
|
this.handleActiveNames('1', this.activeNames, data.settingNoContinue)
|
||||||
|
this.settingObj = JSON.parse(JSON.stringify(data))
|
||||||
|
},
|
||||||
|
/** 获取Rule Definition折叠板form数据 */
|
||||||
|
getRuleObj (data) {
|
||||||
|
this.handleActiveNames('2', this.activeNames, data.ruleNoContinue)
|
||||||
|
this.ruleObj = JSON.parse(JSON.stringify(data))
|
||||||
|
},
|
||||||
|
/** 自动展开收起折叠板 */
|
||||||
|
handleActiveNames (name, arr, flag) {
|
||||||
|
if (!flag) {
|
||||||
|
const list = arr
|
||||||
|
list.splice(list.indexOf(name), 1)
|
||||||
|
if (name === '1' && list.indexOf('2') < 0) {
|
||||||
|
list.push('2')
|
||||||
|
}
|
||||||
|
if (name === '2' && list.indexOf('3') < 0) {
|
||||||
|
list.push('3')
|
||||||
|
}
|
||||||
|
this.activeNames = []
|
||||||
|
list.forEach(t => {
|
||||||
|
this.activeNames.push(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/** 创建policy */
|
||||||
|
createPolicy (flag) {
|
||||||
|
const settingLen = Object.keys(this.settingObj).length
|
||||||
|
const ruleLen = Object.keys(this.ruleObj).length
|
||||||
|
|
||||||
|
if (settingLen > 0 && ruleLen > 0) {
|
||||||
|
this.$refs.form3.validate(valid => {
|
||||||
|
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)
|
||||||
|
formObj.ruleTrigger.atLeast = parseInt(formObj.ruleTrigger.atLeast)
|
||||||
|
formObj.ruleTrigger = JSON.stringify(formObj.ruleTrigger)
|
||||||
|
// 删除多余参数
|
||||||
|
delete formObj.ruleConfigObj
|
||||||
|
delete formObj.ruleTriggerObj
|
||||||
|
delete formObj.editFlag
|
||||||
|
delete formObj.saveFlag
|
||||||
|
|
||||||
|
if (!this.ruleId) {
|
||||||
|
// post调用是新增,put是编辑
|
||||||
|
this.myLoading = true
|
||||||
|
axios.post(api.detection.create.create, formObj).then(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
this.$message({
|
||||||
|
duration: 2000,
|
||||||
|
type: 'success',
|
||||||
|
message: this.$t('tip.saveSuccess')
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$router.push({
|
||||||
|
path: '/detectionPolicy',
|
||||||
|
query: {
|
||||||
|
t: +new Date()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.error(response.data.message)
|
||||||
|
this.$message.error(this.errorMsgHandler(response))
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
|
}).finally(() => {
|
||||||
|
this.myLoading = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log('进来')
|
||||||
|
this.myLoading = true
|
||||||
|
axios.put(api.detection.create.create, formObj).then(response => {
|
||||||
|
if (response.status === 200) {
|
||||||
|
this.$message({
|
||||||
|
duration: 2000,
|
||||||
|
type: 'success',
|
||||||
|
message: this.$t('tip.saveSuccess')
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$router.push({
|
||||||
|
path: '/detectionPolicy',
|
||||||
|
query: {
|
||||||
|
pageNo: self.pageNoForTable ? Number(self.pageNoForTable) : 1,
|
||||||
|
t: +new Date()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.error(response.data.message)
|
||||||
|
this.$message.error(this.errorMsgHandler(response))
|
||||||
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
this.$message.error(this.errorMsgHandler(e))
|
||||||
|
}).finally(() => {
|
||||||
|
this.myLoading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.isComplete = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (settingLen === 0) {
|
||||||
|
this.isComplete = false
|
||||||
|
this.handleFormError('1')
|
||||||
|
} else if (ruleLen === 0) {
|
||||||
|
this.isComplete = false
|
||||||
|
this.handleFormError('2')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleFormError (name) {
|
||||||
|
const list = this.activeNames
|
||||||
|
if (list.indexOf(name) < 0) {
|
||||||
|
list.push(name)
|
||||||
|
this.activeNames = []
|
||||||
|
list.forEach(t => {
|
||||||
|
this.activeNames.push(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.$message.error(this.$t('detection.create.informationFilled'))
|
||||||
|
},
|
||||||
|
handleIntervalByDateType (rule, value, type) {
|
||||||
|
if (value && (type === 'hours' || type === '小时')) {
|
||||||
|
if (parseInt(value) <= 24) {
|
||||||
|
return { flag: true }
|
||||||
|
} else {
|
||||||
|
return { flag: false, msg: this.$t('policy.dateTimeRangeHours') }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (value && (type === 'minutes' || type === '分钟')) {
|
||||||
|
if (parseInt(value) <= 1440) {
|
||||||
|
return { flag: true }
|
||||||
|
} else {
|
||||||
|
return { flag: false, msg: this.$t('policy.dateTimeRangeMinutes') }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (value && (type === 'seconds' || type === '秒')) {
|
||||||
|
if (parseInt(value) <= 86400) {
|
||||||
|
return { flag: true }
|
||||||
|
} else {
|
||||||
|
return { flag: false, msg: this.$t('policy.dateTimeRangeSeconds') }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -50,9 +50,12 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-else-if="item.prop === 'status'">
|
<template v-else-if="item.prop === 'status'">
|
||||||
<div :class="`detection-tag-status${scope.row[item.prop]}`">
|
<div :class="`detection-tag-status${scope.row[item.prop]}`">
|
||||||
{{ switchStatus(scope.row[item.prop]) }}
|
{{ $t(switchStatus(scope.row[item.prop])) }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="item.prop === 'category'">
|
||||||
|
{{ changeCategory(scope.row[item.prop]) }}
|
||||||
|
</template>
|
||||||
<template v-else-if="item.prop === 'description'">
|
<template v-else-if="item.prop === 'description'">
|
||||||
<div style="padding-right: 20px">{{ scope.row[item.prop] }}</div>
|
<div style="padding-right: 20px">{{ scope.row[item.prop] }}</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -77,6 +80,8 @@
|
|||||||
import table from '@/mixins/table'
|
import table from '@/mixins/table'
|
||||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||||
import { switchStatus } from '@/utils/tools'
|
import { switchStatus } from '@/utils/tools'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { detectionUnitList } from '@/utils/constants'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DetectionTable',
|
name: 'DetectionTable',
|
||||||
@@ -127,15 +132,13 @@ export default {
|
|||||||
show: true
|
show: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// label: this.$t('config.user.createTime'),
|
label: this.$t('detection.create.dimensions'),
|
||||||
label: 'Dimensions',
|
|
||||||
prop: 'dimensions',
|
prop: 'dimensions',
|
||||||
minWidth: 204,
|
minWidth: 204,
|
||||||
show: true
|
show: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// label: this.$t('config.user.createTime'),
|
label: this.$t('detection.library'),
|
||||||
label: 'Library',
|
|
||||||
prop: 'library',
|
prop: 'library',
|
||||||
minWidth: 204,
|
minWidth: 204,
|
||||||
show: true
|
show: true
|
||||||
@@ -151,9 +154,9 @@ export default {
|
|||||||
if (n) {
|
if (n) {
|
||||||
n.forEach(t => {
|
n.forEach(t => {
|
||||||
if (t.ruleType === 'indicator_match') {
|
if (t.ruleType === 'indicator_match') {
|
||||||
t.library = t.ruleConfig.knowledge.name
|
t.library = _.get(t, 'ruleConfigObj.knowledgeBase.name', '-')
|
||||||
} else if (t.ruleType === 'threshold') {
|
} else if (t.ruleType === 'threshold') {
|
||||||
t.dimensions = t.ruleConfig.dimensions
|
t.dimensions = _.get(t, 'ruleConfigObj.dimensions', '-')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -165,6 +168,16 @@ export default {
|
|||||||
switchStatus,
|
switchStatus,
|
||||||
rowDoubleClick (data) {
|
rowDoubleClick (data) {
|
||||||
this.$emit('rowDoubleClick', data)
|
this.$emit('rowDoubleClick', data)
|
||||||
|
},
|
||||||
|
changeCategory (value) {
|
||||||
|
if (value) {
|
||||||
|
const obj = detectionUnitList.categoryList.find(d => d.value === value)
|
||||||
|
let label = value
|
||||||
|
if (obj) {
|
||||||
|
label = this.$t(obj.label)
|
||||||
|
}
|
||||||
|
return label
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,14 +11,16 @@
|
|||||||
<span>{{ $t('overall.create') }}</span>
|
<span>{{ $t('overall.create') }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- <button-->
|
<button
|
||||||
<!-- id="knowledge-base-edit"-->
|
:disabled="disableEdit"
|
||||||
<!-- :title="$t('knowledgeBase.editKnowledgeBase')"-->
|
id="knowledge-base-edit"
|
||||||
<!-- class="top-tool-btn margin-r-10"-->
|
:title="$t('knowledgeBase.editKnowledgeBase')"
|
||||||
<!-- style="width:72px;">-->
|
class="top-tool-btn margin-r-10"
|
||||||
<!-- <i class="cn-icon-edit cn-icon" ></i>-->
|
@click="onEdit"
|
||||||
<!-- <span>{{$t('overall.edit')}}</span>-->
|
style="width:72px;">
|
||||||
<!-- </button>-->
|
<i class="cn-icon-edit cn-icon" ></i>
|
||||||
|
<span>{{$t('overall.edit')}}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
:disabled="disableDelete"
|
:disabled="disableDelete"
|
||||||
@@ -51,6 +53,10 @@ export default {
|
|||||||
disableDelete: {
|
disableDelete: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
|
},
|
||||||
|
disableEdit: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
@@ -65,6 +71,9 @@ export default {
|
|||||||
onCreate () {
|
onCreate () {
|
||||||
this.$emit('create')
|
this.$emit('create')
|
||||||
},
|
},
|
||||||
|
onEdit () {
|
||||||
|
this.$emit('edit')
|
||||||
|
},
|
||||||
onDelete (data) {
|
onDelete (data) {
|
||||||
this.$emit('delete', data)
|
this.$emit('delete', data)
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
} from '@/views/charts/charts/tools'
|
} from '@/views/charts/charts/tools'
|
||||||
import unitConvert from '@/utils/unit-convert'
|
import unitConvert from '@/utils/unit-convert'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
import { dateFormatByAppearance, xAxisTimeFormatter, xAxisTimeRich } from '@/utils/date-util'
|
||||||
import { unitTypes } from '@/utils/constants'
|
import { unitTypes } from '@/utils/constants'
|
||||||
|
|
||||||
const severitySeriesIndexMappings = [
|
const severitySeriesIndexMappings = [
|
||||||
@@ -67,8 +67,8 @@ export const multipleBarOption = {
|
|||||||
source: [
|
source: [
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: [{
|
||||||
type: 'category',
|
type: 'time',
|
||||||
axisTick: { show: false },
|
axisTick: { show: false },
|
||||||
axisLine: {
|
axisLine: {
|
||||||
show: true,
|
show: true,
|
||||||
@@ -77,13 +77,16 @@ export const multipleBarOption = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
|
formatter: xAxisTimeFormatter,
|
||||||
|
rich: xAxisTimeRich,
|
||||||
color: '#737373',
|
color: '#737373',
|
||||||
interval: 'auto'
|
interval: 'auto'
|
||||||
},
|
},
|
||||||
|
splitNumber: 8,
|
||||||
splitLine: {
|
splitLine: {
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
},
|
}],
|
||||||
yAxis: {
|
yAxis: {
|
||||||
axisTick: { show: false },
|
axisTick: { show: false },
|
||||||
axisLine: {
|
axisLine: {
|
||||||
|
|||||||
@@ -3,162 +3,243 @@
|
|||||||
<div class="overview__left">
|
<div class="overview__left">
|
||||||
<div class="overview__title">{{ $t('overall.remark') }}</div>
|
<div class="overview__title">{{ $t('overall.remark') }}</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__content">
|
<div class="row__content1" v-if="detection.eventType === 'Command and Control' && detection.isBuiltin == 1">
|
||||||
<template v-if="detection.securityType === 'command and control'">
|
<span class="row__content--link">{{detection.victimIp}}</span> communicated with <span class="row__content--link">{{detection.offenderIp}}</span> that was associated with the indicator of {{detection.eventName}} activity, {{$_.get(detection, 'eventInfoObj.ioc_value', '') || ''}}.
|
||||||
<span
|
</div>
|
||||||
class="row__content--link"
|
<div class="row__content1" v-else-if="detection.eventType === 'Anonymity' && detection.isBuiltin == 1">
|
||||||
@click="goDetail('ip', detection.victimIp)"
|
<span class="row__content--link">{{detection.victimIp}}</span> communicated with <span class="row__content--link">{{detection.offenderIp}}</span> that was associated with the indicator of {{detection.eventName}}.
|
||||||
>{{ detection.victimIp }}</span>
|
</div>
|
||||||
<span>
|
<div class="row__content1" v-else>
|
||||||
{{$t('detection.commandAndControl')}}
|
{{basicInfo.ruleDescription || '-'}}
|
||||||
</span>
|
|
||||||
<span class="row__content--link" @click="goDetail('ip', basicInfo.iocValue)">{{basicInfo.iocValue || '-'}}</span></template
|
|
||||||
>
|
|
||||||
<template v-else>
|
|
||||||
<span
|
|
||||||
class="row__content--link"
|
|
||||||
@click="goDetail('ip', detection.victimIp)"
|
|
||||||
>{{ detection.victimIp }}</span
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
{{$t('detection.payloadAndDelivery')}}
|
|
||||||
</span>
|
|
||||||
<span class="row__content--link"
|
|
||||||
@click="goDetail('ip', basicInfo.iocValue)"
|
|
||||||
>{{
|
|
||||||
basicInfo.iocValue
|
|
||||||
}}</span></template>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__title">Fields</div>
|
<div class="overview__title">Fields</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label">{{ $t('detection.list.startTime') }}</div>
|
<div class="row__label">{{ $t('detection.list.startTime') }}</div>
|
||||||
<div class="row__content">
|
<div class="row__content">
|
||||||
{{
|
<i class="cn-icon cn-icon-time2 row__content__icon"></i>
|
||||||
basicInfo.startTime
|
{{ detection.startTime ? dateFormatByAppearance(detection.startTime) : '-' }}
|
||||||
? dateFormatByAppearance(basicInfo.startTime)
|
|
||||||
: '-'
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label">{{ $t('detections.victimIp') }}</div>
|
<div class="row__label">{{ $t('detections.victimIp') }}</div>
|
||||||
<div class="row__content">{{ basicInfo.victimIp || '-' }}</div>
|
<div class="row__content">{{ detection.victimIp || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label">{{ $t('detections.victimLocation') }}</div>
|
<div class="row__label">{{ $t('detections.victimLocation') }}</div>
|
||||||
<div class="row__content">
|
<div class="row__content">
|
||||||
{{ basicInfo.victimLocationCountry || '-' }}
|
<div v-if="$_.get(basicInfo, 'victimInfo.location.country')">
|
||||||
|
<img v-if="basicInfo.victimInfo.location.country===countryNameIdMapping.Unknown || !countryNameIdMapping[basicInfo.victimInfo.location.country]" src="../../../../public/images/flag/Unknown.svg" class="filter-country-flag">
|
||||||
|
<img v-else :src="require(`../../../../public/images/flag/${countryNameIdMapping[basicInfo.victimInfo.location.country]}.png`)" class="filter-country-flag" >
|
||||||
|
</div>
|
||||||
|
{{ locationRegion(basicInfo.victimInfo) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label">{{ $t('detections.victimAsn') }}</div>
|
<div class="row__label">{{ $t('detections.victimAsn') }}</div>
|
||||||
<div class="row__content">{{ basicInfo.victimAsn || '-' }}</div>
|
<div class="row__content">{{ $_.get(basicInfo, 'victimInfo.asn.asn', '-') || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label">{{ $t('detections.offenderIp') }}</div>
|
<div class="row__label">{{ $t('detections.offenderIp') }}</div>
|
||||||
<div class="row__content">{{ basicInfo.offenderIp || '-' }}</div>
|
<div class="row__content">{{ detection.offenderIp || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label">{{ $t('detections.offenderLocation') }}</div>
|
<div class="row__label">{{ $t('detections.offenderLocation') }}</div>
|
||||||
<div class="row__content">
|
<div class="row__content">
|
||||||
{{ basicInfo.offenderLocationCountry || '-' }}
|
<div v-if="$_.get(basicInfo, 'offenderInfo.location.country')">
|
||||||
|
<img v-if="basicInfo.offenderInfo.location.country===countryNameIdMapping.Unknown || !countryNameIdMapping[basicInfo.offenderInfo.location.country]" src="../../../../public/images/flag/Unknown.svg" class="filter-country-flag">
|
||||||
|
<img v-else :src="require(`../../../../public/images/flag/${countryNameIdMapping[basicInfo.offenderInfo.location.country]}.png`)" class="filter-country-flag" >
|
||||||
|
</div>
|
||||||
|
{{ locationRegion(basicInfo.offenderInfo) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label">{{ $t('detections.offenderAsn') }}</div>
|
<div class="row__label">{{ $t('detections.offenderAsn') }}</div>
|
||||||
<div class="row__content">{{ basicInfo.offenderAsn || '-' }}</div>
|
<div class="row__content">{{ $_.get(basicInfo, 'offenderInfo.asn.asn', '-') || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<div class="overview__row">
|
||||||
<div class="row__label">{{ $t('overall.domain') }}</div>
|
<div class="row__label">{{ $t('overall.domain') }}</div>
|
||||||
<div class="row__content">{{ basicInfo.domain || '-' }}</div>
|
<div class="row__content">{{ detection.domain || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__row">
|
<template v-if="detection.domain">
|
||||||
<div class="row__label">{{ $t('entities.domainCategory') }}</div>
|
<div class="overview__row">
|
||||||
<div class="row__content">
|
<div class="row__label">{{ $t('entities.domainCategory') }}</div>
|
||||||
{{ basicInfo.domainCategoryName || '-' }}
|
<div class="row__content">{{ $_.get(basicInfo, 'domainInfo.category.categoryName', '-') || '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="overview__row">
|
||||||
<div class="overview__row">
|
<div class="row__label">{{ $t('entities.domainDetail.categoryGroup') }}</div>
|
||||||
<div class="row__label">
|
<div class="row__content">{{ $_.get(basicInfo, 'domainInfo.category.categoryGroup', '-') || '-' }}</div>
|
||||||
{{ $t('entities.domainDetail.categoryGroup') }}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row__content">
|
<div class="overview__row">
|
||||||
{{ basicInfo.domainCategoryGroup || '-' }}
|
<div class="row__label">{{ $t('entities.reputationLevel') }}</div>
|
||||||
</div>
|
<div class="row__content" v-if="$_.get(basicInfo, 'domainInfo.category.reputationLevel')">
|
||||||
</div>
|
<div
|
||||||
<div class="overview__row">
|
class="row__tag row__tag__level"
|
||||||
<div class="row__label">{{ $t('entities.reputationLevel') }}</div>
|
:style="`background-color:${riskLevelColor1[basicInfo.domainInfo.category.reputationLevel]}`">
|
||||||
<div class="row__content">
|
{{ reputationLevel(basicInfo.domainInfo.category.reputationLevel) || '-' }}
|
||||||
<div
|
</div>
|
||||||
class="row__tag"
|
|
||||||
:style="`background-color:${eventSeverityColor[basicInfo.domainReputationLevel]}`"
|
|
||||||
>
|
|
||||||
{{ basicInfo.domainReputationLevel || '-' }}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row__content" v-else>-</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
<div class="overview__row">
|
<template v-if="detection.app">
|
||||||
<div class="row__label">APP</div>
|
<div class="overview__row">
|
||||||
<div class="row__content">{{ basicInfo.appName || '-' }}</div>
|
<div class="row__label">APP</div>
|
||||||
</div>
|
<div class="row__content">{{ $_.get(basicInfo, 'appInfo.category.appName', '-') || '-' }}</div>
|
||||||
<div class="overview__row">
|
</div>
|
||||||
<div class="row__label">APP {{ $t('entities.category') }}</div>
|
<div class="overview__row">
|
||||||
<div class="row__content">{{ basicInfo.appCategory || '-' }}</div>
|
<div class="row__label">APP {{ $t('entities.category') }}</div>
|
||||||
</div>
|
<div class="row__content">{{ $_.get(basicInfo, 'appInfo.category.appCategory', '-') || '-' }}</div>
|
||||||
<div class="overview__row">
|
</div>
|
||||||
<div class="row__label">APP {{ $t('entities.subcategory') }}</div>
|
<div class="overview__row">
|
||||||
<div class="row__content">{{ basicInfo.appSubcategory || '-' }}</div>
|
<div class="row__label">APP {{ $t('entities.subcategory') }}</div>
|
||||||
</div>
|
<div class="row__content">{{ $_.get(basicInfo, 'appInfo.category.appSubcategory', '-') || '-' }}</div>
|
||||||
<div class="overview__row">
|
</div>
|
||||||
<div class="row__label">{{ $t('overall.appRisk') }}</div>
|
<div class="overview__row">
|
||||||
<div class="row__content">
|
<div class="row__label">{{ $t('overall.appRisk') }}</div>
|
||||||
<div
|
<div class="row__content" v-if="$_.get(basicInfo, 'appInfo.category.appRisk')">
|
||||||
class="row__tag"
|
<div
|
||||||
:style="`background-color:${eventSeverityColor[basicInfo.appRisk]}`"
|
class="row__tag row__tag__level"
|
||||||
>
|
:style="`background-color:${riskLevelColor[basicInfo.appInfo.category.appRisk]}`">
|
||||||
{{ basicInfo.appRisk || '-' }}
|
{{ appRisk(basicInfo.appInfo.category.appRisk) || '-' }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row__content" v-else>-</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
<div class="overview__row">
|
<template v-if="detection.malware">
|
||||||
<div class="row__label">{{ $t('detections.malware') }}</div>
|
<div class="overview__row">
|
||||||
<div class="row__content">{{ basicInfo.malwareName || '-' }}</div>
|
<div class="row__label">{{ $t('detections.malware') }}</div>
|
||||||
</div>
|
<div class="row__content">{{ $_.get(detection, 'malware.malwareName', '-') || '-' }}</div>
|
||||||
<div class="overview__row">
|
|
||||||
<div class="row__label">{{ $t('detections.malwareAlias') }}</div>
|
|
||||||
<div class="row__content">{{ basicInfo.malwareAlias || '-' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="overview__row">
|
|
||||||
<div class="row__label">{{ $t('detections.malwareDescription') }}</div>
|
|
||||||
<div class="row__content">
|
|
||||||
{{ basicInfo.malwareDescription || '-' }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="overview__row">
|
||||||
<div class="overview__row">
|
<div class="row__label">{{ $t('detections.malwareAlias') }}</div>
|
||||||
<div class="row__label">{{ $t('detections.malwarePlatforms') }}</div>
|
<div class="row__content">{{ $_.get(detection, 'malware.malwareAlias', '-') || '-' }}</div>
|
||||||
<div class="row__content">{{ basicInfo.malwarePlatforms || '-' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="overview__row">
|
|
||||||
<div class="row__label">{{ $t('detections.malwareTechniques') }}</div>
|
|
||||||
<div class="row__content">
|
|
||||||
{{ basicInfo.malwareTechniques || '-' }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="overview__row">
|
||||||
<div class="overview__row">
|
<div class="row__label">{{ $t('detections.malwareDescription') }}</div>
|
||||||
<div class="row__label">{{ $t('detections.malwareGroups') }}</div>
|
<div class="row__content">{{ $_.get(detection, 'malware.mitreAttackDescription', '-') || '-' }}</div>
|
||||||
<div class="row__content">
|
|
||||||
{{ basicInfo.malwareGroups || '-' }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="overview__row">
|
||||||
<div class="overview__row">
|
<div class="row__label">{{ $t('detections.malwarePlatforms') }}</div>
|
||||||
<div class="row__label">{{ $t('detections.reference') }}</div>
|
<div class="row__content" v-if="$_.get(detection, 'malware.mitreAttackPlatforms')">
|
||||||
<div class="row__content row__content--link">
|
<svg class="icon item-popover-up row__content__svg" aria-hidden="true">
|
||||||
{{ reference || '-' }}
|
<use xlink:href="#cn-icon-windows"></use>
|
||||||
|
</svg>
|
||||||
|
{{ detection.malware.mitreAttackPlatforms }}
|
||||||
|
</div>
|
||||||
|
<div class="row__content" v-else>-</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="overview__row">
|
||||||
<!-- <template v-if="detection.securityType === 'command and control' || detection.securityType === 'payload_delivery'">
|
<div class="row__label">{{ $t('detections.malwareTechniques') }}</div>
|
||||||
</template>-->
|
<div class="row__content">{{ $_.get(detection, 'malware.mitreAttackTechniques', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detections.malwareGroups') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'malware.mitreAttackGroups', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detections.reference') }}</div>
|
||||||
|
<div class="row__content row__content--link" v-if="$_.get(detection, 'malware.reference')">
|
||||||
|
{{ detection.malware.reference }}
|
||||||
|
</div>
|
||||||
|
<div class="row__content">-</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="detection.darkweb">
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.nodeTypeLower') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.nodeType', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<template v-if="$_.get(detection.darkweb, 'nodeType', '') === 'tor'">
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.torFingerprint') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.torFingerprint', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.torFlags') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.torFlags', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.torVersion') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.torVersion', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">Tor ORPort</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.torOrPort', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">Tor DirPort</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.torDirPort', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="$_.get(detection.darkweb, 'nodeType', '') === 'i2p'">
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">I2P Hash</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.i2pHash', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.i2pVersion') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.i2pVersion', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.i2pBandwidth') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.i2pBandwidth', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="$_.get(detection.darkweb, 'nodeType', '') === 'mtproxy'">
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">MTProxy Secret</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.mtproxySecret', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.mtproxyPort') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.mtproxyPort', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="$_.get(detection.darkweb, 'nodeType', '') === 'obfs4'">
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.obfs4Fingerprint') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.obfs4Fingerprint', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.obfs4Cert') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.obfs4Cert', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.obfs4IatMode') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.obfs4IatMode', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.obfs4Port') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.obfs4Port', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="$_.get(detection.darkweb, 'nodeType', '') === 'snowflake'">
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.tor.snowflakePort') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'darkweb.snowflakePort', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.libraryId') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'eventInfoObj.knowledge_id', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.libraryName') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'eventInfoObj.name', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.iocType') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'eventInfoObj.ioc_type', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="overview__row">
|
||||||
|
<div class="row__label">{{ $t('detection.iocValue') }}</div>
|
||||||
|
<div class="row__content">{{ $_.get(detection, 'eventInfoObj.ioc_value', '-') || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__right">
|
<div class="overview__right">
|
||||||
<div class="overview__title">{{ $t('detections.goToVictim') }}</div>
|
<div class="overview__title">{{ $t('detections.goToVictim') }}</div>
|
||||||
@@ -167,7 +248,7 @@
|
|||||||
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span>
|
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span>
|
||||||
<span
|
<span
|
||||||
class="row__content--link"
|
class="row__content--link"
|
||||||
@click="goDetail('ip', basicInfo.victimIp)">{{ basicInfo.victimIp }}</span>
|
@click="goDetail('ip', detection.victimIp)">{{ detection.victimIp }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__title">{{ $t('detections.goToOffender') }}</div>
|
<div class="overview__title">{{ $t('detections.goToOffender') }}</div>
|
||||||
@@ -176,22 +257,22 @@
|
|||||||
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span>
|
<span class="row__content--span">{{ $t('detections.viewDetailOf') }}</span>
|
||||||
<span
|
<span
|
||||||
class="row__content--link"
|
class="row__content--link"
|
||||||
@click="goDetail('ip', basicInfo.offenderIp)"
|
@click="goDetail('ip', detection.offenderIp)"
|
||||||
>{{ basicInfo.offenderIp }}</span
|
>{{ detection.offenderIp }}</span
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="row__content--link"
|
class="row__content--link"
|
||||||
@click="goDetail('domain', basicInfo.domain)"
|
@click="goDetail('domain', detection.domain)"
|
||||||
>{{ basicInfo.domain }}</span
|
>{{ detection.domain }}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="overview__title">{{ $t('detections.goToHunt') }}</div>
|
<!-- <div class="overview__title">{{ $t('detections.goToHunt') }}</div>-->
|
||||||
<div class="overview__row">
|
<!-- <div class="overview__row">-->
|
||||||
<div class="row__content row__content--link">
|
<!-- <div class="row__content row__content--link">-->
|
||||||
{{ $t('detections.viewAllRelated') }}
|
<!-- {{ $t('detections.viewAllRelated') }}-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
<div class="overview__title">
|
<div class="overview__title">
|
||||||
{{ $t('detections.relatedDetections') }}
|
{{ $t('detections.relatedDetections') }}
|
||||||
</div>
|
</div>
|
||||||
@@ -221,18 +302,12 @@
|
|||||||
<div class="timeline__severity timeline__severity--high">
|
<div class="timeline__severity timeline__severity--high">
|
||||||
<i
|
<i
|
||||||
class="cn-icon cn-icon-alert-level"
|
class="cn-icon cn-icon-alert-level"
|
||||||
:style="`color:${eventSeverityColor[event.eventSeverity]}`"
|
:style="`color:${eventSeverityColor[event.severity]}`"
|
||||||
></i>
|
></i>
|
||||||
<span>{{ event.eventSeverity }}</span>
|
<span>{{ event.severity }}</span>
|
||||||
</div>
|
|
||||||
<div class="timeline__security-type">
|
|
||||||
{{ event.securityType }}
|
|
||||||
</div>
|
|
||||||
<div class="timeline__start-time">
|
|
||||||
{{
|
|
||||||
dateFormatByAppearance(event.startTime)
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="timeline__security-type">{{ event.eventType }}</div>
|
||||||
|
<div class="timeline__start-time">{{ dateFormatByAppearance(parseInt(event.startTime)) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row-timeline__foot">
|
<div class="row-timeline__foot">
|
||||||
@@ -240,7 +315,7 @@
|
|||||||
class="detection-ip"
|
class="detection-ip"
|
||||||
:class="{
|
:class="{
|
||||||
'detection-ip__current':
|
'detection-ip__current':
|
||||||
[basicInfo.offenderIp, basicInfo.victimIp].indexOf(
|
[detection.offenderIp, detection.victimIp].indexOf(
|
||||||
event.offenderIp,
|
event.offenderIp,
|
||||||
) > -1,
|
) > -1,
|
||||||
}"
|
}"
|
||||||
@@ -252,7 +327,7 @@
|
|||||||
class="detection-ip"
|
class="detection-ip"
|
||||||
:class="{
|
:class="{
|
||||||
'detection-ip__current':
|
'detection-ip__current':
|
||||||
[basicInfo.offenderIp, basicInfo.victimIp].indexOf(
|
[detection.offenderIp, detection.victimIp].indexOf(
|
||||||
event.victimIp,
|
event.victimIp,
|
||||||
) > -1,
|
) > -1,
|
||||||
}"
|
}"
|
||||||
@@ -270,8 +345,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { api } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
import { getMillisecond } from '@/utils/date-util'
|
import { getMillisecond, dateFormatByAppearance } from '@/utils/date-util'
|
||||||
import { eventSeverityColor, unitTypes } from '@/utils/constants'
|
import { eventSeverityColor, unitTypes, countryNameIdMapping, riskLevelMapping, riskLevelColor, riskLevelColor1 } from '@/utils/constants'
|
||||||
import unitConvert from '@/utils/unit-convert'
|
import unitConvert from '@/utils/unit-convert'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
export default {
|
export default {
|
||||||
@@ -282,34 +357,27 @@ export default {
|
|||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
eventSeverityColor,
|
eventSeverityColor,
|
||||||
|
riskLevelColor,
|
||||||
|
riskLevelColor1,
|
||||||
basicInfo: {},
|
basicInfo: {},
|
||||||
events: [],
|
events: [],
|
||||||
reference: 'https://attack.mitre.org'
|
reference: 'https://attack.mitre.org',
|
||||||
|
countryNameIdMapping
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
formatT0 () {
|
formatT0 () {
|
||||||
const vm = this
|
const vm = this
|
||||||
return function (event) {
|
return function (event) {
|
||||||
const diffSeconds = event.diffSeconds
|
const diffSeconds = parseInt(event.diffSeconds)
|
||||||
if (diffSeconds === 0) {
|
if (diffSeconds === 0) {
|
||||||
return 'T0'
|
return 'T0'
|
||||||
}
|
}
|
||||||
const eventStartTime = event.startTime
|
const eventStartTime = parseInt(event.startTime)
|
||||||
const entityStartTime = vm.detection.startTime
|
const entityStartTime = vm.detection.startTime
|
||||||
|
|
||||||
if (
|
if (_.isNumber(diffSeconds) && _.isNumber(eventStartTime) && _.isNumber(entityStartTime)) {
|
||||||
_.isNumber(diffSeconds) &&
|
const suffix = unitConvert(diffSeconds, unitTypes.time, 's', null, 0).join('')
|
||||||
_.isNumber(eventStartTime) &&
|
|
||||||
_.isNumber(entityStartTime)
|
|
||||||
) {
|
|
||||||
const suffix = unitConvert(
|
|
||||||
diffSeconds,
|
|
||||||
unitTypes.time,
|
|
||||||
's',
|
|
||||||
null,
|
|
||||||
0
|
|
||||||
).join('')
|
|
||||||
if (eventStartTime > entityStartTime) {
|
if (eventStartTime > entityStartTime) {
|
||||||
return `T0+${suffix}`
|
return `T0+${suffix}`
|
||||||
} else if (eventStartTime < entityStartTime) {
|
} else if (eventStartTime < entityStartTime) {
|
||||||
@@ -318,62 +386,105 @@ export default {
|
|||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
appRisk () {
|
||||||
|
return function (level) {
|
||||||
|
const m = riskLevelMapping.find(mapping => {
|
||||||
|
return mapping.value == level
|
||||||
|
})
|
||||||
|
return (m && this.$t(m.label)) || level
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reputationLevel () {
|
||||||
|
return function (level) {
|
||||||
|
const m = riskLevelMapping.find(mapping => {
|
||||||
|
return mapping.name == level
|
||||||
|
})
|
||||||
|
return (m && this.$t(m.label)) || level
|
||||||
|
}
|
||||||
|
},
|
||||||
|
locationRegion (info) {
|
||||||
|
return function (info) {
|
||||||
|
if (!info || !info.location) {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
let result = ''
|
||||||
|
if (info.location.country) {
|
||||||
|
result += `${info.location.country},`
|
||||||
|
}
|
||||||
|
if (info.location.province) {
|
||||||
|
result += `${info.location.province},`
|
||||||
|
}
|
||||||
|
if (info.location.city) {
|
||||||
|
result += `${info.location.city},`
|
||||||
|
}
|
||||||
|
result = result.substr(0, result.length - 1)
|
||||||
|
if (!result) {
|
||||||
|
result = '-'
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getMillisecond,
|
getMillisecond,
|
||||||
query () {
|
dateFormatByAppearance,
|
||||||
Promise.all([this.queryBasic(), this.queryEvent()]).then((responses) => {
|
/** 初始化实体详情 */
|
||||||
responses[0].malwareTechniques = responses[0].malwareTechniques.length > 2 ? responses[0].malwareTechniques.replace('[', '').replace(']', '').split(',', 5).join(', ') : ''
|
initEntityDetail () {
|
||||||
responses[0].malwareGroups = responses[0].malwareGroups.length > 2 ? responses[0].malwareGroups.replace('[', '').replace(']', '').split(',', 5).join(', ') : ''
|
// 为完整填充IP信息,攻击者ip、受害者ip都进行调用;
|
||||||
responses[0].malwarePlatforms = responses[0].malwarePlatforms.length > 1 ? responses[0].malwarePlatforms : ''
|
// 根据detection的eventInfo对象的ioc_type进行判断,若为domain,malware信息从domain详情中获取,并填充domain信息
|
||||||
responses[0].malwareDescription = responses[0].malwareDescription.length > 1 ? responses[0].malwareDescription : ''
|
// 若ioc_type为ip,则调用ip接口,填充malware信息
|
||||||
responses[0] && (this.basicInfo = responses[0])
|
// 最后调用app,填充app信息。经上获取完整实体详情则最少需要调用4次接口
|
||||||
responses[1] &&
|
if (this.detection.offenderIp) {
|
||||||
(this.events = responses[1].sort(
|
axios.get(`${api.detection.securityEvent.ipDetail}?resource=${this.detection.offenderIp}`).then(res => {
|
||||||
(e1, e2) => e1.startTime - e2.startTime
|
if (res.status === 200) {
|
||||||
))
|
this.basicInfo.offenderInfo = res.data.data
|
||||||
})
|
}
|
||||||
},
|
})
|
||||||
queryBasic () {
|
}
|
||||||
return new Promise((resolve, reject) => {
|
if (this.detection.victimIp) {
|
||||||
try {
|
axios.get(`${api.detection.securityEvent.ipDetail}?resource=${this.detection.victimIp}`).then(res => {
|
||||||
axios.get(api.detection.securityEvent.overviewBasic, {
|
if (res.status === 200) {
|
||||||
params: {
|
this.basicInfo.victimInfo = res.data.data
|
||||||
eventId: this.detection.eventId,
|
}
|
||||||
startTime: this.detection.startTime,
|
})
|
||||||
endTime: this.detection.endTime
|
}
|
||||||
}
|
if (this.detection.domain) {
|
||||||
}).then((response) => {
|
axios.get(`${api.detection.securityEvent.domainDetail}?resource=${this.detection.domain}`).then(res => {
|
||||||
if (response.status === 200) {
|
if (res.status === 200) {
|
||||||
resolve(response.data.data.result[0])
|
this.basicInfo.domainInfo = res.data.data
|
||||||
} else {
|
}
|
||||||
reject(response.data)
|
})
|
||||||
}
|
}
|
||||||
})
|
if (this.detection.app) {
|
||||||
} catch (e) {
|
axios.get(`${api.detection.securityEvent.appDetail}?resource=${this.detection.app}`).then(res => {
|
||||||
reject(e)
|
if (res.status === 200) {
|
||||||
}
|
this.basicInfo.appInfo = res.data.data
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (this.detection.ruleId) {
|
||||||
|
axios.get(`${api.detection.detail}/${this.detection.ruleId}`).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.basicInfo.ruleDescription = res.data.data.description
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
queryEvent () {
|
queryEvent () {
|
||||||
return new Promise((resolve, reject) => {
|
axios.get(api.detection.securityEvent.relationEvent, {
|
||||||
try {
|
params: {
|
||||||
axios.get(api.detection.securityEvent.overviewEvent, {
|
// startTime: this.detection.startTime,
|
||||||
params: {
|
unbiasedTime: this.detection.startTime,
|
||||||
startTime: this.detection.startTime,
|
offenderIp: this.detection.offenderIp,
|
||||||
offenderIp: this.detection.offenderIp,
|
victimIp: this.detection.victimIp,
|
||||||
victimIp: this.detection.victimIp
|
biasSecond: 3600
|
||||||
}
|
}
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
resolve(response.data.data.result)
|
this.events = response.data.data.result.sort((e1, e2) => e1.startTime - e2.startTime)
|
||||||
} else {
|
} else {
|
||||||
reject(response.data)
|
this.events = []
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
reject(e)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -391,7 +502,18 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.query()
|
this.initEntityDetail()
|
||||||
|
this.queryEvent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.row__label {
|
||||||
|
width: 176px;
|
||||||
|
}
|
||||||
|
.row__content {
|
||||||
|
width: calc(100% - 176px);
|
||||||
|
padding-right: 50px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,173 +0,0 @@
|
|||||||
<template>
|
|
||||||
<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">ID: {{ drawerInfo.ruleId }}</div>
|
|
||||||
<div :class="`detection-tag-status${detailData.status}`">
|
|
||||||
{{ switchStatus(detailData.status) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="drawer-basic-function">
|
|
||||||
<div class="detection-drawer-title">Name</div>
|
|
||||||
<div class="basic-function-value">{{ detailData.name }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="drawer-basic-function">
|
|
||||||
<div class="detection-drawer-title">Type</div>
|
|
||||||
<div class="basic-function-value">{{ detailData.eventType }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="drawer-basic-description">
|
|
||||||
<div class="detection-drawer-title">Description</div>
|
|
||||||
<div class="basic-description-value">{{ detailData.description }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="detection-drawer-collapse">
|
|
||||||
<el-collapse v-model="activeRule">
|
|
||||||
<el-collapse-item title="Rule Definitcm" name="rule">
|
|
||||||
<div class="drawer-collapse-content">
|
|
||||||
|
|
||||||
<div class="drawer-basic-function">
|
|
||||||
<div class="detection-drawer-title">Source</div>
|
|
||||||
<div class="basic-function-value">{{ detailData.category }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="detailData.ruleType==='indicator_match'">
|
|
||||||
<div class="drawer-basic-function">
|
|
||||||
<div class="detection-drawer-title">Library</div>
|
|
||||||
<span class="basic-function-value">{{ detailData.library }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="drawer-basic-function">
|
|
||||||
<div class="detection-drawer-title">Level</div>
|
|
||||||
<div class="detection-drawer-title">
|
|
||||||
<div class="detection__icon" :style="`background-color: ${eventSeverityColor['critical']}`"></div>
|
|
||||||
<div class="basic-function-value">Critical</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else>
|
|
||||||
<div class="drawer-basic-function">
|
|
||||||
<div class="detection-drawer-title">Dimensions</div>
|
|
||||||
<span class="detection-tag-blue">{{ detailData.dimensions }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="drawer-basic-function">
|
|
||||||
<div class="detection-drawer-title">Filters</div>
|
|
||||||
<span class="detection-tag-blue">source</span>
|
|
||||||
<span style="margin: 0 6px;">equal</span><span>19890</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="drawer-basic-function" v-for="item in severityList" :key="item.severity"
|
|
||||||
style="padding-bottom: 0">
|
|
||||||
<div class="detection-drawer-title">
|
|
||||||
<div class="detection__icon" :style="`background-color: ${eventSeverityColor[item.severity]}`"></div>
|
|
||||||
<div>{{ toUpperCaseByString(item.severity) }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="detection-drawer-title">Conditions</div>
|
|
||||||
<div>
|
|
||||||
<div class="detection-tag-gray margin-r-10">> 60 Kpackets/s</div>
|
|
||||||
<div class="detection-tag-gray">> 50 Unique Src IPs</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-collapse-item>
|
|
||||||
</el-collapse>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="detection-drawer-collapse" style="margin: 20px 0">
|
|
||||||
<el-collapse v-model="activeTrigger">
|
|
||||||
<el-collapse-item title="Trigger" name="trigger">
|
|
||||||
<div class="drawer-collapse-content">
|
|
||||||
<div class="drawer-collapse-trigger">
|
|
||||||
Triggered when conditions occur at least
|
|
||||||
<span style="color: #046ECA" v-if="detailData.trigger">
|
|
||||||
{{ detailData.trigger.atLeast }} time
|
|
||||||
</span> in
|
|
||||||
<span style="color: #046ECA" v-if="detailData.trigger">
|
|
||||||
<!--todo 此处返回的是PT5M,具体时间处理根据后续字段来看-->
|
|
||||||
{{ getNumberFromStr(detailData.trigger.interval) }} minutes
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="drawer-basic-function">
|
|
||||||
<div class="detection-drawer-title">Evaluation Frequency</div>
|
|
||||||
<div class="basic-function-value" v-if="detailData.trigger">{{ getNumberFromStr(detailData.trigger.resetInterval) }} minutes</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-collapse-item>
|
|
||||||
</el-collapse>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { switchStatus, toUpperCaseByString } from '@/utils/tools'
|
|
||||||
import { eventSeverityColor } from '@/utils/constants'
|
|
||||||
import axios from 'axios'
|
|
||||||
import { api } from '@/utils/api'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'DetectionDrawer',
|
|
||||||
props: {
|
|
||||||
drawerInfo: {
|
|
||||||
type: Object
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
activeRule: 'rule',
|
|
||||||
activeTrigger: 'trigger',
|
|
||||||
detailData: {},
|
|
||||||
eventSeverityColor,
|
|
||||||
severityList: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
drawerInfo: {
|
|
||||||
immediate: true,
|
|
||||||
deep: true,
|
|
||||||
handler (n) {
|
|
||||||
if (n) {
|
|
||||||
this.getDetailData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
switchStatus,
|
|
||||||
toUpperCaseByString,
|
|
||||||
getDetailData () {
|
|
||||||
this.severityList = [
|
|
||||||
{
|
|
||||||
severity: 'critical',
|
|
||||||
list: ['> 60 Kpackets/s', '> 50 Unique Src IPs']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
severity: 'high',
|
|
||||||
list: ['> 20 Kpackets/s', '> 50 Unique Src IPs']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
axios.get(`${api.detection.detail}/${this.drawerInfo.ruleId}`).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
this.detailData = res.data.data
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getNumberFromStr (str) {
|
|
||||||
return str.match(/\d+(\.\d+)?/g)[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
</style>
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div class="new-detection-filter-title">
|
|
||||||
{{ $t('detections.filters') }}
|
|
||||||
</div>
|
|
||||||
<div class="new-detection-filter-content">
|
|
||||||
<div>
|
|
||||||
<div class="new-filter-content-title">{{ $t('overall.status') }}</div>
|
|
||||||
<div class="new-filter-content-content">
|
|
||||||
<el-checkbox-group v-model="checkStatus" @change="onChangeCategory" style="display: flex;flex-direction: column">
|
|
||||||
<el-checkbox v-for="item in statusList" :key="item.label" class="new-filter-content-checkbox" :label="item.status">
|
|
||||||
<div>{{ item.label }}</div>
|
|
||||||
</el-checkbox>
|
|
||||||
</el-checkbox-group>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="new-filter-content-title">{{ $t('overall.category') }}</div>
|
|
||||||
<div class="new-filter-content-content">
|
|
||||||
<el-checkbox-group v-model="checkCategory" @change="onChangeCategory">
|
|
||||||
<el-checkbox v-for="item in categoryList" :key="item.value" class="new-filter-content-checkbox" :label="item.value">
|
|
||||||
{{ item.label }}
|
|
||||||
</el-checkbox>
|
|
||||||
</el-checkbox-group>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="new-filter-content-title">{{ $t('overall.type') }}</div>
|
|
||||||
<div class="new-filter-content-content">
|
|
||||||
<el-checkbox-group v-model="checkType" @change="onChangeCategory" style="display: flex;flex-direction: column">
|
|
||||||
<el-checkbox v-for="item in typeList" :key="item.value" class="new-filter-content-checkbox" :label="item.value">
|
|
||||||
{{ item.label }}
|
|
||||||
</el-checkbox>
|
|
||||||
</el-checkbox-group>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import axios from 'axios'
|
|
||||||
import { api } from '@/utils/api'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'DetectionFilter',
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
statusList: [],
|
|
||||||
categoryList: [],
|
|
||||||
typeList: [],
|
|
||||||
checkStatus: [],
|
|
||||||
checkCategory: [],
|
|
||||||
checkType: [],
|
|
||||||
url: api.detection.statistics
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
// 开发时删除---start
|
|
||||||
this.statusList = [
|
|
||||||
{ status: 1, label: 'Enabled' },
|
|
||||||
{ status: 0, label: 'Disabled' }
|
|
||||||
]
|
|
||||||
this.checkStatus = [0, 1]
|
|
||||||
this.categoryList = [
|
|
||||||
{ value: 'security', label: 'Security Event' },
|
|
||||||
{ value: 'performance', label: 'Performance Event' },
|
|
||||||
{ value: 'regulatory_risk', label: 'Regulatory Risk Event' }
|
|
||||||
]
|
|
||||||
this.checkCategory = ['security', 'performance', 'regulatory_risk']
|
|
||||||
this.typeList = [
|
|
||||||
{ value: 'c&c', label: 'C&C' },
|
|
||||||
{ value: 'ddos', label: 'DDos' },
|
|
||||||
{ value: 'lateral_movement', label: 'Lateral movement' },
|
|
||||||
{ value: 'brute_force', label: 'Brute force' }
|
|
||||||
]
|
|
||||||
this.checkType = ['c&c', 'ddos', 'lateral_movement', 'brute_force']
|
|
||||||
// 开发时删除---end
|
|
||||||
|
|
||||||
// todo 暂时禁用,后续再开发时解禁
|
|
||||||
// this.getFilterData()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getFilterData (params) {
|
|
||||||
let searchParams = { pageSize: -1 }
|
|
||||||
if (params) {
|
|
||||||
searchParams = { ...searchParams, ...params }
|
|
||||||
}
|
|
||||||
axios.get(this.url, { params: searchParams }).then(response => {
|
|
||||||
if (response.status === 200) {
|
|
||||||
if (response.data.data.statusList) {
|
|
||||||
this.statusList = []
|
|
||||||
response.data.data.statusList.forEach(item => {
|
|
||||||
this.statusList.push({ status: item.status, label: this.switchStatus(item.status) })
|
|
||||||
this.checkStatus.push(item.status)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.categoryList = response.data.data.categoryList
|
|
||||||
if (response.data.data.categoryList) {
|
|
||||||
response.data.data.categoryList.forEach(item => {
|
|
||||||
this.checkCategory.push(item.value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.typeList = response.data.data.typeList
|
|
||||||
if (response.data.data.typeList) {
|
|
||||||
response.data.data.typeList.forEach(item => {
|
|
||||||
this.checkType.push(item.value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.error(response.data)
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
|
||||||
// this.initTypeData()
|
|
||||||
// this.initStatusData()
|
|
||||||
// const self = this
|
|
||||||
// this.$nextTick(() => {
|
|
||||||
// if (self.$refs.knowledgeTreeTypeFilter) {
|
|
||||||
// self.$refs.knowledgeTreeTypeFilter.setCheckedKeys(this.defaultCheckedCategory)
|
|
||||||
// }
|
|
||||||
// if (self.$refs.knowledgeTreeStatusFilter) {
|
|
||||||
// self.$refs.knowledgeTreeStatusFilter.setCheckedKeys(this.defaultCheckedStatus)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onChangeCategory (data) {
|
|
||||||
// todo 暂时禁用,后续再开发时解禁
|
|
||||||
// 根据选择的值,构造不同入参,传给列表页,调用查询列表接口
|
|
||||||
},
|
|
||||||
switchStatus (status) {
|
|
||||||
switch (status) {
|
|
||||||
case 0: return 'Disabled'
|
|
||||||
case 1: return 'Enabled'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="detection-form">
|
|
||||||
|
|
||||||
<div class="detection-form-header">
|
|
||||||
Create Alert Policies
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--第一步:General Settings-->
|
|
||||||
<div class="detection-form-content">
|
|
||||||
<div class="detection-form-collapse">
|
|
||||||
<el-collapse v-model="activeNames">
|
|
||||||
<el-collapse-item name="1">
|
|
||||||
<template #title>
|
|
||||||
<div class="form-collapse-header">
|
|
||||||
<div :class="activeNames[0]==='1' ? 'form-collapse-header-no-active' : 'form-collapse-header-no'">1</div>
|
|
||||||
<div class="form-collapse-header-title">General Settings</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="form-collapse-content">
|
|
||||||
<general-settings ref="form" @setSettingForm="getFormSetting" />
|
|
||||||
</div>
|
|
||||||
</el-collapse-item>
|
|
||||||
</el-collapse>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--第二步:Rule Definition-->
|
|
||||||
<div class="detection-form-collapse">
|
|
||||||
<el-collapse v-model="activeNames" style="position: relative;">
|
|
||||||
<el-collapse-item name="2">
|
|
||||||
<template #title>
|
|
||||||
<div class="form-collapse-header">
|
|
||||||
<div :class="activeNames[0]==='2' ? 'form-collapse-header-no-active' : 'form-collapse-header-no'">2</div>
|
|
||||||
<div class="form-collapse-header-title">Rule Definition</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="form-collapse-content">
|
|
||||||
<rule-definition :settingObj="settingObj" @setRuleObj="getRuleObj" />
|
|
||||||
</div>
|
|
||||||
</el-collapse-item>
|
|
||||||
</el-collapse>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--第三步:Trigger-->
|
|
||||||
<div class="detection-form-collapse">
|
|
||||||
<el-collapse v-model="activeNames">
|
|
||||||
<el-collapse-item name="3">
|
|
||||||
<template #title>
|
|
||||||
<div class="form-collapse-header">
|
|
||||||
<div :class="activeNames[0]==='3' ? 'form-collapse-header-no-active' : 'form-collapse-header-no'">3</div>
|
|
||||||
<div class="form-collapse-header-title">Trigger</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="form-collapse-content margin-t-18">
|
|
||||||
<el-form 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">
|
|
||||||
<el-input size="mini" v-model="triggerObj.atLeast" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<div>times within</div>
|
|
||||||
|
|
||||||
<el-form-item prop="interval">
|
|
||||||
<el-input size="mini" v-model="triggerObj.interval" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item prop="intervalVal">
|
|
||||||
<el-select v-model="triggerObj.intervalVal" class="form-trigger__select" placeholder=" " size="mini">
|
|
||||||
<el-option
|
|
||||||
v-for="item in intervalList"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="trigger-block-item">
|
|
||||||
<div>With the counter resetting after no activity for</div>
|
|
||||||
<el-form-item prop="minute">
|
|
||||||
<el-input size="mini" v-model="triggerObj.minute" oninput="value=value.replace(/[^\d]/g,'')"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<div>minutes</div>
|
|
||||||
</div>
|
|
||||||
</el-form>
|
|
||||||
|
|
||||||
<div class="form-setting__btn1">
|
|
||||||
<el-button @click="createPolicy">Create & enable rule</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-collapse-item>
|
|
||||||
</el-collapse>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import GeneralSettings from '@/components/table/detection/GeneralSettings'
|
|
||||||
import RuleDefinition from '@/components/table/detection/RuleDefinition'
|
|
||||||
import { api } from '@/utils/api'
|
|
||||||
import axios from 'axios'
|
|
||||||
import _ from 'lodash'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'DetectionForm',
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
activeNames: ['1'],
|
|
||||||
settingObj: {}, // General Settings,即第一步的form表单信息
|
|
||||||
ruleObj: {}, // 第二步的form表单信息
|
|
||||||
// 第三步的form表单信息
|
|
||||||
triggerObj: {
|
|
||||||
atLeast: '',
|
|
||||||
interval: '',
|
|
||||||
intervalVal: '',
|
|
||||||
minute: '',
|
|
||||||
finishFlag: false
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
atLeast: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: this.$t('validate.required'),
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
interval: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: this.$t('validate.required'),
|
|
||||||
trigger: 'change'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
intervalVal: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: this.$t('validate.required'),
|
|
||||||
trigger: 'change'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
minute: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: this.$t('validate.required'),
|
|
||||||
trigger: 'blur'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
intervalList: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
GeneralSettings,
|
|
||||||
RuleDefinition
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
this.getStatistics()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
/** 获取下拉列表数据 */
|
|
||||||
getStatistics () {
|
|
||||||
axios.get(api.detection.statistics, { pageSize: -1 }).then(response => {
|
|
||||||
if (response.status === 200) {
|
|
||||||
this.intervalList = _.get(response, 'data.data.intervalList', [])
|
|
||||||
} else {
|
|
||||||
console.error(response.data)
|
|
||||||
}
|
|
||||||
}).finally(() => {
|
|
||||||
})
|
|
||||||
},
|
|
||||||
/** 获取General Settings折叠板form数据 */
|
|
||||||
getFormSetting (data) {
|
|
||||||
this.handleActiveNames('1', this.activeNames)
|
|
||||||
this.settingObj = JSON.parse(JSON.stringify(data))
|
|
||||||
},
|
|
||||||
/** 获取Rule Definition折叠板form数据 */
|
|
||||||
getRuleObj (data) {
|
|
||||||
this.handleActiveNames('2', this.activeNames)
|
|
||||||
this.ruleObj = JSON.parse(JSON.stringify(data))
|
|
||||||
},
|
|
||||||
/** 自动展开收起折叠板 */
|
|
||||||
handleActiveNames (name, arr) {
|
|
||||||
const list = arr
|
|
||||||
list.splice(list.indexOf(name), 1)
|
|
||||||
this.activeNames = []
|
|
||||||
list.forEach(t => {
|
|
||||||
this.activeNames.push(t)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
/** 创建policy */
|
|
||||||
createPolicy () {
|
|
||||||
const settingLen = Object.keys(this.settingObj).length
|
|
||||||
const ruleLen = Object.keys(this.ruleObj).length
|
|
||||||
|
|
||||||
if (settingLen > 0 && ruleLen > 0) {
|
|
||||||
this.$refs.form3.validate(valid => {
|
|
||||||
if (valid) {
|
|
||||||
// 最终提交form
|
|
||||||
// const formObj = { ...this.settingObj, ...this.ruleObj, ...this.triggerObj }
|
|
||||||
this.$message({
|
|
||||||
duration: 2000,
|
|
||||||
type: 'success',
|
|
||||||
message: this.$t('tip.saveSuccess')
|
|
||||||
})
|
|
||||||
|
|
||||||
// axios.post('api', formObj).then(response => {
|
|
||||||
// if (response.status === 200) {
|
|
||||||
// this.$message({
|
|
||||||
// duration: 2000,
|
|
||||||
// type: 'success',
|
|
||||||
// message: this.$t('tip.saveSuccess')
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// this.$router.push({
|
|
||||||
// path: '/detectionNew',
|
|
||||||
// query: {
|
|
||||||
// t: +new Date()
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// } else {
|
|
||||||
// this.$message.error(this.errorMsgHandler(response))
|
|
||||||
// }
|
|
||||||
// }).catch(e => {
|
|
||||||
// console.error(e)
|
|
||||||
// this.$message.error(this.errorMsgHandler(e))
|
|
||||||
// }).finally(() => {
|
|
||||||
// //
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else if (settingLen === 0) {
|
|
||||||
this.handleFormError('1')
|
|
||||||
} else if (ruleLen === 0) {
|
|
||||||
this.handleFormError('2')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleFormError (name) {
|
|
||||||
const list = this.activeNames
|
|
||||||
list.push(name)
|
|
||||||
this.activeNames = []
|
|
||||||
list.forEach(t => {
|
|
||||||
this.activeNames.push(t)
|
|
||||||
})
|
|
||||||
this.$message.error('请确保信息填写完整')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
@search="search"
|
@search="search"
|
||||||
></explorer-search>
|
></explorer-search>
|
||||||
<!-- 内容区 -->
|
<!-- 内容区 -->
|
||||||
<div v-if="showList" style="display: flex;flex-direction: row;">
|
<div v-if="showList" style="display: flex;flex-direction: row;padding-bottom: 20px;">
|
||||||
<entity-filter
|
<entity-filter
|
||||||
:filter-data="newFilterData"
|
:filter-data="newFilterData"
|
||||||
:loading-left="loadingLeft"
|
:loading-left="loadingLeft"
|
||||||
@@ -689,6 +689,44 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.search({ q: '', str: '', metaList: [] })
|
this.search({ q: '', str: '', metaList: [] })
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
queryScoreBase () {
|
||||||
|
const { startTime, endTime } = getNowTime(60 * 24)
|
||||||
|
const params = {
|
||||||
|
startTime: getSecond(startTime),
|
||||||
|
endTime: getSecond(endTime)
|
||||||
|
}
|
||||||
|
const tcp = axios.get(api.npm.overview.tcpSessionDelay, { params: params })
|
||||||
|
const http = axios.get(api.npm.overview.httpResponseDelay, { params: params })
|
||||||
|
const ssl = axios.get(api.npm.overview.sslConDelay, { params: params })
|
||||||
|
const tcpPercent = axios.get(api.npm.overview.tcpLostlenPercent, { params: params })
|
||||||
|
const packetPercent = axios.get(api.npm.overview.packetRetransPercent, { params: params })
|
||||||
|
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
|
||||||
|
const scoreBase = {}
|
||||||
|
res.forEach((t, i) => {
|
||||||
|
if (t.status === 200) {
|
||||||
|
if (i === 0) {
|
||||||
|
scoreBase.establishLatencyMsP10 = _.get(t.data, 'data.result.establishLatencyMsP10', null)
|
||||||
|
scoreBase.establishLatencyMsP90 = _.get(t.data, 'data.result.establishLatencyMsP90', null)
|
||||||
|
} else if (i === 1) {
|
||||||
|
scoreBase.httpResponseLatencyP10 = _.get(t.data, 'data.result.httpResponseLatencyP10', null)
|
||||||
|
scoreBase.httpResponseLatencyP90 = _.get(t.data, 'data.result.httpResponseLatencyP90', null)
|
||||||
|
} else if (i === 2) {
|
||||||
|
scoreBase.sslConLatencyP10 = _.get(t.data, 'data.result.sslConLatencyP10', null)
|
||||||
|
scoreBase.sslConLatencyP90 = _.get(t.data, 'data.result.sslConLatencyP90', null)
|
||||||
|
} else if (i === 3) {
|
||||||
|
scoreBase.tcpLostlenPercentP10 = _.get(t.data, 'data.result.tcpLostlenPercentP10', null)
|
||||||
|
scoreBase.tcpLostlenPercentP90 = _.get(t.data, 'data.result.tcpLostlenPercentP90', null)
|
||||||
|
} else if (i === 4) {
|
||||||
|
scoreBase.pktRetransPercentP10 = _.get(t.data, 'data.result.pktRetransPercentP10', null)
|
||||||
|
scoreBase.pktRetransPercentP90 = _.get(t.data, 'data.result.pktRetransPercentP90', null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$store.commit('setScoreBase', scoreBase)
|
||||||
|
}).catch((e) => {
|
||||||
|
}).finally(() => {
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
@@ -702,8 +740,16 @@ export default {
|
|||||||
if (q && (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1)) {
|
if (q && (q.indexOf('%') === 0 || q.indexOf('%20') > -1 || q.indexOf('%25') > -1)) {
|
||||||
q = decodeURI(q)
|
q = decodeURI(q)
|
||||||
}
|
}
|
||||||
|
// %位置不为0,即内容包含非英文时
|
||||||
|
const str1 = q.substring(q.indexOf('%'), q.indexOf('%') + 3)
|
||||||
|
if (q && q.indexOf('%') > 0 && (str1 !== '%20' || str1 === '%25')) {
|
||||||
|
q = decodeURI(q)
|
||||||
|
}
|
||||||
this.initSearch(q)
|
this.initSearch(q)
|
||||||
this.listMode = listMode
|
this.listMode = listMode
|
||||||
|
// 查询评分基准
|
||||||
|
this.$store.commit('resetScoreBase')
|
||||||
|
this.queryScoreBase()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div @click="showMoreFilter(item, index)"
|
<div @click="showMoreFilter(item, index)"
|
||||||
:class="item.showNum === item.data.length ? 'filter-no-show-more' : 'filter-show-more'">
|
:class="item.showNum === item.data.length ? 'filter-no-show-more' : 'filter-show-more'">
|
||||||
{{ $t('entity.showMore') }}
|
{{ $t('overall.showMore') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-hr"></div>
|
<div class="filter-hr"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -678,7 +678,6 @@ export default {
|
|||||||
// 手动高亮listNode
|
// 手动高亮listNode
|
||||||
const _listNode = _this.graph.findById(listNode.id)
|
const _listNode = _this.graph.findById(listNode.id)
|
||||||
_this.graph.emit('node:click', { item: _listNode, target: _listNode.getKeyShape() })
|
_this.graph.emit('node:click', { item: _listNode, target: _listNode.getKeyShape() })
|
||||||
console.info(_this.stackData)
|
|
||||||
if (_this.stackData.justUndo) {
|
if (_this.stackData.justUndo) {
|
||||||
_this.stackData.justUndo = false
|
_this.stackData.justUndo = false
|
||||||
_this.stackData.redo = []
|
_this.stackData.redo = []
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
<div class="entity-detail graph-basic-info__block-content">
|
<div class="entity-detail graph-basic-info__block-content">
|
||||||
<div class="graph-tag-list">
|
<div class="graph-tag-list">
|
||||||
<div v-for="ic in $_.get(node, 'myData.tags', [])" :key="ic.value">
|
<div v-for="ic in $_.get(node, 'myData.tags', [])" :key="ic.value">
|
||||||
<div class="entity-tag graph-tag-item" :class="`entity-tag--level-two-${ic.type}`">
|
<div class="entity-tag graph-tag-item" :class="`entity-tag--level-two-${ic.type}`" :style="getTagColor(ic.color)">
|
||||||
<span>{{ic.value}}</span>
|
<span>{{ic.value}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { copySelectionText, selectElementText } from '@/utils/tools'
|
import { copySelectionText, selectElementText, getTagColor } from '@/utils/tools'
|
||||||
import { entityType, riskLevelMapping } from '@/utils/constants'
|
import { entityType, riskLevelMapping } from '@/utils/constants'
|
||||||
import chartMixin from '@/views/charts2/chart-mixin'
|
import chartMixin from '@/views/charts2/chart-mixin'
|
||||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||||
@@ -174,6 +174,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getTagColor,
|
||||||
/** 复制实体名称 */
|
/** 复制实体名称 */
|
||||||
copyEntityName () {
|
copyEntityName () {
|
||||||
selectElementText(document.getElementById('entityName'))
|
selectElementText(document.getElementById('entityName'))
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import _ from 'lodash'
|
|||||||
import i18n from '@/i18n'
|
import i18n from '@/i18n'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { api } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
import { entityDetailTags, psiphon3IpType } from '@/utils/constants'
|
import { entityDefaultColor, entityDetailTags, tagValueLabelMapping } from '@/utils/constants'
|
||||||
|
|
||||||
export default class Node {
|
export default class Node {
|
||||||
/*
|
/*
|
||||||
@@ -91,7 +91,7 @@ export default class Node {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (_.isArray(tags.userDefinedTags)) {
|
if (_.isArray(tags.userDefinedTags)) {
|
||||||
_tags = _.concat(_tags, tags.userDefinedTags.map(tag => ({ value: tag.tagValue, type: 'normal' })))
|
_tags = _.concat(_tags, tags.userDefinedTags.map(tag => ({ value: tag.tagValue, color: tag.knowledgeBase ? tag.knowledgeBase.color : entityDefaultColor })))
|
||||||
}
|
}
|
||||||
this.myData.tags = _tags
|
this.myData.tags = _tags
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ export default class Node {
|
|||||||
tagValueHandler (k, k2, value) {
|
tagValueHandler (k, k2, value) {
|
||||||
if (k === 'psiphon3Ip') {
|
if (k === 'psiphon3Ip') {
|
||||||
if (k2 === 'type') {
|
if (k2 === 'type') {
|
||||||
const find = psiphon3IpType.find(t => t.value === value)
|
const find = tagValueLabelMapping.find(t => t.value === value)
|
||||||
if (find) {
|
if (find) {
|
||||||
return find.name
|
return find.name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,11 @@
|
|||||||
<div class="cn-entity__header" style="display: flex;">
|
<div class="cn-entity__header" style="display: flex;">
|
||||||
<span class="cn-entity__header-title">{{ entityData.entityValue || 'Unknown' }}</span>
|
<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 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" :class="`entity-tag--level-two-${item.type}`">
|
<span v-for="(item, index) in levelTwoTags"
|
||||||
|
:key="index"
|
||||||
|
class="entity-tag entity-tag--small margin-r-10 margin-b-10"
|
||||||
|
:class="`entity-tag--level-two-${item.type}`"
|
||||||
|
:style="getTagColor(item.color)">
|
||||||
{{ item.value }}
|
{{ item.value }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
@@ -26,7 +30,7 @@
|
|||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-country"></i>
|
<i class="cn-icon cn-icon-country"></i>
|
||||||
<span class="row-item-label">{{ $t('overall.country') }} : </span>
|
<span class="row-item-label">{{ $t('overall.country') }} : </span>
|
||||||
<span class="row-item-value">{{ entityData.location ? entityData.location.country : '-' }}</span>
|
<span class="row-item-value">{{ $_.get(entityData, 'location.country', '-') || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-position"></i>
|
<i class="cn-icon cn-icon-position"></i>
|
||||||
@@ -36,36 +40,36 @@
|
|||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-cloud"></i>
|
<i class="cn-icon cn-icon-cloud"></i>
|
||||||
<span class="row-item-label">{{ $t('entities.asn') }} : </span>
|
<span class="row-item-label">{{ $t('entities.asn') }} : </span>
|
||||||
<span class="row-item-value">{{ entityData.asn ? entityData.asn.asn : '-' }}</span>
|
<span class="row-item-value">{{ $_.get(entityData, 'asn.asn', '-') || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="entityData.entityType === 'domain'">
|
<template v-else-if="entityData.entityType === 'domain'">
|
||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-category-group"></i>
|
<i class="cn-icon cn-icon-category-group"></i>
|
||||||
<span class="row-item-label">{{ $t('entities.category') }} : </span>
|
<span class="row-item-label">{{ $t('entities.category') }} : </span>
|
||||||
<span class="row-item-value">{{ entityData.category ? entityData.category.categoryGroup : '-' }}</span>
|
<span class="row-item-value">{{ $_.get(entityData, 'category.categoryGroup', '-') || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-sub-category"></i>
|
<i class="cn-icon cn-icon-sub-category"></i>
|
||||||
<span class="row-item-label">{{ $t('entities.subcategory') }} : </span>
|
<span class="row-item-label">{{ $t('entities.subcategory') }} : </span>
|
||||||
<span class="row-item-value">{{ entityData.category ? entityData.category.categoryName : '-' }}</span>
|
<span class="row-item-value">{{ $_.get(entityData, 'category.categoryName', '-') || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-credit-rating"></i>
|
<i class="cn-icon cn-icon-credit-rating"></i>
|
||||||
<span class="row-item-label">{{ $t('entities.reputationLevel') }} : </span>
|
<span class="row-item-label">{{ $t('entities.reputationLevel') }} : </span>
|
||||||
<span class="row-item-value">{{ entityData.category ? entityData.category.reputationLevel : '-' }}</span>
|
<span class="row-item-value">{{ $_.get(entityData, 'category.reputationLevel', '-') || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="entityData.entityType === 'app'">
|
<template v-else-if="entityData.entityType === 'app'">
|
||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-category2"></i>
|
<i class="cn-icon cn-icon-category2"></i>
|
||||||
<span class="row-item-label">{{ $t('entities.category') }} : </span>
|
<span class="row-item-label">{{ $t('entities.category') }} : </span>
|
||||||
<span class="row-item-value">{{ entityData.category ? entityData.category.appCategory : '-' }}</span>
|
<span class="row-item-value">{{ $_.get(entityData, 'category.appCategory', '-') || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-sub-category"></i>
|
<i class="cn-icon cn-icon-sub-category"></i>
|
||||||
<span class="row-item-label">{{ $t('entities.subcategory') }} : </span>
|
<span class="row-item-label">{{ $t('entities.subcategory') }} : </span>
|
||||||
<span class="row-item-value">{{ entityData.category ? entityData.category.appSubcategory : '-' }}</span>
|
<span class="row-item-value">{{ $_.get(entityData, 'category.appSubcategory', '-') || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="basic-info__item">
|
<div class="basic-info__item">
|
||||||
<i class="cn-icon cn-icon-credit-rating"></i>
|
<i class="cn-icon cn-icon-credit-rating"></i>
|
||||||
@@ -139,7 +143,10 @@
|
|||||||
<div class="row-item-label">
|
<div class="row-item-label">
|
||||||
<span class="row-item-label">{{ $t('network.score') }} : </span>
|
<span class="row-item-label">{{ $t('network.score') }} : </span>
|
||||||
<span class="row-item-value" style="position: relative;">
|
<span class="row-item-value" style="position: relative;">
|
||||||
<span v-if="!loadingNetworkQuality">{{ score }}</span>
|
<template v-if="!loadingNetworkQuality && score !=='-'">
|
||||||
|
<span v-for="(dot, i) in scoreDot" :key="i" :class="dot.class"></span>
|
||||||
|
</template>
|
||||||
|
<span>{{score}}</span>
|
||||||
<loading :loading="loadingNetworkQuality" size="small"></loading>
|
<loading :loading="loadingNetworkQuality" size="small"></loading>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -183,8 +190,9 @@ import relatedServer from '@/mixins/relatedServer'
|
|||||||
import Loading from '@/components/common/Loading'
|
import Loading from '@/components/common/Loading'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { api } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
import { entityDetailTags, psiphon3IpType } from '@/utils/constants'
|
import { entityDefaultColor, entityDetailTags, tagValueLabelMapping } from '@/utils/constants'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
import { getTagColor } from '@/utils/tools'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Row',
|
name: 'Row',
|
||||||
@@ -240,6 +248,7 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getTagColor,
|
||||||
initData () {
|
initData () {
|
||||||
let url = ''
|
let url = ''
|
||||||
switch (this.entity.entityType) {
|
switch (this.entity.entityType) {
|
||||||
@@ -258,7 +267,7 @@ export default {
|
|||||||
}
|
}
|
||||||
axios.get(`${url}?resource=${this.entity.entityValue}`).then(response => {
|
axios.get(`${url}?resource=${this.entity.entityValue}`).then(response => {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.entityData = { ...response.data.data, ...this.entity }
|
this.entityData = { ...this.entityData, ...response.data.data, ...this.entity }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -286,28 +295,21 @@ export default {
|
|||||||
Object.keys(res.data[k]).forEach(k2 => {
|
Object.keys(res.data[k]).forEach(k2 => {
|
||||||
const find = entityDetailTags[this.entity.entityType].find(t => t.name === k2)
|
const find = entityDetailTags[this.entity.entityType].find(t => t.name === k2)
|
||||||
if (find) {
|
if (find) {
|
||||||
this.levelTwoTags.push({ key: k2, value: this.tagValueHandler(k, k2, res.data[k][k2]), type: find.type })
|
this.levelTwoTags.push({ key: k2, value: this.tagValueHandler(res.data[k][k2]), type: find.type })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (_.isArray(res.data.userDefinedTags)) {
|
if (_.isArray(res.data.userDefinedTags)) {
|
||||||
this.levelTwoTags = _.concat(this.levelTwoTags, res.data.userDefinedTags.map(tag => ({ value: tag.tagValue, type: 'normal' })))
|
this.levelTwoTags = _.concat(this.levelTwoTags, res.data.userDefinedTags.map(tag => ({ value: tag.tagValue, color: tag.knowledgeBase ? tag.knowledgeBase.color : entityDefaultColor })))
|
||||||
}
|
}
|
||||||
this.hideTagArea = _.isEmpty(this.levelTwoTags)
|
this.hideTagArea = _.isEmpty(this.levelTwoTags)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
tagValueHandler (k, k2, value) {
|
tagValueHandler (value) {
|
||||||
if (k === 'psiphon3Ip') {
|
const find = tagValueLabelMapping.find(t => t.value === value)
|
||||||
if (k2 === 'type') {
|
return find ? find.name : value
|
||||||
const find = psiphon3IpType.find(t => t.value === value)
|
|
||||||
if (find) {
|
|
||||||
return find.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
},
|
},
|
||||||
/* 切换折叠状态 */
|
/* 切换折叠状态 */
|
||||||
switchCollapse () {
|
switchCollapse () {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user