CN-240 feat: 实体详情
This commit is contained in:
@@ -89,14 +89,17 @@
|
|||||||
.cn-panel-crypto {
|
.cn-panel-crypto {
|
||||||
grid-template-columns: repeat(36, 1fr) !important;
|
grid-template-columns: repeat(36, 1fr) !important;
|
||||||
}
|
}
|
||||||
|
.cn-chart:not(.cn-chart__group):not(.cn-chart__block) {
|
||||||
.cn-panel, .cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane, .cn-chart__group .cn-chart__body {
|
&>.cn-chart__body {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cn-panel, .cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane, .cn-chart__group .cn-chart__body, .cn-chart__block .cn-chart__body {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(30, 1fr);
|
grid-template-columns: repeat(30, 1fr);
|
||||||
grid-auto-flow: row;
|
grid-auto-flow: row;
|
||||||
grid-gap: 10px;
|
grid-gap: 10px;
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -107,6 +110,10 @@
|
|||||||
top: 10px;
|
top: 10px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
&>div {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&>.cn-chart {
|
&>.cn-chart {
|
||||||
@@ -126,7 +133,7 @@
|
|||||||
&>.cn-chart__whois>.cn-chart__body {
|
&>.cn-chart__whois>.cn-chart__body {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
&>.cn-chart__echarts, &>.cn-chart__table, &>.cn-chart__map, &>.cn-chart__group, &>.cn-chart__whois, &>.cn-chart__dns-record, &>.cn-chart__app-basic {
|
&>.cn-chart__echarts, &>.cn-chart__table, &>.cn-chart__map, &>.cn-chart__group, &>.cn-chart__block, &>.cn-chart__whois, &>.cn-chart__dns-record, &>.cn-chart__app-basic {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
.cn-chart__header {
|
.cn-chart__header {
|
||||||
@@ -167,12 +174,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&>.cn-chart__group {
|
&>.cn-chart__block {
|
||||||
|
&>.cn-chart__header {
|
||||||
|
height: 60px;
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
&>.cn-chart__body {
|
||||||
|
display: grid !important;
|
||||||
|
grid-template-columns: repeat(30, 1fr);
|
||||||
|
grid-auto-flow: row;
|
||||||
|
grid-gap: 10px;
|
||||||
|
padding: 0 20px;
|
||||||
|
&>.cn-chart {
|
||||||
|
border: 1px solid #E7EAED;
|
||||||
|
}
|
||||||
|
/* detail页面block下的五连图的标题样式改变 */
|
||||||
|
.cn-chart__group .cn-chart__echarts {
|
||||||
|
.cn-chart__header {
|
||||||
|
border-bottom: none !important;
|
||||||
|
|
||||||
|
.header__title {
|
||||||
|
font-size: 14px !important;
|
||||||
|
color: #3976CB !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cn-chart__group {
|
||||||
.cn-chart__header {
|
.cn-chart__header {
|
||||||
border-bottom: 1px solid $--content-right-background-color;
|
border-bottom: 1px solid $--content-right-background-color;
|
||||||
}
|
}
|
||||||
&>.cn-chart__body {
|
&>.cn-chart__body {
|
||||||
display: grid !important;
|
display: grid !important;
|
||||||
|
grid-gap: 10px;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
.cn-chart {
|
.cn-chart {
|
||||||
border: none;
|
border: none;
|
||||||
@@ -518,22 +553,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (min-width : 10px) {
|
@media only screen and (min-width : 10px) {
|
||||||
.cn-panel, .cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane, .cn-chart__group .cn-chart__body {
|
.cn-panel, .cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane,
|
||||||
|
.cn-chart__body {
|
||||||
grid-auto-rows: 25px;
|
grid-auto-rows: 25px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (min-width : 1224px) {
|
@media only screen and (min-width : 1224px) {
|
||||||
.cn-panel, .cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane, .cn-chart__group .cn-chart__body {
|
.cn-panel,
|
||||||
|
.cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane,
|
||||||
|
.cn-chart__body {
|
||||||
grid-auto-rows: 30px;
|
grid-auto-rows: 30px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (min-width : 1824px) {
|
@media only screen and (min-width : 1824px) {
|
||||||
.cn-panel, .cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane, .cn-chart__group .cn-chart__body {
|
.cn-panel,
|
||||||
|
.cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane,
|
||||||
|
.cn-chart__body {
|
||||||
grid-auto-rows: 40px;
|
grid-auto-rows: 40px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (min-width : 2424px) {
|
@media only screen and (min-width : 2424px) {
|
||||||
.cn-panel, .cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane, .cn-chart__group .cn-chart__body {
|
.cn-panel,
|
||||||
|
.cn-panel>.cn-chart__tabs>.el-tabs__content>.el-tab-pane,
|
||||||
|
.cn-chart__body {
|
||||||
grid-auto-rows: 55px;
|
grid-auto-rows: 55px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -627,32 +669,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.entity-detail__body {
|
.entity-detail__body {
|
||||||
height: calc(100% - 70px);
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
&>div {
|
&>div {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(30, 1fr);
|
grid-template-columns: repeat(30, 1fr);
|
||||||
grid-auto-flow: row;
|
grid-auto-flow: row;
|
||||||
grid-auto-rows: var(--chart-height-unit);
|
|
||||||
grid-gap: 10px;
|
grid-gap: 10px;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cn-panel {
|
.cn-panel {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
grid-gap: 10px;
|
grid-gap: 10px;
|
||||||
|
|
||||||
&>.cn-chart>.cn-chart__header {
|
&>.cn-chart>.cn-chart__header {
|
||||||
border-bottom: 1px solid $--content-right-background-color;
|
border-bottom: 1px solid $--content-right-background-color;
|
||||||
.header__title {
|
.header__title>span {
|
||||||
color: #333;
|
color: #1890FF;
|
||||||
|
font-weight: bold;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cn-chart__header {
|
&>.cn-chart>.cn-chart__body {
|
||||||
border-bottom: none;
|
.cn-chart__header {
|
||||||
.header__title {
|
border-bottom: 1px solid $--content-right-background-color;
|
||||||
color: #3976CB;
|
.header__title {
|
||||||
font-size: 14px;
|
color: #666;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
@import './views/entityExplorer/entityExplorer';
|
@import './views/entityExplorer/entityExplorer';
|
||||||
@import './views/entityExplorer/search/explorerSearch';
|
@import './views/entityExplorer/search/explorerSearch';
|
||||||
@import './views/entityExplorer/entityFilter';
|
@import './views/entityExplorer/entityFilter';
|
||||||
|
@import './views/entityExplorer/entityDetail';
|
||||||
@import './views/entityExplorer/entityList/entityList';
|
@import './views/entityExplorer/entityList/entityList';
|
||||||
@import './views/entityExplorer/entityList/card';
|
@import './views/entityExplorer/entityList/card';
|
||||||
@import './views/entityExplorer/entityList/row';
|
@import './views/entityExplorer/entityList/row';
|
||||||
|
|||||||
@@ -102,6 +102,11 @@
|
|||||||
.domain-detail-list__row {
|
.domain-detail-list__row {
|
||||||
display: table-row;
|
display: table-row;
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
.domain-detail-list__label, .domain-detail-list__content {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
.domain-detail-list__label {
|
.domain-detail-list__label {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
padding: 13px 30px;
|
padding: 13px 30px;
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
.entity-detail.cn-home {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.entity-detail__header {
|
||||||
|
flex: 0 0 80px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.cn-entity__name {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #333333;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.cn-entity__icon {
|
||||||
|
margin-left: 26px;
|
||||||
|
margin-right: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
justify-items: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 52px;
|
||||||
|
height: 52px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #F3F7FA;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 22px;
|
||||||
|
color: #4E84B4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&>.entity-detail__body {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 52px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.entity-detail__menu {
|
||||||
|
flex: 0 0 240px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-top: 23px;
|
||||||
|
border-top: 1px solid $--content-right-background-color;
|
||||||
|
|
||||||
|
.menu-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 7px 0 7px 30px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666666;
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding-left: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.menu-item--active {
|
||||||
|
color: #1890FF;
|
||||||
|
|
||||||
|
span {
|
||||||
|
border-left: 2px solid #1890FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.entity-detail__content {
|
||||||
|
height: calc(100% - 28px);
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: $--content-right-background-color;
|
||||||
|
|
||||||
|
&>.cn-entity-detail .entity-detail__body>.cn-panel {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -708,6 +708,10 @@ export function isCryptocurrencyEventList (type) {
|
|||||||
export function isGroup (type) {
|
export function isGroup (type) {
|
||||||
return type === 94
|
return type === 94
|
||||||
}
|
}
|
||||||
|
/* 实体详情块 */
|
||||||
|
export function isBlock (type) {
|
||||||
|
return type === 95
|
||||||
|
}
|
||||||
export function getOption (type) {
|
export function getOption (type) {
|
||||||
const mapping = typeOptionMappings.find(m => m.value === type)
|
const mapping = typeOptionMappings.find(m => m.value === type)
|
||||||
return mapping && mapping.option ? _.cloneDeep(mapping.option) : null
|
return mapping && mapping.option ? _.cloneDeep(mapping.option) : null
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ export default {
|
|||||||
this.showChangePin = true
|
this.showChangePin = true
|
||||||
},
|
},
|
||||||
logout () {
|
logout () {
|
||||||
sessionStorage.removeItem(storageKey.token)
|
localStorage.removeItem(storageKey.token)
|
||||||
get('/logout')
|
get('/logout')
|
||||||
},
|
},
|
||||||
refreshLang () {
|
refreshLang () {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { storageKey } from '@/utils/constants'
|
|||||||
import { loadI18n } from '@/i18n'
|
import { loadI18n } from '@/i18n'
|
||||||
|
|
||||||
const loginWhiteList = ['/login', '/'] // 免登陆白名单
|
const loginWhiteList = ['/login', '/'] // 免登陆白名单
|
||||||
const permissionWhiteList = [...loginWhiteList] // 权限白名单
|
const permissionWhiteList = [...loginWhiteList, '/entityDetail'] // 权限白名单
|
||||||
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
// await test(to, from)
|
// await test(to, from)
|
||||||
@@ -19,9 +19,9 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
const config = await getConfigJson()
|
const config = await getConfigJson()
|
||||||
axios.defaults.baseURL = config.baseUrl
|
axios.defaults.baseURL = config.baseUrl
|
||||||
}
|
}
|
||||||
if (sessionStorage.getItem(storageKey.token)) {
|
if (localStorage.getItem(storageKey.token)) {
|
||||||
// 加载i18n
|
// 加载i18n
|
||||||
if (!sessionStorage.getItem(storageKey.i18n)) {
|
if (!localStorage.getItem(storageKey.i18n)) {
|
||||||
await loadI18n()
|
await loadI18n()
|
||||||
}
|
}
|
||||||
// 加载权限
|
// 加载权限
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ const routes = [
|
|||||||
path: '/login',
|
path: '/login',
|
||||||
component: () => import('@/Login')
|
component: () => import('@/Login')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/entityDetail',
|
||||||
|
component: () => import('@/views/entityExplorer/EntityDetail')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: () => import('@/components/layout/Home'),
|
component: () => import('@/components/layout/Home'),
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ const user = {
|
|||||||
actions: {
|
actions: {
|
||||||
loginSuccess (store, res) {
|
loginSuccess (store, res) {
|
||||||
window.$dayJs.tz.setDefault(res.data.timezone)
|
window.$dayJs.tz.setDefault(res.data.timezone)
|
||||||
sessionStorage.setItem('cn-token', res.data.token)
|
localStorage.setItem('cn-token', res.data.token)
|
||||||
localStorage.setItem('cn-sys-name', res.data.systemName)
|
localStorage.setItem('cn-sys-name', res.data.systemName)
|
||||||
if (res.systemLogo) {
|
if (res.systemLogo) {
|
||||||
localStorage.setItem('cn-sys-logo', res.data.systemLogo)
|
localStorage.setItem('cn-sys-logo', res.data.systemLogo)
|
||||||
@@ -72,9 +72,9 @@ const user = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
logoutSuccess (store, res) {
|
logoutSuccess (store, res) {
|
||||||
sessionStorage.removeItem('cn-username')
|
|
||||||
localStorage.removeItem('cn-username')
|
localStorage.removeItem('cn-username')
|
||||||
sessionStorage.removeItem('cn-token')
|
localStorage.removeItem('cn-username')
|
||||||
|
localStorage.removeItem('cn-token')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export async function getConfigJson () {
|
|||||||
|
|
||||||
export async function getPermission () {
|
export async function getPermission () {
|
||||||
const request = new Promise(resolve => {
|
const request = new Promise(resolve => {
|
||||||
post(api.permission, { token: sessionStorage.getItem('cn-token') }).then(response => {
|
post(api.permission, { token: localStorage.getItem('cn-token') }).then(response => {
|
||||||
resolve({
|
resolve({
|
||||||
menuList: sortByOrderNum(response.data.menus),
|
menuList: sortByOrderNum(response.data.menus),
|
||||||
buttonList: response.data.buttons,
|
buttonList: response.data.buttons,
|
||||||
@@ -116,7 +116,7 @@ export async function getPermission () {
|
|||||||
export async function getI18n () {
|
export async function getI18n () {
|
||||||
const dictData = await getDictList()
|
const dictData = await getDictList()
|
||||||
const langs = dictData.map(d => d.value).join(',')
|
const langs = dictData.map(d => d.value).join(',')
|
||||||
sessionStorage.setItem(storageKey.languages, langs)
|
localStorage.setItem(storageKey.languages, langs)
|
||||||
const request = new Promise(resolve => {
|
const request = new Promise(resolve => {
|
||||||
get(api.i18n, { l: langs }).then(response => {
|
get(api.i18n, { l: langs }).then(response => {
|
||||||
response.data.cn = response.data.zh
|
response.data.cn = response.data.zh
|
||||||
|
|||||||
@@ -84,34 +84,34 @@ export const entityFilterType = {
|
|||||||
],
|
],
|
||||||
domain: [
|
domain: [
|
||||||
{
|
{
|
||||||
column: 'category_group_distinct_count',
|
column: 'categoryGroupDistinctCount',
|
||||||
labelI18nCode: 'entities.domainDetail.categoryGroup',
|
labelI18nCode: 'entities.domainDetail.categoryGroup',
|
||||||
icon: 'cn-icon cn-icon-category'
|
icon: 'cn-icon cn-icon-category'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
column: 'category_distinct_count',
|
column: 'categoryDistinctCount',
|
||||||
labelI18nCode: 'entities.category',
|
labelI18nCode: 'entities.category',
|
||||||
icon: 'cn-icon cn-icon-sub-category'
|
icon: 'cn-icon cn-icon-sub-category'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
column: 'category_group_distinct_count',
|
column: 'categoryGroupDistinctCount',
|
||||||
labelI18nCode: 'entities.reputationLevel',
|
labelI18nCode: 'entities.reputationLevel',
|
||||||
icon: 'cn-icon cn-icon-credit'
|
icon: 'cn-icon cn-icon-credit'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
app: [
|
app: [
|
||||||
{
|
{
|
||||||
column: 'category_distinct_count',
|
column: 'categoryDistinctCount',
|
||||||
labelI18nCode: 'entities.category',
|
labelI18nCode: 'entities.category',
|
||||||
icon: 'cn-icon cn-icon-category'
|
icon: 'cn-icon cn-icon-category'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
column: 'subcategory_distinct_count',
|
column: 'subcategoryDistinctCount',
|
||||||
labelI18nCode: 'entities.subcategory',
|
labelI18nCode: 'entities.subcategory',
|
||||||
icon: 'cn-icon cn-icon-sub-category'
|
icon: 'cn-icon cn-icon-sub-category'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
column: 'risk_distinct_count',
|
column: 'riskDistinctCount',
|
||||||
labelI18nCode: 'entities.risk',
|
labelI18nCode: 'entities.risk',
|
||||||
icon: 'cn-icon cn-icon-risk'
|
icon: 'cn-icon cn-icon-risk'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import axios from 'axios'
|
|||||||
import { storageKey } from '@/utils/constants'
|
import { storageKey } from '@/utils/constants'
|
||||||
|
|
||||||
axios.interceptors.request.use(config => {
|
axios.interceptors.request.use(config => {
|
||||||
const token = sessionStorage.getItem('cn-token')
|
const token = localStorage.getItem('cn-token')
|
||||||
if (token) {
|
if (token) {
|
||||||
config.headers.Authorization = token // 请求头token
|
config.headers.Authorization = token // 请求头token
|
||||||
}
|
}
|
||||||
@@ -41,11 +41,11 @@ axios.interceptors.request.use(
|
|||||||
axios.interceptors.response.use(
|
axios.interceptors.response.use(
|
||||||
response => {
|
response => {
|
||||||
if (licenceErrorCode.indexOf(response.data.code) !== -1) {
|
if (licenceErrorCode.indexOf(response.data.code) !== -1) {
|
||||||
sessionStorage.removeItem(storageKey.token)
|
localStorage.removeItem(storageKey.token)
|
||||||
window.location.href = '/'
|
window.location.href = '/'
|
||||||
} else if (response.status === 200) {
|
} else if (response.status === 200) {
|
||||||
if (accountErrorCode.indexOf(response.data.code) !== -1) {
|
if (accountErrorCode.indexOf(response.data.code) !== -1) {
|
||||||
sessionStorage.removeItem(storageKey.token)
|
localStorage.removeItem(storageKey.token)
|
||||||
window.location.href = '/'
|
window.location.href = '/'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@
|
|||||||
v-model="orderPieTable"
|
v-model="orderPieTable"
|
||||||
class="option__select select-column"
|
class="option__select select-column"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
popper-class="option-popper"
|
popper-class="option-popper is-light"
|
||||||
@change="orderPieTableChange"
|
@change="orderPieTableChange"
|
||||||
>
|
>
|
||||||
<el-option v-for="item in chartPieTableTopOptions" :key="item.value" :value="item.value"> {{item.name}}</el-option>
|
<el-option v-for="item in chartPieTableTopOptions" :key="item.value" :value="item.value"> {{item.name}}</el-option>
|
||||||
@@ -367,7 +367,50 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="cn-chart__body">
|
<div class="cn-chart__body">
|
||||||
<template v-for="chart in chartInfo.children" :key="chart.id">
|
<template v-for="chart in chartInfo.children" :key="chart.id">
|
||||||
<chart :chart="chart" :time-filter="timeFilter" :ref="`chart-${chart.id}`" :entity="entity" :parent-data="groupData"></chart>
|
<chart
|
||||||
|
:chart="chart"
|
||||||
|
:time-filter="timeFilter"
|
||||||
|
:ref="`chart-${chart.id}`"
|
||||||
|
:entity="entity"
|
||||||
|
:parent-data="groupData"
|
||||||
|
:from-block="fromBlock"
|
||||||
|
@getChartCurrentTimeRange="getChartCurrentTimeRange"
|
||||||
|
></chart>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- block -->
|
||||||
|
<div
|
||||||
|
v-else-if="isBlock"
|
||||||
|
class="cn-chart cn-chart__block"
|
||||||
|
:style="computePosition"
|
||||||
|
:id="chartInfo.params && chartInfo.params.anchorPoint"
|
||||||
|
>
|
||||||
|
<div class="cn-chart__header">
|
||||||
|
<chart-error
|
||||||
|
:isError="isError"
|
||||||
|
:errorInfo="errorInfo"
|
||||||
|
>
|
||||||
|
</chart-error>
|
||||||
|
<div class="header__title">
|
||||||
|
<span :title="chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</span>
|
||||||
|
<div style="top: 18px;" class="panel__time" v-if="chartInfo.params && chartInfo.params.showTimeTool">
|
||||||
|
<DateTimeRange class="date-time-range" :start-time="chartTimeFilter.startTime" :end-time="chartTimeFilter.endTime" ref="dateTimeRange" @change="reload"/>
|
||||||
|
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="chartTimeFilter.endTime"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cn-chart__body">
|
||||||
|
<template v-for="chart in chartInfo.children" :key="chart.id">
|
||||||
|
<chart
|
||||||
|
:chart="chart"
|
||||||
|
:time-filter="chartTimeFilter"
|
||||||
|
:ref="`chart-${chart.id}`"
|
||||||
|
:entity="entity"
|
||||||
|
:parent-data="groupData"
|
||||||
|
:from-block="true"
|
||||||
|
@getChartCurrentTimeRange="getChartCurrentTimeRange"
|
||||||
|
></chart>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -564,7 +607,7 @@
|
|||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import * as am4Core from '@amcharts/amcharts4/core'
|
import * as am4Core from '@amcharts/amcharts4/core'
|
||||||
import * as am4Maps from '@amcharts/amcharts4/maps'
|
import * as am4Maps from '@amcharts/amcharts4/maps'
|
||||||
import { shallowRef } from 'vue'
|
import { ref, shallowRef } from 'vue'
|
||||||
import { tableTitleMapping, legendMapping } from '@/components/charts/chart-table-title'
|
import { tableTitleMapping, legendMapping } from '@/components/charts/chart-table-title'
|
||||||
import {
|
import {
|
||||||
isEcharts,
|
isEcharts,
|
||||||
@@ -597,7 +640,7 @@ import {
|
|||||||
isAppBasicInfo,
|
isAppBasicInfo,
|
||||||
isAppRelatedDomain,
|
isAppRelatedDomain,
|
||||||
getChartColor, chartBarColor, timeVerticalFormatter, timeHorizontalFormatter,
|
getChartColor, chartBarColor, timeVerticalFormatter, timeHorizontalFormatter,
|
||||||
categoryHorizontalFormatter, categoryVerticalFormatter, getCharBartColor
|
categoryHorizontalFormatter, categoryVerticalFormatter, getCharBartColor, isBlock
|
||||||
} from '@/components/charts/chart-options'
|
} from '@/components/charts/chart-options'
|
||||||
import ChartError from '@/components/charts/ChartError'
|
import ChartError from '@/components/charts/ChartError'
|
||||||
import EchartsFrame from '@/components/charts/EchartsFrame'
|
import EchartsFrame from '@/components/charts/EchartsFrame'
|
||||||
@@ -613,11 +656,14 @@ import { chartTableDefaultPageSize, chartTableTopOptions, chartActiveIpTableOrde
|
|||||||
import { get, post } from '@/utils/http'
|
import { get, post } from '@/utils/http'
|
||||||
import { replaceUrlPlaceholder, getCapitalGeo, getGeoData, lineToSpace } from '@/utils/tools'
|
import { replaceUrlPlaceholder, getCapitalGeo, getGeoData, lineToSpace } from '@/utils/tools'
|
||||||
import { HeatLegend } from '@/components/amcharts/heatLegend'
|
import { HeatLegend } from '@/components/amcharts/heatLegend'
|
||||||
|
import DateTimeRange from '@/components/common/TimeRange/DateTimeRange'
|
||||||
|
import TimeRefresh from '@/components/common/TimeRange/TimeRefresh'
|
||||||
|
|
||||||
import * as L from 'leaflet'
|
import * as L from 'leaflet'
|
||||||
import 'leaflet/dist/leaflet.css'
|
import 'leaflet/dist/leaflet.css'
|
||||||
import icon from 'leaflet/dist/images/marker-icon.png'
|
import icon from 'leaflet/dist/images/marker-icon.png'
|
||||||
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
|
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
|
||||||
|
import { getNowTime } from '@/utils/date-util'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Chart',
|
name: 'Chart',
|
||||||
@@ -625,6 +671,7 @@ export default {
|
|||||||
chart: Object, // 图表对象,包括id、name、type等数据
|
chart: Object, // 图表对象,包括id、name、type等数据
|
||||||
timeFilter: Object,
|
timeFilter: Object,
|
||||||
parentData: Object,
|
parentData: Object,
|
||||||
|
fromBlock: Boolean,
|
||||||
entity: {
|
entity: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
@@ -639,7 +686,9 @@ export default {
|
|||||||
PieTable,
|
PieTable,
|
||||||
StatisticsLegend,
|
StatisticsLegend,
|
||||||
ChartMap,
|
ChartMap,
|
||||||
ChartError
|
ChartError,
|
||||||
|
DateTimeRange,
|
||||||
|
TimeRefresh
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
@@ -651,6 +700,7 @@ export default {
|
|||||||
tableData: [], // table的所有数据
|
tableData: [], // table的所有数据
|
||||||
currentPageData: [] // table当前页的数据
|
currentPageData: [] // table当前页的数据
|
||||||
},
|
},
|
||||||
|
|
||||||
activeIpTable: {
|
activeIpTable: {
|
||||||
orderBy: 'machine',
|
orderBy: 'machine',
|
||||||
tableData: [
|
tableData: [
|
||||||
@@ -719,9 +769,13 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
initChart () {
|
initChart () {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.queryTimeRange = this.standaloneTimeRange.use
|
if (this.standaloneTimeRange.use) {
|
||||||
? { startTime: parseInt(this.standaloneTimeRange.startTime / 1000), endTime: parseInt(this.standaloneTimeRange.endTime / 1000) }
|
this.queryTimeRange = { startTime: parseInt(this.standaloneTimeRange.startTime / 1000), endTime: parseInt(this.standaloneTimeRange.endTime / 1000) }
|
||||||
: { startTime: parseInt(this.timeFilter.startTime / 1000), endTime: parseInt(this.timeFilter.endTime / 1000) }
|
} else if (this.timeFilter) {
|
||||||
|
this.queryTimeRange = { startTime: parseInt(this.timeFilter.startTime / 1000), endTime: parseInt(this.timeFilter.endTime / 1000) }
|
||||||
|
} else {
|
||||||
|
this.queryTimeRange = { startTime: parseInt(this.chartTimeFilter.startTime / 1000), endTime: parseInt(this.chartTimeFilter.endTime / 1000) }
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const chartParams = this.chartInfo.params
|
const chartParams = this.chartInfo.params
|
||||||
if (this.isMap) {
|
if (this.isMap) {
|
||||||
@@ -972,6 +1026,18 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
timeRefreshChange () {
|
||||||
|
if (!this.$refs.dateTimeRange.isCustom) {
|
||||||
|
const value = this.chartTimeFilter.dateRangeValue
|
||||||
|
this.$refs.dateTimeRange.quickChange(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reload (s, e, v) {
|
||||||
|
this.dateTimeRangeChange(s, e, v)
|
||||||
|
},
|
||||||
|
dateTimeRangeChange (s, e, v) {
|
||||||
|
this.chartTimeFilter = { startTime: s, endTime: e, dateRangeValue: v }
|
||||||
|
},
|
||||||
generateTooltipHTML () {
|
generateTooltipHTML () {
|
||||||
return `
|
return `
|
||||||
<div class="map-tooltip" style="padding-bottom: 10px;">
|
<div class="map-tooltip" style="padding-bottom: 10px;">
|
||||||
@@ -1233,7 +1299,8 @@ export default {
|
|||||||
return this.$_.slice(tableData, (pageNum - 1) * pageSize, pageNum * pageSize)
|
return this.$_.slice(tableData, (pageNum - 1) * pageSize, pageNum * pageSize)
|
||||||
},
|
},
|
||||||
refresh () {
|
refresh () {
|
||||||
this.$emit('getCurrentTimeRange', ({ startTime, endTime }) => {
|
const eventName = this.fromBlock ? 'getChartCurrentTimeRange' : 'getCurrentTimeRange'
|
||||||
|
this.$emit(eventName, ({ startTime, endTime }) => {
|
||||||
this.standaloneTimeRange.use = true
|
this.standaloneTimeRange.use = true
|
||||||
this.standaloneTimeRange.startTime = startTime
|
this.standaloneTimeRange.startTime = startTime
|
||||||
this.standaloneTimeRange.endTime = endTime
|
this.standaloneTimeRange.endTime = endTime
|
||||||
@@ -1252,6 +1319,21 @@ export default {
|
|||||||
callback({ startTime, endTime })
|
callback({ startTime, endTime })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
// 获取最新时间
|
||||||
|
getChartCurrentTimeRange (callback) {
|
||||||
|
console.info(this.isGroup)
|
||||||
|
if (this.isGroup) {
|
||||||
|
this.$emit('getChartCurrentTimeRange', ({ startTime, endTime }) => {
|
||||||
|
console.info(startTime, endTime)
|
||||||
|
callback({ startTime, endTime })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const myEndTime = window.$dayJs.tz().valueOf()
|
||||||
|
const myStartTime = myEndTime - this.chartTimeFilter.dateRangeValue * 60 * 1000
|
||||||
|
console.info(myStartTime, myEndTime)
|
||||||
|
callback({ startTime: myStartTime, endTime: myEndTime })
|
||||||
|
}
|
||||||
|
},
|
||||||
getDataKey (r) {
|
getDataKey (r) {
|
||||||
let key = ''
|
let key = ''
|
||||||
let labelText = ''
|
let labelText = ''
|
||||||
@@ -1337,6 +1419,8 @@ export default {
|
|||||||
this.chartOption.legend.show = false
|
this.chartOption.legend.show = false
|
||||||
}
|
}
|
||||||
const queryParams = { ...this.queryTimeRange, ...this.entity }
|
const queryParams = { ...this.queryTimeRange, ...this.entity }
|
||||||
|
console.info(chartParams.url)
|
||||||
|
console.info(queryParams)
|
||||||
get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => {
|
get(replaceUrlPlaceholder(chartParams.url, queryParams)).then(response => {
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
if (this.$_.isEmpty(response.data.result)) {
|
if (this.$_.isEmpty(response.data.result)) {
|
||||||
@@ -2464,8 +2548,14 @@ export default {
|
|||||||
setup (props) {
|
setup (props) {
|
||||||
const chartInfo = JSON.parse(JSON.stringify(props.chart))
|
const chartInfo = JSON.parse(JSON.stringify(props.chart))
|
||||||
chartInfo.category = getTypeCategory(props.chart.type)
|
chartInfo.category = getTypeCategory(props.chart.type)
|
||||||
|
|
||||||
|
const dateRangeValue = 60
|
||||||
|
const { startTime, endTime } = getNowTime(dateRangeValue)
|
||||||
|
// entity详情内的chart时间工具不是公共的,需要单独定义
|
||||||
|
const chartTimeFilter = ref({ startTime, endTime, dateRangeValue })
|
||||||
return {
|
return {
|
||||||
chartInfo,
|
chartInfo,
|
||||||
|
chartTimeFilter,
|
||||||
layoutConstant,
|
layoutConstant,
|
||||||
chartTableTopOptions,
|
chartTableTopOptions,
|
||||||
chartActiveIpTableOrderOptions,
|
chartActiveIpTableOrderOptions,
|
||||||
@@ -2486,6 +2576,7 @@ export default {
|
|||||||
isMapBlock: isMapBlock(props.chart.type),
|
isMapBlock: isMapBlock(props.chart.type),
|
||||||
isTabs: isTabs(props.chart.type),
|
isTabs: isTabs(props.chart.type),
|
||||||
isGroup: isGroup(props.chart.type),
|
isGroup: isGroup(props.chart.type),
|
||||||
|
isBlock: isBlock(props.chart.type),
|
||||||
isSankey: isSankey(props.chart.type),
|
isSankey: isSankey(props.chart.type),
|
||||||
isIpBasicInfo: isIpBasicInfo(props.chart.type),
|
isIpBasicInfo: isIpBasicInfo(props.chart.type),
|
||||||
isIpHostedDomain: isIpHostedDomain(props.chart.type),
|
isIpHostedDomain: isIpHostedDomain(props.chart.type),
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="padding: 10px 0 20px 20px;" v-if="!isEntityDetail">
|
<div style="padding: 10px 0 20px 20px; overflow: auto" v-if="!isEntityDetail">
|
||||||
<div id="cn-panel" :class="(isCryptocurrency)?'cn-panel cn-panel-crypto':'cn-panel'">
|
<div id="cn-panel"
|
||||||
|
:class="(isCryptocurrency)?'cn-panel cn-panel-crypto':'cn-panel'"
|
||||||
|
>
|
||||||
<div class="panel__time">
|
<div class="panel__time">
|
||||||
<DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/>
|
<DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/>
|
||||||
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
|
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
|
||||||
@@ -35,43 +37,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cn-entity-detail" id="cn-entity-detail" v-else>
|
<div class="cn-entity-detail" id="cn-entity-detail" v-else>
|
||||||
<div class="entity-detail__header">
|
|
||||||
<div class="detail-header__title">
|
|
||||||
<span class="title__icon-circle">
|
|
||||||
<i class="cn-icon" :class="{'cn-icon-ip': entity.ip, 'cn-icon-domain': entity.domain, 'cn-icon-app': entity.app}"></i>
|
|
||||||
</span>
|
|
||||||
<div class="title__name" :title="entity.ip || entity.domain || entity.app || '-'">{{entity.ip || entity.domain || entity.app || '-'}}</div></div>
|
|
||||||
<div class="detail-header__operation">
|
|
||||||
<div class="panel__time">
|
|
||||||
<DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/>
|
|
||||||
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
|
|
||||||
</div>
|
|
||||||
<el-tabs
|
|
||||||
v-model="currentTab"
|
|
||||||
@tab-click="changeTab"
|
|
||||||
>
|
|
||||||
<el-tab-pane
|
|
||||||
v-for="tab in detailTabs"
|
|
||||||
:label="tab.i18n ? $t(tab.i18n) : tab.name"
|
|
||||||
:name="`${tab.id}`"
|
|
||||||
:key="tab.id"
|
|
||||||
:ref="`chart-${tab.id}`"
|
|
||||||
>
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="entity-detail__body">
|
<div class="entity-detail__body">
|
||||||
<div class="cn-panel">
|
<div class="cn-panel" @scroll="scroll" id="cn-panel">
|
||||||
<chart
|
<template v-for="chart in chartList" :key="chart.id">
|
||||||
v-for="chart in detailChartList"
|
<chart
|
||||||
:key="chart.id"
|
:chart="chart"
|
||||||
:chart="chart"
|
:ref="`chart-${chart.id}`"
|
||||||
:time-filter="timeFilter"
|
:entity="entity"
|
||||||
:ref="`chart-${chart.id}`"
|
@getCurrentTimeRange="getCurrentTimeRange"
|
||||||
:entity="entity"
|
></chart>
|
||||||
@getCurrentTimeRange="getCurrentTimeRange"
|
</template>
|
||||||
></chart>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -91,7 +66,8 @@ export default {
|
|||||||
name: 'Panel',
|
name: 'Panel',
|
||||||
props: {
|
props: {
|
||||||
entity: Object,
|
entity: Object,
|
||||||
isEntityDetail: Boolean
|
isEntityDetail: Boolean,
|
||||||
|
typeName: String
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Chart,
|
Chart,
|
||||||
@@ -109,7 +85,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted () {
|
async mounted () {
|
||||||
const path = this.$route.path
|
|
||||||
this.isCryptocurrency = this.$route.path.indexOf('cryptocurrency') > -1
|
this.isCryptocurrency = this.$route.path.indexOf('cryptocurrency') > -1
|
||||||
await this.init()
|
await this.init()
|
||||||
if (!this.$_.isEmpty(this.detailTabs)) {
|
if (!this.$_.isEmpty(this.detailTabs)) {
|
||||||
@@ -144,23 +119,19 @@ export default {
|
|||||||
this.recursionParamsConvert(chart)
|
this.recursionParamsConvert(chart)
|
||||||
return chart
|
return chart
|
||||||
})
|
})
|
||||||
if (this.isEntityDetail) {
|
this.chartList = allCharts
|
||||||
if (!this.$_.isEmpty(allCharts)) {
|
setTimeout(() => {
|
||||||
const rootChart = allCharts[0]
|
this.$emit('chartLoaded', allCharts)
|
||||||
this.detailTabs = rootChart.children
|
})
|
||||||
if (!this.$_.isEmpty(this.detailTabs)) {
|
|
||||||
this.detailChartList = this.detailTabs[0].children
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.chartList = allCharts
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeTab ({ index }) {
|
changeTab ({ index }) {
|
||||||
this.currentTab = this.detailTabs[index].id + ''
|
this.currentTab = this.detailTabs[index].id + ''
|
||||||
this.detailChartList = this.detailTabs[index].children
|
this.detailChartList = this.detailTabs[index].children
|
||||||
},
|
},
|
||||||
|
scroll (e) {
|
||||||
|
this.$emit('scroll', { top: e.target.scrollTop })
|
||||||
|
},
|
||||||
recursionParamsConvert (chart) {
|
recursionParamsConvert (chart) {
|
||||||
chart.params = chart.params ? JSON.parse(chart.params) : null
|
chart.params = chart.params ? JSON.parse(chart.params) : null
|
||||||
if (!this.$_.isEmpty(chart.children)) {
|
if (!this.$_.isEmpty(chart.children)) {
|
||||||
@@ -179,22 +150,9 @@ export default {
|
|||||||
const value = this.timeFilter.dateRangeValue
|
const value = this.timeFilter.dateRangeValue
|
||||||
this.$refs.dateTimeRange.quickChange(value)
|
this.$refs.dateTimeRange.quickChange(value)
|
||||||
}
|
}
|
||||||
/* if (!this.$refs.dateTimeRange) {
|
|
||||||
this.reloadCharts()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (this.$refs.dateTimeRange.isCustom) {
|
|
||||||
this.reloadCharts()
|
|
||||||
} else {
|
|
||||||
const value = this.timeFilter.dateRangeValue
|
|
||||||
this.$refs.dateTimeRange.quickChange(value)
|
|
||||||
} */
|
|
||||||
},
|
},
|
||||||
reload (s, e, v) {
|
reload (s, e, v) {
|
||||||
this.dateTimeRangeChange(s, e, v)
|
this.dateTimeRangeChange(s, e, v)
|
||||||
/* this.$nextTick(() => {
|
|
||||||
this.reloadCharts()
|
|
||||||
}) */
|
|
||||||
},
|
},
|
||||||
// methods
|
// methods
|
||||||
dateTimeRangeChange (s, e, v) {
|
dateTimeRangeChange (s, e, v) {
|
||||||
@@ -204,6 +162,9 @@ export default {
|
|||||||
this.chartList.forEach(chart => {
|
this.chartList.forEach(chart => {
|
||||||
this.$refs[`chart-${chart.id}`] && this.$refs[`chart-${chart.id}`].reloadChart()
|
this.$refs[`chart-${chart.id}`] && this.$refs[`chart-${chart.id}`].reloadChart()
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
jumpToTop (top) {
|
||||||
|
document.querySelector('#cn-panel').scrollTop = top
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
140
src/views/entityExplorer/EntityDetail.vue
Normal file
140
src/views/entityExplorer/EntityDetail.vue
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
<template>
|
||||||
|
<div class="cn-home entity-detail">
|
||||||
|
<div class="entity-detail__header">
|
||||||
|
<div class="cn-entity__icon"><i :class="iconClass"></i></div>
|
||||||
|
<div class="cn-entity__name">{{entityData.name}}</div>
|
||||||
|
</div>
|
||||||
|
<main class="cn-body entity-detail__body">
|
||||||
|
<div class="entity-detail__menu">
|
||||||
|
<template v-for="anchor in anchorPoints" :key="anchor.id">
|
||||||
|
<div class="menu-item" :class="{'menu-item--active': menuIsActive(anchor)}" @click="jumpToAnchor(anchor)">
|
||||||
|
<span>{{anchor.label}}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="entity-detail__content">
|
||||||
|
<cn-panel
|
||||||
|
ref="cnPanel"
|
||||||
|
:entity="entityData"
|
||||||
|
:is-entity-detail="true"
|
||||||
|
@chartLoaded="chartLoaded"
|
||||||
|
@scroll="scroll"
|
||||||
|
></cn-panel>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import Panel from '@/views/charts/Panel'
|
||||||
|
export default {
|
||||||
|
name: 'EntityDetail',
|
||||||
|
components: {
|
||||||
|
cnPanel: Panel
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
anchorPoints: [], // { id, label, top, height }
|
||||||
|
top: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup (props, ctx) {
|
||||||
|
const { query } = useRoute()
|
||||||
|
let panelType
|
||||||
|
const entityData = {}
|
||||||
|
switch (query.entityType) {
|
||||||
|
case 'ip': {
|
||||||
|
panelType = 4
|
||||||
|
entityData.ip = query.name
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'domain': {
|
||||||
|
panelType = 5
|
||||||
|
entityData.domain = query.name
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'app': {
|
||||||
|
panelType = 6
|
||||||
|
entityData.appName = query.name
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
panelType = 4
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entityData.type = panelType
|
||||||
|
return {
|
||||||
|
entityData
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
chartLoaded (chartList) {
|
||||||
|
this.anchorPoints = []
|
||||||
|
let anchorPoints = []
|
||||||
|
chartList.forEach(chart => {
|
||||||
|
if (chart.params.anchorPoint) {
|
||||||
|
const dom = document.querySelector(`#${chart.params.anchorPoint}`)
|
||||||
|
anchorPoints.push({
|
||||||
|
id: chart.params.anchorPoint,
|
||||||
|
label: chart.i18n ? this.$t(chart.i18n) : chart.name,
|
||||||
|
top: dom.offsetTop/* ,
|
||||||
|
height: document.querySelector(`#${chart.params.anchorPoint}}`).scrollHeight */
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 从小到大排序
|
||||||
|
anchorPoints = anchorPoints.sort((a, b) => {
|
||||||
|
return a.top - b.top
|
||||||
|
})
|
||||||
|
if (!this.$_.isEmpty(anchorPoints)) {
|
||||||
|
anchorPoints[0].top = 0
|
||||||
|
}
|
||||||
|
this.anchorPoints = anchorPoints
|
||||||
|
},
|
||||||
|
scroll ({ top }) {
|
||||||
|
this.top = top || 0
|
||||||
|
},
|
||||||
|
jumpToAnchor (anchor) {
|
||||||
|
this.top = anchor.top
|
||||||
|
this.$refs.cnPanel.jumpToTop(anchor.top)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
iconClass () {
|
||||||
|
let className
|
||||||
|
switch (this.entityData.entityType) {
|
||||||
|
case ('ip'): {
|
||||||
|
className = 'cn-icon cn-icon-ip'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case ('domain'): {
|
||||||
|
className = 'cn-icon cn-icon-domain'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case ('app'): {
|
||||||
|
className = 'cn-icon cn-icon-app'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
return className
|
||||||
|
},
|
||||||
|
menuIsActive () {
|
||||||
|
return function (anchor) {
|
||||||
|
return this.currentAnchor ? this.currentAnchor.id === anchor.id : false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentAnchor () {
|
||||||
|
let currentAnchor = null
|
||||||
|
this.anchorPoints.forEach(anchor => {
|
||||||
|
if (anchor.top <= this.top) {
|
||||||
|
currentAnchor = anchor
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return currentAnchor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -150,28 +150,28 @@ export default {
|
|||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
label: this.$t('overall.country'),
|
label: this.$t('overall.country'),
|
||||||
column: 'country_distinct_count',
|
column: 'countryDistinctCount',
|
||||||
topColumn: 'ip_location_country', // top弹框查询字段
|
topColumn: 'ipLocationCountry', // top弹框查询字段
|
||||||
icon: entityFilterType.ip[0].icon,
|
icon: entityFilterType.ip[0].icon,
|
||||||
value: 0
|
value: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.$t('overall.province'),
|
label: this.$t('overall.province'),
|
||||||
column: 'province_distinct_count',
|
column: 'provinceDistinctCount',
|
||||||
topColumn: 'ip_location_province', // top弹框查询字段
|
topColumn: 'ipLocationProvince', // top弹框查询字段
|
||||||
icon: entityFilterType.ip[1].icon,
|
icon: entityFilterType.ip[1].icon,
|
||||||
value: 0
|
value: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.$t('overall.city'),
|
label: this.$t('overall.city'),
|
||||||
column: 'city_distinct_count',
|
column: 'cityDistinctCount',
|
||||||
topColumn: 'ip_location_city', // top弹框查询字段
|
topColumn: 'ip_location_city', // top弹框查询字段
|
||||||
icon: entityFilterType.ip[2].icon,
|
icon: entityFilterType.ip[2].icon,
|
||||||
value: 0
|
value: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.$t('entities.asn'),
|
label: this.$t('entities.asn'),
|
||||||
column: 'asn_distinct_count',
|
column: 'asnDistinctCount',
|
||||||
topColumn: 'ip_asn', // top弹框查询字段
|
topColumn: 'ip_asn', // top弹框查询字段
|
||||||
icon: entityFilterType.ip[3].icon,
|
icon: entityFilterType.ip[3].icon,
|
||||||
value: 0
|
value: 0
|
||||||
@@ -185,21 +185,21 @@ export default {
|
|||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
label: this.$t('entities.category'),
|
label: this.$t('entities.category'),
|
||||||
column: 'category_distinct_count',
|
column: 'categoryDistinctCount',
|
||||||
topColumn: 'app_category', // top弹框查询字段
|
topColumn: 'app_category', // top弹框查询字段
|
||||||
icon: entityFilterType.app[0].icon,
|
icon: entityFilterType.app[0].icon,
|
||||||
value: 0
|
value: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.$t('entities.subcategory'),
|
label: this.$t('entities.subcategory'),
|
||||||
column: 'subcategory_distinct_count',
|
column: 'subcategoryDistinctCount',
|
||||||
topColumn: 'app_subcategory', // top弹框查询字段
|
topColumn: 'app_subcategory', // top弹框查询字段
|
||||||
icon: entityFilterType.app[1].icon,
|
icon: entityFilterType.app[1].icon,
|
||||||
value: 0
|
value: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.$t('entities.risk'),
|
label: this.$t('entities.risk'),
|
||||||
column: 'risk_distinct_count',
|
column: 'riskDistinctCount',
|
||||||
topColumn: 'app_risk', // top弹框查询字段
|
topColumn: 'app_risk', // top弹框查询字段
|
||||||
icon: entityFilterType.app[2].icon,
|
icon: entityFilterType.app[2].icon,
|
||||||
value: 0
|
value: 0
|
||||||
@@ -213,22 +213,22 @@ export default {
|
|||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
label: this.$t('entities.domainDetail.categoryGroup'),
|
label: this.$t('entities.domainDetail.categoryGroup'),
|
||||||
column: 'category_group_distinct_count',
|
column: 'categoryGroupDistinctCount',
|
||||||
topColumn: 'domain_category_group', // top弹框查询字段
|
topColumn: 'domain_category_group', // top弹框查询字段
|
||||||
icon: entityFilterType.domain[0].icon,
|
icon: entityFilterType.domain[0].icon,
|
||||||
value: 0
|
value: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.$t('entities.category'),
|
label: this.$t('entities.category'),
|
||||||
column: 'category_distinct_count',
|
column: 'categoryDistinctCount',
|
||||||
topColumn: 'domain_category', // top弹框查询字段
|
topColumn: 'domain_category', // top弹框查询字段
|
||||||
icon: entityFilterType.domain[1].icon,
|
icon: entityFilterType.domain[1].icon,
|
||||||
value: 0
|
value: 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.$t('entities.reputationLevel'),
|
label: this.$t('entities.reputationLevel'),
|
||||||
column: 'reputation_level_distinct_count',
|
column: 'reputationLevelDistinctCount',
|
||||||
topColumn: 'domain_reputation_level', // top弹框查询字段
|
topColumn: 'domainReputationLevel', // top弹框查询字段
|
||||||
icon: entityFilterType.domain[2].icon,
|
icon: entityFilterType.domain[2].icon,
|
||||||
value: 0
|
value: 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,11 @@
|
|||||||
<span>{{entityData.securityCount || '-'}}</span>
|
<span>{{entityData.securityCount || '-'}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="show-detail" :style="{visibility: !isCollapse ? 'visible' : 'hidden'}">{{$t('overall.detail')}}>></div>
|
<div
|
||||||
|
class="show-detail"
|
||||||
|
:style="{visibility: !isCollapse ? 'visible' : 'hidden'}"
|
||||||
|
@click="showDetail"
|
||||||
|
>{{$t('overall.detail')}}>></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -127,6 +131,16 @@ export default {
|
|||||||
/* 设为折叠状态 */
|
/* 设为折叠状态 */
|
||||||
collapse () {
|
collapse () {
|
||||||
this.isCollapse = true
|
this.isCollapse = true
|
||||||
|
},
|
||||||
|
showDetail () {
|
||||||
|
const { href } = this.$router.resolve({
|
||||||
|
path: '/entityDetail',
|
||||||
|
query: {
|
||||||
|
entityType: this.entityData.entityType,
|
||||||
|
name: this.entityData.ipAddr || this.entityData.domainName || this.entityData.appName
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.open(href, '_blank')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export default {
|
|||||||
let name
|
let name
|
||||||
switch (this.entityData.entityType) {
|
switch (this.entityData.entityType) {
|
||||||
case ('ip'): {
|
case ('ip'): {
|
||||||
name = this.entity.ip
|
name = this.entity.ipAddr
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case ('domain'): {
|
case ('domain'): {
|
||||||
@@ -85,7 +85,7 @@ export default {
|
|||||||
startTime: Math.floor(now.getTime() / 1000 - 3600),
|
startTime: Math.floor(now.getTime() / 1000 - 3600),
|
||||||
endTime: Math.floor(now.getTime() / 1000)
|
endTime: Math.floor(now.getTime() / 1000)
|
||||||
},
|
},
|
||||||
ip: this.entityData.ip
|
ip: this.entityData.ipAddr
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import dataListMixin from '@/mixins/dataList'
|
|||||||
import rolesTable from '@/components/table/settings/RoleTable'
|
import rolesTable from '@/components/table/settings/RoleTable'
|
||||||
import roleBox from '@/components/rightBox/settings/RoleBox'
|
import roleBox from '@/components/rightBox/settings/RoleBox'
|
||||||
import { api } from '@/utils/api'
|
import { api } from '@/utils/api'
|
||||||
|
import {get} from "@/utils/http";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'roles',
|
name: 'roles',
|
||||||
@@ -69,6 +70,16 @@ export default {
|
|||||||
name: ''
|
name: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
edit (u) {
|
||||||
|
get(`${this.url}`, { ids: u.id }).then(response => {
|
||||||
|
if (response.code === 200) {
|
||||||
|
this.object = response.data
|
||||||
|
this.rightBox.show = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user