Compare commits
126 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ee7631d25 | ||
|
|
28c0b3aebf | ||
|
|
b178941f01 | ||
|
|
ecd82b08c7 | ||
|
|
23c88ae447 | ||
|
|
9b2f2f5e21 | ||
|
|
d8de1e5d69 | ||
|
|
502d098413 | ||
|
|
a8a84b6abb | ||
|
|
da9eeae556 | ||
|
|
4125a88bba | ||
|
|
317693e2da | ||
|
|
be79109487 | ||
|
|
b99a20725a | ||
|
|
c40941fa60 | ||
|
|
6fba2c6116 | ||
|
|
2609c2e721 | ||
|
|
158a143d76 | ||
|
|
1dee23435d | ||
|
|
64a6eac4a7 | ||
|
|
8f1adef30d | ||
|
|
2b66aecf44 | ||
|
|
1311e53b65 | ||
|
|
d9677e89f5 | ||
|
|
d89c20a75c | ||
|
|
476c49b08f | ||
|
|
32a04eec4c | ||
|
|
fb9034229e | ||
|
|
43c79b94f1 | ||
|
|
801858c07d | ||
|
|
85d9b3d738 | ||
|
|
ac28e52ca7 | ||
|
|
e2f9eb7f59 | ||
|
|
a9e5915113 | ||
|
|
fdb4ec5cf5 | ||
|
|
04062195e2 | ||
|
|
e29fc1244c | ||
|
|
3fc6a42d99 | ||
|
|
1c776f4119 | ||
|
|
e87deec34c | ||
|
|
5685e6b2c0 | ||
|
|
9fddf7914d | ||
|
|
a55ab9fb15 | ||
|
|
35b1f31601 | ||
|
|
8627cec919 | ||
|
|
ee14b471a8 | ||
|
|
5896931487 | ||
|
|
f87714fae2 | ||
|
|
def8851da0 | ||
|
|
8b3f43eb98 | ||
|
|
3d2623f8cf | ||
|
|
a9fe48933c | ||
|
|
1c2782e8e3 | ||
|
|
4462b5eaa3 | ||
|
|
46a0985f55 | ||
|
|
4d6c444b25 | ||
|
|
e009142e7d | ||
|
|
14a24b268a | ||
|
|
06de8e2bc9 | ||
|
|
d788657048 | ||
|
|
524be68781 | ||
|
|
0139a542da | ||
|
|
da607274d8 | ||
|
|
48426a3955 | ||
|
|
e95ca314a6 | ||
|
|
3d18a4b285 | ||
|
|
2b67cb4a0b | ||
|
|
eadb1e350d | ||
|
|
46a23d9464 | ||
|
|
a7e06c6ffa | ||
|
|
822e7bd9aa | ||
|
|
73952e6811 | ||
|
|
251e0a2018 | ||
|
|
d04bb5a87e | ||
|
|
f6a6ac82bd | ||
|
|
bca147a7db | ||
|
|
afab449f3a | ||
|
|
8bf7b85c2e | ||
|
|
ab146b5b15 | ||
|
|
230e897146 | ||
|
|
949a8e9d86 | ||
|
|
3604783570 | ||
|
|
f60a6bd778 | ||
|
|
5ece1b6c8e | ||
|
|
86c2c8364d | ||
|
|
1f130a6ac8 | ||
|
|
c8af5fd5a1 | ||
|
|
48b7493b2e | ||
|
|
98ba09b586 | ||
|
|
7d85d332df | ||
|
|
6ee5ea6f6e | ||
|
|
6756812c34 | ||
|
|
d2aa5c9b7a | ||
|
|
049d5f92b4 | ||
|
|
7ce190f3c7 | ||
|
|
e9edd9cf05 | ||
|
|
4655eed55f | ||
|
|
cf625c196e | ||
|
|
55fdd3f0e4 | ||
|
|
8aa96da577 | ||
|
|
22bf16a01d | ||
|
|
04e186e7d8 | ||
|
|
38006bd964 | ||
|
|
05677d5fb6 | ||
|
|
156979e79e | ||
|
|
0f2fcbe9e6 | ||
|
|
089887f05b | ||
|
|
c83f64706f | ||
|
|
c82d33fa39 | ||
|
|
eed1d398d8 | ||
|
|
a8643b8543 | ||
|
|
bd1eeec770 | ||
|
|
8cb3f00aa4 | ||
|
|
4fed5a9b8c | ||
|
|
d54054510b | ||
|
|
27bd8260d2 | ||
|
|
29916f8517 | ||
|
|
2bac72eb5d | ||
|
|
dfcc03f11a | ||
|
|
a608ac72f6 | ||
|
|
b5d897608c | ||
|
|
431821154e | ||
|
|
9f488adcb9 | ||
|
|
a31c408327 | ||
|
|
d84483c0dc | ||
|
|
4804748564 |
@@ -1,7 +1,8 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true
|
||||
es2021: true,
|
||||
jest: true
|
||||
},
|
||||
extends: [
|
||||
'plugin:vue/vue3-essential',
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
stages:
|
||||
- gen_git-log
|
||||
- build_project
|
||||
- test
|
||||
- build_image
|
||||
|
||||
cache:
|
||||
@@ -10,7 +11,7 @@ cache:
|
||||
- package.json
|
||||
paths:
|
||||
- node_modules
|
||||
- dist/
|
||||
# - dist/
|
||||
|
||||
before_script:
|
||||
- export CNUI_TAG=$(date +%Y%m%d%H%M%S)
|
||||
@@ -41,21 +42,38 @@ build_project:
|
||||
- cnpm install --save-dev --unsafe-perm
|
||||
- echo "npm run build"
|
||||
- cnpm run build
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
|
||||
when: on_success
|
||||
paths:
|
||||
- dist/
|
||||
only:
|
||||
- dev
|
||||
- tags
|
||||
tags:
|
||||
- galaxy
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- cnpm run test
|
||||
when: on_success
|
||||
only:
|
||||
- dev
|
||||
tags:
|
||||
- galaxy
|
||||
|
||||
build_image:
|
||||
dependencies:
|
||||
- build_project
|
||||
stage: build_image
|
||||
script:
|
||||
- echo "docker build"
|
||||
- sudo docker build --no-cache -t cn-ui:$CNUI_TAG .
|
||||
- sudo docker build --no-cache -t cn-ui-$CI_COMMIT_REF_NAME:$CNUI_TAG .
|
||||
- echo "docker tag"
|
||||
- sudo docker tag cn-ui:$CNUI_TAG 192.168.40.153:9080/cyber-narrator/cn-ui:$CNUI_TAG
|
||||
- sudo docker tag cn-ui-$CI_COMMIT_REF_NAME:$CNUI_TAG 192.168.40.153:9080/cyber-narrator/cn-ui-$CI_COMMIT_REF_NAME:$CNUI_TAG
|
||||
- echo "docker push"
|
||||
- sudo docker push 192.168.40.153:9080/cyber-narrator/cn-ui:$CNUI_TAG
|
||||
- sudo docker push 192.168.40.153:9080/cyber-narrator/cn-ui-$CI_COMMIT_REF_NAME:$CNUI_TAG
|
||||
when: on_success
|
||||
only:
|
||||
- dev
|
||||
@@ -64,6 +82,8 @@ build_image:
|
||||
|
||||
|
||||
build_release_image:
|
||||
dependencies:
|
||||
- build_project
|
||||
stage: build_image
|
||||
script:
|
||||
- echo 'tag名称是'
|
||||
|
||||
@@ -6,6 +6,8 @@ module.exports = {
|
||||
'<rootDir>/test/**/__tests__/**/*.{vue,js,jsx,ts,tsx}',
|
||||
'<rootDir>/test/**/*.{spec,test}.{vue,js,jsx,ts,tsx}'
|
||||
],
|
||||
setupFilesAfterEnv: ['<rootDir>/test/init.js'],
|
||||
verbose: true,
|
||||
testEnvironment: 'jsdom',
|
||||
transform: {
|
||||
'^.+\\.(vue)$': '<rootDir>/node_modules/vue-jest',
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"@vue/component-compiler-utils": "^3.2.0",
|
||||
"@vue/test-utils": "^2.0.0-rc.18",
|
||||
"@vue/test-utils": "^2.2.7",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^26.0.0",
|
||||
"compression-webpack-plugin": "^8.0.1",
|
||||
|
||||
@@ -148,7 +148,7 @@ export default {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
>>>.el-input__inner {
|
||||
:deep .el-input__inner {
|
||||
background-color: #0B325C !important;
|
||||
border: none;
|
||||
border-radius: 0px;
|
||||
@@ -156,10 +156,10 @@ export default {
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
}
|
||||
>>>.el-input__inner:hover {
|
||||
:deep .el-input__inner:hover {
|
||||
border-color: #295688;
|
||||
}
|
||||
>>>.el-input__inner:focus {
|
||||
:deep .el-input__inner:focus {
|
||||
border-color: #295688;
|
||||
}
|
||||
.el-button--primary:hover, .el-button--primary:focus, .el-button--primary:active {
|
||||
@@ -167,10 +167,10 @@ export default {
|
||||
border-color: #21B4ED;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
>>>.el-loading-mask {
|
||||
:deep .el-loading-mask {
|
||||
background-color: transparent;
|
||||
}
|
||||
>>>input {
|
||||
:deep input {
|
||||
-webkit-text-fill-color: rgba(231,234,237, .8) !important;
|
||||
transition: background-color 500000000000000000s ease-in-out 0s !important;
|
||||
caret-color: #fff ;
|
||||
@@ -205,14 +205,14 @@ export default {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
>>>.el-form-item {
|
||||
:deep .el-form-item {
|
||||
width: 334px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
>>>.el-input__prefix {
|
||||
:deep .el-input__prefix {
|
||||
color: #6DBBFF;
|
||||
}
|
||||
>>>.el-input__prefix i {
|
||||
:deep .el-input__prefix i {
|
||||
width: 17px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
107
src/Test.vue
107
src/Test.vue
@@ -1,27 +1,120 @@
|
||||
<template>
|
||||
<span data-test="count">{{count}}</span>
|
||||
<button data-test="button" @click="click">click</button>
|
||||
<span test-id="count">{{count}}</span>
|
||||
<span test-id="id">{{obj.id}}</span>
|
||||
<span test-id="title">{{obj.title}}</span>
|
||||
<button test-id="button" @click="click">click</button>
|
||||
<span test-id="tab">{{lineTab}}</span>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
class="test-table"
|
||||
height="100%"
|
||||
empty-text=" "
|
||||
>
|
||||
<template v-for="(item, index) in tableTitles" :key="index">
|
||||
<el-table-column>
|
||||
<template #default="scope" :column="item">
|
||||
<span :test-id="`${item.prop}${scope.$index}`">{{scope.row[item.prop]}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* vue-jest的测试示例 */
|
||||
import VueRouter from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import axios from 'axios'
|
||||
import { ref } from 'vue'
|
||||
import indexedDBUtils from '@/indexedDB'
|
||||
export default {
|
||||
name: 'Test',
|
||||
data () {
|
||||
return {
|
||||
count: 0
|
||||
count: 0,
|
||||
obj: { id: 1, title: 'title' },
|
||||
differentParamData0: null,
|
||||
differentParamData1: null,
|
||||
indexedDBValue: null,
|
||||
tableData: [
|
||||
{
|
||||
name: 'a',
|
||||
age: 10
|
||||
},
|
||||
{
|
||||
name: 'b',
|
||||
age: 11
|
||||
}
|
||||
],
|
||||
tableTitles: [
|
||||
{ label: 'Name', prop: 'name' },
|
||||
{ label: 'Age', prop: 'age' }
|
||||
],
|
||||
mergeRequestData0: null,
|
||||
mergeRequestData1: null,
|
||||
mergeRequestChildData0: null,
|
||||
mergeRequestChildData1: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
click () {
|
||||
this.count++
|
||||
},
|
||||
async getObj () {
|
||||
axios.get('/api/getObjId').then(response => {
|
||||
this.obj.id = response.data
|
||||
})
|
||||
axios.get('/api/getObjTitle').then(response => {
|
||||
this.obj.title = response.data
|
||||
})
|
||||
},
|
||||
async getCount () {
|
||||
axios.get('/api/getCount').then(response => {
|
||||
this.count = response.data
|
||||
})
|
||||
},
|
||||
async differentRequestParam () {
|
||||
axios.get('/api/differentParam', { params: { name: 0 } }).then(response => {
|
||||
this.differentParamData0 = response.data
|
||||
})
|
||||
axios.get('/api/differentParam', { params: { name: 1 } }).then(response => {
|
||||
this.differentParamData1 = response.data
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 同一url,不同入参的axios请求内包含多个不同url请求的demo
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async mergeRequest () {
|
||||
axios.get('/api/differentParam', { params: { name: 0 } }).then(response => {
|
||||
this.mergeRequestData0 = response.data
|
||||
})
|
||||
axios.get('/api/differentParam', { params: { name: 1 } }).then(response => {
|
||||
this.mergeRequestData1 = response.data
|
||||
axios.get('/api/getChildId').then(response1 => {
|
||||
this.mergeRequestChildData0 = response1.data
|
||||
})
|
||||
axios.get('/api/getChildTitle').then(response2 => {
|
||||
this.mergeRequestChildData1 = response2.data
|
||||
})
|
||||
})
|
||||
},
|
||||
async setIndexedDBValue () {
|
||||
await indexedDBUtils.selectTable('test').put({ id: 1, name: 'test' })
|
||||
},
|
||||
async getIndexedDBValue () {
|
||||
this.indexedDBValue = await indexedDBUtils.selectTable('test').get(1)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
const { currentRoute } = VueRouter.useRouter()
|
||||
setup () {
|
||||
const { query } = useRoute()
|
||||
const { currentRoute } = useRouter()
|
||||
const localstorageValue = localStorage.getItem('key')
|
||||
const lineTab = ref(query.lineTab || '')
|
||||
const path = currentRoute.value.path
|
||||
return {
|
||||
currentRoute
|
||||
lineTab,
|
||||
path,
|
||||
localstorageValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,8 @@
|
||||
z-index: 0;
|
||||
}
|
||||
.main-container {
|
||||
padding: 10px;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
background-color: #f6f6f6;
|
||||
&>div {
|
||||
background-color: white;
|
||||
}
|
||||
@@ -36,7 +35,7 @@
|
||||
align-items : center;
|
||||
position: relative;
|
||||
justify-content: space-between;
|
||||
padding: 14px 20px;
|
||||
padding: 12px 20px;
|
||||
|
||||
&.top-tools--sub {
|
||||
align-items: center;
|
||||
@@ -50,6 +49,12 @@
|
||||
.top-tool-btn {
|
||||
border-left: none;
|
||||
}
|
||||
.top-tool-btn--search:hover {
|
||||
border-left: none !important;
|
||||
}
|
||||
.top-tool-btn--search:focus {
|
||||
border-left: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.top-tool-right {
|
||||
@@ -74,17 +79,28 @@
|
||||
}
|
||||
.top-tool-btn {
|
||||
cursor: pointer;
|
||||
height: 33px;
|
||||
width: 36px;
|
||||
height: 28px;
|
||||
width: 72px;
|
||||
border: 1px solid $--border-color-primary;
|
||||
outline: none;
|
||||
border-radius: $--button-border-radius;
|
||||
background-color: $--button-gray-background-color;
|
||||
transition: background-color linear .1s;
|
||||
|
||||
font-size:12px;
|
||||
font-weight: 500;
|
||||
font-family: NotoSansHans-Medium !important;
|
||||
i {
|
||||
font-size: 14px;
|
||||
color: $--button-gray-color;
|
||||
color: #575757;
|
||||
margin-right:4px;
|
||||
}
|
||||
}
|
||||
|
||||
.top-tool-btn:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.66;
|
||||
i {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,13 +110,14 @@
|
||||
color: #666;
|
||||
}
|
||||
.top-tool-btn:hover:not(.cn-btn-disabled) {
|
||||
border: 1px solid $--border-color-primary;
|
||||
background-color: $--button-gray-hover-background-color;
|
||||
}
|
||||
.top-tool-btn:focus:not(.cn-btn-disabled), .top-tool-btn.is-focus {
|
||||
background-color: $--button-gray-hover-background-color;
|
||||
border: 1px solid $--color-primary !important;
|
||||
background-color: $--button-gray-active-background-color;
|
||||
border: 1px solid $--border-color-primary;
|
||||
i {
|
||||
color: $--button-gray-active-color;
|
||||
color: #575757;
|
||||
}
|
||||
}
|
||||
.top-tool-btn--delete.top-tool-btn:focus:not(.cn-btn-disabled) {
|
||||
@@ -111,6 +128,56 @@
|
||||
color: #F0745A;
|
||||
}
|
||||
}
|
||||
.top-tool-btn--create {
|
||||
background-color: #38ACD2 !important;
|
||||
border-color: #2E88A6 !important;
|
||||
color:#FFFFFF;
|
||||
i {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
.top-tool-btn--create:hover {
|
||||
background-color: #57B8D9 !important;
|
||||
border-color: #2E88A6 !important;
|
||||
color:#FFFFFF;
|
||||
i {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
.top-tool-btn--create:focus {
|
||||
background-color: #31A5CD !important;
|
||||
border-color: #2E88A6 !important;
|
||||
color:#FFFFFF !important;
|
||||
i {
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
}
|
||||
.top-tool-btn--create:disabled {
|
||||
opacity: 0.66;
|
||||
background-color: #38ACD2 !important;
|
||||
border-color: #2E88A6 !important;
|
||||
color:#FFFFFF;
|
||||
i {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-customize {
|
||||
color:$blue;
|
||||
font-size: 12px;
|
||||
.icon-gear{
|
||||
color:#2C72C6;
|
||||
width:12px;
|
||||
height:12px;
|
||||
margin-right:2px;
|
||||
font-size:12px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-customize:hover {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.top-tool-btn--dropdown {
|
||||
position: relative;
|
||||
width: auto;
|
||||
@@ -130,6 +197,7 @@
|
||||
width: calc(100% - 40px);
|
||||
border: 1px solid $--right-box-border-color;
|
||||
border-bottom: none;
|
||||
border-radius:4px;
|
||||
|
||||
.caret-wrapper {
|
||||
height: 23px;
|
||||
@@ -152,7 +220,8 @@
|
||||
th {
|
||||
border-color: $--right-box-border-color;
|
||||
padding: 8px 0;
|
||||
background: #F9F9F9;
|
||||
background: #FFF;
|
||||
border-right:0px;
|
||||
}
|
||||
.el-table__header th:first-of-type {
|
||||
border-left: none;
|
||||
@@ -244,7 +313,7 @@
|
||||
border-right: none !important;
|
||||
}
|
||||
/* 最后一列用box-shadow模拟边框 */
|
||||
.el-table:not(.no-operation):not(.chart-table).el-table--border .el-table__body-wrapper td:nth-last-child(2) {
|
||||
/*.el-table:not(.no-operation):not(.chart-table).el-table--border .el-table__body-wrapper td:nth-last-child(2) {
|
||||
box-shadow: 1px 0 $--right-box-border-color;
|
||||
}
|
||||
.el-table:not(.no-operation):not(.chart-table).el-table--border .el-table__header-wrapper th:nth-last-child(3) {
|
||||
@@ -263,7 +332,7 @@
|
||||
th:last-of-type {
|
||||
border-right: none !important;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
.el-table--border:not(.chart-table)::after, .el-table--group:not(.chart-table)::after {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
z-index: 999999;
|
||||
box-shadow: 0 0 10px #CCC;
|
||||
box-sizing: border-box;
|
||||
|
||||
.pop-title {
|
||||
margin: 10px 0;
|
||||
}
|
||||
.el-button--mini{
|
||||
padding: 5px 7px;
|
||||
}
|
||||
@@ -23,7 +25,6 @@
|
||||
top: 33px;
|
||||
}
|
||||
.custom-labels {
|
||||
margin-top: 12px;
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
@@ -41,8 +42,7 @@
|
||||
font-size: 14px;
|
||||
}
|
||||
.custom-label:hover{
|
||||
color: #cccccc;
|
||||
background-color: #DCDFE6;
|
||||
background-color: rgba(220, 223, 230, .5)
|
||||
}
|
||||
.custom-title{
|
||||
padding: 2px 0 2px 2px;
|
||||
@@ -57,6 +57,14 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.custom-bottom-btns-right {
|
||||
.el-button:nth-of-type(1) {
|
||||
margin-right: 3px;
|
||||
}
|
||||
.el-button .top-tool-btn-save {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.unshow {
|
||||
display: none;
|
||||
@@ -70,12 +78,28 @@
|
||||
border-radius: 2px;
|
||||
background-color: #F9F9F9;
|
||||
transition: background-color linear .1s;
|
||||
padding-left:10px;
|
||||
}
|
||||
|
||||
|
||||
.list-page .top-tools .top-tool-btn--search{
|
||||
width:28px !important;
|
||||
height:28px !important;
|
||||
padding:unset !important;
|
||||
i {
|
||||
font-size: 14px;
|
||||
color: #575757;
|
||||
margin-right:unset !important;
|
||||
}
|
||||
}
|
||||
|
||||
.list-page {
|
||||
.el-input--small{
|
||||
width: 214px !important;
|
||||
line-height: 27px;
|
||||
}
|
||||
.el-input--small .el-input__inner {
|
||||
height: 33px;
|
||||
line-height: 32px;
|
||||
border-radius: 0px;
|
||||
height: 28px;
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
@import './components/common/pagination';
|
||||
// @import './components/entities/entities';
|
||||
@import './components/layout/layout';
|
||||
@import 'components/rightBox/settings/chart-box';
|
||||
@import 'components/rightBox/administration/chart-box';
|
||||
@import 'components/setting/galaxy-proxy-debug';
|
||||
@import 'components/table/settings/galaxy-proxy-table';
|
||||
@import 'components/table/administration/galaxy-proxy-table';
|
||||
@import './components/table/common';
|
||||
@import './views/charts/chart';
|
||||
@import 'views/entityExplorer/entity-explorer';
|
||||
@@ -42,8 +42,8 @@
|
||||
@import './views/chartHeader';
|
||||
@import './views/charts/chartMap';
|
||||
@import 'views/charts/chartRelationShipList';
|
||||
@import './views/report/builtinReport';
|
||||
@import './components/rightBox/report/builtinReportBox';
|
||||
@import 'views/report/report';
|
||||
@import 'components/rightBox/report/reportBox';
|
||||
|
||||
@import './views/charts2/panel';
|
||||
@import './views/charts2/networkOverviewLine';
|
||||
@@ -77,3 +77,4 @@
|
||||
|
||||
@import 'views/administration/AdministrationTabs';
|
||||
|
||||
@import 'views/setting/knowledgeBase';
|
||||
|
||||
@@ -98,11 +98,11 @@
|
||||
//top: 0;
|
||||
//left: 0;
|
||||
display: flex;
|
||||
.line-value-mpackets.mousemove-cursor {
|
||||
.line-value-tabs.mousemove-cursor {
|
||||
border-top: 4px solid #D3D0D8;
|
||||
z-index: 0;
|
||||
}
|
||||
.line-value-mpackets {
|
||||
.line-value-tabs {
|
||||
cursor: pointer;
|
||||
padding: 16px 0 0 20px;
|
||||
border-top: 4px solid transparent;
|
||||
@@ -122,10 +122,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.line-value-mpackets-name {
|
||||
.line-value-tabs-name {
|
||||
position: relative;
|
||||
display: flex;
|
||||
.mpackets-name {
|
||||
.tabs-name {
|
||||
flex: 1;
|
||||
padding-left: 19px;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
padding-right: 20px;
|
||||
|
||||
&.row__label--width130 {
|
||||
flex-basis: 130px;
|
||||
flex-basis: 140px;
|
||||
padding-right: unset;
|
||||
}
|
||||
&.row__label--width160 {
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
.cn-builtin {
|
||||
.cn-report {
|
||||
background: #fff;
|
||||
margin: 10px;
|
||||
height: calc(100% - 20px) !important;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.cn-builtin-left {
|
||||
.cn-report-left {
|
||||
width: 288px;
|
||||
height: 100%;
|
||||
border-right: 1px solid #E7EAED;
|
||||
position: relative;
|
||||
.cn-builtin-left-title {
|
||||
overflow: auto;
|
||||
.cn-report-left-title {
|
||||
padding: 28px 0 26px 13px;
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
.cn-builtin-left-menu {
|
||||
.cn-report-left-menu {
|
||||
width: 250px;
|
||||
word-break: normal;
|
||||
margin: auto;
|
||||
@@ -25,13 +26,13 @@
|
||||
padding: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.cn-builtin-left-menu.cn-active {
|
||||
.cn-report-left-menu.cn-active {
|
||||
background: #F4FAFF;
|
||||
border-radius: 2px;
|
||||
color: #0091FF;
|
||||
}
|
||||
}
|
||||
.cn-builtin-right {
|
||||
.cn-report-right {
|
||||
flex: 1;
|
||||
.list-page .main-container {
|
||||
padding: 0;
|
||||
@@ -73,7 +74,7 @@
|
||||
height: 100%;
|
||||
width: calc(100% - 32px);
|
||||
background: #fff; //盖住fixed产生的阴影
|
||||
::v-deep .is-leaf {
|
||||
:deep .is-leaf {
|
||||
color: #1b2e3b;
|
||||
background: #ebeef5;
|
||||
}
|
||||
365
src/assets/css/components/views/setting/knowledgeBase.scss
Normal file
365
src/assets/css/components/views/setting/knowledgeBase.scss
Normal file
@@ -0,0 +1,365 @@
|
||||
.knowledge-base {
|
||||
&.list-page {
|
||||
height: calc(100% - 52px);
|
||||
}
|
||||
.type-tag {
|
||||
display: inline-block;
|
||||
padding: 0 10px;
|
||||
background-color: #EBF7FA;
|
||||
color: #046ECA;
|
||||
box-shadow: 0 2px 4px 0 rgba(51,51,51,0.02);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.top-title {
|
||||
font-size: 24px;
|
||||
color: #353636;
|
||||
font-weight: 900;
|
||||
line-height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 8px;
|
||||
padding-top: 20px;
|
||||
margin-left:20px;
|
||||
}
|
||||
}
|
||||
.edit-knowledge-base {
|
||||
height: 100%;
|
||||
|
||||
.edit-knowledge-base__header {
|
||||
padding: 30px 0 30px 20px;
|
||||
font-size: 24px;
|
||||
line-height: 24px;
|
||||
font-weight: 900;
|
||||
color: #353636;
|
||||
}
|
||||
.edit-knowledge-base__body {
|
||||
display: flex;
|
||||
height: calc(100% - 147px);
|
||||
padding-left: 20px;
|
||||
overflow: auto;
|
||||
|
||||
.el-steps {
|
||||
margin-left: 10px;
|
||||
|
||||
.el-step {
|
||||
transition: flex-basis ease-in-out .28s;
|
||||
}
|
||||
.el-step__head {
|
||||
.el-step__line {
|
||||
top: 26px;
|
||||
bottom: 2px;
|
||||
background-color: #38ACD2;
|
||||
border-color: transparent;
|
||||
opacity: 0.66;
|
||||
}
|
||||
|
||||
&.is-finish, &.is-process {
|
||||
.el-step__icon {
|
||||
border-color: #38ACD2;
|
||||
color: white;
|
||||
background: #38ACD2;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-process {
|
||||
.el-step__line {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-wait {
|
||||
.el-step__icon {
|
||||
border-color: #38ACD2;
|
||||
color: #38ACD2;
|
||||
}
|
||||
}
|
||||
|
||||
.el-step__icon-inner {
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-collapse {
|
||||
width: 655px;
|
||||
margin-left: 5px;
|
||||
border: none;
|
||||
|
||||
.el-collapse-item.upload-collapse {
|
||||
.el-collapse-item__wrap {
|
||||
height: 260px;
|
||||
}
|
||||
}
|
||||
.el-collapse-item {
|
||||
min-height: 58px;
|
||||
position: relative;
|
||||
|
||||
.el-collapse-item__header {
|
||||
height: unset;
|
||||
line-height: unset;
|
||||
border: none;
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
|
||||
&.focusing:focus:not(:hover) {
|
||||
color: unset;
|
||||
}
|
||||
.form-sub-title {
|
||||
padding-left: 35px;
|
||||
}
|
||||
}
|
||||
[role|=tab] {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.el-collapse-item__arrow {
|
||||
position: absolute;
|
||||
color: #38ACD2;
|
||||
font-weight: bold;
|
||||
}
|
||||
.el-collapse-item__wrap {
|
||||
padding-left: 35px;
|
||||
border: none;
|
||||
}
|
||||
.el-collapse-item__content {
|
||||
position: relative;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.form-input .el-input__inner{
|
||||
padding-right: 50px !important;
|
||||
}
|
||||
|
||||
.upload-error-tip, .preview-error-tip {
|
||||
color: $--color-danger;
|
||||
}
|
||||
.upload-error-tip {
|
||||
margin-top: -11px;
|
||||
}
|
||||
.el-upload {
|
||||
margin-top: 12px;
|
||||
|
||||
.upload-tip {
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
}
|
||||
.el-upload-dragger {
|
||||
width: 320px;
|
||||
border-radius: 2px;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
}
|
||||
|
||||
}
|
||||
.el-upload--error .el-upload-dragger {
|
||||
border-color: $--color-danger;
|
||||
}
|
||||
.el-upload-list {
|
||||
.el-upload-list__item {
|
||||
padding: 0 5px;
|
||||
margin-top: unset;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
background: #F5F8FA;
|
||||
border-radius: 2px;
|
||||
color: #353636;
|
||||
|
||||
.el-icon-close {
|
||||
top: 11px;
|
||||
}
|
||||
.el-icon-close-tip {
|
||||
top: 11px;
|
||||
}
|
||||
.el-progress.el-progress--line {
|
||||
top: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-form {
|
||||
margin-top: 20px;
|
||||
width: 620px;
|
||||
|
||||
label {
|
||||
padding-bottom: 6px;
|
||||
font-size: 14px;
|
||||
color: #333333;
|
||||
line-height: unset;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.el-form-item__content {
|
||||
line-height: unset;
|
||||
|
||||
.el-input__inner {
|
||||
padding-left: 8px;
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
}
|
||||
.el-textarea__inner {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
width: 100%;
|
||||
|
||||
.el-input__inner {
|
||||
background-color: #F5F8FA;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.skeleton-border {
|
||||
position: relative;
|
||||
margin-top: 12px;
|
||||
padding: 15px;
|
||||
border: 1px solid #DCDFE6;
|
||||
border-radius: 2px;
|
||||
|
||||
.skeleton-item-row:not(:nth-of-type(6)) {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.el-skeleton__item {
|
||||
background: #F5F8FA;
|
||||
}
|
||||
.skeleton-tip {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
}
|
||||
}
|
||||
.imported-tip {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 4px;
|
||||
font-size: 14px;
|
||||
color: #333333;
|
||||
|
||||
.cn-icon {
|
||||
font-size: 16px;
|
||||
color: #38ACD2;
|
||||
}
|
||||
}
|
||||
.imported-table-box {
|
||||
position: relative;
|
||||
height: 367px;
|
||||
border: 1px solid #DEDEDE;
|
||||
border-radius: 2px;
|
||||
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
&.imported-table-box--error {
|
||||
border-color: $--color-danger;
|
||||
}
|
||||
.imported-table {
|
||||
padding: 0 12px;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
color: #353636;;
|
||||
}
|
||||
td {
|
||||
font-size: 14px;
|
||||
color: #353636;
|
||||
}
|
||||
.imported-data-msg, .imported-data-item, .imported-data-value {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.imported-data-msg {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.el-icon-close {
|
||||
color: #666;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #111;
|
||||
}
|
||||
}
|
||||
.el-icon-success {
|
||||
color: #749F4D;
|
||||
}
|
||||
.el-icon-error {
|
||||
color: #E26154;
|
||||
}
|
||||
}
|
||||
|
||||
.imported-pagination.pagination {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
margin-top: 4px;
|
||||
padding-top: 8px;
|
||||
height: 42px;
|
||||
border-top: 1px solid #eee;
|
||||
|
||||
.btn-prev, .btn-next, .number {
|
||||
margin: 0 2px;
|
||||
}
|
||||
.el-pager li, .el-pagination .btn-next, .el-pagination .btn-prev {
|
||||
border: none;
|
||||
font-size: 12px;
|
||||
}
|
||||
.el-pagination .el-pager li {
|
||||
color: #353636;
|
||||
}
|
||||
.el-pagination .el-pager li.active {
|
||||
background-color: #38ACD2;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.edit-knowledge-base__footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 60px;
|
||||
margin-top: 3px;
|
||||
box-shadow: 0 -1px 4px 0 rgba(0,0,0,0.10);
|
||||
|
||||
.footer__btn {
|
||||
margin: 0 10px;
|
||||
height: 30px;
|
||||
min-width: 74px;
|
||||
padding: 0 15px;
|
||||
color: white;
|
||||
background-color: #38ACD2;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: background-color linear .2s, color linear .1s;
|
||||
}
|
||||
.footer__btn:hover:not(.footer__btn--disabled) {
|
||||
background-color: lighten(#38ACD2, 10%);
|
||||
}
|
||||
.footer__btn--light {
|
||||
background-color: #F5F6F7;
|
||||
border: 1px solid $--border-color-primary;
|
||||
color: #333;
|
||||
}
|
||||
.footer__btn.footer__btn--light:hover:not(.footer__btn--disabled) {
|
||||
background-color: white;
|
||||
border-color: lighten(#38ACD2, 40%);
|
||||
color: #38ACD2;
|
||||
}
|
||||
.footer__btn--disabled {
|
||||
opacity: .6;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,12 +31,12 @@ $--button-primary-background-color: $--color-primary; // 普通按钮背景色
|
||||
$--button-hover-tint-percent: 20%; // 非灰色按钮在鼠标hover时背景色变浅的幅度
|
||||
$--button-active-shade-percent: 0; // 非灰色按钮在focus时背景色变深的幅度
|
||||
|
||||
$--button-gray-color: #666; // 灰色按钮字色
|
||||
$--button-gray-color: #353636; // 灰色按钮字色
|
||||
$--button-gray-hover-color: $--button-gray-color; // 灰色按钮hover字色
|
||||
$--button-gray-active-color: $--color-primary; // 灰色按钮focus字色
|
||||
$--button-gray-background-color: #F9F9F9; // 灰色按钮背景色
|
||||
$--button-gray-hover-background-color: #FFF; // 灰色按钮hover背景色
|
||||
$--button-gray-active-background-color: $--button-gray-hover-background-color; // 灰色按钮focus背景色
|
||||
$--button-gray-hover-background-color: #EBF1F4; // 灰色按钮hover背景色
|
||||
$--button-gray-active-background-color: #E0E7EA; // 灰色按钮focus背景色
|
||||
$--button-gray-border-color: $--border-color-primary; // 灰色按钮边框色
|
||||
$--button-gray-hover-border-color: $--button-gray-border-color; // 灰色按钮hover边框色
|
||||
$--button-gray-active-border-color-tint-percent: 30%; // 灰色按钮在focus时边框色相对于主题色变浅的幅度
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
/** 重写element-ui变量 **/
|
||||
|
||||
$--color-primary: #0091ff; // 主题色
|
||||
$--color-primary-dark-10: darken(#0091ff, 10%); // 默认主题色 深10%
|
||||
$--color-primary-light-10: lighten(#0091ff, 10%); // 默认主题色 浅10%
|
||||
$--color-primary-light-20: lighten(#0091ff, 20%); // 默认主题色 浅20%
|
||||
$--color-primary: #699DC9; // 主题色
|
||||
$--color-primary-dark-10: darken(#699DC9, 10%); // 默认主题色 深10%
|
||||
$--color-primary-light-10: lighten(#699DC9, 10%); // 默认主题色 浅10%
|
||||
$--color-primary-light-20: lighten(#699DC9, 20%); // 默认主题色 浅20%
|
||||
|
||||
/* menu相关 */
|
||||
$--menu-background-color: #00162B; // menu背景色
|
||||
@@ -31,12 +31,12 @@ $--button-primary-background-color: $--color-primary; // 普通按钮背景色
|
||||
$--button-hover-tint-percent: 20%; // 非灰色按钮在鼠标hover时背景色变浅的幅度
|
||||
$--button-active-shade-percent: 0; // 非灰色按钮在focus时背景色变深的幅度
|
||||
|
||||
$--button-gray-color: #666; // 灰色按钮字色
|
||||
$--button-gray-color: #353636; // 灰色按钮字色
|
||||
$--button-gray-hover-color: $--button-gray-color; // 灰色按钮hover字色
|
||||
$--button-gray-active-color: $--color-primary; // 灰色按钮focus字色
|
||||
$--button-gray-background-color: #F9F9F9; // 灰色按钮背景色
|
||||
$--button-gray-hover-background-color: #FFF; // 灰色按钮hover背景色
|
||||
$--button-gray-active-background-color: $--button-gray-hover-background-color; // 灰色按钮focus背景色
|
||||
$--button-gray-hover-background-color: #EBF1F4; // 灰色按钮hover背景色
|
||||
$--button-gray-active-background-color: #E0E7EA; // 灰色按钮focus背景色
|
||||
$--button-gray-border-color: $--border-color-primary; // 灰色按钮边框色
|
||||
$--button-gray-hover-border-color: $--button-gray-border-color; // 灰色按钮hover边框色
|
||||
$--button-gray-active-border-color-tint-percent: 30%; // 灰色按钮在focus时边框色相对于主题色变浅的幅度
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<template #label>
|
||||
<div class="chart-tabs__label">
|
||||
<i :class="tab.icon"></i>
|
||||
<span>{{ $t(tab.i18n) }}</span>
|
||||
<span>{{ $t(tab.i18n || tab.name) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
@@ -45,6 +45,7 @@
|
||||
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useStore } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'ChartTabs',
|
||||
@@ -69,8 +70,9 @@ export default {
|
||||
setup (props) {
|
||||
const tabsData = ref([])
|
||||
const router = useRouter()
|
||||
const store = useStore()
|
||||
const routerPath = router.currentRoute.value.path
|
||||
const tabList = window.currentChartTabList
|
||||
const tabList = store.getters.getChartTabList
|
||||
let currentTab = '0'
|
||||
|
||||
if (props.data) {
|
||||
@@ -94,7 +96,7 @@ export default {
|
||||
return item.path === routerPath
|
||||
})
|
||||
currentTab = JSON.stringify(currentTab)
|
||||
window.currentChartTabList = [{ path: routerPath, index: currentTab }]
|
||||
store.dispatch('dispatchChartTabList', [{ path: routerPath, index: currentTab }])
|
||||
} else {
|
||||
// 此处为切换界面,如果window里保存的路径和tabsData里的路径一致,选择window数据并使用
|
||||
// 两个不一致的话,则默认选择tabsData里的第一条
|
||||
@@ -108,10 +110,15 @@ export default {
|
||||
|
||||
if (obj0 && obj1) {
|
||||
currentTab = tabList[1].index
|
||||
// 场景:从遮罩面板进入界面时,重置状态,默认选中第一个tab
|
||||
if (routerPath === tabList[0].path) {
|
||||
currentTab = tabList[0].index
|
||||
store.dispatch('dispatchChartTabList', [{ path: tabsData.value[0].path, index: '0' }])
|
||||
}
|
||||
} else if (obj0) {
|
||||
currentTab = tabList[0].index
|
||||
} else {
|
||||
window.currentChartTabList = [{ path: tabsData.value[0].path, index: '0' }]
|
||||
store.dispatch('dispatchChartTabList', [{ path: tabsData.value[0].path, index: '0' }])
|
||||
currentTab = '0'
|
||||
}
|
||||
}
|
||||
@@ -156,9 +163,10 @@ export default {
|
||||
}
|
||||
}
|
||||
})
|
||||
const tabList = this.$store.getters.getChartTabList
|
||||
|
||||
if (window.currentChartTabList && this.router !== 'noRouter') {
|
||||
window.currentChartTabList.forEach((item) => {
|
||||
if (tabList && this.router !== 'noRouter') {
|
||||
tabList.forEach((item) => {
|
||||
this.$nextTick(() => {
|
||||
this.handleActiveBar(parseFloat(item.index))
|
||||
})
|
||||
@@ -167,7 +175,7 @@ export default {
|
||||
this.$nextTick(() => {
|
||||
this.handleActiveBar(this.currentTab)
|
||||
})
|
||||
window.currentChartTabList = null
|
||||
this.$store.dispatch('dispatchChartTabList', null)
|
||||
}
|
||||
},
|
||||
handleActiveBar (index) {
|
||||
@@ -186,7 +194,7 @@ export default {
|
||||
} else {
|
||||
// 数组长度为1,即代表刚刷新界面,获取active的dom添加样式,避免原模式错位问题
|
||||
// 可添加css样式,也可添加class类名,两个操作选一即可
|
||||
if (window.currentChartTabList.length === 1) {
|
||||
if (this.$store.getters.getChartTabList.length === 1) {
|
||||
// 此处操作是因为初始化时给active加border,导致tab下移,故需要将整体往上移动对应高度
|
||||
const topDom = document.getElementsByClassName('el-tabs__header is-top')
|
||||
topDom[0].style.cssText += 'top: -3px'
|
||||
@@ -201,6 +209,7 @@ export default {
|
||||
},
|
||||
handleClick (item) {
|
||||
this.$emit('click', item)
|
||||
const tabList = this.$store.getters.getChartTabList
|
||||
|
||||
if (this.router === 'noRouter') {
|
||||
const { query } = this.$route
|
||||
@@ -210,14 +219,15 @@ export default {
|
||||
})
|
||||
overwriteUrl(newUrl)
|
||||
} else {
|
||||
window.currentChartTabList.push({
|
||||
tabList.push({
|
||||
path: this.tabsData[item.index].path,
|
||||
index: item.index
|
||||
})
|
||||
|
||||
if (window.currentChartTabList.length > 2) {
|
||||
window.currentChartTabList.splice(0, 1)
|
||||
if (tabList.length > 2) {
|
||||
tabList.splice(0, 1)
|
||||
}
|
||||
this.$store.dispatch('dispatchChartTabList', tabList)
|
||||
|
||||
this.$router.push({
|
||||
path: this.tabsData[item.index].path,
|
||||
@@ -230,6 +240,19 @@ export default {
|
||||
},
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer)
|
||||
const path = this.$router.currentRoute.value.path
|
||||
const list = this.$store.getters.getChartTabList
|
||||
if (list && this.router !== 'noRouter') {
|
||||
if (list[1]) {
|
||||
// 去其他界面,清除状态
|
||||
if (path !== list[0].path && path !== list[1].path) {
|
||||
this.$store.dispatch('dispatchChartTabList', null)
|
||||
}
|
||||
} else if (path !== list[0].path) {
|
||||
// 避免刷新页面之后又点击菜单栏进入该界面,还保留上次点击状态
|
||||
this.$store.dispatch('dispatchChartTabList', null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -141,7 +141,6 @@ export default {
|
||||
hoverError (e) {
|
||||
// const dom = document.getElementById('error-content')
|
||||
// if (dom) {
|
||||
// console.log('---', dom.clientHeight)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
:page-size="Number(pageObj.pageSize)"
|
||||
:layout="layout"
|
||||
:total="pageObj.total"
|
||||
v-bind="bind"
|
||||
>
|
||||
<el-select v-model="pageSize" :placeholder="pageSize+$t('pageSize')" size="mini"
|
||||
:popper-append-to-body="appendToBody" class="pagination-size-select" @change="size"
|
||||
@@ -42,15 +43,23 @@ export default {
|
||||
layout: {
|
||||
type: String,
|
||||
default: 'total, prev, pager, next, slot'
|
||||
},
|
||||
bind: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
storePageNoOnUrl: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 添加vue3的setup,目的是添加/获取地址栏的参数
|
||||
*/
|
||||
setup () {
|
||||
setup (props) {
|
||||
const { query } = useRoute()
|
||||
const pageSize = ref(defaultPageSize)
|
||||
const currentPageNo = ref(query.pageNo || 1)
|
||||
const currentPageNo = ref(props.storePageNoOnUrl ? (query.pageNo || (props.pageObj.pageNo || 1)) : (props.pageObj.pageNo || 1))
|
||||
|
||||
return {
|
||||
pageSize,
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
class="date_style"
|
||||
style="position: absolute;top: -53px;left: -536px;"
|
||||
:clearable="false"
|
||||
:default-time="defaultTime"
|
||||
type="datetimerange"
|
||||
@change="timeArrChange"
|
||||
/>
|
||||
@@ -127,6 +128,11 @@ export default {
|
||||
{ value: 2880, name: 'last 2 days' }
|
||||
]
|
||||
const dropdownFlag = ref(false)
|
||||
// 默认日历选择时间,即开始时间YYYY-MM-DD 00:00:00,结束时间YYYY-MM-DD 59:59:59
|
||||
const defaultTime = ref([
|
||||
new Date(2023, 1, 1, 0, 0, 0),
|
||||
new Date(2023, 1, 2, 23, 59, 59)
|
||||
])
|
||||
|
||||
// computed
|
||||
const utcStr = computed(() => {
|
||||
@@ -274,6 +280,7 @@ export default {
|
||||
rangeEchartsData,
|
||||
address,
|
||||
dateRangeArr,
|
||||
defaultTime,
|
||||
dateRangeValue,
|
||||
isCustom,
|
||||
newDateValue,
|
||||
|
||||
@@ -98,7 +98,6 @@ export default {
|
||||
if (val && val.value !== -1) {
|
||||
// 切换轮询请求时间频率时,发现有未结束的请求,终止请求
|
||||
const cancelList = this.$store.state.panel.httpCancel
|
||||
// console.log('timeRefresh.vue------setRefresh------查看终止数量', cancelList, cancelList.length)
|
||||
if (cancelList.length > 0) {
|
||||
cancelList.forEach((cancel, index) => {
|
||||
cancel()
|
||||
|
||||
@@ -42,9 +42,9 @@
|
||||
</div>
|
||||
<div class="cn-header__nav">
|
||||
<i class="cn-icon cn-icon-a-NetworkAnalytics"></i>
|
||||
<el-breadcrumb class="header__left-breadcrumb" :separator="route.indexOf('detection') === -1 && route.indexOf('administration') === -1 ? '>' : ''">
|
||||
<el-breadcrumb-item class="header__left-breadcrumb-item" :id="`breadcrumb${item}`" :title="item"
|
||||
v-for="(item,index) in breadcrumb" :key="item">
|
||||
<el-breadcrumb class="header__left-breadcrumb" separator=">">
|
||||
<el-breadcrumb-item class="header__left-breadcrumb-item" :id="`breadcrumb${item.value}`" :title="item.value"
|
||||
v-for="(item,index) in breadcrumb" :key="item.value">
|
||||
<template v-if="index===3">
|
||||
<div class="header__left-breadcrumb-item-select">
|
||||
<el-popover placement="bottom-start"
|
||||
@@ -54,7 +54,7 @@
|
||||
:hide-after="0"
|
||||
:show-after="0"
|
||||
popper-class="breadcrumb__popper"
|
||||
@show="showBreadcrumbPopover(item)"
|
||||
@show="showBreadcrumbPopover(item.value)"
|
||||
@hide="hideBreadcrumbPopover()"
|
||||
trigger="click">
|
||||
<template #reference>
|
||||
@@ -62,13 +62,13 @@
|
||||
:class="showBackground?'breadcrumb-button__active':''">
|
||||
<span id="breadcrumbValue">
|
||||
<template v-if="curTabProp === 'qtype'">
|
||||
<span>{{ dnsQtypeMapData.get(item)}}</span>
|
||||
<span>{{ dnsQtypeMapData.get(item.value)}}</span>
|
||||
</template>
|
||||
<template v-else-if="curTabProp === 'rcode'">
|
||||
<span>{{ dnsRcodeMapData.get(item)}}</span>
|
||||
<span>{{ dnsRcodeMapData.get(item.value)}}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>{{ item }}</span>
|
||||
<span>{{ item.value }}</span>
|
||||
</template>
|
||||
</span><i class="cn-icon-xiala cn-icon"></i>
|
||||
</div>
|
||||
@@ -82,7 +82,7 @@
|
||||
</div>
|
||||
<ul class="select-dropdown" id="breadcrumbSelectDropdown" @scroll="scrollList()">
|
||||
<li v-for="item in breadcrumbColumnValueListShow" title='' :key="item" :id="item"
|
||||
class="select-dropdown__item" @click="changeValue(item)" :class="selected?'':''">
|
||||
class="select-dropdown__item" @click="changeValue(item)">
|
||||
<template v-if="curTabProp === 'qtype'">
|
||||
<span>{{ dnsQtypeMapData.get(item) }}</span>
|
||||
</template>
|
||||
@@ -99,39 +99,17 @@
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="index===2">
|
||||
<span v-if="route===wholeScreenRouterMapping.dns">{{ $t(item) }}</span>
|
||||
<span v-else class="route-menu" @click="jump(route,item,'',3)">{{ $t(item) }}</span>
|
||||
<span v-if="route===wholeScreenRouterMapping.dns">{{ $t(item.value) }}</span>
|
||||
<span v-else class="route-menu" @click="jump(route,item.value,'',3)">{{ $t(item.value) }}</span>
|
||||
</template>
|
||||
<!-- index=0和index=1的点击跳转由breadcrumb里的数据控制 -->
|
||||
<template v-else-if="index===1">
|
||||
<span class="route-menu" @click="jump(route,'','',2)"
|
||||
v-if="route.indexOf('detection') === -1 && route.indexOf('administration') === -1">{{ item }}</span>
|
||||
<!-- <div class="header__left-breadcrumb-item-select" v-if="route.indexOf('detection') > -1">-->
|
||||
<!-- <el-popover placement="bottom-start"-->
|
||||
<!-- v-if="route.indexOf('detection') > -1"-->
|
||||
<!-- ref="breadcrumbPopover"-->
|
||||
<!-- :show-arrow="false"-->
|
||||
<!-- :append-to-body="false"-->
|
||||
<!-- :hide-after="0"-->
|
||||
<!-- :show-after="0"-->
|
||||
<!-- popper-class="breadcrumb__popper"-->
|
||||
<!-- trigger="click">-->
|
||||
<!-- <template #reference>-->
|
||||
<!-- <div class="breadcrumb-button" id="breadcrumbButton2" :class="showBackground?'breadcrumb-button__active':''" v-if="route.indexOf('detection') > -1">-->
|
||||
<!-- <span id="breadcrumbValue2"> {{item}}</span><i class="cn-icon-xiala cn-icon"></i>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- <el-row type="flex" justify="center" style="width: fit-content;flex-direction: column;">-->
|
||||
<!-- <ul class="select-dropdown" id="breadcrumbSelectDropdown2">-->
|
||||
<!-- <li v-for="item in detectionMenuList" title='' :key="item.name" :id="item.name" class="select-dropdown__item" @click="jump(item.path,'','',2)">-->
|
||||
<!-- <span>{{$t(item.i18n)}}</span>-->
|
||||
<!-- </li>-->
|
||||
<!-- </ul>-->
|
||||
<!-- </el-row>-->
|
||||
<!-- </el-popover>-->
|
||||
<!-- </div>-->
|
||||
<span v-if="item.clickable" class="route-menu" @click="jump(route,'','',2)">{{ item.value }}</span>
|
||||
<span v-else>{{ item.value }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>{{ item }}</span>
|
||||
<span v-if="item.clickable" class="route-menu" @click="jump(item.route,'','',0)">{{ item.value }}</span>
|
||||
<span v-else>{{ item.value }}</span>
|
||||
</template>
|
||||
</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
@@ -233,6 +211,7 @@ import {
|
||||
handleSpecialValue
|
||||
} from '@/utils/tools'
|
||||
import { getNowTime, getSecond } from '@/utils/date-util'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
name: 'Header',
|
||||
@@ -310,7 +289,7 @@ export default {
|
||||
return this.$store.getters.menuList.find(menu => menu.code === 'networkAnalytics')
|
||||
},
|
||||
otherMenu () {
|
||||
return this.$store.getters.menuList.filter(menu => menu.code !== 'networkAnalytics')
|
||||
return this.$store.getters.menuList.filter(menu => ['networkAnalytics', 'chart', 'I18N'].indexOf(menu.code) === -1)
|
||||
|
||||
/* function excludeButton (menu) {
|
||||
for (let i = 0; i < menu.length; i++) {
|
||||
@@ -326,38 +305,28 @@ export default {
|
||||
} */
|
||||
},
|
||||
breadcrumb () {
|
||||
const breadcrumbMap = []
|
||||
this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
|
||||
this.$store.getters.menuList.forEach(menu => {
|
||||
if (this.$_.isEmpty(menu.children) && menu.route) {
|
||||
breadcrumbMap.push({
|
||||
name: this.$t(menu.i18n),
|
||||
path: menu.route,
|
||||
columnName: menu.columnName,
|
||||
columnValue: menu.columnValue
|
||||
})
|
||||
} else if (!this.$_.isEmpty(menu.children)) {
|
||||
menu.children.forEach(child => {
|
||||
breadcrumbMap.push({
|
||||
name: child.i18n ? this.$t(child.i18n) : child.name,
|
||||
parentName: menu.i18n ? this.$t(menu.i18n) : menu.name,
|
||||
path: child.route,
|
||||
columnName: child.columnName,
|
||||
columnValue: child.columnValue
|
||||
})
|
||||
})
|
||||
const breadcrumb = []
|
||||
this.generateBreadcrumb(breadcrumb, this.$store.getters.menuList)
|
||||
// 写死一级和二级菜单是否可以点击跳转
|
||||
if (breadcrumb[0]) {
|
||||
if (['knowledgeBase'].indexOf(breadcrumb[0].code) > -1) {
|
||||
breadcrumb[0].clickable = true
|
||||
}
|
||||
})
|
||||
const breadcrumb = breadcrumbMap.find(b => this.route === b.path)
|
||||
if (breadcrumb[1]) {
|
||||
if (breadcrumb[1].route && breadcrumb[1].route.indexOf('/panel/') === 0) {
|
||||
breadcrumb[1].clickable = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const thirdMenu = this.getUrlParam(this.curTabState.thirdMenu, '')
|
||||
const fourthMenu = this.getUrlParam(this.curTabState.fourthMenu, '')
|
||||
let result = []
|
||||
|
||||
let result = [...breadcrumb]
|
||||
if (fourthMenu) {
|
||||
result = breadcrumb ? [breadcrumb.parentName, breadcrumb.name, thirdMenu, fourthMenu] : []
|
||||
result = [...result, { value: thirdMenu }, { value: fourthMenu }]
|
||||
} else if (thirdMenu) {
|
||||
result = breadcrumb ? [breadcrumb.parentName, breadcrumb.name, thirdMenu] : []
|
||||
} else {
|
||||
result = breadcrumb ? [breadcrumb.parentName, breadcrumb.name] : []
|
||||
result = [...result, { value: thirdMenu }]
|
||||
}
|
||||
return result
|
||||
},
|
||||
@@ -381,6 +350,7 @@ export default {
|
||||
}
|
||||
},
|
||||
async breadcrumb (n) {
|
||||
this.curTabProp = this.$route.query.dimensionType ? this.$route.query.dimensionType : null
|
||||
if (this.$route.params.typeName === fromRoute.dnsServiceInsights) {
|
||||
if (this.dnsQtypeMapData.size === 0) {
|
||||
this.dnsQtypeMapData = await getDnsMapData('dnsQtype')
|
||||
@@ -421,6 +391,32 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
generateBreadcrumb (breadcrumb, menus) {
|
||||
const menu = menus.find(m => m.route === this.route)
|
||||
if (menu) {
|
||||
breadcrumb.unshift({
|
||||
code: menu.code,
|
||||
value: menu.i18n ? this.$t(menu.i18n) : menu.name,
|
||||
route: menu.route,
|
||||
type: menu.type
|
||||
})
|
||||
return true
|
||||
} else {
|
||||
for (let i = 0; i < menus.length; i++) {
|
||||
if (!_.isEmpty(menus[i].children)) {
|
||||
if (this.generateBreadcrumb(breadcrumb, menus[i].children)) {
|
||||
breadcrumb.unshift({
|
||||
code: menus[i].code,
|
||||
value: menus[i].i18n ? this.$t(menus[i].i18n) : menus[i].name,
|
||||
route: menus[i].route,
|
||||
type: menus[i].type
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
handleClose () {
|
||||
this.showChangePin = false
|
||||
},
|
||||
@@ -552,7 +548,7 @@ export default {
|
||||
queryCondition.push('common_l7_protocol=\'' + valueGroup[0] + '\'')
|
||||
queryCondition.push('common_server_port=' + valueGroup[1])
|
||||
}
|
||||
console.log(queryCondition.join(' AND '))
|
||||
// console.log(queryCondition.join(' AND '))
|
||||
this.urlChangeParams[this.curTabState.queryCondition] = queryCondition.join(' AND ')
|
||||
} else {
|
||||
searchProps.forEach(item => {
|
||||
@@ -627,10 +623,8 @@ export default {
|
||||
this.urlChangeParams[this.curTabState.tabOperationBeforeType] = this.getUrlParam(this.curTabState.tabOperationType, '', true)
|
||||
this.urlChangeParams[this.curTabState.tabOperationType] = opeType
|
||||
if (opeType === 3) {
|
||||
if (route !== '/panel/networkOverview') {
|
||||
this.urlChangeParams.queryCondition = ''
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.urlChangeParams[this.curTabState.tabOperationType] = operationType.mainMenu
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="right-box__container">
|
||||
<div class="container__form">
|
||||
<el-form ref="userForm" :model="editObject" :rules="rules" label-position="top" label-width="120px">
|
||||
<el-form ref="reportForm" :model="editObject" :rules="rules" label-position="top" label-width="120px">
|
||||
<!--name-->
|
||||
<el-form-item :label="$t('report.name')" prop="name">
|
||||
<el-input id="account-input-name" v-model="editObject.name" maxlength="64" placeholder=" " show-word-limit size="small" type="text"></el-input>
|
||||
@@ -19,7 +19,6 @@
|
||||
v-model="editObject.config.timeConfig.type"
|
||||
class="right-box__select"
|
||||
collapse-tags
|
||||
:disabled="!!editObject.id"
|
||||
placeholder=" "
|
||||
popper-class="right-box-select-dropdown right-box-select-report "
|
||||
size="small"
|
||||
@@ -31,7 +30,6 @@
|
||||
</el-select>
|
||||
<template v-if="editObject.config.timeConfig.type === 'this'">
|
||||
<el-select id="reportBoxTimeUnitSelect"
|
||||
:disabled="!!editObject.id"
|
||||
v-model="editObject.config.timeConfig.unit"
|
||||
class="right-box__select"
|
||||
collapse-tags
|
||||
@@ -45,7 +43,7 @@
|
||||
</el-select>
|
||||
</template>
|
||||
<div v-else-if="editObject.config.timeConfig.type === 'last' || editObject.config.timeConfig.type === 'previous'" style="display: flex;">
|
||||
<el-input v-model.number="editObject.config.timeConfig.offset" size="small" class="el-input-single" placeholder=" " :disabled="!!editObject.id">
|
||||
<el-input v-model.number="editObject.config.timeConfig.offset" size="small" class="el-input-single" placeholder=" ">
|
||||
<template #prepend><i @click="timeOffsetHandle('m')" class="cn-icon cn-icon-a-"></i></template>
|
||||
<template #append><i @click="timeOffsetHandle('p')" class="cn-icon cn-icon-a-1"></i></template>
|
||||
</el-input>
|
||||
@@ -53,7 +51,6 @@
|
||||
v-model="editObject.config.timeConfig.unit"
|
||||
class="right-box__select right-box__select-single"
|
||||
collapse-tags
|
||||
:disabled="!!editObject.id"
|
||||
placeholder=" "
|
||||
popper-class="right-box-select-dropdown el-select-last"
|
||||
size="small"
|
||||
@@ -73,10 +70,8 @@
|
||||
v-model="editObject.config.startTime"
|
||||
size="small"
|
||||
:format="dateFormat"
|
||||
:disabled="!!editObject.id"
|
||||
:disabled-date="startDisabledDate"
|
||||
@change="startTimeChang"
|
||||
@focus="startFocus"
|
||||
prefix-icon="cn-icon cn-icon-shijian"
|
||||
type="datetime"
|
||||
placeholder=" "
|
||||
@@ -93,10 +88,8 @@
|
||||
v-model="editObject.config.endTime"
|
||||
size="small"
|
||||
:format="dateFormat"
|
||||
:disabled="!!editObject.id"
|
||||
:disabled-date="endDisabledDate"
|
||||
@change="endTimeChange"
|
||||
@focus="endFocus"
|
||||
prefix-icon="cn-icon cn-icon-shijian"
|
||||
type="datetime"
|
||||
placeholder=" "
|
||||
@@ -105,41 +98,41 @@
|
||||
</div>
|
||||
</el-form-item >
|
||||
<el-form-item class="el-height">
|
||||
<el-checkbox v-model="scheduleChecked" :disabled="editObject.config.timeConfig.type === 'customize' || !!editObject.id" :label="$t('report.enableTimeSchedule')" size="large" />
|
||||
<el-checkbox v-model="scheduleChecked" :disabled="editObject.config.timeConfig.type === 'customize'" :label="$t('report.enableTimeSchedule')" size="large" />
|
||||
</el-form-item>
|
||||
<!--Enable time schedule-->
|
||||
<el-form-item prop="enableTimeSchedule" v-if="scheduleChecked">
|
||||
<div class="enable-tab">
|
||||
<div class="enable-tabs" @click="editObject.id ? null : (scheduleType = type.value)" v-for="type in scheduleTypeList" :key="type.value" :class="{'active': scheduleType === type.value, 'disable': editObject.id}">{{$t(type.name)}}</div>
|
||||
<div class="enable-tabs" @click="scheduleTypeChange(type.value)" v-for="type in scheduleTypeList" :key="type.value" :class="{'active': scheduleType === type.value}">{{$t(type.name)}}</div>
|
||||
</div>
|
||||
<div class="enable-tabs-daily" v-if="scheduleType === scheduleTypeList[0].value">
|
||||
<div class="enable-tabs-custom">{{$t('report.customEvery')}}</div>
|
||||
<el-input v-model.number="editObject.config.schedulerConfig.interval" size="small" placeholder=" " style="margin-top: 0.3125rem;" :disabled="!!editObject.id">
|
||||
<el-input v-model.number="editObject.config.schedulerConfig.interval" size="small" placeholder=" " style="margin-top: 0.3125rem;">
|
||||
<template #append>{{$t('report.day')}}</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="enable-tabs-weekly" v-else-if="scheduleType === scheduleTypeList[1].value" :disabled="!!editObject.id">
|
||||
<div class="enable-tabs-weekly" v-else-if="scheduleType === scheduleTypeList[1].value">
|
||||
<!-- 每隔几周暂时隐藏 -->
|
||||
<!-- <div class="enable-tabs-custom">{{$t('report.customEvery')}}</div>
|
||||
<el-input v-model="editObject.config.schedulerConfig.interval" size="small" placeholder="Please input">
|
||||
<template #append>{{$t('report.week')}}</template>
|
||||
</el-input>-->
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.weekDates" style="margin-top: 0.3125rem" :disabled="!!editObject.id">
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.weekDates" style="margin-top: 0.3125rem">
|
||||
<el-checkbox v-for="(item, index) in weekdayList" :key="index" :label="item.value">{{$t(item.name)}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
<!-- 月 -->
|
||||
<div class="enable-tabs-per-month" v-else-if="scheduleType === scheduleTypeList[2].value">
|
||||
<div class="enable-month-tab">
|
||||
<div class="enable-month-tabs" @click="editObject.id ? null : (monthScheduleType = 'daily')" :class="{'active': monthScheduleType === 'daily', 'disable': editObject.id}">{{$t('report.date')}}</div>
|
||||
<div class="enable-month-tabs" @click="editObject.id ? null : (monthScheduleType = 'weekly')" :class="{'active': monthScheduleType === 'weekly', 'disable': editObject.id}">{{$t('report.week')}}</div>
|
||||
<el-checkbox v-model="monthIsCycle" :label="$t('report.cycle')" size="large" :disabled="!!editObject.id"/>
|
||||
<div class="enable-month-tabs" @click="monthScheduleType = 'daily'" :class="{'active': monthScheduleType === 'daily'}">{{$t('report.date')}}</div>
|
||||
<div class="enable-month-tabs" @click="monthScheduleType = 'weekly'" :class="{'active': monthScheduleType === 'weekly'}">{{$t('report.week')}}</div>
|
||||
<el-checkbox v-model="monthIsCycle" :label="$t('report.cycle')" size="large"/>
|
||||
</div>
|
||||
<div class="enable-month-data-tab">
|
||||
<!-- 自定义月,循环 -->
|
||||
<template v-if="monthIsCycle">
|
||||
<div class="enable-tabs-custom">{{$t('report.customEvery')}}</div>
|
||||
<el-input v-model="editObject.config.schedulerConfig.interval" size="small" placeholder=" " style="margin-top: 0.3125rem;" :disabled="!!editObject.id">
|
||||
<el-input v-model="editObject.config.schedulerConfig.interval" size="small" placeholder=" " style="margin-top: 0.3125rem;">
|
||||
<template #append>{{$t('report.month')}}</template>
|
||||
</el-input>
|
||||
</template>
|
||||
@@ -147,8 +140,8 @@
|
||||
<template v-else>
|
||||
<div class="enable-month-moon-custom">{{$t('report.custom')}}</div>
|
||||
<div class="enable-month-all">
|
||||
<el-checkbox v-model="monthCheckedAll" class="enable-month-all-months" :indeterminate="monthIsIndeterminate" @change="monthCheckAllChange" :label="$t('report.allMonths')" :disabled="!!editObject.id"/>
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.months" @change="monthCheckChange" :disabled="!!editObject.id">
|
||||
<el-checkbox v-model="monthCheckedAll" class="enable-month-all-months" :indeterminate="monthIsIndeterminate" @change="monthCheckAllChange" :label="$t('report.allMonths')"/>
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.months" @change="monthCheckChange">
|
||||
<el-checkbox v-for="(item, index) in monthList" :key="index" :label="item.value">{{$t(item.name)}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
@@ -156,8 +149,8 @@
|
||||
<!-- 按日期 -->
|
||||
<template v-if="monthScheduleType === 'daily'">
|
||||
<div class="enable-month-data-tabs">
|
||||
<el-checkbox v-model="dateCheckedAll" :indeterminate="dateIsIndeterminate" @change="dateCheckAllChange" :label="$t('report.all')" size="large" :disabled="!!editObject.id"/>
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.monthDates" @change="dateCheckChange" :disabled="!!editObject.id">
|
||||
<el-checkbox v-model="dateCheckedAll" :indeterminate="dateIsIndeterminate" @change="dateCheckAllChange" :label="$t('report.all')" size="large"/>
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.monthDates" @change="dateCheckChange">
|
||||
<el-checkbox v-for="item in dateList" :key="item" :label="item"/>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
@@ -170,7 +163,6 @@
|
||||
class="right-box__select"
|
||||
multiple
|
||||
placeholder=" "
|
||||
:disabled="!!editObject.id"
|
||||
popper-class="right-box-select-dropdown right-box-select-report"
|
||||
size="small"
|
||||
@change="()=>{ this.$forceUpdate() }">
|
||||
@@ -179,8 +171,8 @@
|
||||
</template>
|
||||
</el-select>
|
||||
<div class="enable-month-week">
|
||||
<el-checkbox v-model="monthWeekdayCheckedAll" class="enable-month-week-all" :label="$t('report.all')" :indeterminate="monthWeekdayIsIndeterminate" @change="monthWeekdayCheckAllChange" size="large" :disabled="!!editObject.id"/>
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.weekDates" @change="monthWeekdayCheckChange" :disabled="!!editObject.id">
|
||||
<el-checkbox v-model="monthWeekdayCheckedAll" class="enable-month-week-all" :label="$t('report.all')" :indeterminate="monthWeekdayIsIndeterminate" @change="monthWeekdayCheckAllChange" size="large"/>
|
||||
<el-checkbox-group v-model="editObject.config.schedulerConfig.weekDates" @change="monthWeekdayCheckChange">
|
||||
<el-checkbox v-for="(item, index) in weekdayList" :key="index" :label="item.value">{{$t(item.name)}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
@@ -230,7 +222,7 @@
|
||||
:disabled="!!editObject.id"
|
||||
popper-class="right-box-select-dropdown right-box-select-report"
|
||||
size="small"
|
||||
@change="typeChange">
|
||||
>
|
||||
<template v-for="category in categoryList" :key="category.id">
|
||||
<el-option :label="category.name" :value="category.id"></el-option>
|
||||
</template>
|
||||
@@ -241,9 +233,12 @@
|
||||
<!-- <el-input v-model="param.value" placeholder=" " v-for="(param, index) in editObject.categoryParams" :key="index" size="small" style="vertical-align: unset;" :disabled="!!editObject.id">
|
||||
<template #prepend>{{param.key}}</template>
|
||||
</el-input>-->
|
||||
<template v-for="(param, index) in editObject.categoryParams" :key="index">
|
||||
<el-input v-if="param.labelType === 'input'" v-model="param.value" placeholder=" " size="small" style="vertical-align: unset;" :disabled="!!editObject.id">
|
||||
<template #prepend>{{param.key}}</template>
|
||||
</el-input>
|
||||
<el-select v-model="param.value"
|
||||
v-for="(param, index) in editObject.categoryParams"
|
||||
:key="index"
|
||||
v-else
|
||||
class="right-box__select right-box__select--param"
|
||||
placeholder=" "
|
||||
filterable
|
||||
@@ -259,8 +254,8 @@
|
||||
<el-option :key="p" :value="p" v-for="p in paramOption.options"></el-option>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
</el-select>
|
||||
</template>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@@ -283,7 +278,43 @@ import { api } from '@/utils/api'
|
||||
import _ from 'lodash'
|
||||
import { get, post, put } from '@/utils/http'
|
||||
import { dateFormat, getMillisecond } from '@/utils/date-util'
|
||||
import { ref } from 'vue'
|
||||
import { ref, getCurrentInstance } from 'vue'
|
||||
import i18n from '@/i18n'
|
||||
export default {
|
||||
name: 'ReportBox',
|
||||
mixins: [rightBoxMixin],
|
||||
props: {
|
||||
categoryList: Array,
|
||||
currentCategoryId: Number
|
||||
},
|
||||
setup () {
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
const startTime = ref('')
|
||||
const endTime = ref('')
|
||||
function endTimeChange (val) {
|
||||
endTime.value = val
|
||||
}
|
||||
function startTimeChang (val) {
|
||||
startTime.value = val
|
||||
}
|
||||
const endDisabledDate = (time) => {
|
||||
if (time.getTime() > new Date()) {
|
||||
return true
|
||||
}
|
||||
if (startTime.value !== '' && startTime.value > time) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
const startDisabledDate = (time) => {
|
||||
if (time.getTime() > new Date()) {
|
||||
return true
|
||||
}
|
||||
if (endTime.value !== '' && endTime.value < time) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
const paramValidator = (rule, value, callback) => {
|
||||
let validate = true
|
||||
if (value && value.length > 0) {
|
||||
@@ -297,71 +328,53 @@ const paramValidator = (rule, value, callback) => {
|
||||
const nameValidator = (rule, value, callback) => {
|
||||
let validate = true
|
||||
const reg = /^[\u4e00-\u9fa5A-Za-z0-9\-\_]*$/
|
||||
if (reg.test(value)) {
|
||||
validate = true
|
||||
} else {
|
||||
validate = reg.test(value)
|
||||
return validate
|
||||
}
|
||||
const startTimeValidator = (rule, value, callback) => {
|
||||
const form = proxy.$refs.reportForm
|
||||
if (form.model.config.endTime) {
|
||||
form.validateField('config.endTime', () => null)
|
||||
}
|
||||
callback()
|
||||
}
|
||||
const endTimeValidator = (rule, value, callback) => {
|
||||
let validate = true
|
||||
if (startTime.value !== '' && value <= startTime.value) {
|
||||
validate = false
|
||||
}
|
||||
return validate
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'ReportBox',
|
||||
mixins: [rightBoxMixin],
|
||||
props: {
|
||||
categoryList: Array,
|
||||
currentCategoryId: Number
|
||||
},
|
||||
setup () {
|
||||
const startTime = ref('')
|
||||
const endTime = ref('')
|
||||
const focus = ref('')
|
||||
const focusDate = ref('')
|
||||
function endTimeChange (val) {
|
||||
endTime.value = val
|
||||
}
|
||||
function startTimeChang (val) {
|
||||
startTime.value = val
|
||||
}
|
||||
function startFocus (val) {
|
||||
focus.value = val.target.value
|
||||
}
|
||||
function endFocus (val) {
|
||||
focusDate.value = val.target.value
|
||||
}
|
||||
const endDisabledDate = (time) => {
|
||||
if (time.getTime() > new Date()) {
|
||||
return true
|
||||
}
|
||||
if (startTime.value != '' && startTime.value > time) {
|
||||
return true
|
||||
}
|
||||
if (focusDate.value != '' && endTime.value > time) {
|
||||
return false
|
||||
} else if (endTime.value != '' && endTime.value < time) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
const startDisabledDate = (time) => {
|
||||
if (time.getTime() > new Date()) {
|
||||
return true
|
||||
}
|
||||
if (focus.value != '' && startTime.value > time) {
|
||||
return false
|
||||
} else if (startTime.value != '' && startTime.value > time) {
|
||||
return true
|
||||
}
|
||||
if (endTime.value != '' && endTime.value < time) {
|
||||
return true
|
||||
}
|
||||
const rules = { // 表单校验规则
|
||||
name: [
|
||||
{ required: true, message: i18n.global.t('validate.required'), trigger: 'blur' },
|
||||
{ validator: nameValidator, message: i18n.global.t('validate.onlyAllowNumberLetterChinese-_'), trigger: 'blur' }
|
||||
],
|
||||
categoryId: [
|
||||
{ required: true, message: i18n.global.t('validate.required'), trigger: 'change' }
|
||||
],
|
||||
schedulerStart: [
|
||||
{ required: true, message: i18n.global.t('validate.required'), trigger: 'change' }
|
||||
],
|
||||
'config.startTime': [
|
||||
{ required: true, message: i18n.global.t('validate.required'), trigger: 'change' },
|
||||
{ validator: startTimeValidator, trigger: 'change' }
|
||||
],
|
||||
'config.endTime': [
|
||||
{ required: true, message: i18n.global.t('validate.required'), trigger: 'change' },
|
||||
{ validator: endTimeValidator, message: i18n.global.t('validate.endTimeGreaterThanStart'), trigger: 'change' }
|
||||
],
|
||||
categoryParams: [
|
||||
{ required: true, message: i18n.global.t('validate.required'), trigger: 'blur' },
|
||||
{ validator: paramValidator, message: i18n.global.t('validate.required'), trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
return {
|
||||
endDisabledDate,
|
||||
startDisabledDate,
|
||||
startTimeChang,
|
||||
endTimeChange,
|
||||
startFocus,
|
||||
endFocus
|
||||
rules
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@@ -391,48 +404,20 @@ export default {
|
||||
monthWeekdayCheckedAll: false,
|
||||
monthWeekdayIsIndeterminate: false,
|
||||
|
||||
rules: { // 表单校验规则
|
||||
name: [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
|
||||
{ validator: nameValidator, message: this.$t('validate.onlyAllowNumberLetterChinese-_'), trigger: 'blur' }
|
||||
],
|
||||
categoryId: [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||
],
|
||||
schedulerStart: [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||
],
|
||||
'config.startTime': [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||
],
|
||||
'config.endTime': [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'change' }
|
||||
],
|
||||
categoryParams: [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
|
||||
{ validator: paramValidator, message: this.$t('validate.required'), trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
paramsOptions: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
scheduleType (n, o) {
|
||||
this.editObject.config.schedulerConfig.type = n
|
||||
if (!this.editObject.id) {
|
||||
this.cleanScheduleConfig()
|
||||
}
|
||||
},
|
||||
scheduleChecked (n) {
|
||||
this.editObject.config.isScheduler = n ? 1 : 0
|
||||
if (!this.editObject.id) {
|
||||
this.cleanScheduleConfig()
|
||||
}
|
||||
},
|
||||
monthScheduleType (n) {
|
||||
if (!this.editObject.id) {
|
||||
this.cleanScheduleConfig()
|
||||
}
|
||||
},
|
||||
monthIsCycle (n) {
|
||||
if (!this.editObject.id) {
|
||||
@@ -566,15 +551,13 @@ export default {
|
||||
this.editObject.config.timeConfig.offset--
|
||||
}
|
||||
}
|
||||
},
|
||||
typeChange (id) {
|
||||
|
||||
},
|
||||
cleanScheduleConfig () {
|
||||
this.editObject.config.schedulerConfig.monthDates = []
|
||||
this.editObject.config.schedulerConfig.weekDates = []
|
||||
this.editObject.config.schedulerConfig.months = []
|
||||
this.editObject.config.schedulerConfig.monthWeekDates = []
|
||||
this.editObject.config.schedulerConfig.interval = 1
|
||||
this.monthIsCycle = true
|
||||
this.dateCheckedAll = false
|
||||
this.dateIsIndeterminate = false
|
||||
@@ -588,11 +571,14 @@ export default {
|
||||
this.scheduleChecked = false
|
||||
}
|
||||
},
|
||||
scheduleTypeChange (val) {
|
||||
this.scheduleType = val
|
||||
},
|
||||
save () {
|
||||
if (this.blockOperation.save) { return }
|
||||
this.blockOperation.save = true
|
||||
|
||||
this.$refs.userForm.validate((valid) => {
|
||||
this.$refs.reportForm.validate((valid) => {
|
||||
if (valid) {
|
||||
let startTime = ''
|
||||
let endTime = ''
|
||||
|
||||
@@ -2,31 +2,29 @@
|
||||
<div :class="from" class="list-page">
|
||||
<!-- 主页面 -->
|
||||
<div class="main-list">
|
||||
<!-- 顶部工具栏 -->
|
||||
<div class="main-container">
|
||||
<!-- 顶部工具栏 -->
|
||||
<div class="top-tools">
|
||||
<div class="top-tool-left" style="min-width: 300px">
|
||||
<slot name="top-tool-left"></slot>
|
||||
</div>
|
||||
<div class="top-tool-right">
|
||||
<!-- <el-input v-model="keyWord" value="keyWord"></el-input>
|
||||
<el-button @click="onsearch" icon="el-icon-search" type="info" size="mini" style="margin-right: 10px"></el-button>-->
|
||||
<div v-if="showLayout.indexOf('search') > -1" class="top-tool-search margin-r-20">
|
||||
<div style="display: flex">
|
||||
<el-input
|
||||
v-model="keyWord" size="small" @keyup.enter="onsearch"></el-input>
|
||||
<!-- <el-button icon="el-icon-search" @click="onsearch" size="small"></el-button>-->
|
||||
<button class="top-tool-btn" style="border-radius: 0px"
|
||||
type="button" @click="onsearch">
|
||||
<el-input v-model="keyWord" size="small" @keyup.enter="onSearch"></el-input>
|
||||
<!-- <el-button icon="el-icon-search" @click="onSearch" size="small"></el-button>-->
|
||||
<button class="top-tool-btn top-tool-btn--search" style="border-radius: 0 2px 2px 0 !important;" @click="onSearch">
|
||||
<i class="el-icon-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-tool-right">
|
||||
<!-- <el-input v-model="keyWord" value="keyWord"></el-input>
|
||||
<el-button @click="onSearch" icon="el-icon-search" type="info" size="mini" style="margin-right: 10px"></el-button>-->
|
||||
|
||||
<slot name="top-tool-right"></slot>
|
||||
<button v-if="showLayout.indexOf('elementSet') > -1" class="top-tool-btn"
|
||||
type="button" @click="tools.showCustomTableTitle = true">
|
||||
<i class="cn-icon-gear cn-icon"></i>
|
||||
</button>
|
||||
<div v-if="showLayout.indexOf('elementSet') > -1" class="btn-customize" @click="tools.showCustomTableTitle = true">
|
||||
<i class="cn-icon-gear cn-icon icon-gear"></i> <span> {{$t('network.customize')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cn-table">
|
||||
@@ -94,7 +92,7 @@ export default {
|
||||
updateCustomTableTitle (custom) {
|
||||
this.$emit('update:customTableTitle', custom)
|
||||
},
|
||||
onsearch () {
|
||||
onSearch () {
|
||||
const params = {
|
||||
q: this.keyWord
|
||||
}
|
||||
|
||||
@@ -19,18 +19,18 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="custom-bottom-btns">
|
||||
<el-button size="mini" v-if="isCancel" :id="tableId+'-element-set-none'" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new is-cancel" type="button" @click="batchHandler(false)">
|
||||
<el-button size="mini" v-if="isCancel" :id="tableId+'-element-set-none'" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new is-cancel" @click="batchHandler(false)">
|
||||
<span class="top-tool-btn-txt">{{$t('overall.clear')}}</span>
|
||||
</el-button>
|
||||
<el-button size="mini" v-if="!isCancel" :id="tableId+'-element-set-all'" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new" type="button" @click="batchHandler(true)">
|
||||
<el-button size="mini" v-if="!isCancel" :id="tableId+'-element-set-all'" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new" @click="batchHandler(true)">
|
||||
<span class="top-tool-btn-txt">{{$t('overall.all')}}</span>
|
||||
</el-button>
|
||||
<div>
|
||||
<el-button size="mini" :id="tableId+'-element-set-esc'" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new" type="button" @click="esc">
|
||||
<div class="custom-bottom-btns-right">
|
||||
<el-button size="mini" :id="tableId+'-element-set-esc'" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new" @click="esc">
|
||||
<span class="top-tool-btn-txt">{{$t('overall.cancel')}}</span>
|
||||
</el-button>
|
||||
<el-button size="mini" :id="tableId+'-element-set-save'" class="cn-btn cn-btn-size-small-new cn-btn-style-normal-new" type="button" @click="save" style="background-color: #0091ff;color:#DCDFE6">
|
||||
<span class="top-tool-btn-txt">{{$t('overall.save')}}</span>
|
||||
<el-button size="mini" :id="tableId+'-element-set-save'" class="cn-btn cn-btn-size-small-new cn-btn-style-normal-new" @click="save" style="background-color: #0091ff;color:#DCDFE6">
|
||||
<span class="top-tool-btn-txt top-tool-btn-save">{{$t('overall.save')}}</span>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -86,6 +86,7 @@ export default {
|
||||
// 单选
|
||||
handler (val, index) {
|
||||
if (!this.allowedAll && !val.allowed && (index === 0 || index === 1 || val.NotSet)) {
|
||||
//
|
||||
} else {
|
||||
this.custom[index].show = !this.custom[index].show
|
||||
}
|
||||
|
||||
@@ -110,7 +110,6 @@
|
||||
<script>
|
||||
import table from '@/mixins/table'
|
||||
import { panelTypeAndRouteMapping } from '@/utils/constants'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
export default {
|
||||
name: 'chartTable',
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
show: true
|
||||
},
|
||||
{
|
||||
label: this.$t('config.operationlog.type'),
|
||||
label: this.$t('overall.type'),
|
||||
prop: 'type',
|
||||
show: true
|
||||
},
|
||||
@@ -47,29 +47,6 @@
|
||||
<span v-else>{{scope.row[item.prop]}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:resizable="false"
|
||||
:width="operationWidth"
|
||||
fixed="right">
|
||||
<template #header>
|
||||
<div class="table-operation-title">{{$t('overall.option')}}</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="table-operation-items">
|
||||
<button class="table-operation-item" @click="tableOperation(['edit', scope.row])"><i class="cn-icon cn-icon-edit"></i></button>
|
||||
<el-dropdown size="medium" trigger="hover" @command="tableOperation">
|
||||
<div class="table-operation-item table-operation-item--more">
|
||||
<i class="cn-icon cn-icon-more-arrow-down"></i>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu >
|
||||
<el-dropdown-item :command="['delete', scope.row]" :disabled="scope.row.id === 1"><i class="cn-icon cn-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
@@ -62,29 +62,6 @@
|
||||
<span v-else>{{scope.row[item.prop]}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:resizable="false"
|
||||
:width="operationWidth"
|
||||
fixed="right">
|
||||
<template #header>
|
||||
<div class="table-operation-title">{{$t('overall.option')}}</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="table-operation-items">
|
||||
<button class="table-operation-item" @click="tableOperation(['edit', scope.row])"><i class="cn-icon cn-icon-edit"></i></button>
|
||||
<el-dropdown size="medium" trigger="hover" @command="tableOperation">
|
||||
<div class="table-operation-item table-operation-item--more">
|
||||
<i class="cn-icon cn-icon-more-arrow-down"></i>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu >
|
||||
<el-dropdown-item :command="['delete', scope.row]" :disabled="scope.row.id === 1"><i class="cn-icon cn-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
@@ -188,24 +188,8 @@
|
||||
<span v-else>{{ scope.row[item.prop] || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:resizable="false"
|
||||
:width="operationWidth"
|
||||
fixed="right">
|
||||
<template #header>
|
||||
<div class="table-operation-title">{{ $t('overall.option') }}</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div class="table-operation-items">
|
||||
<button class="table-operation-item" @click="tableOperation(['edit', scope.row])"><i
|
||||
class="cn-icon cn-icon-bianji"></i></button>
|
||||
<button class="table-operation-item" @click="tableOperation(['delete', scope.row])"><i
|
||||
class="cn-icon cn-icon-shanchu"></i></button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="table-operation-all">
|
||||
<!-- <div class="table-operation-all">
|
||||
<el-checkbox v-model="checkboxAll" :indeterminate="isIndeterminate" @change="selectAll(tableData)"></el-checkbox>
|
||||
<div class="table-operation-all-span">
|
||||
<span>{{ $t('overall.all') }}</span>
|
||||
@@ -216,7 +200,7 @@
|
||||
<span>{{ $t('report.batchDeletion') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -308,6 +292,7 @@ export default {
|
||||
loadingTableId: '',
|
||||
loadingPreviewId: '',
|
||||
downDataList: [],
|
||||
disableEdit:false,//编辑按钮是否不可用,当选择多条记录的时候你,编辑按钮不可用
|
||||
// pageObj: {
|
||||
// pageNo: 1,
|
||||
// pageSize: 20,
|
||||
@@ -556,6 +541,12 @@ export default {
|
||||
})
|
||||
// this.selectIds = selectIds
|
||||
}
|
||||
this.batchDeleteObjs = objs
|
||||
if(objs.length > 1) {
|
||||
this.disableEdit = true
|
||||
}else {
|
||||
this.disableEdit = false
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 全选按钮
|
||||
@@ -574,6 +565,13 @@ export default {
|
||||
this.$refs.dataTable.clearSelection()
|
||||
}
|
||||
|
||||
this.batchDeleteObjs = objs
|
||||
if(objs.length > 1) {
|
||||
this.disableEdit = true
|
||||
}else {
|
||||
this.disableEdit = false
|
||||
}
|
||||
|
||||
// this.selectIds = selectIds
|
||||
},
|
||||
/**
|
||||
135
src/components/table/setting/KnowledgeBaseTable.vue
Normal file
135
src/components/table/setting/KnowledgeBaseTable.vue
Normal file
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<el-table
|
||||
id="knowledgeBaseTable"
|
||||
ref="dataTable"
|
||||
:data="tableData"
|
||||
:height="height"
|
||||
border
|
||||
@header-dragend="dragend"
|
||||
@sort-change="tableDataSort"
|
||||
@selection-change="selectionChange"
|
||||
>
|
||||
<el-table-column
|
||||
:resizable="false"
|
||||
align="center"
|
||||
type="selection"
|
||||
width="55">
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="(item, index) in customTableTitles"
|
||||
:key="`col-${index}`"
|
||||
:fixed="item.fixed"
|
||||
:label="item.label"
|
||||
:min-width="`${item.minWidth}`"
|
||||
:prop="item.prop"
|
||||
:resizable="true"
|
||||
:sort-orders="['ascending', 'descending']"
|
||||
:sortable="item.sortable"
|
||||
:width="`${item.width}`"
|
||||
class="data-column"
|
||||
>
|
||||
<template #header>
|
||||
<span class="data-column__span">{{item.label}}</span>
|
||||
<div class="col-resize-area"></div>
|
||||
</template>
|
||||
<template #default="scope" :column="item">
|
||||
<template v-if="item.prop === 'name'">
|
||||
<template v-if="scope.row.i18n">
|
||||
<span>{{$t(scope.row.i18n)}}</span>
|
||||
</template>
|
||||
<template v-else-if="scope.row.name">
|
||||
<span>{{scope.row.name}}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>-</span>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'tagType'">
|
||||
<span class="type-tag">{{tagTypeText(scope.row[item.prop])}}</span>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'utime' || item.prop === 'ctime'">
|
||||
<template v-if="scope.row[item.prop]">
|
||||
{{dateFormatByAppearance(scope.row[item.prop])}}
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>-</span>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'cuser' || item.prop === 'uuser'">
|
||||
<template v-if="scope.row[item.prop]">
|
||||
{{scope.row[item.prop].username || '-'}}
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>-</span>
|
||||
</template>
|
||||
</template>
|
||||
<span v-else>{{scope.row[item.prop] || '-'}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import table from '@/mixins/table'
|
||||
import { knowledgeBaseType } from '@/utils/constants'
|
||||
export default {
|
||||
name: 'knowledgeBaseTable',
|
||||
mixins: [table],
|
||||
data () {
|
||||
return {
|
||||
tableTitle: [ // 原table列
|
||||
{
|
||||
label: 'ID',
|
||||
prop: 'id',
|
||||
show: true,
|
||||
width: 100,
|
||||
sortable: 'custom'
|
||||
}, {
|
||||
label: this.$t('config.roles.name'),
|
||||
prop: 'tagName',
|
||||
show: true,
|
||||
sortable: 'custom'
|
||||
}, {
|
||||
label: this.$t('overall.type'),
|
||||
prop: 'tagType',
|
||||
show: true
|
||||
}, {
|
||||
label: this.$t('overall.remark'),
|
||||
prop: 'remark',
|
||||
show: true
|
||||
},
|
||||
{
|
||||
label: this.$t('overall.createdBy'),
|
||||
prop: 'cuser',
|
||||
show: true
|
||||
},
|
||||
{
|
||||
label: this.$t('config.user.createTime'),
|
||||
prop: 'ctime',
|
||||
show: false,
|
||||
sortable: 'custom'
|
||||
},
|
||||
{
|
||||
label: this.$t('overall.updatedBy'),
|
||||
prop: 'uuser',
|
||||
show: false
|
||||
},
|
||||
{
|
||||
label: this.$t('overall.updateTime'),
|
||||
prop: 'utime',
|
||||
show: false,
|
||||
sortable: 'custom'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tagTypeText () {
|
||||
return function (type) {
|
||||
const t = knowledgeBaseType.find(t => t.value === type)
|
||||
return t ? t.name : ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,8 +1,19 @@
|
||||
import { dbName, dbGeoDataTableName, dbDrilldownTableConfig } from '@/utils/constants'
|
||||
import Dexie from 'dexie'
|
||||
/* https://dexie.org/ */
|
||||
|
||||
export const db = new Dexie(dbName)
|
||||
db.version(2).stores({
|
||||
const db = new Dexie(dbName)
|
||||
db.version(3).stores({
|
||||
[dbGeoDataTableName]: '++name, geo',
|
||||
[dbDrilldownTableConfig]: '++id, config'
|
||||
[dbDrilldownTableConfig]: '++id, config',
|
||||
test: '++id, name'
|
||||
})
|
||||
function selectTable (tableName) {
|
||||
return db[tableName]
|
||||
}
|
||||
|
||||
const indexedDBUtils = {
|
||||
db,
|
||||
selectTable
|
||||
}
|
||||
export default indexedDBUtils
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { hasButton } from '@/permission'
|
||||
import { dateFormatByAppearance } from '@/utils/date-util'
|
||||
import { storageKey } from '@/utils/constants'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
@@ -21,7 +20,9 @@ export default {
|
||||
query: false
|
||||
},
|
||||
timeout: null,
|
||||
debounceFunc: null
|
||||
debounceFunc: null,
|
||||
// 是否正在单元测试
|
||||
isUnitTesting: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
pageObj: { // 分页对象
|
||||
pageNo: 1,
|
||||
pageSize: defaultPageSize,
|
||||
total: ''
|
||||
total: 0
|
||||
},
|
||||
/* 工具参数 */
|
||||
tools: {
|
||||
@@ -37,6 +37,7 @@ export default {
|
||||
tableData: [],
|
||||
scrollbarWrap: null,
|
||||
delFlag: false,
|
||||
disableEdit:false,//编辑按钮是否不可用,当选择多条记录的时候你,编辑按钮不可用
|
||||
operationWidth: '165' // 操作列宽
|
||||
}
|
||||
},
|
||||
@@ -74,6 +75,11 @@ export default {
|
||||
},
|
||||
selectionChange (objs) {
|
||||
this.batchDeleteObjs = objs
|
||||
if(this.batchDeleteObjs.length > 1) {
|
||||
this.disableEdit = true
|
||||
}else {
|
||||
this.disableEdit = false
|
||||
}
|
||||
},
|
||||
getTableData (params) {
|
||||
if (params) {
|
||||
@@ -95,6 +101,13 @@ export default {
|
||||
this.tableData = response.data.list
|
||||
this.pageObj.total = response.data.total
|
||||
// TODO 回到顶部
|
||||
} else {
|
||||
console.error(response)
|
||||
if (response.message) {
|
||||
this.$message.error(response.message)
|
||||
} else {
|
||||
this.$message.error('Something went wrong...')
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -115,6 +128,39 @@ export default {
|
||||
})
|
||||
})
|
||||
},
|
||||
delBatch () {
|
||||
let ids = []
|
||||
if(this.batchDeleteObjs && this.batchDeleteObjs.length > 0){
|
||||
this.batchDeleteObjs.forEach(item =>{
|
||||
ids.push(item.id)
|
||||
})
|
||||
}
|
||||
if(ids.length === 0){
|
||||
this.$alert(this.$t('tip.pleaseSelect'),{
|
||||
confirmButtonText: this.$t('tip.yes'),
|
||||
type:'warning'
|
||||
})
|
||||
}else {
|
||||
this.$confirm(this.$t('tip.confirmDelete'), {
|
||||
confirmButtonText: this.$t('tip.yes'),
|
||||
cancelButtonText: this.$t('tip.no'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.tools.loading = true
|
||||
axios.delete(this.url + '?ids=' + ids).then(response => {
|
||||
if (response.data.code === 200) {
|
||||
this.delFlag = true
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') })
|
||||
this.getTableData()
|
||||
} else {
|
||||
this.$message.error(response.data.message)
|
||||
}
|
||||
}).finally(() => {
|
||||
this.tools.loading = false
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
newObject () {
|
||||
return JSON.parse(JSON.stringify(this.blankObject))
|
||||
},
|
||||
@@ -153,6 +199,21 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
editSelectRecord(){
|
||||
if(this.batchDeleteObjs.length === 0){
|
||||
this.$alert(this.$t('tip.pleaseSelectForEdit'),{
|
||||
confirmButtonText: this.$t('tip.yes'),
|
||||
type:'warning'
|
||||
})
|
||||
}else {
|
||||
get(`${this.url}/${this.batchDeleteObjs[0].id}`).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.object = response.data
|
||||
this.rightBox.show = true
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
copy (u) {
|
||||
this.object = { ...u, name: 'Copy from ' + u.name, id: '' }
|
||||
this.rightBox.show = true
|
||||
@@ -161,9 +222,15 @@ export default {
|
||||
if (this.$refs.dataTable.loadingTableId === u.id) { // 列表单个下载
|
||||
return
|
||||
}
|
||||
if (localStorage.getItem(storageKey.s3Enable) == 1) {
|
||||
if (u.state !== 1 || u.upload !== 1) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (u.state !== 1) {
|
||||
return
|
||||
}
|
||||
}
|
||||
let fileName = ''
|
||||
let url = ''
|
||||
let params = {}
|
||||
@@ -223,9 +290,15 @@ export default {
|
||||
if (this.$refs.dataTable.loadingPreviewId === u.id) { // 列表单个下载
|
||||
return
|
||||
}
|
||||
if (localStorage.getItem(storageKey.s3Enable) == 1) {
|
||||
if (u.state !== 1 || u.upload !== 1) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (u.state !== 1) {
|
||||
return
|
||||
}
|
||||
}
|
||||
const params = {
|
||||
id: u.id
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export default {
|
||||
if (n) {
|
||||
setTimeout(() => {
|
||||
this.$refs.dataTable.doLayout()
|
||||
}, 100)
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -55,21 +55,7 @@ export default {
|
||||
})
|
||||
},
|
||||
tableDataSort (item) {
|
||||
let orderBy = ''
|
||||
if (item.order === 'ascending') {
|
||||
if (item.prop === 'lastTime') {
|
||||
orderBy = chartTableOrderOptionsMapping[item.prop]
|
||||
} else {
|
||||
orderBy = item.prop
|
||||
}
|
||||
}
|
||||
if (item.order === 'descending') {
|
||||
if (item.prop === 'lastTime') {
|
||||
orderBy = '-' + chartTableOrderOptionsMapping[item.prop]
|
||||
} else {
|
||||
orderBy = '-' + item.prop
|
||||
}
|
||||
}
|
||||
const orderBy = (item.order === 'descending' ? '-' : '') + (item.prop ? (chartTableOrderOptionsMapping[item.prop] || item.prop) : '')
|
||||
this.$emit('orderBy', orderBy)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getPermission } from '@/utils/api'
|
||||
import { loadGeoData } from '@/utils/tools'
|
||||
import axios from 'axios'
|
||||
@@ -18,6 +17,7 @@ router.beforeEach(async (to, from, next) => {
|
||||
loadGeoData()
|
||||
// 加载baseUrl
|
||||
if (!axios.defaults.baseURL) {
|
||||
// eslint-disable-next-line no-undef
|
||||
axios.defaults.baseURL = BASE_CONFIG.baseUrl
|
||||
}
|
||||
if (localStorage.getItem(storageKey.token)) {
|
||||
@@ -36,11 +36,12 @@ router.beforeEach(async (to, from, next) => {
|
||||
store.commit('setRoleList', roleList)
|
||||
}
|
||||
if (to.path) {
|
||||
if (hasMenu(store.getters.menuList, to.path)) {
|
||||
next()
|
||||
/* if (hasMenu(store.getters.menuList, to.path)) {
|
||||
next()
|
||||
} else {
|
||||
ElMessage.error('No access') // TODO 国际化
|
||||
}
|
||||
} */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -80,7 +81,7 @@ export function hasMenu (menuList, route) {
|
||||
export function hasParam (url, param) {
|
||||
let hasParam = false
|
||||
let tempArr = url.split('?')
|
||||
const query = {}
|
||||
// const query = {}
|
||||
if (tempArr[1]) {
|
||||
tempArr = tempArr[1].split('&')
|
||||
tempArr.forEach(t => {
|
||||
|
||||
@@ -21,12 +21,16 @@ const routes = [
|
||||
},
|
||||
{
|
||||
path: '/report/builtIn',
|
||||
component: () => import('@/views/report/reportTest')
|
||||
component: () => import('@/views/report/Report')
|
||||
},
|
||||
{
|
||||
path: '/entityExplorer',
|
||||
component: () => import('@/views/entityExplorer/EntityExplorer')
|
||||
},
|
||||
{
|
||||
path: '/detection',
|
||||
redirect: '/detection/securityEvent'
|
||||
},
|
||||
{
|
||||
path: '/detection/:typeName',
|
||||
component: () => import('@/views/detections/Index')
|
||||
@@ -35,6 +39,14 @@ const routes = [
|
||||
path: '/businessLog/viewer',
|
||||
component: () => import('@/views/businessLog/Viewer')
|
||||
},
|
||||
{
|
||||
path: '/knowledgeBase',
|
||||
component: () => import('@/views/setting/KnowledgeBase')
|
||||
},
|
||||
{
|
||||
path: '/knowledgeBase/form',
|
||||
component: () => import('@/views/setting/KnowledgeBaseForm')
|
||||
},
|
||||
{
|
||||
name: 'Administration',
|
||||
path: '/administration',
|
||||
@@ -51,31 +63,26 @@ const routes = [
|
||||
path: '/administration/role',
|
||||
component: () => import('@/views/administration/Roles')
|
||||
},
|
||||
{
|
||||
name: 'I18n',
|
||||
path: '/administration/i18n',
|
||||
component: () => import('@/views/administration/I18n')
|
||||
},
|
||||
{
|
||||
name: 'OperationLog',
|
||||
path: '/administration/operationLog',
|
||||
component: () => import('@/views/administration/OperationLog')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'GalaxyProxy',
|
||||
path: '/administration/galaxyProxy',
|
||||
component: () => import('@/views/administration/GalaxyProxy')
|
||||
name: 'I18n',
|
||||
path: '/i18n',
|
||||
component: () => import('@/views/administration/I18n')
|
||||
},
|
||||
{
|
||||
name: 'Chart',
|
||||
path: '/administration/chart',
|
||||
path: '/chart',
|
||||
component: () => import('@/views/administration/Chart')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
|
||||
@@ -12,7 +12,8 @@ const store = createStore({
|
||||
return {
|
||||
i18n: false,
|
||||
showEntityTypeSelector: false, // 在entity explore页面时,控制header显示实体类型选择框
|
||||
from: '' // entity type
|
||||
from: '', // entity type
|
||||
test: 'jest' // 用于单测的demo
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
@@ -24,6 +25,9 @@ const store = createStore({
|
||||
},
|
||||
entityName (state) {
|
||||
return state.entityName
|
||||
},
|
||||
getTest (state) {
|
||||
return state.test
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
@@ -37,6 +41,9 @@ const store = createStore({
|
||||
},
|
||||
showEntityTypeSelector (state, show) {
|
||||
state.showEntityTypeSelector = show
|
||||
},
|
||||
setTest (state, test) {
|
||||
state.test = test
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -59,7 +59,8 @@ const panel = {
|
||||
rangeEchartsData: {}, // 框选echarts图表
|
||||
routerHistoryList: [], // 路由跳转记录列表
|
||||
dnsQtypeMapData: [],
|
||||
dnsRcodeMapData: []
|
||||
dnsRcodeMapData: [],
|
||||
chartTabList: null // chartTabs组件的tab状态点击列表,初始化为null方便原有逻辑计算
|
||||
},
|
||||
mutations: {
|
||||
setShowRightBox (state, flag) {
|
||||
@@ -151,6 +152,9 @@ const panel = {
|
||||
},
|
||||
setRouterHistoryList (state, list) {
|
||||
state.routerHistoryList = list
|
||||
},
|
||||
setChartTabList (state, list) {
|
||||
state.chartTabList = list
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
@@ -225,6 +229,9 @@ const panel = {
|
||||
},
|
||||
getRouterHistoryList (state) {
|
||||
return state.routerHistoryList
|
||||
},
|
||||
getChartTabList (state) {
|
||||
return state.chartTabList
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@@ -253,6 +260,9 @@ const panel = {
|
||||
},
|
||||
clearPanel (store) {
|
||||
store.commit('cleanPanel')
|
||||
},
|
||||
dispatchChartTabList (store, list) {
|
||||
store.commit('setChartTabList', list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ElMessage } from 'element-plus' // dependent on utc plugin
|
||||
import { storageKey, dbDrilldownTableConfig } from '@/utils/constants'
|
||||
import { getConfigVersion } from '@/utils/tools'
|
||||
import { api } from '@/utils/api'
|
||||
import { db } from '@/indexedDB'
|
||||
import indexedDBUtils from '@/indexedDB'
|
||||
|
||||
const user = {
|
||||
state () {
|
||||
@@ -92,7 +92,7 @@ const user = {
|
||||
if (res.code === 200 && res.page.list && res.page.list.length > 0) {
|
||||
// 从接口返回整体配置,再读取用户缓存,将对应条目覆盖,作为使用的配置
|
||||
const defaultConfigs = JSON.parse(res.page.list[0].cvalue)
|
||||
await db[dbDrilldownTableConfig].put({
|
||||
await indexedDBUtils.selectTable(dbDrilldownTableConfig).put({
|
||||
id: 'default',
|
||||
version: defaultConfigs.version,
|
||||
config: defaultConfigs.config
|
||||
@@ -100,7 +100,7 @@ const user = {
|
||||
const userId = localStorage.getItem(storageKey.userId)
|
||||
const oldVersion = await getConfigVersion(userId)
|
||||
if (oldVersion !== defaultConfigs.version) {
|
||||
db[dbDrilldownTableConfig].delete(userId)
|
||||
indexedDBUtils.selectTable(dbDrilldownTableConfig).delete(userId)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -33,6 +33,8 @@ export const api = {
|
||||
chartList: '/visual/chart/list',
|
||||
// galaxyProxy
|
||||
galaxyProxy: '/galaxy/setting',
|
||||
// 知识库
|
||||
knowledgeBase: '/knowledge',
|
||||
|
||||
// 报告相关
|
||||
reportJob: '/report/job',
|
||||
@@ -318,11 +320,12 @@ export async function getI18n () {
|
||||
|
||||
/* 获得原始的3611-2 json字符串数据 */
|
||||
export async function getIso36112JsonData (suffix) {
|
||||
const url = `${window.location.protocol}//${window.location.host}/geojson/${suffix}.json`
|
||||
const request = new Promise(resolve => {
|
||||
axios({
|
||||
url: `${window.location.protocol}//${window.location.host}:${window.location.port}/geojson/${suffix}.json`
|
||||
}).then(response => {
|
||||
axios({ url }).then(response => {
|
||||
resolve(response.data || response || null)
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
})
|
||||
return await request
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export const defaultPageSize = 20
|
||||
|
||||
// indexedDB库名
|
||||
export const dbName = 'cn-db'
|
||||
// indexedDB表名
|
||||
export const dbGeoDataTableName = 'geodata'
|
||||
export const dbDrilldownTableConfig = 'cn-drilldown-table-config'
|
||||
export const storageKey = {
|
||||
@@ -120,7 +122,8 @@ export const chartTableColumnMapping = {
|
||||
ip: 'IP'
|
||||
}
|
||||
export const chartTableOrderOptionsMapping = {
|
||||
lastTime: 'last_time'
|
||||
lastTime: 'last_time',
|
||||
tagName: 'tag_name'
|
||||
}
|
||||
export const chartPieTableTopOptions = [
|
||||
{ name: 'Sessions', value: 'sessions' },
|
||||
@@ -275,6 +278,21 @@ export const cycle = {
|
||||
pre: 1
|
||||
}
|
||||
|
||||
export const knowledgeBaseType = [
|
||||
{
|
||||
name: 'IP',
|
||||
value: 'ip'
|
||||
},
|
||||
{
|
||||
name: 'Domain',
|
||||
value: 'domain'
|
||||
},
|
||||
{
|
||||
name: 'APP',
|
||||
value: 'app'
|
||||
}
|
||||
]
|
||||
|
||||
export const curTabState = {
|
||||
curTab: 'curTab',
|
||||
tableMetric: 'tableMetric',
|
||||
|
||||
@@ -5,8 +5,7 @@ import { storageKey, iso36112, topDomain, echartsFontSize, dbGeoDataTableName, n
|
||||
import { getIso36112JsonData, getDictList } from '@/utils/api'
|
||||
import { format } from 'echarts'
|
||||
import router from '@/router'
|
||||
import { db } from '@/indexedDB'
|
||||
import { useRoute } from 'vue-router'
|
||||
import indexedDBUtils from '@/indexedDB'
|
||||
|
||||
export const tableSort = {
|
||||
// 是否需要排序
|
||||
@@ -488,11 +487,11 @@ export function loadGeoData () {
|
||||
keys.push(storageKey.iso36112Capital)
|
||||
keys.push(storageKey.iso36112WorldLow)
|
||||
keys.forEach(async k => {
|
||||
const queryData = await db[dbGeoDataTableName].get({ name: k })
|
||||
const queryData = await indexedDBUtils.selectTable(dbGeoDataTableName).get({ name: k })
|
||||
if (!queryData) {
|
||||
const data = await getIso36112JsonData(iso36112[k])
|
||||
if (data) {
|
||||
db[dbGeoDataTableName].add({
|
||||
indexedDBUtils.selectTable(dbGeoDataTableName).add({
|
||||
name: k,
|
||||
geo: data
|
||||
})
|
||||
@@ -505,14 +504,14 @@ export function loadGeoData () {
|
||||
* 使用indexedDB缓存地图数据
|
||||
* */
|
||||
export async function getGeoData (key) {
|
||||
const data = await db[dbGeoDataTableName].get({ name: key })
|
||||
const data = await indexedDBUtils.selectTable(dbGeoDataTableName).get({ name: key })
|
||||
if (data) {
|
||||
return data.geo
|
||||
} else {
|
||||
if (iso36112[key]) {
|
||||
const d = await getIso36112JsonData(iso36112[key])
|
||||
if (d) {
|
||||
db[dbGeoDataTableName].add({
|
||||
indexedDBUtils.selectTable(dbGeoDataTableName).add({
|
||||
name: key,
|
||||
geo: d
|
||||
})
|
||||
@@ -533,14 +532,14 @@ export function getUserDrilldownTableGeo (userId) {
|
||||
return data[userId]
|
||||
}
|
||||
|
||||
function JSONParse (data) {
|
||||
const firstParse = JSON.parse(data)
|
||||
if (typeof firstParse === 'string') {
|
||||
return JSON.parse(firstParse)
|
||||
} else {
|
||||
return firstParse
|
||||
}
|
||||
}
|
||||
// function JSONParse (data) {
|
||||
// const firstParse = JSON.parse(data)
|
||||
// if (typeof firstParse === 'string') {
|
||||
// return JSON.parse(firstParse)
|
||||
// } else {
|
||||
// return firstParse
|
||||
// }
|
||||
// }
|
||||
|
||||
export function copyValue (item) {
|
||||
const str = item
|
||||
@@ -879,9 +878,9 @@ export async function getDnsMapData (type) {
|
||||
}
|
||||
export function handleSpecialValue (value) {
|
||||
if (value) {
|
||||
value = value.replaceAll("'", "\\\\'")
|
||||
.replaceAll('"', '\\"')
|
||||
.replaceAll('&', '%26')
|
||||
value = value.replace(/\'/g, "\\\\'")
|
||||
.replace(/\"/g, '\\"')
|
||||
.replace(/\&/g, '%26')
|
||||
}
|
||||
return value
|
||||
}
|
||||
@@ -895,13 +894,13 @@ export function combineTabList (tableType, list, commonTabList) {
|
||||
const commonTab = commonTabList.find(item => item.name === tabName)
|
||||
tab.label = commonTab ? commonTab.i18n : ''
|
||||
tab.prop = commonTab ? commonTab.prop : ''
|
||||
if (!tab.hasOwnProperty('checked')) {
|
||||
if (!Object.prototype.hasOwnProperty.call(tab, 'checked')) {
|
||||
tab.checked = tab ? tab.show : true
|
||||
}
|
||||
if (!tab.hasOwnProperty('disabled')) {
|
||||
if (!Object.prototype.hasOwnProperty.call(tab, 'disabled')) {
|
||||
tab.disabled = tab ? !tab.enable : false
|
||||
}
|
||||
if (!tab.hasOwnProperty('panelId')) {
|
||||
if (!Object.prototype.hasOwnProperty.call(tab, 'panelId')) {
|
||||
tab.panelId = tab ? tab.panelIdOfFourthMenu : null
|
||||
}
|
||||
// 代码里写死的
|
||||
@@ -937,7 +936,7 @@ export async function getDefaultCurTab (tableType, metric, columnName) {
|
||||
export async function readDrilldownTableConfigByUser () {
|
||||
// 获取用户定制的自定义配置
|
||||
const userId = localStorage.getItem(storageKey.userId)
|
||||
const userLocalConfig = await db[dbDrilldownTableConfig].get({ id: userId })
|
||||
const userLocalConfig = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: userId })
|
||||
let defaultDrillDownTableConfigs = []
|
||||
if (userLocalConfig) {
|
||||
defaultDrillDownTableConfigs = userLocalConfig.config
|
||||
@@ -946,15 +945,15 @@ export async function readDrilldownTableConfigByUser () {
|
||||
}
|
||||
|
||||
export async function getConfigVersion (id) {
|
||||
let defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: id })
|
||||
let defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: id })
|
||||
if (!defaultConfigInDb) {
|
||||
defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' })
|
||||
defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: 'default' })
|
||||
}
|
||||
return defaultConfigInDb.version || ''
|
||||
}
|
||||
|
||||
export async function combineDrilldownTableWithUserConfig () {
|
||||
const defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' })
|
||||
const defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: 'default' })
|
||||
const defaultConfigGroup = defaultConfigInDb ? defaultConfigInDb.config : []
|
||||
const currentUserConfigGroup = await readDrilldownTableConfigByUser()
|
||||
if (defaultConfigGroup && currentUserConfigGroup && currentUserConfigGroup.length > 0) {
|
||||
@@ -1086,3 +1085,81 @@ export function colorGradientCalculation (startColor, endColor, values) {
|
||||
export function colorHexToRgbArr (hex) {
|
||||
return [1, 3, 5].map((h) => parseInt(hex.substring(h, h + 2), 16))
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过事件类型eventType转换对应名称
|
||||
* @param type
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getNameByEventType (type) {
|
||||
switch (type) {
|
||||
case 'http error': {
|
||||
return 'http error ratio'
|
||||
}
|
||||
case 'dns error': {
|
||||
return 'dns error ratio'
|
||||
}
|
||||
case 'high dns response time': {
|
||||
return 'dns response time'
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
折线图通过事件类型 type 转换对应名称
|
||||
*/
|
||||
export function getLineType (type) {
|
||||
switch (type) {
|
||||
case 'bytes': {
|
||||
return 'Bits/s'
|
||||
}
|
||||
case 'packets': {
|
||||
return 'Packets/s'
|
||||
}
|
||||
case 'sessions': {
|
||||
return 'Sessions/s'
|
||||
}
|
||||
case 'queries': {
|
||||
return 'Queries/s'
|
||||
}
|
||||
default: return type
|
||||
}
|
||||
}
|
||||
/**
|
||||
npm折线图通过事件类型 type 转换对应 index 以及 unit
|
||||
*/
|
||||
export function getLineIndexUnit (type, show) {
|
||||
switch (type) {
|
||||
case 'establishLatencyMs': {
|
||||
return show ? '(ms)' : 0
|
||||
}
|
||||
case 'tcpLostlenPercent': {
|
||||
return show ? '(%)' : 3
|
||||
}
|
||||
case 'pktRetransPercent': {
|
||||
return show ? '(%)' : 4
|
||||
}
|
||||
case 'httpResponseLatency': {
|
||||
return show ? '(ms)' : 1
|
||||
}
|
||||
case 'sslConLatency': {
|
||||
return show ? '(ms)' : 2
|
||||
}
|
||||
}
|
||||
}
|
||||
export function getLineIndexUnit2 (type) {
|
||||
if (type.indexOf('total') > -1) {
|
||||
return 0
|
||||
} else if (type.indexOf('inbound') > -1) {
|
||||
return 1
|
||||
} else if (type.indexOf('outbound') > -1) {
|
||||
return 2
|
||||
} else if (type.indexOf('internal') > -1) {
|
||||
return 3
|
||||
} else if (type.indexOf('through') > -1) {
|
||||
return 4
|
||||
} else if (type.indexOf('other') > -1) {
|
||||
return 5
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import chartTable from '@/components/table/settings/ChartTable'
|
||||
import chartTable from '@/components/table/administration/ChartTable'
|
||||
import chartBox from '@/components/rightBox/settings/ChartBox'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import galaxyProxyBox from '@/components/rightBox/settings/GalaxyProxyBox'
|
||||
import galaxyProxyTable from '@/components/table/settings/GalaxyProxyTable'
|
||||
import galaxyProxyTable from '@/components/table/administration/GalaxyProxyTable'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import { api } from '@/utils/api'
|
||||
import { get, put } from '@/utils/http'
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import i18nTable from '@/components/table/settings/I18nTable'
|
||||
import i18nTable from '@/components/table/administration/I18nTable'
|
||||
import i18nBox from '@/components/rightBox/settings/I18nBox'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
|
||||
@@ -16,45 +16,21 @@
|
||||
|
||||
<script>
|
||||
import ChartTabs from '@/components/common/ChartTabs'
|
||||
import { useStore } from 'vuex'
|
||||
export default {
|
||||
name: 'index',
|
||||
components: {
|
||||
ChartTabs
|
||||
},
|
||||
data () {
|
||||
setup () {
|
||||
const store = useStore()
|
||||
const menu = store.getters.menuList.find(m => m.code === 'administration')
|
||||
const tabsData = menu.children.map(l => ({
|
||||
...l,
|
||||
path: l.route
|
||||
})).sort((a, b) => a.sort - b.sort)
|
||||
return {
|
||||
tabsData: [
|
||||
{
|
||||
i18n: 'overall.user',
|
||||
path: '/administration/user',
|
||||
icon: 'cn-icon cn-icon-user2'
|
||||
},
|
||||
{
|
||||
i18n: 'overall.role',
|
||||
path: '/administration/role',
|
||||
icon: 'cn-icon cn-icon-role2'
|
||||
},
|
||||
{
|
||||
i18n: 'overall.operationLog',
|
||||
path: '/administration/operationLog',
|
||||
icon: 'cn-icon cn-icon-operation-log'
|
||||
},
|
||||
{
|
||||
i18n: 'I18n',
|
||||
path: '/administration/i18n',
|
||||
icon: 'cn-icon cn-icon-i18n'
|
||||
},
|
||||
{
|
||||
i18n: 'galaxyProxy.galaxyProxy',
|
||||
path: '/administration/galaxyProxy',
|
||||
icon: 'cn-icon cn-icon-proxy'
|
||||
},
|
||||
{
|
||||
i18n: 'overall.chart',
|
||||
path: '/administration/chart',
|
||||
icon: 'cn-icon cn-icon-chart'
|
||||
}
|
||||
]
|
||||
tabsData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import operationLogTable from '@/components/table/settings/OperationLogTable'
|
||||
import operationLogTable from '@/components/table/administration/OperationLogTable'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
export default {
|
||||
|
||||
@@ -9,11 +9,23 @@
|
||||
:layout="['columnCustomize','elementSet','search']"
|
||||
@search="search"
|
||||
>
|
||||
<template v-slot:top-tool-right>
|
||||
<button id="roles-add" :title="$t('overall.createRole')" class="top-tool-btn margin-r-10"
|
||||
type="button" @click="add">
|
||||
<i class="cn-icon-add cn-icon"></i>
|
||||
<template v-slot:top-tool-left>
|
||||
<button id="roles-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="roles-edit" class="top-tool-btn margin-r-10" :disabled="disableEdit"
|
||||
@click="edit">
|
||||
<i class="cn-icon-edit cn-icon"></i>
|
||||
<span>{{$t('overall.edit')}}</span>
|
||||
</button>
|
||||
<button id="roles-delete" class="top-tool-btn margin-r-10"
|
||||
@click="delBatch">
|
||||
<i class="cn-icon-delete cn-icon"></i>
|
||||
<span>{{$t('overall.delete')}}</span>
|
||||
</button>
|
||||
|
||||
<delete-button id="role-list-batch-delete" :api="url" :delete-objs="batchDeleteObjs" @after="getTableData" @before="delFlag=true"></delete-button>
|
||||
</template>
|
||||
<template v-slot:default>
|
||||
@@ -48,7 +60,7 @@
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import rolesTable from '@/components/table/settings/RoleTable'
|
||||
import rolesTable from '@/components/table/administration/RoleTable'
|
||||
import roleBox from '@/components/rightBox/settings/RoleBox'
|
||||
import { api } from '@/utils/api'
|
||||
import { get } from '@/utils/http'
|
||||
@@ -78,8 +90,14 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
edit (u) {
|
||||
get(`${this.url}`, { ids: u.id }).then(response => {
|
||||
edit () {
|
||||
if(this.batchDeleteObjs.length === 0){
|
||||
this.$alert(this.$t('tip.pleaseSelectForEdit'),{
|
||||
confirmButtonText: this.$t('tip.yes'),
|
||||
type:'warning'
|
||||
})
|
||||
}else {
|
||||
get(`${this.url}`, { ids: this.batchDeleteObjs[0].id }).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.object = response.data.list[0]
|
||||
this.rightBox.show = true
|
||||
@@ -88,4 +106,5 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -9,14 +9,21 @@
|
||||
:layout="['columnCustomize','elementSet','search']"
|
||||
@search="search"
|
||||
>
|
||||
<template #top-tool-right>
|
||||
<button
|
||||
id="account-add"
|
||||
class="top-tool-btn margin-r-10"
|
||||
type="button"
|
||||
@click="add"
|
||||
>
|
||||
<i class="cn-icon-add cn-icon"/>
|
||||
<template #top-tool-left>
|
||||
<button id="account-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="account-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="account-delete" class="top-tool-btn margin-r-10"
|
||||
@click="delBatch">
|
||||
<i class="cn-icon-delete cn-icon"></i>
|
||||
<span>{{$t('overall.delete')}}</span>
|
||||
</button>
|
||||
</template>
|
||||
<template #default>
|
||||
@@ -53,7 +60,7 @@
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import userTable from '@/components/table/settings/UserTable'
|
||||
import userTable from '@/components/table/administration/UserTable'
|
||||
import userBox from '@/components/rightBox/settings/UserBox'
|
||||
import { api } from '@/utils/api'
|
||||
|
||||
|
||||
@@ -370,17 +370,12 @@ export default {
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
const { currentRoute } = useRouter()
|
||||
|
||||
function isEntityDetail (r) {
|
||||
return r.indexOf('entityDetail') > -1
|
||||
}
|
||||
const dateRangeValue = isEntityDetail(currentRoute.value.path) ? 60 * 24 : 60
|
||||
const dateRangeValue = 60
|
||||
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||
// entity详情内的chart时间工具不是公共的,需要单独定义
|
||||
const chartTimeFilter = ref({ startTime, endTime, dateRangeValue })
|
||||
// 复制一份prop中需要被组件v-model的内容,避免报错
|
||||
const copyOrderPieTable = props.orderPieTable
|
||||
const copyOrderPieTable = ref(props.orderPieTable)
|
||||
return {
|
||||
chartTimeFilter,
|
||||
chartTableTopOptions,
|
||||
|
||||
@@ -107,11 +107,8 @@ export default {
|
||||
const { params } = useRoute()
|
||||
panelType = props.entity ? props.entity.type : panelTypeAndRouteMapping[params.typeName]
|
||||
|
||||
function isEntityDetail (t) {
|
||||
return [4, 5, 6].indexOf(t) > -1
|
||||
}
|
||||
// date
|
||||
const dateRangeValue = isEntityDetail(panelType) ? 60 * 24 : 60
|
||||
const dateRangeValue = 60
|
||||
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||
const timeFilter = ref({ startTime, endTime, dateRangeValue })
|
||||
|
||||
@@ -150,14 +147,12 @@ export default {
|
||||
if (panels && panels.length > 0) {
|
||||
this.panel = panels[0]
|
||||
}
|
||||
// console.log(this.panel)
|
||||
if (this.panel.id) {
|
||||
if (this.panel.params) {
|
||||
this.panel.params = JSON.parse(this.panel.params)
|
||||
} else {
|
||||
this.panel.params = {}
|
||||
}
|
||||
// console.log(this.panel)
|
||||
const allCharts = (await getChartList({ panelId: this.panel.id, pageSize: -1 })).map(chart => {
|
||||
chart.i = chart.id
|
||||
this.recursionParamsConvert(chart)
|
||||
|
||||
@@ -114,8 +114,8 @@ export default {
|
||||
},
|
||||
reload () {
|
||||
this.copyDataList.forEach(item => {
|
||||
if (this.$refs['chart' + item.id]) {
|
||||
this.$refs['chart' + item.id].reload()
|
||||
if (this.$refs['chart' + item.id] && this.$refs['chart' + item.id][0]) {
|
||||
this.$refs['chart' + item.id][0].reload()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -32,8 +32,8 @@ export default {
|
||||
methods: {
|
||||
reload () {
|
||||
this.dnsScreenDataList.forEach(item => {
|
||||
if (this.$refs['chart' + item.id]) {
|
||||
this.$refs['chart' + item.id].getChartData()
|
||||
if (this.$refs['chart' + item.id] && this.$refs['chart' + item.id][0]) {
|
||||
this.$refs['chart' + item.id][0].getChartData()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -239,19 +239,16 @@ export default {
|
||||
panelType = props.entity ? props.entity.type : panelTypeAndRouteMapping[params.typeName]
|
||||
}
|
||||
|
||||
function isEntityDetail (t) {
|
||||
return [4, 5, 6].indexOf(t) > -1
|
||||
}
|
||||
// 获取url携带的range、startTime、endTime
|
||||
const rangeParam = query.range
|
||||
const startTimeParam = query.startTime
|
||||
const endTimeParam = query.endTime
|
||||
// 若url携带了,使用携带的值,否则使用默认值。
|
||||
|
||||
const dateRangeValue = rangeParam ? parseInt(query.range) : (isEntityDetail(panelType) ? 60 * 24 : 60)
|
||||
const dateRangeValue = rangeParam ? parseInt(query.range) : 60
|
||||
const timeFilter = ref({ dateRangeValue })
|
||||
if (!startTimeParam || !endTimeParam) {
|
||||
const { startTime, endTime } = getNowTime(isEntityDetail(panelType) ? 60 * 24 : 60)
|
||||
const { startTime, endTime } = getNowTime(60)
|
||||
timeFilter.value.startTime = startTime
|
||||
timeFilter.value.endTime = endTime
|
||||
} else {
|
||||
@@ -334,6 +331,8 @@ export default {
|
||||
if (!this.$refs.dateTimeRange.isCustom) {
|
||||
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))
|
||||
|
||||
@@ -123,11 +123,8 @@ export default {
|
||||
this.toggleLoading(true)
|
||||
get(api.dnsInsight.activeMaliciousDomain, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
const data = res.data.result
|
||||
if (!data || data.length === 0) {
|
||||
this.isNoData = true
|
||||
}
|
||||
this.tableData = data
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.tableData = res.data.result
|
||||
} else {
|
||||
this.isNoData = true
|
||||
}
|
||||
|
||||
@@ -95,6 +95,9 @@ export default {
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('resize', this.resize)
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -147,6 +147,9 @@ export default {
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('resize', this.resize)
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -208,9 +208,7 @@ export default {
|
||||
this.toggleLoading(true)
|
||||
get(api.dnsInsight.recentEvents, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
if (!res.data.result || res.data.result.length === 0) {
|
||||
this.isNoData = true
|
||||
}
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.tableData = res.data.result
|
||||
this.tableData.forEach((t, index) => {
|
||||
if (index > 5) {
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
<div class="line-header-left">
|
||||
<div class="line-value-active" v-if="lineTab"></div>
|
||||
<div class="line-value">
|
||||
<div class="line-value-mpackets"
|
||||
<div class="line-value-tabs"
|
||||
v-show="item.show"
|
||||
:class=" {'is-active': lineTab === item.class, 'mousemove-cursor': mousemoveCursor === item.class}"
|
||||
v-for="(item, index) in mpackets"
|
||||
v-for="(item, index) in tabs"
|
||||
:key="index"
|
||||
@mouseenter="mouseenter(item)"
|
||||
@mouseleave="mouseleave(item)"
|
||||
@click="activeChange(item, index)">
|
||||
<div class="line-value-mpackets-name">
|
||||
<div class="line-value-tabs-name">
|
||||
<div :class="item.class"></div>
|
||||
<div class="mpackets-name">{{$t(item.name)}}</div>
|
||||
<div class="tabs-name">{{$t(item.name)}}</div>
|
||||
</div>
|
||||
<div class="line-value-unit">
|
||||
<span class="line-value-unit-number">{{unitConvert(item.analysis.avg, unitTypes.number)[0]}}</span>
|
||||
@@ -79,7 +79,7 @@ import { getSecond } from '@/utils/date-util'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { getLineType, overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
export default {
|
||||
name: 'DnsTrafficLine',
|
||||
components: {
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
label: 'Maximum'
|
||||
}
|
||||
],
|
||||
mpackets: [
|
||||
tabs: [
|
||||
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.inbound', class: 'inbound', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.outbound', class: 'outbound', show: true, invertTab: true, positioning: 2, data: [], unitType: '' }
|
||||
@@ -202,68 +202,14 @@ export default {
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.lineTab = ''
|
||||
this.mpackets = [
|
||||
this.tabs = [
|
||||
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.inbound', class: 'inbound', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.outbound', class: 'outbound', show: true, invertTab: true, positioning: 2, data: [], unitType: '' }
|
||||
]
|
||||
}
|
||||
res.data.result.forEach((t) => {
|
||||
if (t.type === 'bytes' && val === 'Bits/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].analysis = t.totalBitsRate.analysis
|
||||
mpackets[1].analysis = t.inboundBitsRate.analysis
|
||||
mpackets[2].analysis = t.outboundBitsRate.analysis
|
||||
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
|
||||
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
|
||||
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
|
||||
let num = 0
|
||||
mpackets.forEach(e => {
|
||||
e.unitType = 'bps'
|
||||
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
|
||||
e.show = false
|
||||
num += 1
|
||||
} else {
|
||||
e.show = true
|
||||
if (!active && show !== this.lineRefer) {
|
||||
this.legendSelectChange(e, 'index')
|
||||
this.initData(res.data.result, val, active, show)
|
||||
}
|
||||
}
|
||||
if (this.lineTab === e.class) {
|
||||
if (parseFloat(e.analysis.avg) <= 0) {
|
||||
this.lineTab = ''
|
||||
this.lineRefer = ''
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
if (num === 3) {
|
||||
mpackets[0].invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(mpackets[0], 0)
|
||||
this.echartsInit(this.mpackets)
|
||||
} else {
|
||||
this.echartsInit(this.mpackets, show)
|
||||
if (!this.lineRefer) this.lineRefer = 'Average'
|
||||
}
|
||||
} else if (t.type === 'queries' && val === 'Queries/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].analysis = t.totalQueryRate.analysis
|
||||
mpackets[0].data = t.totalQueryRate.values ? t.totalQueryRate.values : []
|
||||
mpackets.forEach((e, i) => {
|
||||
if (i !== 0) {
|
||||
e.show = false
|
||||
}
|
||||
e.unitType = 'queries/s'
|
||||
e.invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(e, 0)
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
this.echartsInit(this.mpackets, true)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
@@ -377,7 +323,7 @@ export default {
|
||||
this.chartOption.tooltip.formatter = (params) => {
|
||||
params.forEach(t => {
|
||||
t.seriesName = this.$t(t.seriesName)
|
||||
this.mpackets.forEach(e => {
|
||||
this.tabs.forEach(e => {
|
||||
if (this.$t(e.name) === t.seriesName) {
|
||||
t.borderColor = chartColor3[e.positioning]
|
||||
}
|
||||
@@ -420,16 +366,16 @@ export default {
|
||||
legendSelectChange (item, index, val) {
|
||||
if (index === 'index') {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
} else if (this.mpackets[index] && this.mpackets[index].name === item.name) {
|
||||
} else if (this.tabs[index] && this.tabs[index].name === item.name) {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
this.mpackets.forEach((t) => {
|
||||
this.tabs.forEach((t) => {
|
||||
if (t.name !== item.name) {
|
||||
this.dispatchLegendUnSelectAction(t.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (val === 'active') {
|
||||
this.mpackets.forEach(t => {
|
||||
this.tabs.forEach(t => {
|
||||
if (item.name === t.name) {
|
||||
t.invertTab = !t.invertTab
|
||||
} else {
|
||||
@@ -441,7 +387,7 @@ export default {
|
||||
} else {
|
||||
this.lineTab = t.class
|
||||
}
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
this.dispatchLegendSelectAction(e.name)
|
||||
})
|
||||
}
|
||||
@@ -449,8 +395,8 @@ export default {
|
||||
}
|
||||
},
|
||||
handleActiveBar () {
|
||||
if (document.querySelector('.network .line-value-mpackets.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-mpackets.is-active')
|
||||
if (document.querySelector('.network .line-value-tabs.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-tabs.is-active')
|
||||
const activeBar = document.querySelector('.network .line-value-active')
|
||||
activeBar.style.cssText += `width: ${clientWidth}px; left: ${offsetLeft + this.leftOffset + clientLeft}px;`
|
||||
}
|
||||
@@ -463,7 +409,7 @@ export default {
|
||||
this.lineTab = ''
|
||||
this.handleActiveBar()
|
||||
this.showMarkLine = !this.showMarkLine
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
if (!e.invertTab) {
|
||||
e.invertTab = true
|
||||
}
|
||||
@@ -475,9 +421,9 @@ export default {
|
||||
let echartsData
|
||||
const chartOption = this.myChart.getOption()
|
||||
if (this.lineTab) {
|
||||
echartsData = this.mpackets.filter(t => t.show === true && t.invertTab === false)
|
||||
echartsData = this.tabs.filter(t => t.show === true && t.invertTab === false)
|
||||
} else {
|
||||
echartsData = this.mpackets.filter(t => t.show === true)
|
||||
echartsData = this.tabs.filter(t => t.show === true)
|
||||
}
|
||||
if (this.lineRefer === 'Average' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
@@ -526,12 +472,85 @@ export default {
|
||||
dataIntegrationArray.sort((a, b) => { return a[1] - b[1] })
|
||||
const sortIndex = dataIntegrationArray.findIndex(a => a[2] === index)
|
||||
return this.sizes[sortIndex]
|
||||
},
|
||||
initData (data, val, active, show) {
|
||||
let lineData = []
|
||||
if (data !== undefined && data.length > 0) {
|
||||
data.forEach((item) => {
|
||||
item.type = getLineType(item.type)
|
||||
if (item.type === val) {
|
||||
lineData = Object.keys(item).map(t => {
|
||||
return {
|
||||
...item[t]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
lineData.splice(0, 1)
|
||||
const tabs = _.cloneDeep(this.tabs)
|
||||
if (val === 'Queries/s') {
|
||||
lineData.forEach((d, i) => {
|
||||
tabs[i].data = d.values
|
||||
tabs[i].analysis = d.analysis
|
||||
})
|
||||
tabs.forEach((e, i) => {
|
||||
if (i !== 0) {
|
||||
e.show = false
|
||||
}
|
||||
e.unitType = 'queries/s'
|
||||
e.invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(e, 0)
|
||||
})
|
||||
this.tabs = tabs
|
||||
this.echartsInit(this.tabs, true)
|
||||
} else {
|
||||
const unit = 'bps'
|
||||
this.legendInit(lineData, active, show, unit, tabs)
|
||||
}
|
||||
},
|
||||
legendInit (data, active, show, type, dnsData) {
|
||||
data.forEach((d, i) => {
|
||||
dnsData[i].data = d.values
|
||||
dnsData[i].analysis = d.analysis
|
||||
})
|
||||
let num = 0
|
||||
dnsData.forEach(e => {
|
||||
e.unitType = type
|
||||
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
|
||||
e.show = false
|
||||
num += 1
|
||||
} else {
|
||||
e.show = true
|
||||
if (!active && show !== this.lineRefer) {
|
||||
this.legendSelectChange(e, 'index')
|
||||
}
|
||||
}
|
||||
if (this.lineTab === e.class) {
|
||||
if (parseFloat(e.analysis.avg) <= 0) {
|
||||
this.lineTab = ''
|
||||
this.lineRefer = ''
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
this.tabs = dnsData
|
||||
if (num === 3) {
|
||||
dnsData[0].invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(dnsData[0], 0)
|
||||
this.echartsInit(this.tabs)
|
||||
} else {
|
||||
this.echartsInit(this.tabs, show)
|
||||
if (!this.lineRefer) this.lineRefer = 'Average'
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.timer = setTimeout(() => {
|
||||
if (this.lineTab) {
|
||||
const data = this.mpackets.find(t => t.class === this.lineTab)
|
||||
const data = this.tabs.find(t => t.class === this.lineTab)
|
||||
this.activeChange(data, data.positioning)
|
||||
} else {
|
||||
this.init()
|
||||
@@ -542,7 +561,9 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.chartOption = null
|
||||
this.unitConvert = null
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="link-blocks">
|
||||
<div class="block-list" style="position: relative">
|
||||
<div class="block-list__title" v-if="!showError">{{ $t('linkMonitor.links') }}</div>
|
||||
<div class="block-list__title" v-if="!showError1">{{ $t('linkMonitor.links') }}</div>
|
||||
|
||||
<!--无数据noData-->
|
||||
<chart-no-data v-if="isNoData"></chart-no-data>
|
||||
<chart-no-data v-if="linkNoData" test-id="linkBlockNoData"></chart-no-data>
|
||||
|
||||
<div class="block-list__list" v-show="!isNoData">
|
||||
<chart-error v-if="showError" :content="errorMsg1" />
|
||||
<div class="block-list__list" v-show="!linkNoData">
|
||||
<chart-error v-if="showError1" :content="errorMsg1" />
|
||||
<el-popover
|
||||
v-else
|
||||
placement="bottom"
|
||||
@@ -29,20 +29,20 @@
|
||||
<div class="popper-content__link-id">Link ID: {{ item.linkId }}</div>
|
||||
<div class="popper-content__link-info">
|
||||
<div class="info__label">{{ $t('linkMonitor.linkBlock.total') }}</div>
|
||||
<div class="info__value" style="margin-left: 8px">
|
||||
<div class="info__value" :test-id="`linkBlockTotal${index}`" style="margin-left: 8px">
|
||||
{{ unitConvert(item.totalBitsRate, unitTypes.bps).join(' ') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="popper-content__link-info">
|
||||
<div class="info__label">{{ $t('linkMonitor.linkBlock.bandwidthUsage') }}</div>
|
||||
<div class="info__value" style="display: flex">
|
||||
<div>
|
||||
<div :test-id="`linkBlockEgressUsage${index}`">
|
||||
<svg class="icon item-popover-up" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-egress"></use>
|
||||
</svg>
|
||||
{{ convertValue(item.egressUsage) }}
|
||||
</div>
|
||||
<div>
|
||||
<div :test-id="`linkBlockIngressUsage${index}`">
|
||||
<svg class="icon item-popover-down" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-ingress"></use>
|
||||
</svg>
|
||||
@@ -57,12 +57,12 @@
|
||||
</div>
|
||||
|
||||
<div class="block-list" >
|
||||
<div class="block-list__title" v-if="!showError">{{ $t('linkMonitor.nextHopInternet') }}</div>
|
||||
<div class="block-list__title" v-if="!showError2">{{ $t('linkMonitor.nextHopInternet') }}</div>
|
||||
|
||||
<chart-no-data v-if="isNoData"></chart-no-data>
|
||||
<chart-no-data v-if="nextHopNoData" test-id="nextHpNoData"></chart-no-data>
|
||||
|
||||
<div class="block-list__list" v-show="!isNoData">
|
||||
<chart-error v-if="showError" :content="errorMsg2" />
|
||||
<div class="block-list__list" v-show="!nextHopNoData">
|
||||
<chart-error v-if="showError2" :content="errorMsg2" />
|
||||
<el-popover
|
||||
v-else
|
||||
placement="bottom"
|
||||
@@ -84,20 +84,20 @@
|
||||
<div class="popper-content__link-id">Next-Hop Internet: {{ item.linkDirection }}</div>
|
||||
<div class="popper-content__link-info">
|
||||
<div class="info__label">{{ $t('linkMonitor.linkBlock.total') }}</div>
|
||||
<div class="info__value" style="margin-left: 8px">
|
||||
<div class="info__value" :test-id="`nextHopTotal${index}`" style="margin-left: 8px">
|
||||
{{ unitConvert(item.totalBitsRate, unitTypes.bps).join(' ') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="popper-content__link-info">
|
||||
<div class="info__label">{{ $t('linkMonitor.linkBlock.bandwidthUsage') }}</div>
|
||||
<div class="info__value" style="display: flex">
|
||||
<div>
|
||||
<div :test-id="`nextHopEgressUsage${index}`">
|
||||
<svg class="icon item-popover-up" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-egress"></use>
|
||||
</svg>
|
||||
{{ convertValue(item.egressUsage) }}
|
||||
</div>
|
||||
<div>
|
||||
<div :test-id="`nextHopIngressUsage${index}`">
|
||||
<svg class="icon item-popover-down" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-ingress"></use>
|
||||
</svg>
|
||||
@@ -118,13 +118,13 @@ import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ref } from 'vue'
|
||||
import { get } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import { colorGradientCalculation } from '@/utils/tools'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { drillDownPanelTypeMapping, storageKey, unitTypes } from '@/utils/constants'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import ChartError from '@/components/common/Error'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'LinkBlock',
|
||||
@@ -135,12 +135,14 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isNoData: false,
|
||||
linkNoData: false,
|
||||
nextHopNoData: false,
|
||||
unitTypes,
|
||||
linkData: [],
|
||||
nextHopData: [],
|
||||
gradientColor: ['#FF005C', '#40537E'], // [start, end]
|
||||
showError: false,
|
||||
showError1: false,
|
||||
showError2: false,
|
||||
errorMsg1: '',
|
||||
errorMsg2: ''
|
||||
}
|
||||
@@ -175,20 +177,20 @@ export default {
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
|
||||
const dataRequest = get(api.linkMonitor.analysis, params)
|
||||
const nextHopRequest = get(api.linkMonitor.nextHopAnalysis, params)
|
||||
const dataRequest = axios.get(api.linkMonitor.analysis, { params: params })
|
||||
const nextHopRequest = axios.get(api.linkMonitor.nextHopAnalysis, { params: params })
|
||||
|
||||
Promise.all([dataRequest, nextHopRequest]).then(res => {
|
||||
if (res[0].code === 200 && res[1].code === 200) {
|
||||
this.showError = false
|
||||
Promise.all([dataRequest, nextHopRequest]).then(response => {
|
||||
const res = []
|
||||
res[0] = response[0].data
|
||||
res[1] = response[1].data
|
||||
if (res[0].code === 200) {
|
||||
this.showError1 = false
|
||||
|
||||
const linkData = res[0].data.result
|
||||
const nextHopData = res[1].data.result
|
||||
|
||||
this.isNoData = linkData.length === 0 && nextHopData.length === 0
|
||||
if (this.isNoData) {
|
||||
return
|
||||
}
|
||||
this.linkNoData = linkData.length === 0
|
||||
if (!this.linkNoData) {
|
||||
const data = []
|
||||
linkData.forEach(d => {
|
||||
const info = linkInfo.find(i => i.originalLinkId === d.linkId)
|
||||
@@ -234,7 +236,19 @@ export default {
|
||||
s.popoverWidth = this.computePopoverWidth(s.egressUsage, s.ingressUsage)
|
||||
})
|
||||
this.linkData = sorted
|
||||
}
|
||||
} else {
|
||||
this.linkNoData = false
|
||||
this.showError1 = true
|
||||
this.errorMsg1 = res[0].message
|
||||
}
|
||||
|
||||
if (res[1].code === 200) {
|
||||
this.showError2 = false
|
||||
|
||||
const nextHopData = res[1].data.result
|
||||
this.nextHopNoData = nextHopData.length === 0
|
||||
if (!this.nextHopNoData) {
|
||||
let directionArr = []
|
||||
nextHopData.forEach((item) => {
|
||||
if (item.egressLinkDirection !== '' && item.ingressLinkDirection !== '') {
|
||||
@@ -285,16 +299,18 @@ export default {
|
||||
})
|
||||
|
||||
this.nextHopData = nextHopSorted
|
||||
}
|
||||
} else {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg1 = res[0].message
|
||||
this.showError2 = true
|
||||
this.nextHopNoData = false
|
||||
this.errorMsg2 = res[1].message
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.linkNoData = false
|
||||
this.nextHopNoData = false
|
||||
this.showError1 = true
|
||||
this.showError2 = true
|
||||
// todo 此处数据还待验证
|
||||
this.errorMsg1 = e.message
|
||||
this.errorMsg2 = e.message
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="link-direction-grid">
|
||||
<!--左侧链路出入口-->
|
||||
<popover-content :isNoData="isLinkNoData" :gridData="linkGridData" :showError="isLinkShowError" :content="linkErrorMsg" style="width: 900px;"/>
|
||||
<popover-content :title="$t('linkMonitor.egressLink') + ' & ' + $t('linkMonitor.ingressLink')" :isNoData="isLinkNoData" :gridData="linkGridData" :showError="isLinkShowError" :content="linkErrorMsg" style="width: 900px;"/>
|
||||
|
||||
<!--右侧链路下一跳-->
|
||||
<popover-content :isNoData="isNextNoData" :gridData="nextGridData" :showError="isNextShowError" :content="nextErrorMsg" />
|
||||
<popover-content :title="$t('linkMonitor.nextHopInternetOfGrid')" :isNoData="isNextNoData" :gridData="nextGridData" :showError="isNextShowError" :content="nextErrorMsg" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import { api } from '@/utils/api'
|
||||
import { get } from '@/utils/http'
|
||||
import { storageKey } from '@/utils/constants'
|
||||
import PopoverContent from './LinkDirectionGrid/PopoverContent'
|
||||
import { computeScore } from '@/utils/tools'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'LinkDirectionGrid',
|
||||
@@ -56,11 +56,14 @@ export default {
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
|
||||
const dataRequest = get(api.linkMonitor.bigramAnalysis, params)
|
||||
const nextHopRequest = get(api.linkMonitor.bigramNextHopAnalysis, params)
|
||||
const dataRequest = axios.get(api.linkMonitor.bigramAnalysis, { params: params })
|
||||
const nextHopRequest = axios.get(api.linkMonitor.bigramNextHopAnalysis, { params: params })
|
||||
this.toggleLoading(true)
|
||||
|
||||
Promise.all([dataRequest, nextHopRequest]).then(res => {
|
||||
Promise.all([dataRequest, nextHopRequest]).then(response => {
|
||||
const res = []
|
||||
res[0] = response[0].data
|
||||
res[1] = response[1].data
|
||||
if (res[0].code === 200) {
|
||||
this.isLinkShowError = false
|
||||
// 链路流量数据
|
||||
@@ -95,7 +98,7 @@ export default {
|
||||
// 分数低于3分,赋红点
|
||||
d.score = this.localComputeScore(d)
|
||||
|
||||
d.scoreLow3 = d.score < 3
|
||||
d.scoreLow3 = d.score < 3 || d.score === '-'
|
||||
|
||||
if (data) {
|
||||
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
|
||||
@@ -140,12 +143,12 @@ export default {
|
||||
|
||||
// 链路下一跳信息
|
||||
const nextLinkData = res[1].data.result
|
||||
// 接口数据乱序,根据出方向排序,再根据同个出方向下的入进行排序
|
||||
// 接口数据乱序,根据入方向排序,再根据同个入方向下的出方向进行排序
|
||||
nextLinkData.sort((a, b) => {
|
||||
if (a.ingressLinkDirection !== b.ingressLinkDirection) {
|
||||
return a.ingressLinkDirection.localeCompare(b.ingressLinkDirection)
|
||||
return a.ingressLinkDirection.localeCompare(b.ingressLinkDirection, 'zh')
|
||||
}
|
||||
return a.egressLinkDirection.localeCompare(b.egressLinkDirection)
|
||||
return a.egressLinkDirection.localeCompare(b.egressLinkDirection, 'zh')
|
||||
})
|
||||
|
||||
this.isNextNoData = nextLinkData.length === 0
|
||||
@@ -182,7 +185,7 @@ export default {
|
||||
// 分数低于3分,赋红点
|
||||
d.score = this.localComputeScore(d)
|
||||
|
||||
d.scoreLow3 = d.score < 3
|
||||
d.scoreLow3 = d.score < 3 || d.score === '-'
|
||||
|
||||
if (data) {
|
||||
const existedEgressLink = data.egress.find(e => e.linkId === egressLink.linkId)
|
||||
@@ -225,13 +228,11 @@ export default {
|
||||
this.nextErrorMsg = res[1].message
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
|
||||
this.isLinkShowError = true
|
||||
this.linkErrorMsg = e[0].message
|
||||
this.linkErrorMsg = e.message
|
||||
|
||||
this.isNextShowError = true
|
||||
this.nextErrorMsg = e[1].message
|
||||
this.nextErrorMsg = e.message
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<template>
|
||||
<div class="link-statistical-dimension" style="position: relative">
|
||||
<div class="dimension-title">{{ $t('linkMonitor.egressLink') }} & {{ $t('linkMonitor.ingressLink') }}
|
||||
</div>
|
||||
<div class="dimension-title">{{title}}</div>
|
||||
|
||||
<chart-no-data v-if="isNoData"></chart-no-data>
|
||||
<chart-no-data v-if="isNoData" :test-id="`noData${gridData.length}`"></chart-no-data>
|
||||
|
||||
<chart-error class="link-block-error" v-if="showError" :content="content"/>
|
||||
|
||||
@@ -21,13 +20,13 @@
|
||||
<span v-if="row.nextHop">{{ row.nextHop }}</span>
|
||||
<span v-else>{{ row.linkId }}</span>
|
||||
</div>
|
||||
<div v-for="(item, index2) in row.egress" :key="index2">
|
||||
<div v-for="(item, index3) in row.egress" :key="index3">
|
||||
|
||||
<el-popover :width="item.popoverWidth" placement="right" trigger="hover">
|
||||
<template #reference>
|
||||
<div class="data-item data-item__hover">
|
||||
<div :class="row.egress[index2].usageMore90 ? 'data-item__point-red':'data-item__point'"></div>
|
||||
<div :class="row.egress[index2].scoreLow3 ? 'data-item__point-red':'data-item__point'"></div>
|
||||
<div :test-id="`usagePoint${gridData.length}-${index2+1}-${index3+1}`" :class="item.usageMore90 ? 'data-item__point-red':'data-item__point'"></div>
|
||||
<div :test-id="`scorePoint${gridData.length}-${index2+1}-${index3+1}`" :class="item.scoreLow3 ? 'data-item__point-red':'data-item__point'"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -35,13 +34,13 @@
|
||||
<template #default>
|
||||
<div class="item-popover-header">
|
||||
<!--兼容下一跳情况-->
|
||||
<span v-if="row.nextHop">{{ row.nextHop }}</span>
|
||||
<span v-else>{{ row.linkId }}</span>
|
||||
<span v-if="row.nextHop" :test-id="`toNextHop${index2+1}`">{{ row.nextHop }}</span>
|
||||
<span v-else :test-id="`fromLinkId${index2+1}`">{{ row.linkId }}</span>
|
||||
<svg class="icon item-popover-header-icon" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-arrow-right2"></use>
|
||||
</svg>
|
||||
<span v-if="row.nextHop">{{ row.egress[index2].egressLinkDirection }}</span>
|
||||
<span v-else>{{ row.egress[index2].linkId }}</span>
|
||||
<span v-if="row.nextHop" :test-id="`toNextHop${index3+1}`">{{ item.egressLinkDirection }}</span>
|
||||
<span v-else :test-id="`toLinkId${index3+1}`">{{ item.linkId }}</span>
|
||||
</div>
|
||||
|
||||
<div class="item-popover-block">
|
||||
@@ -49,24 +48,24 @@
|
||||
|
||||
<div style="display: flex">
|
||||
<div class="row-dot">
|
||||
<div :class="row.egress[index2].usageMore90 ? 'red-dot':'green-dot'"></div>
|
||||
<div :class="item.usageMore90 ? 'red-dot':'green-dot'"></div>
|
||||
</div>
|
||||
<div class="item-popover-block-content">
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t('linkMonitor.bandwidthUsage') }}</div>
|
||||
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
<div style="margin-left: -10px">
|
||||
<div class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
|
||||
<div :test-id="`egressUsage${gridData.length}-${index2+1}-${index3+1}`" style="margin-left: -10px">
|
||||
<svg class="icon item-popover-up" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-egress"></use>
|
||||
</svg>
|
||||
{{ convertValue(row.egress[index2].egressUsage) }}
|
||||
{{ convertValue(item.egressUsage) }}
|
||||
</div>
|
||||
<div>
|
||||
<div :test-id="`ingressUsage${gridData.length}-${index2+1}-${index3+1}`">
|
||||
<svg class="icon item-popover-down" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-ingress"></use>
|
||||
</svg>
|
||||
{{ convertValue(row.egress[index2].ingressUsage) }}
|
||||
{{ convertValue(item.ingressUsage) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -74,8 +73,8 @@
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t('linkMonitor.linkBlock.total') }}</div>
|
||||
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].totalBitsRate, unitTypes.bps).join('') }}
|
||||
<div :test-id="`totalBitsRate${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
|
||||
{{ unitConvert(item.totalBitsRate, unitTypes.bps).join('') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,48 +86,48 @@
|
||||
|
||||
<div style="display: flex">
|
||||
<div class="row-dot">
|
||||
<div :class="row.egress[index2].scoreLow3 ? 'red-dot':'green-dot'"></div>
|
||||
<div :class="item.scoreLow3 ? 'red-dot':'green-dot'"></div>
|
||||
</div>
|
||||
<div class="item-popover-block-content">
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t('linkMonitor.npmScore1') }}</div>
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ row.egress[index2].score }}
|
||||
<div :test-id="`score${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
|
||||
{{ item.score }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t(npmNetworkName[0].name) }}</div>
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].establishLatencyMs, unitTypes.time).join('') }}
|
||||
<div :test-id="`tcp${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
|
||||
{{ unitConvert(item.establishLatencyMs, unitTypes.time).join('') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t(npmNetworkName[1].name) }}</div>
|
||||
<div class="block-content-item-value" :style="{'width': row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].httpResponseLatency, unitTypes.time).join('') }}
|
||||
<div :test-id="`http${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{'width': item.valueWidth + 'px'}">
|
||||
{{ unitConvert(item.httpResponseLatency, unitTypes.time).join('') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t(npmNetworkName[2].name) }}</div>
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].sslConLatency, unitTypes.time).join('') }}
|
||||
<div :test-id="`ssl${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
|
||||
{{ unitConvert(item.sslConLatency, unitTypes.time).join('') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t(npmNetworkName[3].name) }}</div>
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].tcpLostlenPercent, unitTypes.percent).join('') }}
|
||||
<div :test-id="`packetLoss${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
|
||||
{{ unitConvert(item.tcpLostlenPercent, unitTypes.percent).join('') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="block-content-item">
|
||||
<div class="block-content-item-name">{{ $t(npmNetworkName[4].name) }}</div>
|
||||
<div class="block-content-item-value" :style="{width: row.egress[index2].valueWidth + 'px'}">
|
||||
{{ unitConvert(row.egress[index2].pktRetransPercent, unitTypes.percent).join('') }}
|
||||
<div :test-id="`packetRetrans${gridData.length}-${index2+1}-${index3+1}`" class="block-content-item-value" :style="{width: item.valueWidth + 'px'}">
|
||||
{{ unitConvert(item.pktRetransPercent, unitTypes.percent).join('') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -156,7 +155,8 @@ export default {
|
||||
gridData: Array,
|
||||
isNoData: Boolean,
|
||||
showError: Boolean,
|
||||
content: String
|
||||
content: String,
|
||||
title: String
|
||||
},
|
||||
components: {
|
||||
ChartError,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="link-traffic-line">
|
||||
<link-traffic-drill-down-list
|
||||
:chart="chart"
|
||||
:line-data="mpackets"
|
||||
:line-data="tabs[0]"
|
||||
:time-filter="timeFilter">
|
||||
</link-traffic-drill-down-list>
|
||||
<div class="line network link-traffic">
|
||||
@@ -12,22 +12,24 @@
|
||||
<div class="line-header-left">
|
||||
<div class="line-value-active" v-if="lineTab"></div>
|
||||
<div class="line-value">
|
||||
<div class="line-value-mpackets"
|
||||
<div class="line-value-tabs"
|
||||
v-show="item.show"
|
||||
:class=" {'is-active': lineTab === item.class, 'mousemove-cursor': mousemoveCursor === item.class}"
|
||||
v-for="(item, index) in mpackets"
|
||||
v-for="(item, index) in tabs"
|
||||
:key="index"
|
||||
@mouseenter="mouseenter(item)"
|
||||
@mouseleave="mouseleave(item)"
|
||||
@click="activeChange(item, index)">
|
||||
<div class="line-value-mpackets-name">
|
||||
@click="activeChange(item, index)"
|
||||
:test-id="`tab-${index}`">
|
||||
<div class="line-value-tabs-name">
|
||||
<div :class="item.class"></div>
|
||||
<div class="mpackets-name">{{$t(item.name)}}</div>
|
||||
<div class="tabs-name">{{$t(item.name)}}</div>
|
||||
</div>
|
||||
<div class="line-value-unit">
|
||||
<div class="line-value-unit" :test-id="`tabContent${index}`">
|
||||
<span class="line-value-unit-number">{{unitConvert(item.analysis.avg, unitTypes.number)[0]}}</span>
|
||||
<span class="line-value-unit-number2">
|
||||
<span>{{unitConvert(item.analysis.avg, unitTypes.number)[1]}}</span><span v-if="item.unitType">{{item.unitType}}</span>
|
||||
<span>{{unitConvert(item.analysis.avg, unitTypes.number)[1]}}</span>
|
||||
<span v-if="item.unitType">{{item.unitType}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -51,7 +53,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: calc(100% - 74px); position: relative">
|
||||
<chart-no-data v-if="isNoData"></chart-no-data>
|
||||
<chart-no-data v-if="isNoData" test-id="noData"></chart-no-data>
|
||||
<div class="chart-drawing" v-show="showMarkLine && !isNoData" id="linkTrafficLineChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,14 +69,14 @@ import { useRoute } from 'vue-router'
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { chartColor3, chartColor4, unitTypes } from '@/utils/constants'
|
||||
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { getLineType, overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import { get } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import _ from 'lodash'
|
||||
import * as echarts from 'echarts'
|
||||
import { linkTrafficLineChartOption } from '@/views/charts2/charts/options/echartOption'
|
||||
import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'LinkTrafficLine',
|
||||
@@ -112,7 +114,7 @@ export default {
|
||||
label: 'Packets/s'
|
||||
}
|
||||
],
|
||||
mpackets: [
|
||||
tabs: [
|
||||
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'linkMonitor.ingress', class: 'ingress', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'linkMonitor.egress', class: 'egress', show: true, invertTab: true, positioning: 2, data: [], unitType: '' }
|
||||
@@ -176,105 +178,21 @@ export default {
|
||||
}
|
||||
}
|
||||
this.loading = true
|
||||
get(api.linkMonitor.totalTrafficAnalysis, params).then((res) => {
|
||||
axios.get(api.linkMonitor.totalTrafficAnalysis, { params: params }).then((res) => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.lineTab = ''
|
||||
this.mpackets = [
|
||||
this.tabs = [
|
||||
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'linkMonitor.ingress', class: 'ingress', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'linkMonitor.egress', class: 'egress', show: true, invertTab: true, positioning: 2, data: [], unitType: '' }
|
||||
]
|
||||
}
|
||||
res.data.result.forEach((t) => {
|
||||
if (t.type === 'bytes' && val === 'Bits/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].analysis = t.totalBitsRate.analysis
|
||||
mpackets[1].analysis = t.ingressBitsRate.analysis
|
||||
mpackets[2].analysis = t.egressBitsRate.analysis
|
||||
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
|
||||
mpackets[1].data = t.ingressBitsRate.values ? t.ingressBitsRate.values : []
|
||||
mpackets[2].data = t.egressBitsRate.values ? t.egressBitsRate.values : []
|
||||
let num = 0
|
||||
mpackets.forEach(e => {
|
||||
e.unitType = 'bps'
|
||||
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
|
||||
e.show = false
|
||||
num += 1
|
||||
} else {
|
||||
e.show = true
|
||||
if (!active && !show) {
|
||||
this.legendSelectChange(e, 'index')
|
||||
this.initData(res.data.result, val, active, show)
|
||||
}
|
||||
}
|
||||
if (this.lineTab === e.class) {
|
||||
if (parseFloat(e.analysis.avg) <= 0) {
|
||||
this.lineTab = ''
|
||||
this.lineRefer = ''
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
if (num === 3) {
|
||||
mpackets[0].invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(mpackets[0], 0)
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.mpackets)
|
||||
})
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.mpackets)
|
||||
if (!this.lineRefer) this.lineRefer = 'Average'
|
||||
})
|
||||
}
|
||||
} else if (t.type === 'packets' && val === 'Packets/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].analysis = t.totalPacketsRate.analysis
|
||||
mpackets[1].analysis = t.ingressPacketsRate.analysis
|
||||
mpackets[2].analysis = t.egressPacketsRate.analysis
|
||||
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
|
||||
mpackets[1].data = t.ingressPacketsRate.values ? t.ingressPacketsRate.values : []
|
||||
mpackets[2].data = t.egressPacketsRate.values ? t.egressPacketsRate.values : []
|
||||
let num = 0
|
||||
mpackets.forEach(e => {
|
||||
e.unitType = 'packets/s'
|
||||
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
|
||||
e.show = false
|
||||
num += 1
|
||||
} else {
|
||||
e.show = true
|
||||
if (!active && !show) {
|
||||
this.legendSelectChange(e, 'index')
|
||||
}
|
||||
}
|
||||
if (this.lineTab === e.class) {
|
||||
if (parseFloat(e.analysis.avg) <= 0) {
|
||||
this.lineTab = ''
|
||||
this.lineRefer = ''
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
if (num === 3) {
|
||||
mpackets[0].invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(mpackets[0], 0)
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.mpackets)
|
||||
})
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.mpackets)
|
||||
if (!this.lineRefer) this.lineRefer = 'Average'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.showError = true
|
||||
this.errorMsg = res.message
|
||||
@@ -283,12 +201,13 @@ export default {
|
||||
console.error(e)
|
||||
this.showError = true
|
||||
this.errorMsg = e.message
|
||||
// this.isNoData = true
|
||||
this.isNoData = false
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
echartsInit (echartsData) {
|
||||
if (!this.isUnitTesting) {
|
||||
if (this.lineTab) {
|
||||
this.handleActiveBar()
|
||||
echartsData = echartsData.filter(t => t.show === true && t.invertTab === false)
|
||||
@@ -339,7 +258,7 @@ export default {
|
||||
this.chartOption.tooltip.formatter = (params) => {
|
||||
params.forEach(t => {
|
||||
t.seriesName = this.$t(t.seriesName)
|
||||
this.mpackets.forEach(e => {
|
||||
this.tabs.forEach(e => {
|
||||
if (this.$t(e.name) === t.seriesName) {
|
||||
t.borderColor = chartColor3[e.positioning]
|
||||
}
|
||||
@@ -350,6 +269,7 @@ export default {
|
||||
}
|
||||
this.showMarkLine = true
|
||||
this.myChart.setOption(this.chartOption)
|
||||
}
|
||||
},
|
||||
activeChange (item, index) {
|
||||
if (this.isNoData) return
|
||||
@@ -381,16 +301,16 @@ export default {
|
||||
legendSelectChange (item, index, val) {
|
||||
if (index === 'index') {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
} else if (this.mpackets[index] && this.mpackets[index].name === item.name) {
|
||||
} else if (this.tabs[index] && this.tabs[index].name === item.name) {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
this.mpackets.forEach((t) => {
|
||||
this.tabs.forEach((t) => {
|
||||
if (t.name !== item.name) {
|
||||
this.dispatchLegendUnSelectAction(t.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (val === 'active') {
|
||||
this.mpackets.forEach(t => {
|
||||
this.tabs.forEach(t => {
|
||||
if (item.name === t.name) {
|
||||
t.invertTab = !t.invertTab
|
||||
} else {
|
||||
@@ -402,7 +322,7 @@ export default {
|
||||
} else {
|
||||
this.lineTab = t.class
|
||||
}
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
this.dispatchLegendSelectAction(e.name)
|
||||
})
|
||||
}
|
||||
@@ -410,8 +330,8 @@ export default {
|
||||
}
|
||||
},
|
||||
handleActiveBar () {
|
||||
if (document.querySelector('.network .line-value-mpackets.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-mpackets.is-active')
|
||||
if (document.querySelector('.network .line-value-tabs.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-tabs.is-active')
|
||||
const activeBar = document.querySelector('.network .line-value-active')
|
||||
activeBar.style.cssText += `width: ${clientWidth}px; left: ${offsetLeft + this.leftOffset + clientLeft}px;`
|
||||
}
|
||||
@@ -424,7 +344,7 @@ export default {
|
||||
this.lineTab = ''
|
||||
this.handleActiveBar()
|
||||
this.showMarkLine = !this.showMarkLine
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
if (!e.invertTab) {
|
||||
e.invertTab = true
|
||||
}
|
||||
@@ -457,12 +377,71 @@ export default {
|
||||
dataIntegrationArray.sort((a, b) => { return a[1] - b[1] })
|
||||
const sortIndex = dataIntegrationArray.findIndex(a => a[2] === index)
|
||||
return this.sizes[sortIndex]
|
||||
},
|
||||
initData (data, val, active, show) {
|
||||
let lineData = []
|
||||
if (data !== undefined && data.length > 0) {
|
||||
data.forEach((item) => {
|
||||
item.type = getLineType(item.type)
|
||||
if (item.type === val) {
|
||||
lineData = Object.keys(item).map(t => {
|
||||
return {
|
||||
...item[t]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
lineData.splice(0, 1)
|
||||
const tabs = _.cloneDeep(this.tabs)
|
||||
const unit = val === 'Bits/s' ? 'bps' : 'packets/s'
|
||||
this.legendInit(lineData, active, show, unit, tabs)
|
||||
},
|
||||
legendInit (data, active, show, type, linkData) {
|
||||
data.forEach((d, i) => {
|
||||
linkData[i].data = d.values
|
||||
linkData[i].analysis = d.analysis
|
||||
})
|
||||
let num = 0
|
||||
linkData.forEach(e => {
|
||||
e.unitType = type
|
||||
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
|
||||
e.show = false
|
||||
num += 1
|
||||
} else {
|
||||
e.show = true
|
||||
if (!active && !show) {
|
||||
this.legendSelectChange(e, 'index')
|
||||
}
|
||||
}
|
||||
if (this.lineTab === e.class) {
|
||||
if (parseFloat(e.analysis.avg) <= 0) {
|
||||
this.lineTab = ''
|
||||
this.lineRefer = ''
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
this.tabs = linkData
|
||||
if (num === 3) {
|
||||
linkData[0].invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(linkData[0], 0)
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.tabs)
|
||||
})
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.tabs)
|
||||
if (!this.lineRefer) this.lineRefer = 'Average'
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.timer = setTimeout(() => {
|
||||
if (this.lineTab) {
|
||||
const data = this.mpackets.find(t => t.class === this.lineTab)
|
||||
const data = this.tabs.find(t => t.class === this.lineTab)
|
||||
this.activeChange(data, data.positioning)
|
||||
} else {
|
||||
this.init()
|
||||
@@ -473,7 +452,9 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.chartOption = null
|
||||
this.unitConvert = null
|
||||
}
|
||||
|
||||
@@ -102,15 +102,12 @@ export default {
|
||||
if (condition.length > 1) {
|
||||
if (n === 0) {
|
||||
params.q = condition.find(c => c.indexOf('common_ingress_link_id') > -1 || c.indexOf('ingress_link_direction') > -1)
|
||||
} else {
|
||||
params.q = condition.find(c => c.indexOf('common_egress_link_id') > -1 || c.indexOf('egress_link_direction') > -1)
|
||||
}
|
||||
}
|
||||
if (n === 0) {
|
||||
url = api.linkMonitor.drilldownQuadrupleIngressAnalysis // 入口
|
||||
} else {
|
||||
params.q = condition.find(c => c.indexOf('common_egress_link_id') > -1 || c.indexOf('egress_link_direction') > -1)
|
||||
url = api.linkMonitor.drilldownQquadrupleEgressAnalysis // 出口
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (n === 0) {
|
||||
url = api.linkMonitor.quadrupleIngressAnalysis // 入口
|
||||
|
||||
@@ -6,36 +6,42 @@
|
||||
<div v-else>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('network.total')}}</div>
|
||||
<div class="link-traffic-list-center-value" v-if="lineData[0] && lineData[0].analysis">{{unitConvert(lineData[0].analysis.avg, unitTypes.bps).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" v-if="lineData && lineData.analysis" test-id="line-tabContent">
|
||||
<span>{{unitConvert(lineData.analysis.avg, unitTypes.number)[0]}}</span>
|
||||
<span>
|
||||
<span>{{unitConvert(lineData.analysis.avg, unitTypes.number)[1]}}</span>
|
||||
<span v-if="lineData.unitType">{{lineData.unitType}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('linkMonitor.bandwidthUsage')}}</div>
|
||||
<div class="link-traffic-list-center-value" v-if="bandWidth && lineData[0] && lineData[0].analysis">{{unitConvert(lineData[0].analysis.avg / bandWidth, unitTypes.percent).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" v-if="lineData && lineData.analysis && bandWidth" test-id="line-percent">{{unitConvert(lineData.analysis.avg / bandWidth, unitTypes.percent).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" v-else>-</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('linkMonitor.npmScore')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{linkTrafficListData.npmScore || '-'}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-score">{{linkTrafficListData.npmScore || '-'}}</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.tcpConnectionEstablishLatency')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.establishLatencyMs), unitTypes.time).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-tcp">{{unitConvert(Math.floor(linkTrafficListData.establishLatencyMs), unitTypes.time).join('')}}</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.httpResponse')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.httpResponseLatency), unitTypes.time).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-http">{{unitConvert(Math.floor(linkTrafficListData.httpResponseLatency), unitTypes.time).join('')}}</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.sslResponseLatency')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{unitConvert(Math.floor(linkTrafficListData.sslConLatency), unitTypes.time).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-ssl">{{unitConvert(Math.floor(linkTrafficListData.sslConLatency), unitTypes.time).join('')}}</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('networkAppPerformance.packetLoss')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.tcpLostlenPercent, unitTypes.percent).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-packetLoss">{{unitConvert(linkTrafficListData.tcpLostlenPercent, unitTypes.percent).join('')}}</div>
|
||||
</div>
|
||||
<div class="link-traffic-list-center">
|
||||
<div class="link-traffic-list-center-label">{{$t('overall.packetRetrans')}}</div>
|
||||
<div class="link-traffic-list-center-value">{{unitConvert(linkTrafficListData.pktRetransPercent, unitTypes.percent).join('')}}</div>
|
||||
<div class="link-traffic-list-center-value" test-id="line-packetRetrans">{{unitConvert(linkTrafficListData.pktRetransPercent, unitTypes.percent).join('')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,7 +51,6 @@
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { storageKey, unitTypes } from '@/utils/constants'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { get } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import { ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
@@ -53,6 +58,7 @@ import { getSecond } from '@/utils/date-util'
|
||||
import { computeScore } from '@/utils/tools'
|
||||
import Loading from '@/components/common/Loading'
|
||||
import ChartError from '@/components/common/Error'
|
||||
import axios from 'axios'
|
||||
export default {
|
||||
name: 'linkTrafficList',
|
||||
mixins: [chartMixin],
|
||||
@@ -136,7 +142,8 @@ export default {
|
||||
}
|
||||
}
|
||||
this.loading = true
|
||||
get(api.linkMonitor.networkAnalysis, params).then(res => {
|
||||
axios.get(api.linkMonitor.networkAnalysis, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
@@ -154,10 +161,9 @@ export default {
|
||||
this.errorMsg = res.message
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
this.showError = true
|
||||
this.errorMsg = e.message
|
||||
// this.isNoData = true
|
||||
this.isNoData = false
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
@@ -165,6 +171,9 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
this.linkTrafficData()
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -6,31 +6,31 @@
|
||||
</div>
|
||||
|
||||
<div class="app-cards">
|
||||
<div class="app-card" @mouseenter="mouseenter(app)" @mouseleave="mouseleave(app)" v-for="(app, index) in appData" :key="app.type + app.name">
|
||||
<div class="app-card" @mouseenter="mouseenter(app)" @mouseleave="mouseleave(app)" v-for="(app, index) in appData" :key="app.type + app.name" test-id="app-data-card">
|
||||
<div class="app-card-title">
|
||||
<div class="app-card-title-name">
|
||||
<i class="cn-icon" :class="app.type === 'provider' ? 'cn-icon-entity' : 'cn-icon-app2'"></i>
|
||||
<span @click="drillDownData(app.type, app.name)">{{app.name}}</span>
|
||||
<i class="cn-icon" :class="app.type === 'provider' ? 'cn-icon-entity' : 'cn-icon-app2'" :test-id="`icon${index}`"></i>
|
||||
<span @click="drillDownData(app.type, app.name)" :test-id="`name${index}`">{{app.name}}</span>
|
||||
</div>
|
||||
<div class="app-card-title-more">
|
||||
<span v-show="app.showMore"><i class="cn-icon cn-icon-more-dark" @mouseenter="mouseenterMore(app)"></i></span>
|
||||
<span class="app-card-title-more-delete" @click="del(app, index)" v-show="app.moreOptions" @mouseleave="mouseleaveMore(app)"><i class="cn-icon cn-icon-delete"></i>{{$t('overall.delete')}}</span>
|
||||
<span v-show="app.showMore"><i class="cn-icon cn-icon-more-dark" @mouseenter="mouseenterMore(app)" test-id="mouseenter-dark"></i></span>
|
||||
<span class="app-card-title-more-delete" @click="del(app, index)" v-show="app.moreOptions" @mouseleave="mouseleaveMore(app)" test-id="mouseleave-more"><i class="cn-icon cn-icon-delete"></i>{{$t('overall.delete')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-card__bodys">
|
||||
<div class="app-card__body">
|
||||
<div class="app-card__body-content">
|
||||
<div class="app-card__body-content-value">
|
||||
<div class="app-card__body-content-number">{{unitConvert(app.rate, unitTypes.number).join(' ')}}</div>
|
||||
<div class="app-card__body-content-percent red" v-if="app.value > 0">
|
||||
<div class="app-card__body-content-number" :test-id="`rate${index}`">{{unitConvert(app.rate, unitTypes.number).join(' ')}}</div>
|
||||
<div class="app-card__body-content-percent red" v-if="app.value > 0" :test-id="`percent${index}`">
|
||||
<span v-if="app.value <= 5">
|
||||
+{{unitConvert(app.value, unitTypes.percent).join('')}}
|
||||
</span>
|
||||
<span v-else>>500.00%</span>
|
||||
</div>
|
||||
<div class="app-card__body-content-percent green" v-else-if="app.value < 0">
|
||||
<div class="app-card__body-content-percent green" v-else-if="app.value < 0" :test-id="`percent${index}`">
|
||||
<span v-if="app.value >= -5">
|
||||
-{{unitConvert(app.value, unitTypes.percent).join('').replaceAll('-', '')}}
|
||||
-{{unitConvert(app.value, unitTypes.percent).join('').replace(/-/g, '')}}
|
||||
</span>
|
||||
<span v-else>>500.00%</span>
|
||||
</div>
|
||||
@@ -39,8 +39,8 @@
|
||||
</div>
|
||||
<div class="app-card__body-previous">
|
||||
<div>Total</div>
|
||||
<div v-if="metric === 'Bits/s'">{{unitConvert(app.total, unitTypes.byte).join(' ')}}</div>
|
||||
<div v-else>{{unitConvert(app.total, unitTypes.number).join(' ')}}</div>
|
||||
<div v-if="metric === 'Bits/s'" :test-id="`total${index}`">{{unitConvert(app.total, unitTypes.byte).join(' ')}}</div>
|
||||
<div v-else :test-id="`total${index}`">{{unitConvert(app.total, unitTypes.number).join(' ')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart__drawing" v-show="!isNoData" :id="`chart-${app.name}-${app.type}`"></div>
|
||||
@@ -48,7 +48,7 @@
|
||||
</div>
|
||||
<div class="app-card app-card--create">
|
||||
<i class="cn-icon cn-icon-add1" @click="addApp"></i>
|
||||
<span @click="addApp">{{$t('overall.add')}}</span>
|
||||
<span @click="addApp" test-id="add">{{$t('overall.add')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-drawer
|
||||
@@ -62,7 +62,7 @@
|
||||
<div class="add-app__header">
|
||||
<div class="header__title">{{$t('overall.add')}}</div>
|
||||
<div class="header__operations">
|
||||
<div class="header__operation header__operation--cancel" @click="cancelApp">{{$t('overall.cancel')}}</div>
|
||||
<div class="header__operation header__operation--cancel" @click="cancelApp" test-id="cancel-app">{{$t('overall.cancel')}}</div>
|
||||
<div class="header__operation header__operation--save" @click="save">{{$t('overall.save')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -71,16 +71,16 @@
|
||||
<el-tab-pane :label="$t('network.providers')" :name="0">
|
||||
<div class="body__apps" :class="{'body__apps-no-grid': providerOptions.length === 0}">
|
||||
<loading :loading="loadingBody"></loading>
|
||||
<chart-no-data v-if="providerOptions.length === 0 && !loadingBody"></chart-no-data>
|
||||
<div class="body__app" v-else :class="{'provide-show': app.provideShow}" v-for="(app, index) in providerOptions" :key="index" @click="appCheckedChange(app, 0)">
|
||||
<chart-no-data v-if="providerOptions.length === 0 && !loadingBody" test-id="noData"></chart-no-data>
|
||||
<div class="body__app" v-else :class="{'provide-show': app.provideShow}" v-for="(app, index) in providerOptions" :key="index" @click="appCheckedChange(app, 0)" :test-id="`provide${index}`">
|
||||
<div class="body__app-content">
|
||||
<div class="body__app-left">
|
||||
<span><i class="cn-icon" :class="app.icon"></i></span>
|
||||
<span class="body__app-left-title">{{app.value}}</span>
|
||||
<span><i class="cn-icon" :class="app.icon" :test-id="`provide-icon${index}`"></i></span>
|
||||
<span class="body__app-left-title" :test-id="`provide-title${index}`">{{app.value}}</span>
|
||||
</div>
|
||||
<div class="body__app-content-right" v-if="app.provideShow"><span><i class="cn-icon cn-icon-a-allclear"></i></span></div>
|
||||
</div>
|
||||
<div class="body__app-value" v-if="app.remark" :title="app.remark">{{app.remark}}</div>
|
||||
<div class="body__app-value" v-if="app.remark" :title="app.remark" :test-id="`provide-remark${index}`">{{app.remark}}</div>
|
||||
<div v-else>-</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -89,22 +89,22 @@
|
||||
<div class="body__apps" :class="{'body__apps-no-grid': appOptions.length === 0}">
|
||||
<loading :loading="loadingBody"></loading>
|
||||
<chart-no-data v-if="appOptions.length === 0 && !loadingBody"></chart-no-data>
|
||||
<div class="body__app" v-else :class="{'app-show': app.appShow}" v-for="(app, index) in appOptions" :key="index" @click="appCheckedChange(app, 1)">
|
||||
<div class="body__app" v-else :class="{'app-show': app.appShow}" v-for="(app, index) in appOptions" :key="index" @click="appCheckedChange(app, 1)" :test-id="`app${index}`">
|
||||
<div class="body__app-content">
|
||||
<div class="body__app-left">
|
||||
<span><i class="cn-icon" :class="app.icon"></i></span>
|
||||
<span class="body__app-left-title">{{app.value}}</span>
|
||||
<span><i class="cn-icon" :class="app.icon" :test-id="`app-icon${index}`"></i></span>
|
||||
<span class="body__app-left-title" :test-id="`app-title${index}`">{{app.value}}</span>
|
||||
</div>
|
||||
<div class="body__app-content-right" v-if="app.appShow"><span><i class="cn-icon cn-icon-a-allclear"></i></span></div>
|
||||
</div>
|
||||
<div class="body__app-value" v-if="app.remark" :title="app.remark">{{app.remark}}</div>
|
||||
<div class="body__app-value" v-if="app.remark" :title="app.remark" :test-id="`app-remark${index}`">{{app.remark}}</div>
|
||||
<div v-else>-</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="body__searcher">
|
||||
<el-input v-model="searcherApp" @input="searcherAppChange" size="mini" :placeholder="$t('networkOverview.search')" prefix-icon="el-icon-search"></el-input>
|
||||
<el-input v-model="searcherApp" @input="searcherAppChange" size="mini" :placeholder="$t('networkOverview.search')" prefix-icon="el-icon-search" test-id="search-input"></el-input>
|
||||
</div>
|
||||
<div class="body__loading"><loading :loading="loading"></loading></div>
|
||||
</div>
|
||||
@@ -119,7 +119,7 @@ import { storageKey, unitTypes, networkTable, operationType, curTabState } from
|
||||
import * as echarts from 'echarts'
|
||||
import { appListChartOption } from '@/views/charts2/charts/options/echartOption'
|
||||
import { shallowRef } from 'vue'
|
||||
import { get, put } from '@/utils/http'
|
||||
import { put } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import _ from 'lodash'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
@@ -128,6 +128,7 @@ import loading from '@/components/common/Loading'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import { appStackedLineTooltipFormatter } from '@/views/charts/charts/tools'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'NetworkOverviewApps',
|
||||
@@ -152,7 +153,6 @@ export default {
|
||||
searcherApp: '',
|
||||
// 选中的app,不区分app和provider
|
||||
toSaveApp: [],
|
||||
appShowType: 'bytes',
|
||||
pageObj: { // 分页对象
|
||||
pageNo: 1,
|
||||
pageSize: 24,
|
||||
@@ -228,8 +228,8 @@ export default {
|
||||
return `'${item.name}'`
|
||||
}).join(',')
|
||||
}
|
||||
prevRequest = get(api.netWorkOverview.applicationCycleTrafficTotal, params)
|
||||
request = get(api.netWorkOverview.applicationTrafficAnalysis, params)
|
||||
prevRequest = axios.get(api.netWorkOverview.applicationCycleTrafficTotal, { params: params })
|
||||
request = axios.get(api.netWorkOverview.applicationTrafficAnalysis, { params: params })
|
||||
this.handleData(prevRequest, request, 'app')
|
||||
}
|
||||
if (providerCards.length > 0) {
|
||||
@@ -240,15 +240,15 @@ export default {
|
||||
return `'${item.name}'`
|
||||
}).join(',')
|
||||
}
|
||||
prevRequest = get(api.netWorkOverview.appCompanyCycleTrafficTotal, params)
|
||||
request = get(api.netWorkOverview.appCompanyTrafficAnalysis, params)
|
||||
prevRequest = axios.get(api.netWorkOverview.appCompanyCycleTrafficTotal, { params: params })
|
||||
request = axios.get(api.netWorkOverview.appCompanyTrafficAnalysis, { params: params })
|
||||
this.handleData(prevRequest, request, 'provider')
|
||||
}
|
||||
},
|
||||
handleData (prevRequest, request, _t) {
|
||||
this.toggleLoading(true)
|
||||
Promise.all([prevRequest, request]).then(res => {
|
||||
this.isNoData = (res[0].data.result.length && res[1].data.result.length) === 0
|
||||
this.isNoData = (res[0].data.data.result.length && res[1].data.data.result.length) === 0
|
||||
if (this.isNoData) {
|
||||
this.appData = this.appData.map(t => {
|
||||
return {
|
||||
@@ -257,10 +257,10 @@ export default {
|
||||
}
|
||||
})
|
||||
}
|
||||
if (res[0].code === 200 && res[1].code === 200) {
|
||||
if (res[0].data.code === 200 && res[1].data.code === 200) {
|
||||
this.showError = false
|
||||
const prevData = res[0].data.result
|
||||
const data = res[1].data.result
|
||||
const prevData = res[0].data.data.result
|
||||
const data = res[1].data.data.result
|
||||
let toCompareType = 'bytes'
|
||||
if (this.metric === 'Sessions/s') {
|
||||
toCompareType = 'sessions'
|
||||
@@ -298,16 +298,6 @@ export default {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
},
|
||||
metricChange (value) {
|
||||
if (value === 'Bits/s') {
|
||||
this.appShowType = 'bytes'
|
||||
} else if (value === 'Packets/s') {
|
||||
this.appShowType = 'packets'
|
||||
} else if (value === 'Sessions/s') {
|
||||
this.appShowType = 'sessions'
|
||||
}
|
||||
this.init()
|
||||
},
|
||||
getUrlParam (param, defaultValue, isNumber) {
|
||||
if (isNumber) {
|
||||
return this.$route.query[param] ? Number(this.$route.query[param]) : defaultValue
|
||||
@@ -401,6 +391,7 @@ export default {
|
||||
this.urlChangeParams = {}
|
||||
},
|
||||
initChart (obj) {
|
||||
if (!this.isUnitTesting) {
|
||||
let chart = this.myChart.find(m => m.name === obj.name && m.type === obj.type)
|
||||
if (!chart) {
|
||||
chart = echarts.init(document.getElementById(`chart-${obj.name}-${obj.type}`))
|
||||
@@ -434,6 +425,7 @@ export default {
|
||||
chart.resize()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
handleScroll (e) {
|
||||
const clientHeight = e.target.clientHeight
|
||||
@@ -469,8 +461,9 @@ export default {
|
||||
}
|
||||
if (parseFloat(this.appTypeTab) === 0) {
|
||||
params.type = 'overviewProvide'
|
||||
get(api.dict, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
axios.get(api.dict, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200 && res.data.list) {
|
||||
res.data.list = res.data.list.filter(l => !this.appData.some(pd => pd.type === 'provider' && pd.name === l.value))
|
||||
this.pageObj.pages = res.data.pages
|
||||
res.data.list.forEach(t => {
|
||||
@@ -494,9 +487,10 @@ export default {
|
||||
})
|
||||
} else if (parseFloat(this.appTypeTab) === 1) {
|
||||
params.type = 'overviewApp'
|
||||
get(api.dict, params).then(res => {
|
||||
res.data.list = res.data.list.filter(l => !this.appData.some(pd => pd.type === 'app' && pd.name === l.value))
|
||||
axios.get(api.dict, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
res.data.list = res.data.list.filter(l => !this.appData.some(pd => pd.type === 'app' && pd.name === l.value))
|
||||
this.pageObj.pages = res.data.pages
|
||||
res.data.list.forEach(t => {
|
||||
this.toSaveApp.forEach(e => {
|
||||
@@ -675,13 +669,6 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
// moreChange (app) {
|
||||
// this.appData.forEach(t => {
|
||||
// if (t.name === app.name && t.type === app.type) {
|
||||
// t.moreOptions = !t.moreOptions
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
resize () {
|
||||
this.myChart.forEach(t => {
|
||||
t.resize()
|
||||
@@ -718,7 +705,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.chart.params && this.chart.params.app) {
|
||||
if (this.chart && this.chart.params && this.chart.params.app) {
|
||||
const userId = parseInt(localStorage.getItem(storageKey.userId))
|
||||
const apps = _.cloneDeep(this.chart.params.app)
|
||||
let app = apps.find(p => p.user === userId)
|
||||
@@ -734,7 +721,9 @@ export default {
|
||||
window.removeEventListener('resize', this.resize)
|
||||
clearTimeout(this.timerScroll)
|
||||
clearTimeout(this.timerSearch)
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="ddos-detection">
|
||||
<chart-no-data v-if="isNoData"></chart-no-data>
|
||||
<chart-no-data v-if="isNoData" test-id="noData"></chart-no-data>
|
||||
<chart-error info v-if="showError" :content="errorMsg" />
|
||||
|
||||
<div class="ddos-detection-title">
|
||||
@@ -11,15 +11,15 @@
|
||||
<div class="ddos-detection-type">
|
||||
<div class="ddos-detection-type-value">
|
||||
<div class="ddos-detection-type-value-name">{{$t('network.numberOfAttacks')}}</div>
|
||||
<div class="ddos-detection-type-value-number">{{$_.get(ddosData, 'attackerCount') || 0}}</div>
|
||||
<div class="ddos-detection-type-value-number" test-id="attackerCount">{{unitConvert($_.get(ddosData, 'attackerCount'), unitTypes.number).join(' ')}}</div>
|
||||
</div>
|
||||
<div class="ddos-detection-type-value">
|
||||
<div class="ddos-detection-type-value-name">{{$t('network.number0fVictims')}}</div>
|
||||
<div class="ddos-detection-type-value-number">{{$_.get(ddosData, 'victimCount') || 0}}</div>
|
||||
<div class="ddos-detection-type-value-number" test-id="victimCount">{{unitConvert($_.get(ddosData, 'victimCount'), unitTypes.number).join(' ')}}</div>
|
||||
</div>
|
||||
<div class="ddos-detection-type-value">
|
||||
<div class="ddos-detection-type-value-name">{{$t('network.number0fDetectedAttackEvents')}}</div>
|
||||
<div class="ddos-detection-type-value-number ddos-event">{{$_.get(ddosData, 'attackEventCount') || 0}}</div>
|
||||
<div class="ddos-detection-type-value-number ddos-event" test-id="attackEventCount">{{unitConvert($_.get(ddosData, 'attackEventCount'), unitTypes.number).join(' ')}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-button size="small">{{$t('network.ddosDetection')}}<i class="cn-icon cn-icon-arrow-right"></i></el-button>
|
||||
@@ -29,11 +29,13 @@
|
||||
|
||||
<script>
|
||||
import { api } from '@/utils/api'
|
||||
import { get } from '@/utils/http'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import ChartError from '@/components/common/Error'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { unitTypes } from '@/utils/constants'
|
||||
import axios from 'axios'
|
||||
export default {
|
||||
name: 'NetworkOverviewDdosDetection',
|
||||
components: {
|
||||
@@ -44,6 +46,8 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
ddosData: {},
|
||||
unitConvert,
|
||||
unitTypes,
|
||||
isNoData: false,
|
||||
showError: false,
|
||||
errorMsg: ''
|
||||
@@ -59,19 +63,16 @@ export default {
|
||||
methods: {
|
||||
ddosDetectDataRequests () {
|
||||
const params = {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
startTime: this.timeFilter && this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : '',
|
||||
endTime: this.timeFilter && this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : ''
|
||||
}
|
||||
this.toggleLoading(true)
|
||||
get(api.netWorkOverview.ddosEventAnalysis, params).then(res => {
|
||||
axios.get(api.netWorkOverview.ddosEventAnalysis, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
if (res.data.result.length === 0) {
|
||||
this.isNoData = true
|
||||
} else {
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.ddosData = res.data.result[0]
|
||||
this.isNoData = false
|
||||
}
|
||||
} else {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
@@ -87,7 +88,12 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.ddosDetectDataRequests()
|
||||
})
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -5,25 +5,29 @@
|
||||
<div class="line-header-left">
|
||||
<div class="line-value-active" v-if="lineTab"></div>
|
||||
<div class="line-value">
|
||||
<div class="line-value-mpackets"
|
||||
v-show="item.show"
|
||||
<template v-for="(item, index) in tabs">
|
||||
<div class="line-value-tabs"
|
||||
:class=" {'is-active': lineTab === item.class, 'mousemove-cursor': mousemoveCursor === item.class}"
|
||||
v-for="(item, index) in mpackets"
|
||||
v-if="item.show"
|
||||
:key="index"
|
||||
@mouseenter="mouseenter(item)"
|
||||
@mouseleave="mouseleave(item)"
|
||||
@click="activeChange(item, index)">
|
||||
<div class="line-value-mpackets-name">
|
||||
@click="activeChange(item, index,true)"
|
||||
:test-id="`tab${index}`"
|
||||
>
|
||||
<div class="line-value-tabs-name">
|
||||
<div :class="item.class"></div>
|
||||
<div class="mpackets-name">{{$t(item.name)}}</div>
|
||||
<div class="tabs-name" :test-id="`tabTitle${index}`">{{ $t(item.name) }}</div>
|
||||
</div>
|
||||
<div class="line-value-unit">
|
||||
<div class="line-value-unit" :test-id="`tabContent${index}`">
|
||||
<span class="line-value-unit-number">{{ unitConvert(item.analysis.avg, unitTypes.number)[0] }}</span>
|
||||
<span class="line-value-unit-number2">
|
||||
<span>{{unitConvert(item.analysis.avg, unitTypes.number)[1]}}</span><span v-if="item.unitType">{{item.unitType}}</span>
|
||||
<span>{{ unitConvert(item.analysis.avg, unitTypes.number)[1] }}</span>
|
||||
<span v-if="item.unitType">{{ item.unitType }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-select line-header-right">
|
||||
@@ -46,7 +50,7 @@
|
||||
</div>
|
||||
<div style="height: calc(100% - 74px); position: relative">
|
||||
<chart-no-data v-if="isNoData && !showError"></chart-no-data>
|
||||
<div class="chart-drawing" v-show="showMarkLine && !isNoData && !showError" id="overviewLineChart"></div>
|
||||
<div class="chart-drawing" v-show="showMarkLine && !isNoData && !showError" ref="overviewLineChart"></div>
|
||||
<!-- todo 后续改动,此处为框选返回-->
|
||||
<!-- <div id="brushBtn" style="position: absolute;left: 0;top: 0;" v-show="mouseDownFlag">-->
|
||||
<!-- <el-button @click.stop="backBrushHistory">返回</el-button>-->
|
||||
@@ -63,14 +67,15 @@ import { unitTypes, chartColor3, chartColor4 } from '@/utils/constants.js'
|
||||
import { ref, shallowRef } from 'vue'
|
||||
import { stackedLineTooltipFormatter } from '@/views/charts/charts/tools'
|
||||
import _ from 'lodash'
|
||||
import { get } from '@/utils/http'
|
||||
import axios from 'axios'
|
||||
import { api } from '@/utils/api'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { getLineType, overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import ChartError from '@/components/common/Error'
|
||||
|
||||
export default {
|
||||
name: 'NetworkOverviewLine',
|
||||
components: {
|
||||
@@ -116,14 +121,69 @@ export default {
|
||||
label: 'Maximum'
|
||||
}
|
||||
],
|
||||
mpackets: [
|
||||
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.inbound', class: 'inbound', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.outbound', class: 'outbound', show: true, invertTab: true, positioning: 2, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.internal', class: 'internal', show: true, invertTab: true, positioning: 3, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.through', class: 'through', show: true, invertTab: true, positioning: 4, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.other', class: 'other', show: true, invertTab: true, positioning: 5, data: [], unitType: '' }
|
||||
tabsTemplate: [
|
||||
{
|
||||
analysis: {},
|
||||
name: 'network.total',
|
||||
class: 'total',
|
||||
show: true,
|
||||
invertTab: true,
|
||||
positioning: 0,
|
||||
data: [],
|
||||
unitType: ''
|
||||
},
|
||||
{
|
||||
analysis: {},
|
||||
name: 'network.inbound',
|
||||
class: 'inbound',
|
||||
show: true,
|
||||
invertTab: true,
|
||||
positioning: 1,
|
||||
data: [],
|
||||
unitType: ''
|
||||
},
|
||||
{
|
||||
analysis: {},
|
||||
name: 'network.outbound',
|
||||
class: 'outbound',
|
||||
show: true,
|
||||
invertTab: true,
|
||||
positioning: 2,
|
||||
data: [],
|
||||
unitType: ''
|
||||
},
|
||||
{
|
||||
analysis: {},
|
||||
name: 'network.internal',
|
||||
class: 'internal',
|
||||
show: true,
|
||||
invertTab: true,
|
||||
positioning: 3,
|
||||
data: [],
|
||||
unitType: ''
|
||||
},
|
||||
{
|
||||
analysis: {},
|
||||
name: 'network.through',
|
||||
class: 'through',
|
||||
show: true,
|
||||
invertTab: true,
|
||||
positioning: 4,
|
||||
data: [],
|
||||
unitType: ''
|
||||
},
|
||||
{
|
||||
analysis: {},
|
||||
name: 'network.other',
|
||||
class: 'other',
|
||||
show: true,
|
||||
invertTab: true,
|
||||
positioning: 5,
|
||||
data: [],
|
||||
unitType: ''
|
||||
}
|
||||
],
|
||||
tabs: [],
|
||||
unitConvert,
|
||||
unitTypes,
|
||||
chartDateObject: [],
|
||||
@@ -169,7 +229,7 @@ export default {
|
||||
metric (n) {
|
||||
this.handleActiveBar()
|
||||
this.showMarkLine = !this.showMarkLine
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
if (!e.invertTab) {
|
||||
e.invertTab = true
|
||||
}
|
||||
@@ -186,161 +246,23 @@ export default {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
let condition = ''
|
||||
if (this.queryCondition && this.tabOperationType !== '3') {
|
||||
if (this.queryCondition) {
|
||||
params.q = this.queryCondition
|
||||
} else if (this.tabOperationType == '3' && this.queryCondition) {
|
||||
if (this.queryCondition.indexOf(' OR ') > -1) {
|
||||
if (this.networkOverviewBeforeTab === 'isp') {
|
||||
condition = this.queryCondition.split(/["|'= ](.*?)["|'= ]/)
|
||||
params.q = `notEmpty(${condition[0]}) OR notEmpty(${condition[9]})`
|
||||
} else {
|
||||
condition = this.queryCondition.split(/["|'= ](.*?)["|'= ]/)
|
||||
params.q = `notEmpty(${condition[0]}) OR notEmpty(${condition[5]})`
|
||||
}
|
||||
} else {
|
||||
condition = this.queryCondition.split(/['=](.*?)['=]/)
|
||||
params.q = `notEmpty(${condition[0]})`
|
||||
}
|
||||
}
|
||||
this.toggleLoading(true)
|
||||
|
||||
get(api.netWorkOverview.totalTrafficAnalysis, params).then((res) => {
|
||||
axios.get(api.netWorkOverview.totalTrafficAnalysis, { params: params }).then(response => {
|
||||
const res = response.data
|
||||
// const res = mockData.bytes.boundary.data
|
||||
this.errorMsg = res.message
|
||||
|
||||
if (res.code === 200) {
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.showError = false
|
||||
|
||||
if (this.isNoData) {
|
||||
this.lineTab = ''
|
||||
this.mpackets = [
|
||||
{ analysis: {}, name: 'network.total', class: 'total', show: true, invertTab: true, positioning: 0, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.inbound', class: 'inbound', show: true, invertTab: true, positioning: 1, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.outbound', class: 'outbound', show: true, invertTab: true, positioning: 2, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.internal', class: 'internal', show: true, invertTab: true, positioning: 3, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.through', class: 'through', show: true, invertTab: true, positioning: 4, data: [], unitType: '' },
|
||||
{ analysis: {}, name: 'network.other', class: 'other', show: true, invertTab: true, positioning: 5, data: [], unitType: '' }
|
||||
]
|
||||
}
|
||||
res.data.result.forEach((t) => {
|
||||
if (t.type === 'bytes' && val === 'Bits/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].analysis = t.totalBitsRate.analysis
|
||||
mpackets[1].analysis = t.inboundBitsRate.analysis
|
||||
mpackets[2].analysis = t.outboundBitsRate.analysis
|
||||
mpackets[3].analysis = t.internalBitsRate.analysis
|
||||
mpackets[4].analysis = t.throughBitsRate.analysis
|
||||
mpackets[5].analysis = t.other.analysis
|
||||
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
|
||||
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
|
||||
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
|
||||
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
|
||||
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
|
||||
mpackets[5].data = t.other.values ? t.other.values : []
|
||||
let num = 0
|
||||
mpackets.forEach(e => {
|
||||
e.unitType = 'bps'
|
||||
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
|
||||
e.show = false
|
||||
num += 1
|
||||
this.tabs = _.cloneDeep(this.tabsTemplate)
|
||||
} else {
|
||||
e.show = true
|
||||
if (!active && show !== this.lineRefer) {
|
||||
this.legendSelectChange(e, 'index')
|
||||
this.initData(res.data.result, val, active, show, n)
|
||||
}
|
||||
}
|
||||
if (this.lineTab === e.class) {
|
||||
if (parseFloat(e.analysis.avg) <= 0) {
|
||||
this.lineTab = ''
|
||||
this.lineRefer = ''
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
if (num === 5) {
|
||||
mpackets[0].invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(mpackets[0], 0)
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.mpackets, true)
|
||||
})
|
||||
} else {
|
||||
if (n) this.lineTab = ''
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.mpackets, show)
|
||||
if (!this.lineRefer) this.lineRefer = 'Average'
|
||||
})
|
||||
}
|
||||
} else if (t.type === 'packets' && val === 'Packets/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].analysis = t.totalPacketsRate.analysis
|
||||
mpackets[1].analysis = t.inboundPacketsRate.analysis
|
||||
mpackets[2].analysis = t.outboundPacketsRate.analysis
|
||||
mpackets[3].analysis = t.internalPacketsRate.analysis
|
||||
mpackets[4].analysis = t.throughPacketsRate.analysis
|
||||
mpackets[5].analysis = t.other.analysis
|
||||
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
|
||||
mpackets[1].data = t.inboundPacketsRate.values ? t.inboundPacketsRate.values : []
|
||||
mpackets[2].data = t.outboundPacketsRate.values ? t.outboundPacketsRate.values : []
|
||||
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
|
||||
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
|
||||
mpackets[5].data = t.other.values ? t.other.values : []
|
||||
let num = 0
|
||||
mpackets.forEach(e => {
|
||||
e.unitType = 'packets/s'
|
||||
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
|
||||
e.show = false
|
||||
num += 1
|
||||
} else {
|
||||
e.show = true
|
||||
if (!active && show !== this.lineRefer) {
|
||||
this.legendSelectChange(e, 'index')
|
||||
}
|
||||
}
|
||||
if (this.lineTab === e.class) {
|
||||
if (parseFloat(e.analysis.avg) <= 0) {
|
||||
this.lineTab = ''
|
||||
this.lineRefer = ''
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
if (num === 5) {
|
||||
mpackets[0].invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(mpackets[0], 0)
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.mpackets, true)
|
||||
})
|
||||
} else {
|
||||
if (n) this.lineTab = ''
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.mpackets, show)
|
||||
if (!this.lineRefer) this.lineRefer = 'Average'
|
||||
})
|
||||
}
|
||||
} else if (t.type === 'sessions' && val === 'Sessions/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].analysis = t.totalSessionsRate.analysis
|
||||
mpackets[0].data = t.totalSessionsRate.values ? t.totalSessionsRate.values : []
|
||||
mpackets.forEach((e, i) => {
|
||||
if (i !== 0) {
|
||||
e.show = false
|
||||
}
|
||||
e.unitType = 'sessions/s'
|
||||
e.invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(e, 0)
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.mpackets, true)
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.showError = true
|
||||
this.errorMsg = res.message
|
||||
@@ -357,44 +279,47 @@ export default {
|
||||
/**
|
||||
* 初始化echartsdom,用于右键点击返回框选
|
||||
*/
|
||||
domInit () {
|
||||
const self = this
|
||||
// 去掉默认的contextmenu事件,否则会和右键事件同时出现。
|
||||
document.oncontextmenu = function (e) {
|
||||
e.preventDefault()
|
||||
}
|
||||
document.getElementById('overviewLineChart').onmousedown = function (e) {
|
||||
// e.button: 0左键,1滚轮,2右键
|
||||
if (e.button === 2) {
|
||||
self.myChart.dispatchAction({
|
||||
type: 'brush',
|
||||
areas: [] // 删除选框
|
||||
})
|
||||
self.mouseDownFlag = true
|
||||
document.getElementById('brushBtn').style.left = e.layerX + 'px'
|
||||
document.getElementById('brushBtn').style.top = e.layerY + 74 + 'px'
|
||||
}
|
||||
}
|
||||
},
|
||||
// domInit () {
|
||||
// const self = this
|
||||
// // 去掉默认的contextmenu事件,否则会和右键事件同时出现。
|
||||
// document.oncontextmenu = function (e) {
|
||||
// e.preventDefault()
|
||||
// }
|
||||
// document.getElementById('overviewLineChart').onmousedown = function (e) {
|
||||
// // e.button: 0左键,1滚轮,2右键
|
||||
// if (e.button === 2) {
|
||||
// self.myChart.dispatchAction({
|
||||
// type: 'brush',
|
||||
// areas: [] // 删除选框
|
||||
// })
|
||||
// self.mouseDownFlag = true
|
||||
// document.getElementById('brushBtn').style.left = e.layerX + 'px'
|
||||
// document.getElementById('brushBtn').style.top = e.layerY + 74 + 'px'
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
echartsInit (echartsData, show) {
|
||||
// echarts内容在单元测试时不执行
|
||||
if (!this.isUnitTesting) {
|
||||
if (this.lineTab) {
|
||||
this.handleActiveBar()
|
||||
echartsData = echartsData.filter(t => t.show === true && t.invertTab === false)
|
||||
echartsData = echartsData.filter(t => t.show === true && t.class === this.lineTab) // t.invertTab === false
|
||||
} else {
|
||||
echartsData = echartsData.filter(t => t.show === true)
|
||||
}
|
||||
const _this = this
|
||||
// !this.myChart && (this.myChart = echarts.init(dom))
|
||||
// 此处为验证是否因dom未销毁,导致图表出错,后续可能会改
|
||||
let dom = null
|
||||
dom = document.getElementById('overviewLineChart')
|
||||
|
||||
this.chartOption = stackedLineChartOption
|
||||
const chartOption = this.chartOption.series[0]
|
||||
this.chartOption.series = echartsData.map((t, i) => {
|
||||
return {
|
||||
...chartOption,
|
||||
name: t.name,
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
lineStyle: {
|
||||
color: chartColor3[t.positioning],
|
||||
width: 1
|
||||
@@ -476,7 +401,7 @@ export default {
|
||||
this.chartOption.tooltip.formatter = (params) => {
|
||||
params.forEach(t => {
|
||||
t.seriesName = this.$t(t.seriesName)
|
||||
this.mpackets.forEach(e => {
|
||||
this.tabs.forEach(e => {
|
||||
if (this.$t(e.name) === t.seriesName) {
|
||||
t.borderColor = chartColor3[e.positioning]
|
||||
}
|
||||
@@ -486,7 +411,7 @@ export default {
|
||||
}
|
||||
this.showMarkLine = true
|
||||
this.$nextTick(() => {
|
||||
this.myChart = echarts.init(dom)
|
||||
this.myChart = echarts.init(this.$refs.overviewLineChart)
|
||||
this.myChart.setOption(this.chartOption)
|
||||
// 设置参见官网:https://echarts.apache.org/zh/api.html#action.brush.brush
|
||||
this.myChart.dispatchAction({
|
||||
@@ -534,12 +459,19 @@ export default {
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
activeChange (item, index) {
|
||||
activeChange (item, index, isClick) { // isClick:代表是通过点击操作来的
|
||||
if (this.isNoData) return
|
||||
if (isClick && this.lineTab === item.class) { // 点击高亮 tab 后取消高亮,恢复到全不高亮的状态
|
||||
this.legendSelectChange(item, index, 'active', true)
|
||||
this.lineTab = ''
|
||||
this.showMarkLine = false
|
||||
} else {
|
||||
this.lineTab = item.class
|
||||
this.legendSelectChange(item, index, 'active')
|
||||
this.showMarkLine = !item.invertTab
|
||||
}
|
||||
this.init(this.metric, this.showMarkLine, 'active')
|
||||
},
|
||||
mouseenter (item) {
|
||||
@@ -562,19 +494,25 @@ export default {
|
||||
name: name
|
||||
})
|
||||
},
|
||||
legendSelectChange (item, index, val) {
|
||||
legendSelectChange (item, index, val, isActiveAll) {
|
||||
if (index === 'index') {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
} else if (this.mpackets[index] && this.mpackets[index].name === item.name) {
|
||||
} else if (this.tabs[index] && this.tabs[index].name === item.name) {
|
||||
if (isActiveAll) {
|
||||
this.tabs.forEach((t) => {
|
||||
this.dispatchLegendSelectAction(t.name)
|
||||
})
|
||||
} else {
|
||||
this.dispatchLegendSelectAction(item.name)
|
||||
this.mpackets.forEach((t) => {
|
||||
this.tabs.forEach((t) => {
|
||||
if (t.name !== item.name) {
|
||||
this.dispatchLegendUnSelectAction(t.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
if (val === 'active') {
|
||||
this.mpackets.forEach(t => {
|
||||
this.tabs.forEach(t => {
|
||||
if (item.name === t.name) {
|
||||
t.invertTab = !t.invertTab
|
||||
} else {
|
||||
@@ -586,7 +524,7 @@ export default {
|
||||
} else {
|
||||
this.lineTab = t.class
|
||||
}
|
||||
this.mpackets.forEach((e) => {
|
||||
this.tabs.forEach((e) => {
|
||||
this.dispatchLegendSelectAction(e.name)
|
||||
})
|
||||
}
|
||||
@@ -594,44 +532,52 @@ export default {
|
||||
}
|
||||
},
|
||||
handleActiveBar () {
|
||||
if (document.querySelector('.network .line-value-mpackets.is-active')) {
|
||||
const { offsetLeft, clientWidth, clientLeft } = document.querySelector('.network .line-value-mpackets.is-active')
|
||||
if (document.querySelector('.network .line-value-tabs.is-active')) {
|
||||
const {
|
||||
offsetLeft,
|
||||
clientWidth,
|
||||
clientLeft
|
||||
} = document.querySelector('.network .line-value-tabs.is-active')
|
||||
const activeBar = document.querySelector('.network .line-value-active')
|
||||
activeBar.style.cssText += `width: ${clientWidth}px; left: ${offsetLeft + this.leftOffset + clientLeft}px;`
|
||||
}
|
||||
},
|
||||
resize () {
|
||||
if (this.myChart) {
|
||||
this.myChart.resize()
|
||||
}
|
||||
},
|
||||
referenceSelectChange (val) {
|
||||
this.lineRefer = val
|
||||
let echartsData
|
||||
const chartOption = this.myChart.getOption()
|
||||
if (this.lineTab) {
|
||||
echartsData = this.mpackets.filter(t => t.show === true && t.invertTab === false)
|
||||
echartsData = this.tabs.filter(t => t.show === true && t.class === this.lineTab) // t.invertTab === false
|
||||
} else {
|
||||
echartsData = this.mpackets.filter(t => t.show === true)
|
||||
echartsData = this.tabs.filter(t => t.show === true)
|
||||
}
|
||||
if (!this.isUnitTesting) {
|
||||
const chartOption = this.myChart.getOption()
|
||||
if (this.lineRefer === 'Average' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
chartOption.series.forEach((t) => {
|
||||
if (t.name === echartsData[0].name) {
|
||||
t.markLine.data = [{ yAxis: echartsData[0].analysis.avg }]
|
||||
}
|
||||
})
|
||||
} else if (this.lineRefer === '95th Percentile' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
chartOption.series.forEach((t) => {
|
||||
if (t.name === echartsData[0].name) {
|
||||
t.markLine.data = [{ yAxis: echartsData[0].analysis.p95 }]
|
||||
}
|
||||
})
|
||||
} else if (this.lineRefer === 'Maximum' && this.showMarkLine) {
|
||||
chartOption.series.forEach((t, i) => {
|
||||
chartOption.series.forEach((t) => {
|
||||
if (t.name === echartsData[0].name) {
|
||||
t.markLine.data = [{ yAxis: echartsData[0].analysis.max }]
|
||||
}
|
||||
})
|
||||
}
|
||||
this.myChart.setOption(chartOption)
|
||||
}
|
||||
},
|
||||
symbolSizeSortChange (index, time) {
|
||||
const dataIntegrationArray = []
|
||||
@@ -677,38 +623,121 @@ export default {
|
||||
otherData[2] = 5
|
||||
}
|
||||
}
|
||||
dataIntegrationArray.sort((a, b) => { return a[1] - b[1] })
|
||||
dataIntegrationArray.sort((a, b) => {
|
||||
return a[1] - b[1]
|
||||
})
|
||||
const sortIndex = dataIntegrationArray.findIndex(a => a[2] === index)
|
||||
return this.sizes[sortIndex]
|
||||
},
|
||||
initData (data, val, active, show, n) {
|
||||
let lineData = []
|
||||
if (data !== undefined && data.length > 0) {
|
||||
data.forEach((item) => {
|
||||
item.type = getLineType(item.type)
|
||||
if (item.type === val) {
|
||||
lineData = Object.keys(item).map(t => {
|
||||
return {
|
||||
...item[t]
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
lineData.splice(0, 1)
|
||||
if (val === 'Sessions/s') {
|
||||
const tabs = _.cloneDeep(this.tabsTemplate)
|
||||
lineData.forEach((d, i) => {
|
||||
tabs[i].data = d.values
|
||||
tabs[i].analysis = d.analysis
|
||||
})
|
||||
tabs.forEach((e, i) => {
|
||||
if (i !== 0) {
|
||||
e.show = false
|
||||
}
|
||||
e.unitType = 'sessions/s'
|
||||
e.invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(e, 0)
|
||||
})
|
||||
this.tabs = tabs
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.tabs, true)
|
||||
})
|
||||
} else {
|
||||
const unit = val === 'Bits/s' ? 'bps' : 'packets/s'
|
||||
this.legendInit(lineData, active, show, unit, n)
|
||||
}
|
||||
},
|
||||
legendInit (data, active, show, type, n) {
|
||||
const tabs = _.cloneDeep(this.tabsTemplate)
|
||||
data.forEach((d, i) => {
|
||||
tabs[i].data = d.values
|
||||
tabs[i].analysis = d.analysis
|
||||
})
|
||||
let num = 0
|
||||
const self = this
|
||||
tabs.forEach(e => {
|
||||
e.unitType = type
|
||||
if (e.name !== 'network.total' && parseFloat(e.analysis.avg) === 0) {
|
||||
e.show = false
|
||||
num += 1
|
||||
} else {
|
||||
e.show = true
|
||||
if (!active && show !== self.lineRefer) {
|
||||
self.legendSelectChange(e, 'index')
|
||||
}
|
||||
}
|
||||
if (self.lineTab === e.class) {
|
||||
if (parseFloat(e.analysis.avg) <= 0) {
|
||||
self.lineTab = ''
|
||||
self.lineRefer = ''
|
||||
self.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
this.tabs = tabs
|
||||
if (num === 5) {
|
||||
tabs[0].invertTab = false
|
||||
this.lineTab = 'total'
|
||||
this.legendSelectChange(tabs[0], 0)
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.tabs, true)
|
||||
})
|
||||
} else {
|
||||
if (n) this.lineTab = ''
|
||||
this.$nextTick(() => {
|
||||
this.echartsInit(this.tabs, show)
|
||||
if (!this.lineRefer) this.lineRefer = 'Average'
|
||||
})
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 鼠标右键返回框选的时间范围
|
||||
*/
|
||||
backBrushHistory () {
|
||||
this.myChart.dispatchAction({
|
||||
type: 'brush',
|
||||
areas: [] // 删除选框
|
||||
})
|
||||
if (this.brushHistory.length > 0) {
|
||||
this.$store.commit('setRangeEchartsData', _.cloneDeep(this.brushHistory[0]))
|
||||
this.brushHistory.shift()
|
||||
}
|
||||
this.mouseDownFlag = false
|
||||
}
|
||||
// backBrushHistory () {
|
||||
// this.myChart.dispatchAction({
|
||||
// type: 'brush',
|
||||
// areas: [] // 删除选框
|
||||
// })
|
||||
// if (this.brushHistory.length > 0) {
|
||||
// this.$store.commit('setRangeEchartsData', _.cloneDeep(this.brushHistory[0]))
|
||||
// this.brushHistory.shift()
|
||||
// }
|
||||
// this.mouseDownFlag = false
|
||||
// }
|
||||
},
|
||||
mounted () {
|
||||
// todo 初始化鼠标事件,开启右键返回
|
||||
// this.domInit()
|
||||
this.myChart = null
|
||||
this.chartOption = null
|
||||
this.timer = setTimeout(() => {
|
||||
if (this.lineTab) {
|
||||
const data = this.mpackets.find(t => t.class === this.lineTab)
|
||||
if (data && data.positioning) {
|
||||
this.activeChange(data, data.positioning)
|
||||
}
|
||||
const self = this
|
||||
self.timer = setTimeout(() => {
|
||||
if (self.lineTab && self.metric !== 'Sessions/s') {
|
||||
const data = self.tabsTemplate.find(t => t.class === self.lineTab)
|
||||
self.activeChange(data, data.positioning)
|
||||
} else {
|
||||
this.init()
|
||||
self.init()
|
||||
}
|
||||
}, 200)
|
||||
window.addEventListener('resize', this.resize)
|
||||
@@ -717,11 +746,13 @@ export default {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
|
||||
let myChart = echarts.getInstanceByDom(document.getElementById('overviewLineChart'))
|
||||
let myChart = echarts.getInstanceByDom(this.$refs.overviewLineChart)
|
||||
if (myChart) {
|
||||
echarts.dispose(myChart)
|
||||
}
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
// 检测时发现该方法占用较大内存,且未被释放
|
||||
this.unitConvert = null
|
||||
myChart = null
|
||||
|
||||
@@ -61,7 +61,6 @@ export default {
|
||||
methods: {
|
||||
init () {
|
||||
const params = {
|
||||
// startTime: true,
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
@@ -193,6 +192,14 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
const dom = document.getElementById('chart1')
|
||||
const dom2 = document.getElementById('chart2')
|
||||
if (dom) {
|
||||
echarts.dispose(dom)
|
||||
}
|
||||
if (dom2) {
|
||||
echarts.dispose(dom2)
|
||||
}
|
||||
this.myChart = null
|
||||
this.myChart2 = null
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
border
|
||||
:cell-style="tableCellStyle"
|
||||
:header-cell-style="tableHeaderCellStyle"
|
||||
:row-class-name="rowClassName"
|
||||
:class="tableClass"
|
||||
height="100%"
|
||||
empty-text=" "
|
||||
@@ -47,7 +48,7 @@
|
||||
<template #default="scope" :column="item">
|
||||
<template v-if="item.columnType === tableColumnType.chainRatio" >
|
||||
<div class="data-total" >
|
||||
<div class="data-value">
|
||||
<div class="data-value" :test-id="`data-value-${item.prop}${scope.row.index}`">
|
||||
<template v-if="showUnit && item.unit">
|
||||
{{scope.row[item.prop]?((scope.row[item.prop][0]||scope.row[item.prop][0]===0)? unitConvert(scope.row[item.prop][0], item.unit).join(' ') : '-'):'' }}
|
||||
</template>
|
||||
@@ -55,16 +56,16 @@
|
||||
{{scope.row[item.prop]?((scope.row[item.prop][0]||scope.row[item.prop][0]===0)? unitConvert(scope.row[item.prop][0], unitTypes.number).join(' ') : '-'):'' }}
|
||||
</template>
|
||||
</div>
|
||||
<div class="data-trend">
|
||||
<div class="data-trend" :test-id="`data-trend-all-${item.prop}${scope.row.index}`">
|
||||
<template v-if="scope.row[item.prop]">
|
||||
<div v-if="scope.row[item.prop][1] === 'up'" class="data-total-trend data-total-trend-red">
|
||||
<i class="cn-icon-rise1 cn-icon"></i><span>{{scope.row[item.prop][2]}}</span>
|
||||
<div v-if="scope.row[item.prop][1] === 'up'" class="data-total-trend data-total-trend-red" :test-id="`data-trend-${item.prop}${scope.row.index}`">
|
||||
<i class="cn-icon-rise1 cn-icon" :test-id="`data-trend-icon-${item.prop}${scope.row.index}`"></i><span :test-id="`data-trend-value-${item.prop}${scope.row.index}`">{{scope.row[item.prop][2]}}</span>
|
||||
</div>
|
||||
<div v-else-if="scope.row[item.prop][1] === 'down'" class="data-total-trend data-total-trend-green">
|
||||
<i class="cn-icon-decline cn-icon"></i><span>{{scope.row[item.prop][2]}}</span>
|
||||
<div v-else-if="scope.row[item.prop][1] === 'down'" class="data-total-trend data-total-trend-green" :test-id="`data-trend-${item.prop}${scope.row.index}`">
|
||||
<i class="cn-icon-decline cn-icon" :test-id="`data-trend-icon-${item.prop}${scope.row.index}`"></i><span :test-id="`data-trend-value-${item.prop}${scope.row.index}`">{{scope.row[item.prop][2]}}</span>
|
||||
</div>
|
||||
<div v-else-if="scope.row[item.prop][1] === 'noChange'" class="data-total-trend data-total-trend-black">
|
||||
<i class="cn-icon-constant cn-icon"></i>
|
||||
<div v-else-if="scope.row[item.prop][1] === 'noChange'" class="data-total-trend data-total-trend-black" :test-id="`data-trend-${item.prop}${scope.row.index}`">
|
||||
<i class="cn-icon-constant cn-icon" :test-id="`data-trend-icon-${item.prop}${scope.row.index}`"></i>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
@@ -74,7 +75,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.columnType === tableColumnType.dillDown" >
|
||||
<div v-if="isOnlyRead" >
|
||||
<div v-if="isOnlyRead" :test-id="`dnsMapType-${scope.row.index}`">
|
||||
<template v-if="tableType === fromRoute.dnsServiceInsights && isDnsMapType">
|
||||
{{dnsMapData.get(scope.row['tab'])}}
|
||||
</template>
|
||||
@@ -82,7 +83,7 @@
|
||||
{{scope.row['tab']}}
|
||||
</template>
|
||||
</div>
|
||||
<div v-else class="data-click" @click="handleTabValue(item.name,scope.row['tab'])">
|
||||
<div v-else class="data-click" :test-id="`dnsMapType-${scope.row.index}`" @click="handleTabValue(item.name,scope.row['tab'])">
|
||||
<template v-if="tableType === fromRoute.dnsServiceInsights && isDnsMapType">
|
||||
{{dnsMapData.get(scope.row['tab'])}}
|
||||
</template>
|
||||
@@ -94,10 +95,10 @@
|
||||
<template v-else-if="item.columnType === tableColumnType.percent" >
|
||||
<div class="dns-in-ex">
|
||||
<div class="dns-percent-pic">
|
||||
<div v-if="scope.row[item.prop][0] !== false" class="div-green" id="green" :style="`width:${scope.row[item.prop][0]}`"></div>
|
||||
<div v-if="scope.row[item.prop][0] !== false" class="div-yellow" id="yellow" :style="`width:${scope.row[item.prop][1]}`"></div>
|
||||
<div v-if="scope.row[item.prop][0] !== false" class="div-green" id="green" :test-id="`percent-green-${scope.row.index}`" :style="`width:${scope.row[item.prop][0]}`"></div>
|
||||
<div v-if="scope.row[item.prop][0] !== false" class="div-yellow" id="yellow" :test-id="`percent-yellow-${scope.row.index}`" :style="`width:${scope.row[item.prop][1]}`"></div>
|
||||
</div>
|
||||
<div class="dns-percent">{{scope.row[item.prop][2]}}</div>
|
||||
<div class="dns-percent" :test-id="`percent-value-${scope.row.index}`">{{scope.row[item.prop][2]}}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'score'" >
|
||||
@@ -105,10 +106,10 @@
|
||||
<div v-if="scope.row.score <= 2" class="data-score data-score-red" >
|
||||
{{scope.row[item.prop] ? unitConvert(scope.row[item.prop], unitTypes.number).join(' ') : '0'}}
|
||||
</div>
|
||||
<div v-else-if="scope.row.score <= 4" class="data-score data-score-yellow" >
|
||||
<div v-else-if="scope.row.score <= 4" class="data-score data-score-yellow" :test-id="`score-${scope.row.index}`">
|
||||
{{scope.row[item.prop] ? unitConvert(scope.row[item.prop], unitTypes.number).join(' ') : '0'}}
|
||||
</div>
|
||||
<div v-else-if="scope.row.score <= 6" class="data-score data-score-green" >
|
||||
<div v-else-if="scope.row.score <= 6" class="data-score data-score-green" :test-id="`score-${scope.row.index}`">
|
||||
{{scope.row[item.prop] ? unitConvert(scope.row[item.prop], unitTypes.number).join(' ') : '0'}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -215,8 +216,8 @@ import unitConvert from '@/utils/unit-convert'
|
||||
import { getChainRatio, computeScore, urlParamsHandler, overwriteUrl, readDrilldownTableConfigByUser, combineDrilldownTableWithUserConfig, getDnsMapData, handleSpecialValue, getConfigVersion } from '@/utils/tools'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { db } from '@/indexedDB'
|
||||
import _ from 'lodash'
|
||||
import indexedDBUtils from '@/indexedDB'
|
||||
|
||||
export default {
|
||||
name: 'NetworkOverviewTabs',
|
||||
@@ -326,6 +327,10 @@ export default {
|
||||
},
|
||||
mixins: [chartMixin],
|
||||
methods: {
|
||||
rowClassName ({ row, rowIndex }) {
|
||||
// 把每一行的索引放进row
|
||||
row.index = rowIndex
|
||||
},
|
||||
/* 参数 extraParams 额外请求参数 */
|
||||
getChartData (extraParams = {}) {
|
||||
this.initState()
|
||||
@@ -1053,7 +1058,6 @@ export default {
|
||||
type: tabList[0].prop
|
||||
}
|
||||
this.changeUrlTabState()
|
||||
// const condition = this.$store.getters.getQueryCondition
|
||||
const condition = this.getQueryCondition()
|
||||
if (condition) {
|
||||
queryParams = {
|
||||
@@ -1539,13 +1543,13 @@ export default {
|
||||
const commonTab = this.commonTabList.find(item => item.name === tabName)
|
||||
tab.label = commonTab ? commonTab.i18n : ''
|
||||
tab.prop = commonTab ? commonTab.prop : ''
|
||||
if (!tab.hasOwnProperty('checked') || tab.checked === undefined || tab.checked === null) {
|
||||
if (!Object.prototype.hasOwnProperty.call(tab, 'checked') || tab.checked === undefined || tab.checked === null) {
|
||||
tab.checked = tab ? tab.show : true
|
||||
}
|
||||
if (!tab.hasOwnProperty('disabled') || tab.disabled === undefined || tab.disabled === null) {
|
||||
if (!Object.prototype.hasOwnProperty.call(tab, 'disabled') || tab.disabled === undefined || tab.disabled === null) {
|
||||
tab.disabled = tab ? !tab.enable : false
|
||||
}
|
||||
if (!tab.hasOwnProperty('panelId') || tab.panelId === undefined || tab.panelId === null) {
|
||||
if (!Object.prototype.hasOwnProperty.call(tab, 'panelId') || tab.panelId === undefined || tab.panelId === null) {
|
||||
tab.panelId = tab ? tab.panelIdOfFourthMenu : null
|
||||
}
|
||||
// 代码里写死的
|
||||
@@ -1562,7 +1566,7 @@ export default {
|
||||
const drilldownTabFull = []
|
||||
const drilldownTabList = tab.drilldownTabs
|
||||
drilldownTabList.forEach(drilldownTab => {
|
||||
if (!drilldownTab.hasOwnProperty('name') || drilldownTab.name === undefined || drilldownTab.name === null) {
|
||||
if (!Object.prototype.hasOwnProperty.call(drilldownTab, 'name') || drilldownTab.name === undefined || drilldownTab.name === null) {
|
||||
const drilldownTabName = drilldownTab ? (drilldownTab.name ? drilldownTab.name : drilldownTab) : ''
|
||||
const fullTab = oldList.find(item => item.name === drilldownTabName)
|
||||
const drilldownTabWithAllInfo = this.$_.cloneDeep(fullTab)
|
||||
@@ -1660,7 +1664,7 @@ export default {
|
||||
let isSetDrilldownTabInfo = false
|
||||
if (tabList && tabList.length > 0) {
|
||||
const drilldownTab = tabList[0].drilldownTabs
|
||||
if (drilldownTab && drilldownTab.length > 0 && drilldownTab.hasOwnProperty('name')) {
|
||||
if (drilldownTab && drilldownTab.length > 0 && Object.prototype.hasOwnProperty.call(drilldownTab, 'name')) {
|
||||
isSetDrilldownTabInfo = true
|
||||
}
|
||||
}
|
||||
@@ -1729,7 +1733,7 @@ export default {
|
||||
version = await getConfigVersion('default')
|
||||
}
|
||||
// 更新缓存中的配置
|
||||
await db[dbDrilldownTableConfig].put({
|
||||
await indexedDBUtils.selectTable(dbDrilldownTableConfig).put({
|
||||
id: this.userId,
|
||||
version: version,
|
||||
config: this.$_.cloneDeep(curUserConfigGroup)
|
||||
@@ -1743,7 +1747,7 @@ export default {
|
||||
const tabItem = this.curTable.tabs.find(tabItem => tabItem.name === tab.name)
|
||||
tab.hiddenDrilldownTabs = this.getHiddenDrilldownTabNameGroup(tabItem)
|
||||
if (tab && tab.hasMetricSearch === true) {
|
||||
const columnsForMetric = tab.metrics.find(metric => metric.name === this.metric)
|
||||
// const columnsForMetric = tab.metrics.find(metric => metric.name === this.metric)
|
||||
tab.metrics.forEach(metric => {
|
||||
const oldSortColumns = metric.columns
|
||||
const newSortColumns = this.customTableTitles.slice(1)
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
<chart-no-data v-if="isNoData"></chart-no-data>
|
||||
<div class="npm-app-body" v-else>
|
||||
<div class="npm-app-body-patch" v-for="(data, index) in tableData" :key="index">
|
||||
<div class="npm-app-body-icon"><span><i :class="data.icon"></i></span></div>
|
||||
<div class="npm-app-body-color" v-for="(item, index) in 6" :key="index" :class="{'score-color': data.score >= index + 1}"></div>
|
||||
<div class="npm-app-body-icon"><span><i :class="data.icon" :test-id="`iconContent${index}`"></i></span></div>
|
||||
<div class="npm-app-body-color" v-for="index2 in 6" :key="index2" :class="{'score-color': data.score >= index2}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -48,7 +48,7 @@
|
||||
<div v-else-if="scope.row.bytesRateChainRatio < 0" class="data-total-trend data-total-trend-green">
|
||||
<i class="cn-icon-decline cn-icon"></i>
|
||||
<span v-if="scope.row.bytesRateChainRatio >= -5">
|
||||
{{unitConvert(scope.row.bytesRateChainRatio, unitTypes.percent).join('').replaceAll('-', '')}}
|
||||
{{unitConvert(scope.row.bytesRateChainRatio, unitTypes.percent).join('').replace(/-/g, '')}}
|
||||
</span>
|
||||
<span v-else>>500.00%</span>
|
||||
</div>
|
||||
@@ -71,7 +71,7 @@
|
||||
<div v-else-if="scope.row.outboundBytesRateChainRatio < 0" class="data-total-trend data-total-trend-green">
|
||||
<i class="cn-icon-decline cn-icon"></i>
|
||||
<span v-if="scope.row.outboundBytesRateChainRatio >= -5">
|
||||
{{unitConvert(scope.row.outboundBytesRateChainRatio, unitTypes.percent).join('').replaceAll('-', '')}}
|
||||
{{unitConvert(scope.row.outboundBytesRateChainRatio, unitTypes.percent).join('').replace(/-/g, '')}}
|
||||
</span>
|
||||
<span v-else>>500.00%</span>
|
||||
</div>
|
||||
@@ -82,39 +82,39 @@
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'inbound'">
|
||||
<div class="data-total-value">{{unitConvert(scope.row.inboundPacketsRate, unitTypes.bps).join(' ')}}</div>
|
||||
<div class="data-total-value" :test-id="`inbound-packet-${scope.row.appSubcategory}`">{{unitConvert(scope.row.inboundPacketsRate, unitTypes.bps).join(' ')}}</div>
|
||||
<div class="data-trend">
|
||||
<div v-if="scope.row.inboundBytesRateChainRatio > 0" class="data-total-trend data-total-trend-red">
|
||||
<i class="cn-icon-rise1 cn-icon"></i>
|
||||
<span v-if="scope.row.inboundBytesRateChainRatio <= 5">
|
||||
<span v-if="scope.row.inboundBytesRateChainRatio <= 5" :test-id="`inbound-${scope.row.appSubcategory}`">
|
||||
{{unitConvert(scope.row.inboundBytesRateChainRatio, unitTypes.percent).join('')}}
|
||||
</span>
|
||||
<span v-else>>500.00%</span>
|
||||
<span v-else :test-id="`inbound-${scope.row.appSubcategory}`">>500.00%</span>
|
||||
</div>
|
||||
<div v-else-if="scope.row.inboundBytesRateChainRatio < 0" class="data-total-trend data-total-trend-green">
|
||||
<i class="cn-icon-decline cn-icon"></i>
|
||||
<span v-if="scope.row.inboundBytesRateChainRatio >= -5">
|
||||
{{unitConvert(scope.row.inboundBytesRateChainRatio, unitTypes.percent).join('').replaceAll('-', '')}}
|
||||
<span v-if="scope.row.inboundBytesRateChainRatio >= -5" :test-id="`inbound-${scope.row.appSubcategory}`">
|
||||
{{unitConvert(scope.row.inboundBytesRateChainRatio, unitTypes.percent).join('').replace(/-/g, '')}}
|
||||
</span>
|
||||
<span v-else>>500.00%</span>
|
||||
<span v-else :test-id="`inbound-${scope.row.appSubcategory}`">>500.00%</span>
|
||||
</div>
|
||||
<div v-else-if="scope.row.inboundBytesRateChainRatio === 0" class="data-total-trend data-total-trend-black">
|
||||
<div v-else-if="scope.row.inboundBytesRateChainRatio === 0" :test-id="`inbound-${scope.row.appSubcategory}`" class="data-total-trend data-total-trend-black">
|
||||
<i class="cn-icon-constant cn-icon"></i>
|
||||
</div>
|
||||
<div v-else></div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'score'">
|
||||
<div v-if="scope.row.score <= 2" :class="{'data-score-red': scope.row.score <= 2}" class="data-score">
|
||||
<div v-if="scope.row.score <= 2" :test-id="`score-${scope.row.appSubcategory}`" class="data-score data-score-red">
|
||||
{{scope.row.score}}
|
||||
</div>
|
||||
<div v-else-if="scope.row.score <= 4" :class="{'data-score-yellow': scope.row.score <= 4}" class="data-score">
|
||||
<div v-else-if="scope.row.score <= 4" :test-id="`score-${scope.row.appSubcategory}`" class="data-score data-score-yellow">
|
||||
{{scope.row.score}}
|
||||
</div>
|
||||
<div v-else-if="scope.row.score <= 6" :class="{'data-score-green': scope.row.score <= 6}" class="data-score">
|
||||
<div v-else-if="scope.row.score <= 6" :test-id="`score-${scope.row.appSubcategory}`" class="data-score data-score-green">
|
||||
{{scope.row.score}}
|
||||
</div>
|
||||
<div v-else-if="scope.row.score === '-'" class="data-score-no-data">
|
||||
<div v-else-if="scope.row.score === '-'" :test-id="`score-${scope.row.appSubcategory}`" class="data-score-no-data">
|
||||
-
|
||||
</div>
|
||||
</template>
|
||||
@@ -138,17 +138,12 @@ import { unitTypes, npmCategoryInfoMapping, networkTable, operationType, npmCate
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import { api } from '@/utils/api'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import { get } from '@/utils/http'
|
||||
import {
|
||||
getChainRatio,
|
||||
computeScore,
|
||||
urlParamsHandler,
|
||||
overwriteUrl,
|
||||
getUserDrilldownTableConfig
|
||||
} from '@/utils/tools'
|
||||
import { computeScore, getChainRatio, getUserDrilldownTableConfig, overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import ChartError from '@/components/common/Error'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'NpmAppCategoryScore',
|
||||
data () {
|
||||
@@ -198,15 +193,15 @@ export default {
|
||||
endTime: getSecond(this.timeFilter.endTime)
|
||||
}
|
||||
// 获取table后三列内容
|
||||
const currentTrafficRequest = get(api.npm.overview.appTrafficAnalysis, { ...params, cycle: 0 })
|
||||
const lastCycleTrafficRequest = get(api.npm.overview.appTrafficAnalysis, { ...params, cycle: 1 })
|
||||
const currentTrafficRequest = axios.get(api.npm.overview.appTrafficAnalysis, { params: { ...params, cycle: 0 } })
|
||||
const lastCycleTrafficRequest = axios.get(api.npm.overview.appTrafficAnalysis, { params: { ...params, cycle: 1 } })
|
||||
this.toggleLoading(true)
|
||||
Promise.all([currentTrafficRequest, lastCycleTrafficRequest]).then(res => {
|
||||
if (res[0].code === 200 && res[1].code === 200) {
|
||||
if (res[0].data.code === 200 && res[1].data.code === 200) {
|
||||
this.showError = false
|
||||
this.errorMsg = ''
|
||||
const prevData = res[1].data.result
|
||||
const data = res[0].data.result
|
||||
const prevData = res[1].data.data.result
|
||||
const data = res[0].data.data.result
|
||||
if (data && data.length > 0) {
|
||||
this.isNoData = false
|
||||
const tableData = data.map(d => {
|
||||
@@ -228,24 +223,23 @@ export default {
|
||||
return result
|
||||
})
|
||||
// 计算分数
|
||||
const tcpRequest = get(api.npm.overview.appTcpSessionDelay, params)
|
||||
const httpRequest = get(api.npm.overview.appHttpResponseDelay, params)
|
||||
const sslRequest = get(api.npm.overview.appSslConDelay, params)
|
||||
const tcpLostRequest = get(api.npm.overview.appTcpLostlenPercent, params)
|
||||
const packetRetransRequest = get(api.npm.overview.appPacketRetransPercent, params)
|
||||
const tcpRequest = axios.get(api.npm.overview.appTcpSessionDelay, { params: params })
|
||||
const httpRequest = axios.get(api.npm.overview.appHttpResponseDelay, { params: params })
|
||||
const sslRequest = axios.get(api.npm.overview.appSslConDelay, { params: params })
|
||||
const tcpLostRequest = axios.get(api.npm.overview.appTcpLostlenPercent, { params: params })
|
||||
const packetRetransRequest = axios.get(api.npm.overview.appPacketRetransPercent, { params: params })
|
||||
Promise.all([tcpRequest, httpRequest, sslRequest, tcpLostRequest, packetRetransRequest]).then(res => {
|
||||
const keyPre = ['tcp', 'http', 'ssl', 'tcpLost', 'packetRetrans']
|
||||
let msg = ''
|
||||
|
||||
res.forEach((r, i) => {
|
||||
if (r.code === 200) {
|
||||
if (r.data.code === 200) {
|
||||
tableData.forEach(t => {
|
||||
const find = r.data.result.find(d => d.appSubcategory === t.appSubcategory)
|
||||
t[keyPre[i] + 'Score'] = find
|
||||
t[keyPre[i] + 'Score'] = r.data.data.result.find(d => d.appSubcategory === t.appSubcategory)
|
||||
})
|
||||
} else {
|
||||
this.showError = true
|
||||
msg = msg + ',' + r.message
|
||||
msg = msg + ',' + r.data.data.message
|
||||
if (msg.indexOf(',') === 0) {
|
||||
msg = msg.substring(1, msg.length)
|
||||
}
|
||||
@@ -348,7 +342,7 @@ export default {
|
||||
}
|
||||
})
|
||||
let toPanel = null
|
||||
list.forEach((item, index) => {
|
||||
list.forEach(item => {
|
||||
if (item.label === tabType) {
|
||||
item.checked = false
|
||||
toPanel = item.panelId
|
||||
@@ -360,8 +354,7 @@ export default {
|
||||
this.$store.commit('setNetworkOverviewTabList', list)
|
||||
const tabObjGroup = list.filter(item => item.checked)
|
||||
if (tabObjGroup && tabObjGroup.length > 0) {
|
||||
const curTab = tabObjGroup[0]
|
||||
this.urlChangeParams[this.curTabState.curTab] = curTab
|
||||
this.urlChangeParams[this.curTabState.curTab] = tabObjGroup[0]
|
||||
}
|
||||
this.changeUrlTabState()
|
||||
this.$router.push({
|
||||
@@ -384,6 +377,9 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
this.init()
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,29 +1,11 @@
|
||||
<template>
|
||||
<div class="npm-app-event">
|
||||
<!-- <div class="metric-select">
|
||||
<el-select
|
||||
v-model="metric"
|
||||
class="option__select select-column"
|
||||
popper-class="option-popper common-select"
|
||||
:popper-append-to-body="false"
|
||||
key="tabMetric"
|
||||
@change="changeMetric"
|
||||
size="mini"
|
||||
width="100">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.label"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<span>{{ $t('network.metric') }}:</span>
|
||||
</div>-->
|
||||
<el-table
|
||||
id="tabTable"
|
||||
ref="dataTable"
|
||||
:data="tableData"
|
||||
class="npm-app-event-table"
|
||||
:row-class-name="rowClassName"
|
||||
height="100%"
|
||||
empty-text=""
|
||||
>
|
||||
@@ -33,34 +15,33 @@
|
||||
<span class="data-column__span">{{ $t(item.label) }}</span>
|
||||
</template>
|
||||
<template #default="scope" :column="item">
|
||||
<div class="data-app-event-table">
|
||||
<div class="data-app-event-table" :test-id="`${item.prop}${scope.row.index}`">
|
||||
<template v-if="item.prop === 'domain' ||item.prop === 'appName' ||item.prop === 'serverIp' ">
|
||||
<span class="data-applications">{{ scope.row[item.prop] }}</span>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'eventSeverity'" >
|
||||
<template v-if="scope.row[item.prop]==='critical'">
|
||||
<div v-for="item in 5" class="red-dot" :key="item"></div>
|
||||
<div v-for="item in 5" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
|
||||
</template>
|
||||
<template v-else-if="scope.row[item.prop]==='high'">
|
||||
<div v-for="item in 4" class="red-dot" :key="item"></div>
|
||||
<div class="grey-dot"></div>
|
||||
<div v-for="item in 4" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
|
||||
<div v-for="item in 1" class="grey-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${4+item}`"></div>
|
||||
</template>
|
||||
<template v-else-if="scope.row[item.prop]==='medium'">
|
||||
<div v-for="item in 3" class="red-dot" :key="item"></div>
|
||||
<div v-for="item in 2" class="grey-dot" :key="item"></div>
|
||||
<div v-for="item in 3" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
|
||||
<div v-for="item in 2" class="grey-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${3+item}`"></div>
|
||||
</template>
|
||||
<template v-else-if="scope.row[item.prop]==='low'">
|
||||
<div v-for="item in 2" class="red-dot" :key="item"></div>
|
||||
<div v-for="item in 3" class="grey-dot" :key="item"></div>
|
||||
<div v-for="item in 2" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
|
||||
<div v-for="item in 3" class="grey-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${2+item}`"></div>
|
||||
</template>
|
||||
<template v-else-if="scope.row[item.prop]==='info'">
|
||||
<div v-for="item in 1" class="red-dot" :key="item"></div>
|
||||
<div v-for="item in 4" class="grey-dot" :key="item"></div>
|
||||
<div v-for="item in 1" class="red-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${item}`"></div>
|
||||
<div v-for="item in 4" class="grey-dot" :key="item" :test-id="`eventSeverityValue${scope.row.index}${1+item}`"></div>
|
||||
</template>
|
||||
<span class="data-severity">{{ scope.row[item.prop] }}</span>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'eventType'">
|
||||
<!-- <span class="data-eventType" v-for="type in scope.row[item.prop]">{{type}}</span>-->
|
||||
<span class="data-eventType">{{ scope.row[item.prop] }}</span>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'count'">
|
||||
@@ -73,7 +54,7 @@
|
||||
</template>
|
||||
<template v-slot:empty>
|
||||
<div class="table-no-data" v-show="isNoData">
|
||||
<div class="table-no-data__title">{{ $t('npm.noData') }}</div>
|
||||
<div class="table-no-data__title" test-id="noData">{{ $t('npm.noData') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table>
|
||||
@@ -153,6 +134,10 @@ export default {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
rowClassName ({ row, rowIndex }) {
|
||||
// 把每一行的索引放进row
|
||||
row.index = rowIndex
|
||||
},
|
||||
init () {
|
||||
this.toggleLoading(true)
|
||||
this.isNoData = false
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<chart-error tooltip v-if="showError" :content="errorMsg"></chart-error>
|
||||
</div>
|
||||
<div class="npm-event-pie">
|
||||
<chart-no-data v-if="isNoData"></chart-no-data>
|
||||
<chart-no-data v-if="isNoData" test-id="noData"></chart-no-data>
|
||||
<div class="npm-event-pies" v-show="!isNoData">
|
||||
<div class="chart-drawing" id="chart"></div>
|
||||
<div class="npm-event-pie-legends">
|
||||
@@ -13,14 +13,14 @@
|
||||
<div class="npm-event-pie-legend-title" v-if="chartData.length > 0">{{ $t('overall.type') }}</div>
|
||||
<template v-for="(legend, index) in chartData" :key="index">
|
||||
<div class="npm-event-pie-legend-type">
|
||||
<div class="npm-event-pie-legend-type-severity">{{legend.name}}</div>
|
||||
<div class="npm-event-pie-legend-type-severity" :test-id="`testNode${index}`">{{legend.name}}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="npm-event-pie-legend">
|
||||
<div class="npm-event-pie-legend-title" v-if="chartData.length > 0">{{ $t('network.total') }}</div>
|
||||
<template v-for="(legend, index) in chartData" :key="index">
|
||||
<div class="npm-event-pie-legend-total">{{legend.value}}</div>
|
||||
<div class="npm-event-pie-legend-total" :test-id="`total${index}`">{{legend.value}}</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
<script>
|
||||
import { shallowRef } from 'vue'
|
||||
import { get } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import * as echarts from 'echarts'
|
||||
import { pieChartOption3 } from '@/views/charts2/charts/options/echartOption'
|
||||
@@ -39,6 +38,7 @@ import { getSecond } from '@/utils/date-util'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import ChartError from '@/components/common/Error'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'NpmEventsByType',
|
||||
@@ -65,7 +65,7 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
timeFilter: {
|
||||
handler (n) {
|
||||
handler () {
|
||||
this.eventsByTypeData()
|
||||
}
|
||||
}
|
||||
@@ -91,11 +91,11 @@ export default {
|
||||
return num
|
||||
}
|
||||
}
|
||||
this.myChart.on('mouseover', function (params) {
|
||||
this.myChart.on('mouseover', function () {
|
||||
_this.chartOption.series[0].label.show = false
|
||||
_this.myChart.setOption(_this.chartOption)
|
||||
})
|
||||
this.myChart.on('mouseout', function (params) {
|
||||
this.myChart.on('mouseout', function () {
|
||||
_this.chartOption.series[0].label.show = true
|
||||
_this.myChart.setOption(_this.chartOption)
|
||||
})
|
||||
@@ -108,7 +108,8 @@ export default {
|
||||
type: 'severity'
|
||||
}
|
||||
this.toggleLoading(true)
|
||||
get(api.npm.events.recentEvents, params).then(res => {
|
||||
axios.get(api.npm.events.recentEvents, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
@@ -117,7 +118,9 @@ export default {
|
||||
const hit = arrData.find(e => e.name === t.eventType)
|
||||
if (hit) {
|
||||
arrData.forEach(d => {
|
||||
if (hit.name === d.name) {
|
||||
d.value++
|
||||
}
|
||||
})
|
||||
} else {
|
||||
arrData.push({ name: t.eventType, value: 1 })
|
||||
@@ -126,8 +129,10 @@ export default {
|
||||
this.chartData = arrData.sort((a, b) => { return b.value - a.value })
|
||||
this.$nextTick(() => {
|
||||
if (this.chartData.length > 0) {
|
||||
if (!this.isUnitTesting) {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.isNoData = false
|
||||
@@ -152,7 +157,9 @@ export default {
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('resize', this.resize)
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.chartOption = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,21 +2,22 @@
|
||||
<div class="npm-header">
|
||||
<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-icon" :class="item.eventSeverity"></div>
|
||||
<div class="npm-header-body-severity-value">{{item.eventSeverity}}</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>
|
||||
<chart-error v-if="showError" tooltip :content="errorMsg" />
|
||||
<div v-else class="npm-header-body-total">{{item.count}}</div>
|
||||
<div v-else class="npm-header-body-total" :test-id="`total${index}`">{{item.count}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import { get } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import ChartError from '@/components/common/Error'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'NpmEventsHeader',
|
||||
components: { ChartError },
|
||||
@@ -65,12 +66,13 @@ export default {
|
||||
methods: {
|
||||
recentEventsListData () {
|
||||
const params = {
|
||||
startTime: getSecond(this.timeFilter.startTime),
|
||||
endTime: getSecond(this.timeFilter.endTime),
|
||||
startTime: this.timeFilter && this.timeFilter.startTime ? getSecond(this.timeFilter.startTime) : '',
|
||||
endTime: this.timeFilter && this.timeFilter.endTime ? getSecond(this.timeFilter.endTime) : '',
|
||||
type: this.type
|
||||
}
|
||||
this.toggleLoading(true)
|
||||
get(api.npm.events.list, params).then(res => {
|
||||
axios.get(api.npm.events.list, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
if (res.data.result.length === 0) {
|
||||
@@ -96,7 +98,9 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.recentEventsListData()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -336,7 +336,9 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.chartOption = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,60 @@
|
||||
<template>
|
||||
<div class="npm-network-quantity">
|
||||
<single-value
|
||||
v-if="npmNetworkData.length>0"
|
||||
:npm-network-name="npmNetworkName"
|
||||
:npm-network-data="npmNetworkData"
|
||||
></single-value>
|
||||
<div class="single-value" v-for="(npm, index) in newNpmNetworkData" :key="index">
|
||||
<div class="single-value__title" style="display: flex">
|
||||
{{ $t(npmNetworkName[index].name) }}
|
||||
<chart-error v-if="npm.message" tooltip :content="npm.message"></chart-error>
|
||||
</div>
|
||||
|
||||
<div class="single-value__content" >
|
||||
<div class="single-value__content-number" v-if="index ===0 || index ===1 || index ===2" :test-id="`singleValueContent${index}`">
|
||||
{{ unitConvert(npm.Avg, unitTypes.time).join(' ') }}
|
||||
</div>
|
||||
<div class="single-value__content-number" v-else :test-id="`singleValueContent${index}`">
|
||||
{{unitConvert(npm.Avg, unitTypes.percent).join(' ')}}
|
||||
</div>
|
||||
<div v-if="npm.value > 0" class="single-value__content-trend single-value__content-trend-red" >
|
||||
<i class="cn-icon-rise1 cn-icon" :test-id="`singleValueTrendIcon${index}`"></i>
|
||||
<span v-if="npm.value <= 5" :test-id="`singleValueTrendValue${index}`">
|
||||
{{ unitConvert(npm.value, unitTypes.percent).join('') }}
|
||||
</span>
|
||||
<span v-else :test-id="`singleValueTrendValue${index}`">>500.00%</span>
|
||||
</div>
|
||||
<div v-else-if="npm.value < 0" class="single-value__content-trend single-value__content-trend-green" >
|
||||
<i class="cn-icon-decline cn-icon" :test-id="`singleValueTrendIcon${index}`"></i>
|
||||
<span v-if="npm.value >= -5" :test-id="`singleValueTrendValue${index}`">
|
||||
{{ unitConvert(npm.value, unitTypes.percent).join('') }}
|
||||
</span>
|
||||
<span v-else :test-id="`singleValueTrendValue${index}`">>500.00%</span>
|
||||
</div>
|
||||
<div v-else-if="npm.value === 0" class="single-value__content-trend single-value__content-trend-black">
|
||||
<i class="cn-icon-constant cn-icon" :test-id="`singleValueTrendIcon${index}`"></i>
|
||||
</div>
|
||||
<div v-else></div>
|
||||
</div>
|
||||
|
||||
<div class="single-value__circle">
|
||||
<div class="single-value__circle-p95" :test-id="`singleValueP95${index}`">
|
||||
<span v-if="index ===0 || index ===1 || index ===2">
|
||||
P95:{{ unitConvert(npm.P95, unitTypes.time).join(' ') }}</span>
|
||||
<span v-else>
|
||||
P95:{{ unitConvert(npm.P95, unitTypes.percent).join(' ') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="single-value__circle-p99" :test-id="`singleValueP99${index}`">
|
||||
<span v-if="index ===0 || index ===1 || index ===2">
|
||||
P99:{{ unitConvert(npm.P99, unitTypes.time).join(' ') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
P99:{{ unitConvert(npm.P99, unitTypes.percent).join(' ') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SingleValue from '@/views/charts2/charts/npm/localComponents/SingleValue'
|
||||
import { get } from '@/utils/http'
|
||||
import { getSecond } from '@/utils/date-util'
|
||||
import { api } from '@/utils/api'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
@@ -18,9 +62,11 @@ import _ from 'lodash'
|
||||
import { getChainRatio } from '@/utils/tools'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ref } from 'vue'
|
||||
import { unitTypes } from '@/utils/constants'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import axios from 'axios'
|
||||
export default {
|
||||
name: 'NpmNetworkQuantity',
|
||||
components: { SingleValue },
|
||||
mixins: [chartMixin],
|
||||
setup () {
|
||||
const { query } = useRoute()
|
||||
@@ -39,6 +85,8 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
unitTypes,
|
||||
unitConvert,
|
||||
npmNetworkName: [
|
||||
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency' },
|
||||
{ name: 'networkAppPerformance.httpResponse' },
|
||||
@@ -48,6 +96,7 @@ export default {
|
||||
],
|
||||
npmNetworkCycleData: [],
|
||||
npmNetworkLastCycleData: [],
|
||||
newNpmNetworkData: [],
|
||||
npmNetworkData: [],
|
||||
side: '',
|
||||
chartData: {},
|
||||
@@ -68,7 +117,7 @@ export default {
|
||||
npmNetworkCycleQuery () {
|
||||
let condition = ''
|
||||
let url = ''
|
||||
if (this.queryCondition.indexOf(' OR ') > -1) {
|
||||
if (this.queryCondition && this.queryCondition.indexOf(' OR ') > -1) {
|
||||
condition = this.queryCondition.split(/["|'](.*?)["|']/)
|
||||
} else {
|
||||
condition = this.queryCondition
|
||||
@@ -84,37 +133,38 @@ export default {
|
||||
} else if (parseFloat(this.tabIndex) === 1) {
|
||||
this.side = 'server'
|
||||
}
|
||||
if (condition && (typeof condition !== 'object') && type) {
|
||||
if (type === 'clientIp' || type === 'serverIp') {
|
||||
if (parseFloat(this.tabIndex) === 0) {
|
||||
if (condition && (typeof condition !== 'object') && type) { // 判断 condition 不为空并且不为对象 type 不为空
|
||||
if (type === 'clientIp' || type === 'serverIp') { // type = clientIp || serverIp
|
||||
if (parseFloat(this.tabIndex) === 0) { // npm 下钻 tabIndex 为 0
|
||||
type = 'clientIp'
|
||||
} else if (parseFloat(this.tabIndex) === 1) {
|
||||
} else if (parseFloat(this.tabIndex) === 1) { // npm 下钻 tabIndex 为 1
|
||||
type = 'serverIp'
|
||||
}
|
||||
params.q = `ip='${condition.split(/'(.*?)'/)[1]}'`
|
||||
params.q = `ip='${condition.split(/'(.*?)'/)[1]}'` // 拼接字段作为参数
|
||||
} else if (type === 'clientCity') {
|
||||
params.q = `client_city='${condition.split(/'(.*?)'/)[1]}'`
|
||||
params.q = `client_city='${condition.split(/'(.*?)'/)[1]}'` // 拼接字段作为参数
|
||||
} else if (type === 'serverCity') {
|
||||
params.q = `server_city='${condition.split(/'(.*?)'/)[1]}'`
|
||||
params.q = `server_city='${condition.split(/'(.*?)'/)[1]}'` // 拼接字段作为参数
|
||||
} else {
|
||||
params.q = condition
|
||||
params.q = condition // 默认参数
|
||||
}
|
||||
params.type = type
|
||||
} else if (condition.length > 1 && type && type === 'ip') {
|
||||
params.q = `${type}='${condition[1]}' and side='${this.side}'`
|
||||
} else if (condition.length > 1 && type && type === 'ip') { // condition 为数组时数组长度不为 0 | type 不为空 | type为ip
|
||||
params.q = `${type}='${condition[1]}' and side='${this.side}'` // 拼接字段作为参数
|
||||
params.type = type
|
||||
} else if (condition.length > 1 && type && type !== 'ip') {
|
||||
if (type === 'country' || type === 'asn' || type === 'province' || type === 'city' || type === 'isp') {
|
||||
params.q = `${type}='${condition[1]}'`
|
||||
} else if (condition.length > 1 && type && type !== 'ip') { // condition 为数组时数组长度不为 0 | type 不为空 | type不为ip
|
||||
if (type === 'country' || type === 'asn' || type === 'province' || type === 'city' || type === 'isp') { // 根据接口所需,调整参数
|
||||
params.q = `${type}='${condition[1]}'` // 拼接字段作为参数
|
||||
params.type = type
|
||||
} else if (type === 'idcRenter') {
|
||||
params.q = `idc_renter='${condition[1]}'`
|
||||
params.q = `idc_renter='${condition[1]}'` // 拼接字段作为参数
|
||||
params.type = type
|
||||
} else {
|
||||
params.q = `${condition[0]}'${condition[1]}'`
|
||||
params.q = `${condition[0]}'${condition[1]}'` // 拼接字段作为参数
|
||||
params.type = type
|
||||
}
|
||||
}
|
||||
// 区分 3 级菜单和 2 级菜单使用不同的 url
|
||||
if (parseFloat(this.tabOperationType) === 3) {
|
||||
url = api.npm.overview.allNetworkAnalysis
|
||||
} else {
|
||||
@@ -123,7 +173,8 @@ export default {
|
||||
if ((type && condition) || type) {
|
||||
params.type = params.type || type
|
||||
this.toggleLoading(true)
|
||||
get(url, params).then(res => {
|
||||
axios.get(url, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.npmNetworkCycleData = res.data.result
|
||||
}
|
||||
@@ -133,21 +184,21 @@ export default {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
} else {
|
||||
const tcp = get(api.npm.overview.tcpSessionDelay, params)
|
||||
const http = get(api.npm.overview.httpResponseDelay, params)
|
||||
const ssl = get(api.npm.overview.sslConDelay, params)
|
||||
const tcpPercent = get(api.npm.overview.tcpLostlenPercent, params)
|
||||
const packetPercent = get(api.npm.overview.packetRetransPercent, params)
|
||||
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 })
|
||||
this.toggleLoading(true)
|
||||
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
|
||||
// 状态为200的,赋值接口数据,不为200的传入报错提示message,
|
||||
// 传给子组件SingleValue,再进行error处理,注:error处理不在此处处理
|
||||
this.npmNetworkCycleData = []
|
||||
res.forEach(t => {
|
||||
if (t.code === 200) {
|
||||
this.npmNetworkCycleData.push(t.data.result)
|
||||
if (t.data.code === 200) {
|
||||
this.npmNetworkCycleData.push(t.data.data.result)
|
||||
} else {
|
||||
this.npmNetworkCycleData.push(t)
|
||||
this.npmNetworkCycleData.push(t.data)
|
||||
}
|
||||
})
|
||||
this.npmNetworkLastCycleQuery()
|
||||
@@ -177,7 +228,8 @@ export default {
|
||||
if ((params.type && params.q) || (param && param.type)) {
|
||||
params.type = params.type || param.type
|
||||
this.toggleLoading(true)
|
||||
get(url, params).then(res => {
|
||||
axios.get(url, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.npmNetworkLastCycleData = res.data.result
|
||||
} else {
|
||||
@@ -195,20 +247,20 @@ export default {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
} else {
|
||||
const tcp = get(api.npm.overview.tcpSessionDelay, params)
|
||||
const http = get(api.npm.overview.httpResponseDelay, params)
|
||||
const ssl = get(api.npm.overview.sslConDelay, params)
|
||||
const tcpPercent = get(api.npm.overview.tcpLostlenPercent, params)
|
||||
const packetPercent = get(api.npm.overview.packetRetransPercent, params)
|
||||
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 })
|
||||
this.toggleLoading(true)
|
||||
Promise.all([tcp, http, ssl, tcpPercent, packetPercent]).then(res => {
|
||||
// 状态为200的,赋值接口数据,不为200的保留报错提示message,
|
||||
// 传给子组件SingleValue,再进行error处理,注:error处理不在此处处理
|
||||
res.forEach(t => {
|
||||
if (t.code === 200) {
|
||||
this.npmNetworkLastCycleData.push(t.data.result)
|
||||
if (t.data.code === 200) {
|
||||
this.npmNetworkLastCycleData.push(t.data.data.result)
|
||||
} else {
|
||||
this.npmNetworkLastCycleData.push(t)
|
||||
this.npmNetworkLastCycleData.push(t.data)
|
||||
}
|
||||
this.npmNetworkQuantity(this.npmNetworkCycleData, this.npmNetworkLastCycleData, 1)
|
||||
})
|
||||
@@ -271,6 +323,39 @@ export default {
|
||||
})
|
||||
this.npmNetworkData = cycle
|
||||
}
|
||||
this.initData(this.npmNetworkData)
|
||||
},
|
||||
initData (data) {
|
||||
// 处理数据后的数组
|
||||
const dealList = []
|
||||
|
||||
if (data !== undefined && data.length > 0) {
|
||||
data.forEach((item) => {
|
||||
const tempObj = {}
|
||||
for (const i in item) {
|
||||
if (item.msg || item.message) {
|
||||
// 为了兼容字段为msg的情况
|
||||
tempObj.message = item.msg ? item.msg : item.message
|
||||
} else {
|
||||
// 将含有avg、p90等关键字使用avg、p90来代替,形成统一属性
|
||||
if (i.indexOf('Avg') > -1) {
|
||||
tempObj.Avg = item[i]
|
||||
} else if (i.indexOf('P50') > -1) {
|
||||
tempObj.P50 = item[i]
|
||||
} else if (i.indexOf('P90') > -1) {
|
||||
tempObj.P90 = item[i]
|
||||
} else if (i.indexOf('P95') > -1) {
|
||||
tempObj.P95 = item[i]
|
||||
} else if (i.indexOf('P99') > -1) {
|
||||
tempObj.P99 = item[i]
|
||||
}
|
||||
tempObj.value = item.value
|
||||
}
|
||||
}
|
||||
dealList.push(tempObj)
|
||||
})
|
||||
this.newNpmNetworkData = dealList
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
@@ -282,6 +367,7 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer1)
|
||||
clearTimeout(this.timer2)
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -21,15 +21,15 @@
|
||||
<template #default="scope" :column="item">
|
||||
<div class="data-recent-table">
|
||||
<template v-if="item.prop === 'eventSeverity'">
|
||||
<span class="data-recent-table-severity" :class="scope.row[item.prop]">{{scope.row[item.prop]}}</span>
|
||||
<span class="data-recent-table-severity" :class="scope.row[item.prop]" :test-id="`eventSeverity-${scope.row.eventSeverity}-${scope.$index}`">{{scope.row[item.prop]}}</span>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'eventKey'">
|
||||
<span class="data-recent-table-entity click-active" @click="jumpPage(scope.row)">{{splitEventKey(scope.row[item.prop])}}</span>
|
||||
<span class="data-recent-table-entity click-active" @click="jumpPage(scope.row)" :test-id="`eventKey-${splitEventKey(scope.row.eventKey)}-${scope.$index}`">{{splitEventKey(scope.row[item.prop])}}</span>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'eventType'">
|
||||
<span class="data-recent-table-eventType">{{scope.row[item.prop]}}</span>
|
||||
<span class="data-recent-table-eventType" :test-id="`eventType-${scope.row.eventType}-${scope.$index}`">{{scope.row[item.prop]}}</span>
|
||||
</template>
|
||||
<span v-else-if="scope.row[item.prop]">{{scope.row[item.prop]}}</span>
|
||||
<span v-else-if="scope.row[item.prop]" :test-id="`startTime-${scope.$index}`">{{scope.row[item.prop]}}</span>
|
||||
<span v-else>-</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -40,7 +40,7 @@
|
||||
<svg class="icon" aria-hidden="true">
|
||||
<use xlink:href="#cn-icon-good"></use>
|
||||
</svg>
|
||||
<div class="table-no-data__title">{{ $t('npm.thereNoEvents') }}</div>
|
||||
<div class="table-no-data__title" test-id="noData">{{ $t('npm.thereNoEvents') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table>
|
||||
@@ -48,13 +48,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import { getSecond, dateFormatByAppearance } from '@/utils/date-util'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ref } from 'vue'
|
||||
import ChartError from '@/components/common/Error'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'NpmRecentEvents',
|
||||
@@ -99,7 +99,7 @@ export default {
|
||||
endTime: getSecond(this.timeFilter.endTime),
|
||||
limit: 8
|
||||
}
|
||||
if (condition.length > 1 && this.dimensionType) {
|
||||
if (condition && condition.length > 1 && this.dimensionType) {
|
||||
params.param = condition[1]
|
||||
params.type = this.dimensionType
|
||||
if (params.type === 'serverIp' || params.type === 'clientIp') params.type = 'ip'
|
||||
@@ -114,7 +114,8 @@ export default {
|
||||
url = api.npm.events.recentEvents
|
||||
}
|
||||
this.toggleLoading(true)
|
||||
get(url, params).then(res => {
|
||||
axios.get(url, { params: params }).then(res => {
|
||||
res = res.data
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
@@ -125,11 +126,12 @@ export default {
|
||||
})
|
||||
this.tableData = res.data.result
|
||||
} else {
|
||||
// this.isNoData = true
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = res.message
|
||||
}
|
||||
}).catch(error => {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = error.message
|
||||
}).finally(() => {
|
||||
@@ -151,6 +153,7 @@ export default {
|
||||
return name
|
||||
},
|
||||
jumpPage (item) {
|
||||
this.beforeRouterPush()
|
||||
this.$router.push({
|
||||
path: '/detection/performanceEvent',
|
||||
query: {
|
||||
@@ -158,6 +161,36 @@ export default {
|
||||
eventId: item.eventId
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 在路由跳转前,即下钻前将路由数据保存起来,确保回退和前进保留当时状态
|
||||
*/
|
||||
beforeRouterPush () {
|
||||
const currentRouter = this.$_.cloneDeep(this.$route.query)
|
||||
const historyList = this.$_.cloneDeep(this.$store.getters.getRouterHistoryList)
|
||||
|
||||
const tempObj = {
|
||||
t: currentRouter.t,
|
||||
query: currentRouter,
|
||||
path: this.$_.cloneDeep(this.$route.path),
|
||||
params: this.$_.cloneDeep(this.$route.params)
|
||||
}
|
||||
if (historyList.length > 0) {
|
||||
let flag = true
|
||||
historyList.forEach((item, index) => {
|
||||
if (item.t === currentRouter.t) {
|
||||
historyList[index] = tempObj
|
||||
flag = false
|
||||
}
|
||||
if (!flag) {
|
||||
return true
|
||||
}
|
||||
})
|
||||
if (flag) historyList.push(tempObj)
|
||||
} else {
|
||||
historyList.push(tempObj)
|
||||
}
|
||||
this.$store.commit('setRouterHistoryList', historyList)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
@@ -22,7 +22,6 @@ import { get } from '@/utils/http'
|
||||
import { api } from '@/utils/api'
|
||||
import { drillDownPanelTypeMapping } from '@/utils/constants'
|
||||
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ref } from 'vue'
|
||||
export default {
|
||||
name: 'NpmTabs',
|
||||
|
||||
@@ -42,7 +42,7 @@ import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import _ from 'lodash'
|
||||
import chartMixin from '@/views/charts2/chart-mixin'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import { getLineType, getLineIndexUnit, getLineIndexUnit2, overwriteUrl, urlParamsHandler } from '@/utils/tools'
|
||||
import ChartError from '@/components/common/Error'
|
||||
|
||||
export default {
|
||||
@@ -71,7 +71,7 @@ export default {
|
||||
unitConvert,
|
||||
unitTypes,
|
||||
side: '',
|
||||
mpackets: [
|
||||
tabs: [
|
||||
{ name: this.$t('network.total'), show: true, positioning: 0, data: [], unitType: 'number' },
|
||||
{ name: this.$t('network.inbound'), show: true, positioning: 1, data: [], unitType: 'number' },
|
||||
{ name: this.$t('network.outbound'), show: true, positioning: 2, data: [], unitType: 'number' },
|
||||
@@ -80,11 +80,11 @@ export default {
|
||||
{ name: this.$t('network.other'), show: true, positioning: 5, data: [], unitType: 'number' }
|
||||
],
|
||||
npmQuantity: [
|
||||
{ name: this.$t('networkAppPerformance.tcpConnectionEstablishLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: this.$t('networkAppPerformance.httpResponse'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: this.$t('networkAppPerformance.sslResponseLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: this.$t('networkAppPerformance.packetLoss'), show: true, positioning: 0, data: [], unitType: unitTypes.percent },
|
||||
{ name: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent }
|
||||
{ name: this.$t('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: this.$t('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: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 4 }
|
||||
],
|
||||
chartData: {},
|
||||
metricOptions: [
|
||||
@@ -144,7 +144,6 @@ export default {
|
||||
if (!val) {
|
||||
val = this.metricFilter
|
||||
}
|
||||
// const conditionStr = this.$route.query.queryCondition ? this.$route.query.queryCondition : ''
|
||||
let condition = ''
|
||||
let type = this.dimensionType
|
||||
if (this.queryCondition.indexOf(' OR ') > -1) {
|
||||
@@ -200,7 +199,7 @@ export default {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.mpackets = [
|
||||
this.tabs = [
|
||||
{ name: this.$t('network.total'), show: true, positioning: 0, data: [], unitType: 'number' },
|
||||
{ name: this.$t('network.inbound'), show: true, positioning: 1, data: [], unitType: 'number' },
|
||||
{ name: this.$t('network.outbound'), show: true, positioning: 2, data: [], unitType: 'number' },
|
||||
@@ -209,92 +208,16 @@ export default {
|
||||
{ name: this.$t('network.other'), show: true, positioning: 5, data: [], unitType: 'number' }
|
||||
]
|
||||
this.npmQuantity = [
|
||||
{ name: this.$t('networkAppPerformance.tcpConnectionEstablishLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: this.$t('networkAppPerformance.httpResponse'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: this.$t('networkAppPerformance.sslResponseLatency'), show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: this.$t('networkAppPerformance.packetLoss'), show: true, positioning: 0, data: [], unitType: unitTypes.percent },
|
||||
{ name: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent }
|
||||
{ name: this.$t('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: this.$t('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: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 4 }
|
||||
]
|
||||
} else {
|
||||
console.info(res.data.result)
|
||||
this.initData(res.data.result, val)
|
||||
}
|
||||
res.data.result.forEach((t) => {
|
||||
if (t.type === 'bytes' && val === 'Bits/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
|
||||
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
|
||||
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
|
||||
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
|
||||
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
|
||||
mpackets[5].data = t.other.values ? t.other.values : []
|
||||
mpackets.forEach((e) => {
|
||||
e.show = true
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
this.echartsInit(this.mpackets)
|
||||
} else if (t.type === 'packets' && val === 'Packets/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
|
||||
mpackets[1].data = t.inboundPacketsRate.values ? t.inboundPacketsRate.values : []
|
||||
mpackets[2].data = t.outboundPacketsRate.values ? t.outboundPacketsRate.values : []
|
||||
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
|
||||
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
|
||||
mpackets[5].data = t.other.values ? t.other.values : []
|
||||
mpackets.forEach((e) => {
|
||||
e.show = true
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
this.echartsInit(this.mpackets)
|
||||
} else if (t.type === 'sessions' && val === 'Sessions/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].data = t.totalSessionsRate.values ? t.totalSessionsRate.values : []
|
||||
mpackets.forEach((e, i) => {
|
||||
if (i !== 0) {
|
||||
e.show = false
|
||||
}
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
this.echartsInit(this.mpackets)
|
||||
} else if (t.type === 'establishLatencyMs' && val === 'establishLatencyMs') {
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
npmQuantity[0].data = t.establishLatencyMsAvg.values ? t.establishLatencyMsAvg.values : []
|
||||
npmQuantity.forEach((e, i) => {
|
||||
e.show = i === 0
|
||||
})
|
||||
this.npmQuantity = npmQuantity
|
||||
this.echartsInit(this.npmQuantity, '(ms)')
|
||||
} else if (t.type === 'httpResponseLatency' && val === 'httpResponseLatency') {
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
npmQuantity[1].data = t.httpResponseLatencyAvg.values ? t.httpResponseLatencyAvg.values : []
|
||||
npmQuantity.forEach((e, i) => {
|
||||
e.show = i === 1
|
||||
})
|
||||
this.npmQuantity = npmQuantity
|
||||
this.echartsInit(this.npmQuantity, '(ms)')
|
||||
} else if (t.type === 'sslConLatency' && val === 'sslConLatency') {
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
npmQuantity[2].data = t.sslConLatencyAvg.values ? t.sslConLatencyAvg.values : []
|
||||
npmQuantity.forEach((e, i) => {
|
||||
e.show = i === 2
|
||||
})
|
||||
this.npmQuantity = npmQuantity
|
||||
this.echartsInit(this.npmQuantity, '(ms)')
|
||||
} else if (t.type === 'tcpLostlenPercent' && val === 'tcpLostlenPercent') {
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
npmQuantity[3].data = t.tcpLostlenPercentAvg.values ? t.tcpLostlenPercentAvg.values : []
|
||||
npmQuantity.forEach((e, i) => {
|
||||
e.show = i === 3
|
||||
})
|
||||
this.npmQuantity = npmQuantity
|
||||
this.echartsInit(this.npmQuantity, '(%)')
|
||||
} else if (t.type === 'pktRetransPercent' && val === 'pktRetransPercent') {
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
npmQuantity[4].data = t.pktRetransPercentAvg.values ? t.pktRetransPercentAvg.values : []
|
||||
npmQuantity.forEach((e, i) => {
|
||||
e.show = i === 4
|
||||
})
|
||||
this.npmQuantity = npmQuantity
|
||||
this.echartsInit(this.npmQuantity, '(%)')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
@@ -304,123 +227,48 @@ export default {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = e.message
|
||||
console.error(e)
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
} else {
|
||||
if (val === 'Bits/s' || val === 'Packets/s' || val === 'Sessions/s') {
|
||||
this.toggleLoading(true)
|
||||
get(api.npm.overview.totalTrafficAnalysis, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.mpackets = [
|
||||
{ name: 'network.total', show: true, positioning: 0, data: [], unitType: 'number' },
|
||||
{ name: 'network.inbound', show: true, positioning: 1, data: [], unitType: 'number' },
|
||||
{ name: 'network.outbound', show: true, positioning: 2, data: [], unitType: 'number' },
|
||||
{ name: 'network.internal', show: true, positioning: 3, data: [], unitType: 'number' },
|
||||
{ name: 'network.through', show: true, positioning: 4, data: [], unitType: 'number' },
|
||||
{ name: 'network.other', show: true, positioning: 5, data: [], unitType: 'number' }
|
||||
]
|
||||
}
|
||||
res.data.result.forEach((t) => {
|
||||
if (t.type === 'bytes' && val === 'Bits/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].data = t.totalBitsRate.values ? t.totalBitsRate.values : []
|
||||
mpackets[1].data = t.inboundBitsRate.values ? t.inboundBitsRate.values : []
|
||||
mpackets[2].data = t.outboundBitsRate.values ? t.outboundBitsRate.values : []
|
||||
mpackets[3].data = t.internalBitsRate.values ? t.internalBitsRate.values : []
|
||||
mpackets[4].data = t.throughBitsRate.values ? t.throughBitsRate.values : []
|
||||
mpackets[5].data = t.other.values ? t.other.values : []
|
||||
mpackets.forEach((e) => {
|
||||
e.show = true
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
this.echartsInit(this.mpackets)
|
||||
} else if (t.type === 'packets' && val === 'Packets/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].data = t.totalPacketsRate.values ? t.totalPacketsRate.values : []
|
||||
mpackets[1].data = t.inboundPacketsRate.values ? t.inboundPacketsRate.values : []
|
||||
mpackets[2].data = t.outboundPacketsRate.values ? t.outboundPacketsRate.values : []
|
||||
mpackets[3].data = t.internalPacketsRate.values ? t.internalPacketsRate.values : []
|
||||
mpackets[4].data = t.throughPacketsRate.values ? t.throughPacketsRate.values : []
|
||||
mpackets[5].data = t.other.values ? t.other.values : []
|
||||
mpackets.forEach((e) => {
|
||||
e.show = true
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
this.echartsInit(this.mpackets)
|
||||
} else if (t.type === 'sessions' && val === 'Sessions/s') {
|
||||
const mpackets = _.cloneDeep(this.mpackets)
|
||||
mpackets[0].data = t.totalSessionsRate.values ? t.totalSessionsRate.values : []
|
||||
mpackets.forEach((e, i) => {
|
||||
if (i !== 0) {
|
||||
e.show = false
|
||||
}
|
||||
})
|
||||
this.mpackets = mpackets
|
||||
this.echartsInit(this.mpackets)
|
||||
}
|
||||
})
|
||||
const totalTrafficAnalysis = get(api.npm.overview.totalTrafficAnalysis, params)
|
||||
const totalNetworkAnalysis = get(api.npm.overview.totalNetworkAnalysis, params)
|
||||
const totalHttpResponseDelay = get(api.npm.overview.totalHttpResponseDelay, params)
|
||||
const totalSslConDelay = get(api.npm.overview.totalSslConDelay, params)
|
||||
const npmLineData = []
|
||||
Promise.all([totalNetworkAnalysis, totalTrafficAnalysis, totalHttpResponseDelay, totalSslConDelay]).then(res => {
|
||||
res.forEach(item => {
|
||||
if (item.code === 200) {
|
||||
npmLineData.push(...item.data.result)
|
||||
} else {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = res.message
|
||||
}
|
||||
}).catch(e => {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = e.message
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
} else if (val === 'establishLatencyMs' || val === 'tcpLostlenPercent' || val === 'pktRetransPercent') {
|
||||
this.toggleLoading(true)
|
||||
get(api.npm.overview.totalNetworkAnalysis, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
this.isNoData = npmLineData.length === 0
|
||||
if (this.isNoData) {
|
||||
this.tabs = [
|
||||
{ name: this.$t('network.total'), show: true, positioning: 0, data: [], unitType: 'number' },
|
||||
{ name: this.$t('network.inbound'), show: true, positioning: 1, data: [], unitType: 'number' },
|
||||
{ name: this.$t('network.outbound'), show: true, positioning: 2, data: [], unitType: 'number' },
|
||||
{ name: this.$t('network.internal'), show: true, positioning: 3, data: [], unitType: 'number' },
|
||||
{ name: this.$t('network.through'), show: true, positioning: 4, data: [], unitType: 'number' },
|
||||
{ name: this.$t('network.other'), show: true, positioning: 5, data: [], unitType: 'number' }
|
||||
]
|
||||
this.npmQuantity = [
|
||||
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
|
||||
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
|
||||
{ name: this.$t('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: this.$t('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: this.$t('overall.packetRetrans'), show: true, positioning: 0, data: [], unitType: unitTypes.percent, index: 4 }
|
||||
]
|
||||
}
|
||||
res.data.result.forEach((t) => {
|
||||
if (t.type === 'establishLatencyMs' && val === 'establishLatencyMs') {
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
npmQuantity[0].data = t.establishLatencyMs.values ? t.establishLatencyMs.values : []
|
||||
npmQuantity.forEach((e, i) => {
|
||||
e.show = i === 0
|
||||
})
|
||||
this.npmQuantity = npmQuantity
|
||||
this.echartsInit(this.npmQuantity, '(ms)')
|
||||
} else if (t.type === 'tcpLostlenPercent' && val === 'tcpLostlenPercent') {
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
npmQuantity[3].data = t.tcpLostlenPercent.values ? t.tcpLostlenPercent.values : []
|
||||
npmQuantity.forEach((e, i) => {
|
||||
e.show = i === 3
|
||||
})
|
||||
this.npmQuantity = npmQuantity
|
||||
this.echartsInit(this.npmQuantity, '(%)')
|
||||
} else if (t.type === 'pktRetransPercent' && val === 'pktRetransPercent') {
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
npmQuantity[4].data = t.pktRetransPercent.values ? t.pktRetransPercent.values : []
|
||||
npmQuantity.forEach((e, i) => {
|
||||
e.show = i === 4
|
||||
})
|
||||
this.npmQuantity = npmQuantity
|
||||
this.echartsInit(this.npmQuantity, '(%)')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = res.message
|
||||
console.info(npmLineData)
|
||||
this.initData(npmLineData, val)
|
||||
}
|
||||
}).catch(e => {
|
||||
this.isNoData = false
|
||||
@@ -429,83 +277,6 @@ export default {
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
} else if (val === 'httpResponseLatency') {
|
||||
this.toggleLoading(true)
|
||||
get(api.npm.overview.totalHttpResponseDelay, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.npmQuantity = [
|
||||
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
|
||||
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
|
||||
]
|
||||
}
|
||||
res.data.result.forEach(t => {
|
||||
if (t.type === 'httpResponseLatency' && val === 'httpResponseLatency') {
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
npmQuantity[1].data = t.httpResponseLatency.values ? t.httpResponseLatency.values : []
|
||||
npmQuantity.forEach((e, i) => {
|
||||
e.show = i === 1
|
||||
})
|
||||
this.npmQuantity = npmQuantity
|
||||
this.echartsInit(this.npmQuantity, '(ms)')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = res.message
|
||||
}
|
||||
}).catch(e => {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = e.message
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
} else if (val === 'sslConLatency') {
|
||||
this.toggleLoading(true)
|
||||
get(api.npm.overview.totalSslConDelay, params).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.showError = false
|
||||
this.isNoData = res.data.result.length === 0
|
||||
if (this.isNoData) {
|
||||
this.npmQuantity = [
|
||||
{ name: 'networkAppPerformance.tcpConnectionEstablishLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.httpResponse', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.sslResponseLatency', show: true, positioning: 0, data: [], unitType: unitTypes.time },
|
||||
{ name: 'networkAppPerformance.packetLoss', show: true, positioning: 0, data: [], unitType: unitTypes.percent },
|
||||
{ name: 'overall.packetRetrans', show: true, positioning: 0, data: [], unitType: unitTypes.percent }
|
||||
]
|
||||
}
|
||||
res.data.result.forEach(t => {
|
||||
if (t.type === 'sslConLatency' && val === 'sslConLatency') {
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
npmQuantity[2].data = t.sslConLatency.values ? t.sslConLatency.values : []
|
||||
npmQuantity.forEach((e, i) => {
|
||||
e.show = i === 2
|
||||
})
|
||||
this.npmQuantity = npmQuantity
|
||||
this.echartsInit(this.npmQuantity, '(ms)')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = res.message
|
||||
}
|
||||
}).catch(e => {
|
||||
this.isNoData = false
|
||||
this.showError = true
|
||||
this.errorMsg = e.message
|
||||
}).finally(() => {
|
||||
this.toggleLoading(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
echartsInit (echartsData, legendUnit) {
|
||||
@@ -514,7 +285,7 @@ export default {
|
||||
if (echartsData.length > 0) {
|
||||
const dom = document.getElementById('chart-line')
|
||||
!this.myChart && (this.myChart = echarts.init(dom))
|
||||
this.chartOption = trafficLineChartOption
|
||||
this.chartOption = _.cloneDeep(trafficLineChartOption)
|
||||
const chartOption = this.chartOption.series[0]
|
||||
this.chartOption.series = echartsData.map((t) => {
|
||||
this.chartOption.yAxis[0].axisLabel.formatter = (value) => {
|
||||
@@ -533,7 +304,7 @@ export default {
|
||||
color: chartColor3[t.positioning],
|
||||
width: 1
|
||||
},
|
||||
stack: t.name !== 'network.total' ? 'network.total' : '',
|
||||
stack: t.name !== this.$t('network.total') ? this.$t('network.total') : '',
|
||||
areaStyle: {
|
||||
opacity: 0.1,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
@@ -552,7 +323,7 @@ export default {
|
||||
})
|
||||
this.chartOption.tooltip.formatter = (params) => {
|
||||
params.forEach(t => {
|
||||
this.mpackets.forEach(e => {
|
||||
this.tabs.forEach(e => {
|
||||
if (e.name === t.seriesName) {
|
||||
t.borderColor = chartColor3[e.positioning]
|
||||
}
|
||||
@@ -619,6 +390,81 @@ export default {
|
||||
},
|
||||
resize () {
|
||||
this.myChart.resize()
|
||||
},
|
||||
initData (data, val) {
|
||||
let lineData = []
|
||||
if (data !== undefined && data.length > 0) {
|
||||
data.forEach(item => {
|
||||
item.type = getLineType(item.type)
|
||||
if (['Bits/s', 'Packets/s', 'Sessions/s'].indexOf(val) > -1) {
|
||||
if (item.type === val) {
|
||||
lineData = Object.keys((item)).map(t => {
|
||||
return {
|
||||
...item[t],
|
||||
index: getLineIndexUnit2(t, false),
|
||||
key: t
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (item.type === val) {
|
||||
lineData = Object.keys((item)).map(t => {
|
||||
return {
|
||||
...item[t],
|
||||
index: getLineIndexUnit(item.type, false),
|
||||
unit: getLineIndexUnit(item.type, true),
|
||||
key: t
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
lineData.splice(0, 1)
|
||||
console.info(lineData)
|
||||
const tabs = _.cloneDeep(this.tabs)
|
||||
const npmQuantity = _.cloneDeep(this.npmQuantity)
|
||||
if (val === 'Sessions/s') {
|
||||
lineData.forEach((d, i) => {
|
||||
tabs[i].data = d.values
|
||||
tabs[i].analysis = d.analysis
|
||||
})
|
||||
tabs.forEach((e, i) => {
|
||||
if (i !== 0) {
|
||||
e.show = false
|
||||
}
|
||||
})
|
||||
this.tabs = tabs
|
||||
this.echartsInit(this.tabs)
|
||||
} else if (val !== 'Bits/s' && val !== 'Packets/s') {
|
||||
this.legendInit(lineData, npmQuantity, true)
|
||||
} else {
|
||||
this.legendInit(lineData, tabs, false)
|
||||
}
|
||||
},
|
||||
legendInit (data, npmData, show) {
|
||||
data.forEach((d, i) => {
|
||||
if (show) {
|
||||
npmData[d.index].data = d.values
|
||||
npmData[d.index].analysis = d.analysis
|
||||
} else {
|
||||
npmData[d.index].data = d.values
|
||||
npmData[d.index].analysis = d.analysis
|
||||
}
|
||||
})
|
||||
if (show) {
|
||||
npmData.forEach((e, i) => {
|
||||
e.show = i === data[0].index
|
||||
})
|
||||
this.npmQuantity = npmData
|
||||
this.echartsInit(this.npmQuantity, data[0].unit)
|
||||
} else {
|
||||
npmData.forEach((e) => {
|
||||
e.show = true
|
||||
})
|
||||
this.tabs = npmData
|
||||
this.echartsInit(this.tabs)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
@@ -633,8 +479,9 @@ export default {
|
||||
beforeUnmount () {
|
||||
clearTimeout(this.timer)
|
||||
window.removeEventListener('resize', this.resize)
|
||||
this.myChart = null
|
||||
this.myChart = null
|
||||
if (this.myChart) {
|
||||
echarts.dispose(this.myChart)
|
||||
}
|
||||
this.unitConvert = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
<template>
|
||||
<div class="single-value" v-for="(npm, index) in newNpmNetworkData" :key="index">
|
||||
<div class="single-value__title" style="display: flex">
|
||||
{{ $t(npmNetworkName[index].name) }}
|
||||
<chart-error v-if="npm.message" tooltip :content="npm.message"></chart-error>
|
||||
</div>
|
||||
|
||||
<div class="single-value__content">
|
||||
<div class="single-value__content-number" v-if="index ===0 || index ===1 || index ===2">
|
||||
{{ unitConvert(npm.Avg, unitTypes.time).join(' ') }}
|
||||
</div>
|
||||
<div class="single-value__content-number" v-else>
|
||||
{{unitConvert(npm.Avg, unitTypes.percent).join(' ')}}
|
||||
</div>
|
||||
<div v-if="npm.value > 0" class="single-value__content-trend single-value__content-trend-red">
|
||||
<i class="cn-icon-rise1 cn-icon"></i>
|
||||
<span v-if="npm.value <= 5">
|
||||
{{ unitConvert(npm.value, unitTypes.percent).join('') }}
|
||||
</span>
|
||||
<span v-else>>500.00%</span>
|
||||
</div>
|
||||
<div v-else-if="npm.value < 0" class="single-value__content-trend single-value__content-trend-green">
|
||||
<i class="cn-icon-decline cn-icon"></i>
|
||||
<span v-if="npm.value >= -5">
|
||||
{{ unitConvert(npm.value, unitTypes.percent).join('').replaceAll('-', '') }}
|
||||
</span>
|
||||
<span v-else>>500.00%</span>
|
||||
</div>
|
||||
<div v-else-if="npm.value === 0" class="single-value__content-trend single-value__content-trend-black">
|
||||
<i class="cn-icon-constant cn-icon"></i>
|
||||
</div>
|
||||
<div v-else></div>
|
||||
</div>
|
||||
|
||||
<div class="single-value__circle">
|
||||
<div class="single-value__circle-p95">
|
||||
<span v-if="index ===0 || index ===1 || index ===2">
|
||||
P95:{{ unitConvert(npm.P95, unitTypes.time).join(' ') }}</span>
|
||||
<span v-else>
|
||||
P95:{{ unitConvert(npm.P95, unitTypes.percent).join(' ') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="single-value__circle-p99">
|
||||
<span v-if="index ===0 || index ===1 || index ===2">
|
||||
P99:{{ unitConvert(npm.P99, unitTypes.time).join(' ') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
P99:{{ unitConvert(npm.P99, unitTypes.percent).join(' ') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { unitTypes } from '@/utils/constants'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import ChartError from '@/components/common/Error'
|
||||
|
||||
export default {
|
||||
name: 'SingleValue',
|
||||
components: { ChartError },
|
||||
props: {
|
||||
npmNetworkName: Array,
|
||||
npmNetworkData: Array
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
unitTypes,
|
||||
unitConvert,
|
||||
newNpmNetworkData: [] // 整合处理传过来的数据列表
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
npmNetworkData: {
|
||||
deep: true,
|
||||
handler () {
|
||||
this.initData()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.initData()
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
initData () {
|
||||
// 传过来的数据
|
||||
const npmNetworkData = this.npmNetworkData
|
||||
// 处理数据后的数组
|
||||
const dealList = []
|
||||
|
||||
if (npmNetworkData !== undefined && npmNetworkData.length > 0) {
|
||||
npmNetworkData.forEach((item) => {
|
||||
const tempObj = {}
|
||||
for (const i in item) {
|
||||
if (item.msg || item.message) {
|
||||
// 为了兼容字段为msg的情况
|
||||
tempObj.message = item.msg ? item.msg : item.message
|
||||
} else {
|
||||
// 将含有avg、p90等关键字使用avg、p90来代替,形成统一属性
|
||||
if (i.indexOf('Avg') > -1) {
|
||||
tempObj.Avg = item[i]
|
||||
} else if (i.indexOf('P50') > -1) {
|
||||
tempObj.P50 = item[i]
|
||||
} else if (i.indexOf('P90') > -1) {
|
||||
tempObj.P90 = item[i]
|
||||
} else if (i.indexOf('P95') > -1) {
|
||||
tempObj.P95 = item[i]
|
||||
} else if (i.indexOf('P99') > -1) {
|
||||
tempObj.P99 = item[i]
|
||||
}
|
||||
tempObj.value = item.value
|
||||
}
|
||||
}
|
||||
dealList.push(tempObj)
|
||||
})
|
||||
this.newNpmNetworkData = dealList
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -134,15 +134,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.$route.query.eventId) {
|
||||
if (parseFloat(this.$route.query.eventId) === this.detection.eventId) {
|
||||
const container = document.getElementById('cnContainer')
|
||||
container.scrollTop = 555 + this.index * 97
|
||||
|
||||
this.isCollapse = false
|
||||
this.$emit('switchCollapse', this.isCollapse, this.index)
|
||||
}
|
||||
}
|
||||
this.initExpendTab()
|
||||
},
|
||||
computed: {
|
||||
iconClass () {
|
||||
@@ -186,7 +178,7 @@ export default {
|
||||
this.$emit('switchCollapse', this.isCollapse, this.index)
|
||||
|
||||
if (this.isCollapse) {
|
||||
const newQuery = this.$route.query // 深拷贝路由数据
|
||||
const newQuery = this.$route.query
|
||||
delete newQuery.eventId
|
||||
this.reloadUrl(newQuery, 'cleanOldParams')
|
||||
} else {
|
||||
@@ -207,6 +199,33 @@ export default {
|
||||
newUrl = urlParamsHandler(window.location.href, query, newParam, clean)
|
||||
}
|
||||
overwriteUrl(newUrl)
|
||||
},
|
||||
/**
|
||||
* 初始化从npm跳转过来的id,并展开tab
|
||||
*/
|
||||
initExpendTab () {
|
||||
if (this.$route.query.eventId) {
|
||||
if (this.$route.query.eventId === this.detection.eventId) {
|
||||
const container = document.getElementById('cnContainer')
|
||||
const dom = document.getElementsByClassName('cn-detection__case')
|
||||
// 未展开的item折叠块,高度67+下边距10+底部线高度1,兼容不同分辨率下的tab高度
|
||||
let itemHeight = 78
|
||||
if (dom && this.index > 0) {
|
||||
itemHeight = dom[0].clientHeight + 11
|
||||
}
|
||||
|
||||
let topHeight = 554 + this.index * itemHeight
|
||||
// 经过测试对比,第7个以后的tab会往上移动,但是手动展开和自动展开tab的滚动条高度一致,为解决该问题,自动加上误差值
|
||||
if (this.index > 6) {
|
||||
topHeight = topHeight + 6
|
||||
}
|
||||
|
||||
container.scrollTop = topHeight
|
||||
|
||||
this.isCollapse = false
|
||||
this.$emit('switchCollapse', this.isCollapse, this.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -842,7 +842,7 @@ export default {
|
||||
setup () {
|
||||
const { params } = useRoute()
|
||||
const pageType = params.typeName
|
||||
const dateRangeValue = 60 * 24
|
||||
const dateRangeValue = 60
|
||||
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||
const timeFilter = ref({ startTime, endTime, dateRangeValue })
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<div class="metric__column">
|
||||
<div class="overview__title">{{$t('detections.metric')}}</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__content--metric ">{{detection.eventType || '-'}}</div>
|
||||
<div class="row__content--metric ">{{getNameByEventType(detection.eventType) || '-'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric__column">
|
||||
@@ -95,7 +95,7 @@ import { get } from '@/utils/http'
|
||||
import * as echarts from 'echarts'
|
||||
import { markRaw } from 'vue'
|
||||
import { metricOption } from '@/views/detections/options/detectionOptions'
|
||||
import { sortBy, reverseSortBy } from '@/utils/tools'
|
||||
import { sortBy, reverseSortBy, getNameByEventType } from '@/utils/tools'
|
||||
import _ from 'lodash'
|
||||
export default {
|
||||
name: 'DetectionPerformanceEventAppOverview',
|
||||
@@ -134,6 +134,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNameByEventType,
|
||||
query () {
|
||||
this.queryBasic().then(responses => {
|
||||
responses && (this.basicInfo = responses)
|
||||
@@ -180,6 +181,10 @@ export default {
|
||||
this.chartOptionMetric.series[2].data = this.metricList.slice(endIndex - 1, this.metricList.length).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
|
||||
}
|
||||
|
||||
this.chartOptionMetric.series.forEach(item => {
|
||||
item.name = this.getNameByEventType(this.detection.eventType)
|
||||
})
|
||||
|
||||
this.chartOptionMetric && this.metricChart.setOption(this.chartOptionMetric)
|
||||
},
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<div class="metric__column">
|
||||
<div class="overview__title">{{$t('detections.metric')}}</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__content--metric ">{{detection.eventType || '-'}}</div>
|
||||
<div class="row__content--metric ">{{getNameByEventType(detection.eventType) || '-'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric__column">
|
||||
@@ -98,7 +98,7 @@ import { get } from '@/utils/http'
|
||||
import * as echarts from 'echarts'
|
||||
import { markRaw } from 'vue'
|
||||
import { metricOption } from '@/views/detections/options/detectionOptions'
|
||||
import { sortBy, reverseSortBy } from '@/utils/tools'
|
||||
import { sortBy, reverseSortBy, getNameByEventType } from '@/utils/tools'
|
||||
import _ from 'lodash'
|
||||
export default {
|
||||
name: 'DetectionPerformanceEventDomainOverview',
|
||||
@@ -165,6 +165,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNameByEventType,
|
||||
query () {
|
||||
this.queryBasic().then(responses => {
|
||||
responses && (this.basicInfo = responses)
|
||||
@@ -212,6 +213,10 @@ export default {
|
||||
this.chartOptionMetric.series[2].data = this.metricList.slice(endIndex - 1, this.metricList.length).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
|
||||
}
|
||||
|
||||
this.chartOptionMetric.series.forEach(item => {
|
||||
item.name = this.getNameByEventType(this.detection.eventType)
|
||||
})
|
||||
|
||||
this.chartOptionMetric && this.metricChart.setOption(this.chartOptionMetric)
|
||||
},
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<div class="metric__column">
|
||||
<div class="overview__title">{{$t('detections.metric')}}</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__content--metric ">{{getNameByType(detection.eventType) || '-'}}</div>
|
||||
<div class="row__content--metric ">{{getNameByEventType(detection.eventType) || '-'}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric__column">
|
||||
@@ -88,7 +88,7 @@ import { get } from '@/utils/http'
|
||||
import * as echarts from 'echarts'
|
||||
import { markRaw } from 'vue'
|
||||
import { metricOption } from '@/views/detections/options/detectionOptions'
|
||||
import { sortBy, reverseSortBy } from '@/utils/tools'
|
||||
import { sortBy, reverseSortBy, getNameByEventType } from '@/utils/tools'
|
||||
import _ from 'lodash'
|
||||
|
||||
export default {
|
||||
@@ -129,6 +129,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getNameByEventType,
|
||||
query () {
|
||||
this.queryBasic().then(responses => {
|
||||
responses && (this.basicInfo = responses)
|
||||
@@ -173,9 +174,11 @@ export default {
|
||||
this.chartOptionMetric.series[1].data = this.metricList.slice(startIndex - 1, endIndex).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
|
||||
this.chartOptionMetric.series[2].data = this.metricList.slice(endIndex - 1, this.metricList.length).map(v => [Number(v[0]) * 1000, Number(v[1]), unitTypes.number])
|
||||
}
|
||||
|
||||
this.chartOptionMetric.series.forEach(item => {
|
||||
item.name = this.getNameByType(this.detection.eventType)
|
||||
item.name = this.getNameByEventType(this.detection.eventType)
|
||||
})
|
||||
|
||||
this.chartOptionMetric && this.metricChart.setOption(this.chartOptionMetric)
|
||||
},
|
||||
queryMetric () {
|
||||
@@ -236,29 +239,6 @@ export default {
|
||||
}
|
||||
})
|
||||
window.open(href, '_blank')
|
||||
},
|
||||
/**
|
||||
* 通过事件类型转换对应名称
|
||||
* @param type
|
||||
* @returns {string}
|
||||
*/
|
||||
getNameByType (type) {
|
||||
switch (type) {
|
||||
case 'http error': {
|
||||
return 'http error ratio'
|
||||
}
|
||||
case 'dns error': {
|
||||
return 'dns error ratio'
|
||||
}
|
||||
case 'high dns response time': {
|
||||
return 'dns response time'
|
||||
}
|
||||
// 目前ui并未找到此类型,添加以防不测
|
||||
case 'high http resopnse time':
|
||||
default: {
|
||||
return 'http response time'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
@@ -324,8 +324,8 @@ export default {
|
||||
getMillisecond,
|
||||
query () {
|
||||
Promise.all([this.queryBasic(), this.queryEvent()]).then((responses) => {
|
||||
responses[0].malwareTechniques = responses[0].malwareTechniques.length > 2 ? responses[0].malwareTechniques.replace('[', '').split(',', 5).join(', ') : ''
|
||||
responses[0].malwareGroups = responses[0].malwareGroups.length > 2 ? responses[0].malwareGroups.replace('[', '').split(',', 5).join(', ') : ''
|
||||
responses[0].malwareTechniques = responses[0].malwareTechniques.length > 2 ? responses[0].malwareTechniques.replace('[', '').replace(']', '').split(',', 5).join(', ') : ''
|
||||
responses[0].malwareGroups = responses[0].malwareGroups.length > 2 ? responses[0].malwareGroups.replace('[', '').replace(']', '').split(',', 5).join(', ') : ''
|
||||
responses[0].malwarePlatforms = responses[0].malwarePlatforms.length > 1 ? responses[0].malwarePlatforms : ''
|
||||
responses[0].malwareDescription = responses[0].malwareDescription.length > 1 ? responses[0].malwareDescription : ''
|
||||
responses[0] && (this.basicInfo = responses[0])
|
||||
|
||||
@@ -717,7 +717,7 @@ export default {
|
||||
}
|
||||
},
|
||||
setup () {
|
||||
const dateRangeValue = 60 * 24
|
||||
const dateRangeValue = 60
|
||||
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||
const timeFilter = ref({ startTime, endTime, dateRangeValue })
|
||||
return {
|
||||
|
||||
@@ -22,6 +22,14 @@
|
||||
<div class="row__label row__label--width130">{{$t('entities.org')}}</div>
|
||||
<div class="row__content">{{entityData.domainWhoisOrg || '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.icpCompanyName')}}</div>
|
||||
<div class="row__content">{{entityData.domainIcpCompanyName || '-'}}</div>
|
||||
</div>
|
||||
<div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('entities.icpLicense')}}</div>
|
||||
<div class="row__content">{{entityData.domainIcpSiteLicense || '-'}}</div>
|
||||
</div>
|
||||
<!-- <div class="overview__row">
|
||||
<div class="row__label row__label--width130">{{$t('overall.remark')}}</div>
|
||||
<div class="row__content">{{entityData.domainDescription || '-'}}</div>
|
||||
@@ -352,7 +360,9 @@ export default {
|
||||
domainDescription: response.data.result.domainDescription,
|
||||
domainReputationScore: response.data.result.domainReputationScore,
|
||||
domainWhoisAddress: response.data.result.domainWhoisAddress,
|
||||
domainWhoisOrg: response.data.result.domainWhoisOrg
|
||||
domainWhoisOrg: response.data.result.domainWhoisOrg,
|
||||
domainIcpCompanyName: response.data.result.domainIcpCompanyName,
|
||||
domainIcpSiteLicense: response.data.result.domainIcpSiteLicense
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<div class="cn-builtin">
|
||||
<div class="cn-builtin-left">
|
||||
<div class="cn-report">
|
||||
<div class="cn-report-left">
|
||||
<loading :loading="builtinLeftLoading"></loading>
|
||||
<div class="cn-builtin-left-title">
|
||||
<div class="cn-report-left-title">
|
||||
{{$t('report.category')}}
|
||||
</div>
|
||||
<div class="cn-builtin-left-menu" :class="{'cn-active': !builtinId}" @click="builtinTabs(null)">
|
||||
<div class="cn-report-left-menu" :class="{'cn-active': !builtinId}" @click="builtinTabs(null)">
|
||||
{{$t('dns.all')}}
|
||||
</div>
|
||||
<div class="cn-builtin-left-menu" :class="{'cn-active': builtinId === item.id}" v-for="item in builtinReportLeftMenu" :key="item.id" @click="builtinTabs(item.id)">
|
||||
<div class="cn-report-left-menu" :class="{'cn-active': builtinId === item.id}" v-for="item in builtinReportLeftMenu" :key="item.id" @click="builtinTabs(item.id)">
|
||||
{{item.name}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="cn-builtin-right">
|
||||
<div class="cn-report-right">
|
||||
<cn-data-list
|
||||
ref="dataList"
|
||||
:tableId="tableId"
|
||||
@@ -22,19 +22,26 @@
|
||||
:layout="['search']"
|
||||
@search="search"
|
||||
>
|
||||
<template #top-tool-right>
|
||||
<button
|
||||
id="account-add"
|
||||
class="top-tool-btn"
|
||||
type="button"
|
||||
@click="add"
|
||||
>
|
||||
<i class="cn-icon-add cn-icon"/>
|
||||
<template #top-tool-left>
|
||||
<button id="account-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="report-edit" class="top-tool-btn margin-r-10" :disabled="disableEdit"
|
||||
@click="editReport">
|
||||
<i class="cn-icon-edit cn-icon"></i>
|
||||
<span>{{$t('overall.edit')}}</span>
|
||||
</button>
|
||||
<button id="report-delete" class="top-tool-btn margin-r-10"
|
||||
@click="delBatch">
|
||||
<i class="cn-icon-delete cn-icon"></i>
|
||||
<span>{{$t('overall.delete')}}</span>
|
||||
</button>
|
||||
</template>
|
||||
<template #default>
|
||||
<loading :loading="builtinRightLoading"></loading>
|
||||
<builtin-report-table
|
||||
<report-table
|
||||
ref="dataTable"
|
||||
:api="url"
|
||||
:custom-table-title="tools.customTableTitle"
|
||||
@@ -73,7 +80,7 @@
|
||||
|
||||
<script>
|
||||
import { get } from '@/utils/http'
|
||||
import builtinReportTable from '@/components/table/report/reportTestTable'
|
||||
import ReportTable from '@/components/table/report/ReportTable'
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import { api } from '@/utils/api'
|
||||
@@ -148,7 +155,7 @@ export default {
|
||||
'report.november',
|
||||
'report.december'
|
||||
],
|
||||
tableId: 'builtinReportTable',
|
||||
tableId: 'reportTable',
|
||||
builtinLeftLoading: false,
|
||||
builtinRightLoading: false,
|
||||
getNum: -1
|
||||
@@ -171,7 +178,7 @@ export default {
|
||||
components: {
|
||||
Loading,
|
||||
cnDataList,
|
||||
builtinReportTable,
|
||||
ReportTable,
|
||||
ReportBox
|
||||
},
|
||||
mounted () {
|
||||
@@ -210,7 +217,7 @@ export default {
|
||||
methods: {
|
||||
queryGetTempData () {
|
||||
this.builtinLeftLoading = true
|
||||
get(api.reportCategory).then(res => {
|
||||
get(api.reportCategory, { pageSize: 999 }).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.builtinReportLeftMenu = res.data.list.map(c => {
|
||||
return {
|
||||
@@ -287,6 +294,19 @@ export default {
|
||||
this.object = u
|
||||
this.rightBox.show = true
|
||||
},
|
||||
editReport () {
|
||||
if(this.batchDeleteObjs.length === 0){
|
||||
this.$alert(this.$t('tip.pleaseSelectForEdit'),{
|
||||
confirmButtonText: this.$t('tip.yes'),
|
||||
type:'warning'
|
||||
})
|
||||
}else {
|
||||
let curRecord = this.batchDeleteObjs[0]
|
||||
this.initConfig(curRecord)
|
||||
this.object = curRecord
|
||||
this.rightBox.show = true
|
||||
}
|
||||
},
|
||||
initConfig (u) {
|
||||
if (!u.config) {
|
||||
u.config = {
|
||||
41
src/views/setting/Index.vue
Normal file
41
src/views/setting/Index.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="administration entity-explorer entity-explorer--show-list">
|
||||
<!-- 顶部工具栏,在列表页显示 -->
|
||||
<div class="explorer-top-tools explorer-detection-top-tools">
|
||||
<div class="explorer-top-tools-title">{{$t('overall.knowledgeBase')}}</div>
|
||||
</div>
|
||||
<div style="width: 100%;padding-bottom: 26px;">
|
||||
<chart-tabs :data="tabsData" router></chart-tabs>
|
||||
</div>
|
||||
<!-- 内容区 -->
|
||||
<div class="explorer-container administration-container">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ChartTabs from '@/components/common/ChartTabs'
|
||||
import { useStore } from 'vuex'
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
ChartTabs
|
||||
},
|
||||
setup () {
|
||||
const store = useStore()
|
||||
const menu = store.getters.menuList.find(m => m.code === 'setting')
|
||||
const tabsData = menu.children.map(l => ({
|
||||
...l,
|
||||
path: l.route
|
||||
})).sort((a, b) => a.sort - b.sort)
|
||||
return {
|
||||
tabsData
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
128
src/views/setting/KnowledgeBase.vue
Normal file
128
src/views/setting/KnowledgeBase.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<div style="height: 100%;" class="knowledge-base">
|
||||
<div class="top-title">
|
||||
{{$t('overall.knowledgeBase')}}
|
||||
</div>
|
||||
<cn-data-list
|
||||
ref="dataList"
|
||||
:tableId="tableId"
|
||||
v-model:custom-table-title="tools.customTableTitle"
|
||||
:api="url"
|
||||
from="knowledge-base"
|
||||
:layout="['columnCustomize','elementSet','search']"
|
||||
@search="search"
|
||||
>
|
||||
<template v-slot:top-tool-left>
|
||||
<button id="knowledge-base-add" :title="$t('knowledgeBase.createKnowledgeBase')" class="top-tool-btn margin-r-10 top-tool-btn--create"
|
||||
@click="jumpToCreatePage">
|
||||
<i class="cn-icon-xinjian cn-icon"></i>
|
||||
<span>{{$t('overall.create')}}</span>
|
||||
</button>
|
||||
<!--
|
||||
<button id="knowledge-base-edit" :title="$t('knowledgeBase.editKnowledgeBase')" class="top-tool-btn margin-r-10" :disabled="disableEdit"
|
||||
@click="edit">
|
||||
<i class="cn-icon-edit cn-icon" ></i>
|
||||
<span>{{$t('overall.edit')}}</span>
|
||||
</button>
|
||||
-->
|
||||
<button id="knowledge-base-delete" :title="$t('knowledgeBase.deleteKnowledgeBase')" class="top-tool-btn margin-r-10"
|
||||
@click="delBatch">
|
||||
<i class="cn-icon-delete cn-icon"></i>
|
||||
<span>{{$t('overall.delete')}}</span>
|
||||
</button>
|
||||
</template>
|
||||
<template v-slot:default>
|
||||
<knowledge-base-table
|
||||
ref="dataTable"
|
||||
v-loading="tools.loading"
|
||||
:api="url"
|
||||
:custom-table-title="tools.customTableTitle"
|
||||
:height="mainTableHeight"
|
||||
:table-data="tableData"
|
||||
@delete="del"
|
||||
@edit="edit"
|
||||
@orderBy="tableDataSort"
|
||||
@reload="getTableData"
|
||||
@selectionChange="selectionChange"
|
||||
></knowledge-base-table>
|
||||
</template>
|
||||
<!-- 分页组件 -->
|
||||
<template #pagination>
|
||||
<pagination ref="pagination" :page-obj="pageObj" :table-id="tableId" @pageNo='pageNo' @pageSize='pageSize'></pagination>
|
||||
</template>
|
||||
</cn-data-list>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import cnDataList from '@/components/table/CnDataList'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import KnowledgeBaseTable from '@/components/table/setting/KnowledgeBaseTable'
|
||||
import { api } from '@/utils/api'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'knowledgeBase',
|
||||
components: {
|
||||
cnDataList,
|
||||
KnowledgeBaseTable
|
||||
},
|
||||
mixins: [dataListMixin],
|
||||
data () {
|
||||
return {
|
||||
url: api.knowledgeBase,
|
||||
tableId: 'knowledgeBaseTable' // 需要分页的table的id,用于记录每页数量
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
edit (u) {
|
||||
axios.get(`${this.url}`, { params: { ids: u.id } }).then(response => {
|
||||
if (response.data.code === 200) {
|
||||
this.object = response.data.data.list[0]
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
if (e.response.data && e.response.data.message) {
|
||||
this.$message.error(e.response.data.message)
|
||||
} else {
|
||||
this.$message.error('Something went wrong...')
|
||||
}
|
||||
})
|
||||
},
|
||||
del (row) {
|
||||
this.$confirm(this.$t('tip.confirmDelete'), {
|
||||
confirmButtonText: this.$t('tip.yes'),
|
||||
cancelButtonText: this.$t('tip.no'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.tools.loading = true
|
||||
axios.delete(this.url + '?ids=' + row.id).then(response => {
|
||||
if (response.data.code === 200) {
|
||||
this.delFlag = true
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.deleteSuccess') })
|
||||
this.getTableData()
|
||||
} else {
|
||||
this.$message.error(response.data.message)
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
if (e.response.data && e.response.data.message) {
|
||||
this.$message.error(e.response.data.message)
|
||||
} else {
|
||||
this.$message.error('Something went wrong...')
|
||||
}
|
||||
}).finally(() => {
|
||||
this.tools.loading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
jumpToCreatePage () {
|
||||
this.$router.push({
|
||||
path: '/knowledgeBase/form',
|
||||
query: {
|
||||
t: +new Date()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
510
src/views/setting/KnowledgeBaseForm.vue
Normal file
510
src/views/setting/KnowledgeBaseForm.vue
Normal file
@@ -0,0 +1,510 @@
|
||||
<template>
|
||||
<div class="edit-knowledge-base">
|
||||
<div class="edit-knowledge-base__header">{{$t('overall.create')}}</div>
|
||||
<div class="edit-knowledge-base__body">
|
||||
<el-steps direction="vertical" :active="activeStep">
|
||||
<el-step v-for="(height, index) in stepHeights" :style="`flex-basis: ${height}px; flex-shrink: 0;`" :key="index"></el-step>
|
||||
</el-steps>
|
||||
<el-collapse v-model="activeCollapses">
|
||||
<el-collapse-item name="0">
|
||||
<template #title><div class="form-sub-title">{{$t('knowledgeBase.editInformation')}}</div></template>
|
||||
<el-form :model="editObject" label-position="top" ref="form" :rules="rules">
|
||||
<!--name-->
|
||||
<el-form-item :label="$t('config.roles.name')" prop="tagName">
|
||||
<el-input class="form-input" maxlength="64" placeholder="" :disabled="!!editObject.id" show-word-limit size="mini" type="text" v-model="editObject.tagName" @blur="tagNameBlur"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('overall.type')" prop="tagType">
|
||||
<el-select v-model="editObject.tagType"
|
||||
class="form-select"
|
||||
placeholder=" "
|
||||
popper-class="form-select-popper"
|
||||
:disabled="!!editObject.id || typeSelectDisable"
|
||||
size="mini"
|
||||
>
|
||||
<template v-for="type in knowledgeBaseType" :key="type.name">
|
||||
<el-option :label="type.name" :value="type.value"></el-option>
|
||||
</template>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('overall.remark')" prop="remark">
|
||||
<el-input maxlength="255" show-word-limit :rows="4" size='mini' type="textarea" v-model="editObject.remark" id="role-box-input-remark"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name="1" class="upload-collapse">
|
||||
<template #title><div class="form-sub-title">{{$t('overall.importFromFile')}}</div></template>
|
||||
<loading :loading="uploadLoading"></loading>
|
||||
<el-upload :action="`${baseUrl}knowledge/import`"
|
||||
:headers="uploadHeaders"
|
||||
:data="uploadParams"
|
||||
:multiple="false"
|
||||
:file-list="fileList"
|
||||
:on-change="fileChange"
|
||||
:on-success="uploadSuccess"
|
||||
:on-remove="onRemove"
|
||||
:before-upload="beforeUpload"
|
||||
:on-progress="onUpload"
|
||||
:on-error="uploadError"
|
||||
:class="uploadErrorTip ? 'el-upload--error' : ''"
|
||||
drag
|
||||
:accept="fileTypeLimit"
|
||||
ref="upload"
|
||||
>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">
|
||||
<div>{{$t('knowledgeBase.dropFileHereOr')}}<em>{{$t('knowledgeBase.clickToUpload')}}</em></div>
|
||||
<div class="upload-tip">{{$t('knowledgeBase.supportCsv')}}</div>
|
||||
</div>
|
||||
</el-upload>
|
||||
<transition name="el-zoom-in-top">
|
||||
<div class="upload-error-tip" v-if="uploadErrorTip">{{uploadErrorTip}}</div>
|
||||
</transition>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item name="2">
|
||||
<template #title><div class="form-sub-title">{{$t('overall.preview')}}</div></template>
|
||||
<div class="skeleton-border" v-if="!uploaded">
|
||||
<el-skeleton>
|
||||
<template #template>
|
||||
<div v-for="item of 6" :key="item" class="skeleton-item-row">
|
||||
<el-skeleton-item variant="text" style="width: calc(33% - 25px); margin-right: 38px;"/>
|
||||
<el-skeleton-item variant="text" style="width: calc(33% - 25px); margin-right: 38px;"/>
|
||||
<el-skeleton-item variant="text" style="width: calc(33% - 26px);"/>
|
||||
</div>
|
||||
</template>
|
||||
</el-skeleton>
|
||||
<div class="skeleton-tip">{{$t('knowledgeBase.skeletonTip')}}</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="imported-tip"><i class="cn-icon cn-icon-baocuo"/>
|
||||
{{$t('knowledgeBase.importTip', { total: originalImportInfo.total, succeeded: originalImportInfo.succeeded, failed: originalImportInfo.failed })}}
|
||||
</div>
|
||||
<div class="imported-table-box" :class="previewErrorTip ? 'imported-table-box--error' : ''">
|
||||
<table class="imported-table" v-if="!importedDataNoData">
|
||||
<tr>
|
||||
<th width="230">{{importedTableFirstColumn}}</th>
|
||||
<th width="180">Label</th>
|
||||
<th>{{$t('overall.import')}}</th>
|
||||
<th width="16"></th>
|
||||
</tr>
|
||||
<tr v-for="(d, i) in showImportedData" :key="importedType + d.tagItem + d.tagValue + i">
|
||||
<td class="imported-data-item" :title="d.tagItem">{{d.tagItem}}</td>
|
||||
<td class="imported-data-value" :title="d.tagValue">{{d.tagValue}}</td>
|
||||
<td class="imported-data-msg" :title="d.msg"><i :class="d.status === 1 ? 'el-icon-success' : 'el-icon-error'"></i> {{d.msg}}</td>
|
||||
<td><i class="el-icon-close" @click="removeImportedData(i)"></i></td>
|
||||
</tr>
|
||||
</table>
|
||||
<chart-no-data v-else></chart-no-data>
|
||||
<Pagination
|
||||
class="imported-pagination"
|
||||
:page-obj="importedPageObj"
|
||||
:store-page-no-on-url="false"
|
||||
layout="prev,pager,next"
|
||||
@pageNo='pageNo'
|
||||
@prev-click="prev"
|
||||
@next-click="next"
|
||||
></Pagination>
|
||||
</div>
|
||||
<transition name="el-zoom-in-top">
|
||||
<div class="preview-error-tip" v-if="previewErrorTip">{{previewErrorTip}}</div>
|
||||
</transition>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
<div class="edit-knowledge-base__footer">
|
||||
<button class="footer__btn footer__btn--light" @click="cancel">
|
||||
<span>{{$t('overall.cancel')}}</span>
|
||||
</button>
|
||||
<button style="position: relative;" :class="{'footer__btn--disabled': blockOperation.save}" :disabled="blockOperation.save" class="footer__btn" @click="save">
|
||||
<loading size="small" :loading="blockOperation.save"></loading>
|
||||
<span>{{$t('overall.save')}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ref } from 'vue'
|
||||
import _ from 'lodash'
|
||||
import { knowledgeBaseType, storageKey, unitTypes } from '@/utils/constants'
|
||||
import Pagination from '@/components/common/Pagination'
|
||||
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||
import axios from 'axios'
|
||||
import { api } from '@/utils/api'
|
||||
import unitConvert from '@/utils/unit-convert'
|
||||
import Loading from '@/components/common/Loading'
|
||||
export default {
|
||||
name: 'CreateKnowledgeBase',
|
||||
components: {
|
||||
Pagination,
|
||||
ChartNoData,
|
||||
Loading
|
||||
},
|
||||
data () {
|
||||
const nameValidator = (rule, value, callback) => {
|
||||
let validate = true
|
||||
// /^[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEFA-Za-z0-9\-\_]*$/
|
||||
const reg = /^[\u4e00-\u9fa5A-Za-z0-9\-\_]*$/
|
||||
validate = reg.test(value)
|
||||
return validate
|
||||
}
|
||||
const nameAndTypeValidator = async (rule, value, callback) => {
|
||||
this.$refs.form.clearValidate('tagType')
|
||||
let validate = true
|
||||
const response = await this.getKnowledgeBaseList()
|
||||
if (response.data.code === 200) {
|
||||
const find = response.data.data.list.find(d => d.tagName === value && d.tagType === this.editObject.tagType)
|
||||
if (find) {
|
||||
validate = false
|
||||
callback(new Error())
|
||||
}
|
||||
}
|
||||
return validate
|
||||
}
|
||||
const typeAndNameValidator = async (rule, value, callback) => {
|
||||
this.$refs.form.clearValidate('tagName')
|
||||
let validate = true
|
||||
const response = await this.getKnowledgeBaseList()
|
||||
if (response.data.code === 200) {
|
||||
const find = response.data.data.list.find(d => d.tagName === this.editObject.tagName && d.tagType === value)
|
||||
if (find) {
|
||||
validate = false
|
||||
callback(new Error())
|
||||
}
|
||||
}
|
||||
return validate
|
||||
}
|
||||
return {
|
||||
rules: {
|
||||
tagName: [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'blur' },
|
||||
{ validator: nameValidator, message: this.$t('validate.onlyAllowNumberLetterChinese-_'), trigger: 'blur' },
|
||||
{ validator: nameAndTypeValidator, message: this.$t('validate.duplicateRecord', { columns: '(' + this.$t('config.roles.name') + '+' + this.$t('overall.type') + ')' }), trigger: 'blur' }
|
||||
],
|
||||
tagType: [
|
||||
{ required: true, message: this.$t('validate.required'), trigger: 'change' },
|
||||
{ validator: typeAndNameValidator, message: this.$t('validate.duplicateRecord', { columns: '(' + this.$t('config.roles.name') + '+' + this.$t('overall.type') + ')' }), trigger: 'change' }
|
||||
],
|
||||
remark: [
|
||||
{ validator: nameValidator, message: this.$t('validate.onlyAllowNumberLetterChinese-_'), trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
tagNameBlur () {
|
||||
if (!this.tagNameFirstBlur) {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
this.tagNameFirstBlur = true
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
fileChange (files, fileList) {
|
||||
this.fileList = fileList.slice(-1)
|
||||
},
|
||||
uploadError () {
|
||||
this.uploadLoading = false
|
||||
this.$message.error(this.$t('tip.uploadFailed', { msg: 'error' }))
|
||||
},
|
||||
uploadSuccess (response) {
|
||||
this.uploaded = response.code === 200
|
||||
if (response.code === 200) {
|
||||
// 上传成功后去掉upload和preview的错误提示
|
||||
this.uploadErrorTip = ''
|
||||
this.previewErrorTip = ''
|
||||
|
||||
this.importedType = this.editObject.tagType
|
||||
const originalImportedData = _.cloneDeep(response.data.data)
|
||||
this.importedDataNoData = originalImportedData.length === 0
|
||||
this.originalImportInfo = {
|
||||
total: originalImportedData.length,
|
||||
succeeded: originalImportedData.filter(d => d.status === 1).length,
|
||||
failed: originalImportedData.filter(d => d.status !== 1).length
|
||||
}
|
||||
originalImportedData.sort((a, b) => b.status - a.status)
|
||||
this.importedData = originalImportedData
|
||||
this.handleShowImportedData()
|
||||
} else {
|
||||
this.uploadLoading = false
|
||||
this.$message.error(this.$t('tip.uploadFailed', { msg: response.message }))
|
||||
}
|
||||
},
|
||||
onRemove (files, fileList) {
|
||||
this.uploaded = false
|
||||
this.typeSelectDisable = false
|
||||
this.importedData = []
|
||||
this.showImportedData = []
|
||||
this.originalImportInfo = {
|
||||
total: null,
|
||||
succeeded: null,
|
||||
failed: null
|
||||
}
|
||||
},
|
||||
beforeUpload (file) {
|
||||
// 判断后缀,仅支持.csv
|
||||
if (!_.endsWith(file.name, '.csv')) {
|
||||
this.$message.error(this.$t('validate.fileTypeLimit', { types: this.fileTypeLimit }))
|
||||
this.fileList = []
|
||||
return false
|
||||
}
|
||||
// 判断文件大小
|
||||
if (file.size > this.uploadFileSizeLimit) {
|
||||
this.$message.error(this.$t('validate.fileSizeLimit', { size: unitConvert(this.uploadFileSizeLimit, unitTypes.byte).join('') }))
|
||||
this.fileList = []
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
onUpload (event, file) {
|
||||
this.uploadLoading = true
|
||||
this.typeSelectDisable = true
|
||||
},
|
||||
handleShowImportedData () {
|
||||
const startIndex = (this.importedPageObj.pageNo - 1) * this.importedPageObj.pageSize
|
||||
const endIndex = this.importedPageObj.pageNo * this.importedPageObj.pageSize
|
||||
this.showImportedData = this.importedData.slice(startIndex, endIndex)
|
||||
this.$nextTick(() => {
|
||||
this.uploadLoading = false
|
||||
})
|
||||
},
|
||||
pageNo (val) {
|
||||
this.importedPageObj.pageNo = val
|
||||
},
|
||||
prev () {
|
||||
this.importedPageObj.pageNo--
|
||||
},
|
||||
next () {
|
||||
this.importedPageObj.pageNo++
|
||||
},
|
||||
removeImportedData (index) {
|
||||
const toRemoveIndex = (this.importedPageObj.pageNo - 1) * this.importedPageObj.pageSize + index
|
||||
this.importedData.splice(toRemoveIndex, 1)
|
||||
this.importedPageObj.total--
|
||||
this.handleShowImportedData()
|
||||
// 若删除后本页无数据,则页码减1,或者提示无数据
|
||||
if (this.showImportedData.length === 0) {
|
||||
if (this.importedData.length > 0) {
|
||||
this.importedPageObj.pageNo--
|
||||
this.handleShowImportedData()
|
||||
} else {
|
||||
this.importedDataNoData = true
|
||||
}
|
||||
}
|
||||
// 删除后若有错误提示且列表中不再有错误项,则清空错误提示
|
||||
if (!this.hasErrorImportedData() && this.previewErrorTip) {
|
||||
this.previewErrorTip = ''
|
||||
}
|
||||
},
|
||||
cancel () {
|
||||
this.$router.push({
|
||||
path: '/knowledgeBase',
|
||||
t: +new Date()
|
||||
})
|
||||
},
|
||||
save () {
|
||||
if (this.blockOperation.save) { return }
|
||||
this.blockOperation.save = true
|
||||
// 校验form + upload + preview
|
||||
this.$refs.form.validate(valid => {
|
||||
this.$refs.form.validateField('tagName')
|
||||
if (!this.uploaded) {
|
||||
this.uploadErrorTip = this.$t('validate.required')
|
||||
} else {
|
||||
this.uploadErrorTip = ''
|
||||
}
|
||||
|
||||
if (this.importedData.length === 0) {
|
||||
this.previewErrorTip = this.$t('validate.required')
|
||||
} else if (this.hasErrorImportedData()) {
|
||||
this.previewErrorTip = this.$t('validate.pleaseCheckForErrorItem')
|
||||
} else {
|
||||
this.previewErrorTip = ''
|
||||
}
|
||||
if (valid) {
|
||||
// 校验通过后组织数据、请求接口
|
||||
if (valid && !this.uploadErrorTip && !this.previewErrorTip) {
|
||||
const postData = {
|
||||
tagName: this.editObject.tagName,
|
||||
tagType: this.editObject.tagType,
|
||||
data: []
|
||||
}
|
||||
this.importedData.forEach(d => {
|
||||
const findData = postData.data.find(d2 => d2.tagValue === d.tagValue)
|
||||
if (findData) {
|
||||
findData.itemList.add(d.tagItem)
|
||||
} else {
|
||||
const set = new Set()
|
||||
set.add(d.tagItem)
|
||||
postData.data.push({
|
||||
tagValue: d.tagValue,
|
||||
itemList: set
|
||||
})
|
||||
}
|
||||
})
|
||||
postData.data.forEach(d => {
|
||||
d.itemList = [...d.itemList]
|
||||
})
|
||||
postData.remark = this.editObject.remark
|
||||
axios.post(this.url, postData).then(response => {
|
||||
if (response.data.code === 200) {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.saveSuccess') })
|
||||
this.$router.push({
|
||||
path: '/knowledgeBase',
|
||||
t: +new Date()
|
||||
})
|
||||
} else {
|
||||
this.$message.error(response.data.message)
|
||||
}
|
||||
}).catch(e => {
|
||||
console.error(e)
|
||||
if (e.response.data && e.response.data.message) {
|
||||
this.$message.error(e.response.data.message)
|
||||
} else {
|
||||
this.$message.error('Something went wrong...')
|
||||
}
|
||||
}).finally(() => {
|
||||
this.blockOperation.save = false
|
||||
})
|
||||
} else {
|
||||
this.blockOperation.save = false
|
||||
}
|
||||
} else {
|
||||
this.blockOperation.save = false
|
||||
}
|
||||
})
|
||||
},
|
||||
hasErrorImportedData () {
|
||||
return this.importedData.filter(d => d.status !== 1).length > 0
|
||||
},
|
||||
async getKnowledgeBaseList () {
|
||||
return await axios.get(this.url, { params: { pageSize: 999 } })
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
uploadParams () {
|
||||
return {
|
||||
type: this.editObject.tagType
|
||||
}
|
||||
},
|
||||
importedTableFirstColumn () {
|
||||
const t = this.knowledgeBaseType.find(t => t.value === this.importedType)
|
||||
return t ? t.name : ''
|
||||
},
|
||||
activeStep () {
|
||||
if (this.tagNameFirstBlur) {
|
||||
return this.uploaded ? 2 : 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeCollapses (n) {
|
||||
const index0 = n.indexOf('0')
|
||||
const index1 = n.indexOf('1')
|
||||
if (index0 > -1) {
|
||||
if (this.stepHeights[0] === this.stepHeightConstant.collapse) {
|
||||
this.stepHeights.splice(0, 1, this.stepHeightConstant.first)
|
||||
}
|
||||
} else {
|
||||
if (this.stepHeights[0] === this.stepHeightConstant.first) {
|
||||
this.stepHeights.splice(0, 1, this.stepHeightConstant.collapse)
|
||||
}
|
||||
}
|
||||
if (index1 > -1) {
|
||||
if (this.stepHeights[1] === this.stepHeightConstant.collapse) {
|
||||
this.stepHeights.splice(1, 1, this.stepHeightConstant.second)
|
||||
}
|
||||
} else {
|
||||
if (this.stepHeights[1] === this.stepHeightConstant.second) {
|
||||
this.stepHeights.splice(1, 1, this.stepHeightConstant.collapse)
|
||||
}
|
||||
}
|
||||
},
|
||||
importedData (n) {
|
||||
this.importedPageObj.total = n.length
|
||||
},
|
||||
'importedPageObj.pageNo': {
|
||||
handler (n) {
|
||||
this.handleShowImportedData()
|
||||
}
|
||||
}
|
||||
},
|
||||
setup () {
|
||||
const { query } = useRoute()
|
||||
const knowledgeBaseId = ref(query.id || '')
|
||||
const url = api.knowledgeBase
|
||||
// 空白对象
|
||||
const blankObject = {
|
||||
tagName: '',
|
||||
buildIn: '',
|
||||
id: '',
|
||||
tagType: 'ip',
|
||||
remark: '',
|
||||
updateTime: ''
|
||||
}
|
||||
// form绑定的对象
|
||||
const editObject = ref(_.cloneDeep(blankObject))
|
||||
// 折叠组件控制
|
||||
const activeCollapses = ref(['0', '1', '2'])
|
||||
// 步骤条控制
|
||||
const stepHeightConstant = {
|
||||
collapse: 58,
|
||||
first: 333,
|
||||
second: 284
|
||||
}
|
||||
const stepHeights = ref([stepHeightConstant.first, stepHeightConstant.second, stepHeightConstant.collapse])
|
||||
// 所有导入的数据
|
||||
const importedData = ref([])
|
||||
// 导入数据的原始数量信息
|
||||
const originalImportInfo = ref({
|
||||
total: null,
|
||||
succeeded: null,
|
||||
failed: null
|
||||
})
|
||||
// table中显示的导入的数据
|
||||
const showImportedData = ref([])
|
||||
const importedPageObj = ref({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
total: null
|
||||
})
|
||||
const importedType = ref('')
|
||||
// 没上传过文件的提示
|
||||
const uploadErrorTip = ref('')
|
||||
// 预览区无内容的提示
|
||||
const previewErrorTip = ref('')
|
||||
return {
|
||||
knowledgeBaseId,
|
||||
editObject,
|
||||
tagNameFirstBlur: ref(false),
|
||||
blankObject,
|
||||
activeCollapses,
|
||||
stepHeightConstant,
|
||||
stepHeights,
|
||||
knowledgeBaseType,
|
||||
importedData,
|
||||
showImportedData,
|
||||
importedPageObj,
|
||||
importedType,
|
||||
baseUrl: BASE_CONFIG.baseUrl,
|
||||
fileList: ref([]),
|
||||
uploadHeaders: {
|
||||
'Cn-Authorization': localStorage.getItem(storageKey.token)
|
||||
},
|
||||
uploaded: ref(false),
|
||||
importedDataNoData: ref(false),
|
||||
url,
|
||||
originalImportInfo,
|
||||
uploadErrorTip,
|
||||
previewErrorTip,
|
||||
typeSelectDisable: ref(false),
|
||||
uploadFileSizeLimit: 100 * 1024 * 1024,
|
||||
uploadLoading: ref(false),
|
||||
fileTypeLimit: '.csv'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,82 +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-right>
|
||||
<button
|
||||
id="account-add"
|
||||
class="top-tool-btn margin-r-10"
|
||||
type="button"
|
||||
@click="add"
|
||||
>
|
||||
<i class="cn-icon-add cn-icon"/>
|
||||
</button>
|
||||
</template>
|
||||
<template #default>
|
||||
<chart-table
|
||||
ref="dataTable"
|
||||
v-loading="tools.loading"
|
||||
:api="url"
|
||||
: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"
|
||||
: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/settings/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,144 +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-right>
|
||||
<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"
|
||||
type="button" @click="add">
|
||||
<i class="cn-icon-add cn-icon"></i>
|
||||
</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>
|
||||
<galaxy-proxy-table
|
||||
ref="dataTable"
|
||||
v-loading="tools.loading"
|
||||
:api="url"
|
||||
: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"
|
||||
: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/settings/GalaxyProxyTable'
|
||||
import dataListMixin from '@/mixins/data-list'
|
||||
import { api } from '@/utils/api'
|
||||
import { get, put } from '@/utils/http'
|
||||
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) {
|
||||
get(`${this.url}/${u.id}`).then(response => {
|
||||
if (response.code === 200) {
|
||||
const editObject = response.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 () {
|
||||
put(`${this.url}/clearCache`).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.$message({ duration: 2000, type: 'success', message: this.$t('tip.success') })
|
||||
} else {
|
||||
this.$message.error(response.msg || response.message)
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$message.error(this.$t('tip.unknownError'))
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user