feat: dashboard定义
This commit is contained in:
@@ -2,7 +2,7 @@ module.exports = {
|
|||||||
plugins: {
|
plugins: {
|
||||||
autoprefixer: {},
|
autoprefixer: {},
|
||||||
'postcss-plugin-px2rem': {
|
'postcss-plugin-px2rem': {
|
||||||
rootValue: 16,
|
rootValue: 14,
|
||||||
exclude: /node_modules/i,
|
exclude: /node_modules/i,
|
||||||
minPixelValue: 3,
|
minPixelValue: 3,
|
||||||
selectorBlackList: ['.html', 'iconfont', '.ttf', '.css']
|
selectorBlackList: ['.html', 'iconfont', '.ttf', '.css']
|
||||||
|
|||||||
@@ -15,36 +15,37 @@
|
|||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
</body>
|
</body>
|
||||||
<style>
|
<style>
|
||||||
@media only screen and (min-width: 800px) {
|
body,html{font-size: 14px !important;}
|
||||||
|
/*@media only screen and (min-width: 800px) {
|
||||||
body,html{font-size: 12px !important;}
|
body,html{font-size: 12px !important;}
|
||||||
} /*>=800的设备*/
|
} !*>=800的设备*!
|
||||||
|
|
||||||
@media only screen and (min-width: 1024px) {
|
@media only screen and (min-width: 1024px) {
|
||||||
body,html{font-size: 12px !important;}
|
body,html{font-size: 12px !important;}
|
||||||
} /*>=1024的设备*/
|
} !*>=1024的设备*!
|
||||||
|
|
||||||
@media only screen and (min-width: 1280px) {
|
@media only screen and (min-width: 1280px) {
|
||||||
body,html{font-size: 12px !important;}
|
body,html{font-size: 12px !important;}
|
||||||
}/*>=1280的设备*/
|
}!*>=1280的设备*!
|
||||||
|
|
||||||
@media only screen and (min-width: 1366px) {
|
@media only screen and (min-width: 1366px) {
|
||||||
body,html{font-size: 12px !important; }
|
body,html{font-size: 12px !important; }
|
||||||
}/*>=1366的设备*/
|
}!*>=1366的设备*!
|
||||||
|
|
||||||
@media only screen and (min-width: 1440px) {
|
@media only screen and (min-width: 1440px) {
|
||||||
body,html{font-size: 12px !important;}
|
body,html{font-size: 12px !important;}
|
||||||
}/*>=1440的设备*/
|
}!*>=1440的设备*!
|
||||||
|
|
||||||
@media only screen and (min-width: 1680px) {
|
@media only screen and (min-width: 1680px) {
|
||||||
body,html{font-size: 14px !important;}
|
body,html{font-size: 14px !important;}
|
||||||
}/*>=1680的设备*/
|
}!*>=1680的设备*!
|
||||||
|
|
||||||
@media only screen and (min-width: 1920px) {
|
@media only screen and (min-width: 1920px) {
|
||||||
body,html{font-size: 16px !important;}
|
body,html{font-size: 16px !important;}
|
||||||
}/*>=1920的设备*/
|
}!*>=1920的设备*!
|
||||||
|
|
||||||
@media only screen and (min-width: 2560px) {
|
@media only screen and (min-width: 2560px) {
|
||||||
body,html{font-size: 22px !important;}
|
body,html{font-size: 22px !important;}
|
||||||
}/*>=2560的设备*/
|
}!*>=2560的设备*!*/
|
||||||
</style>
|
</style>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -2,14 +2,12 @@
|
|||||||
height: calc(100% - 50px);
|
height: calc(100% - 50px);
|
||||||
background-color: $--content-right-background-color;
|
background-color: $--content-right-background-color;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
&>div {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cn-header {
|
.cn-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
border-bottom: 1px solid #e2e5ec;
|
||||||
|
|
||||||
.header__left {
|
.header__left {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -18,7 +16,8 @@
|
|||||||
.header__left-breadcrumb.el-breadcrumb {
|
.header__left-breadcrumb.el-breadcrumb {
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
.header__left-breadcrumb-item.el-breadcrumb-item {
|
.header__left-breadcrumb-item.el-breadcrumb-item {
|
||||||
display: inline-block; max-width: 300px;
|
display: inline-block;
|
||||||
|
max-width: 300px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
@import './views/detections/detection-list/detection-list';
|
@import './views/detections/detection-list/detection-list';
|
||||||
@import './views/detections/detection-list/row';
|
@import './views/detections/detection-list/row';
|
||||||
@import './views/detections/detection-overview';
|
@import './views/detections/detection-overview';
|
||||||
@import './views/charts/panel';
|
// @import './views/charts/panel';
|
||||||
@import 'views/charts/chartIpOpenPortBar';
|
@import 'views/charts/chartIpOpenPortBar';
|
||||||
@import './views/charts/chartTable';
|
@import './views/charts/chartTable';
|
||||||
@import './views/charts/chartSingleValue';
|
@import './views/charts/chartSingleValue';
|
||||||
@@ -45,5 +45,5 @@
|
|||||||
@import './views/report/builtinReport';
|
@import './views/report/builtinReport';
|
||||||
@import './components/rightBox/report/builtinReportBox';
|
@import './components/rightBox/report/builtinReportBox';
|
||||||
|
|
||||||
|
@import './views/charts2/panel';
|
||||||
//@import '../chart';
|
//@import '../chart';
|
||||||
|
|||||||
25
src/assets/css/components/views/charts2/panel.scss
Normal file
25
src/assets/css/components/views/charts2/panel.scss
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
.panel-box {
|
||||||
|
height: calc(100% - 20px);
|
||||||
|
.panel__header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 0 20px 20px;
|
||||||
|
|
||||||
|
.panel__title {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #353636;
|
||||||
|
}
|
||||||
|
.panel__time {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.chart-list {
|
||||||
|
height: calc(100% - 46px);
|
||||||
|
overflow: auto;
|
||||||
|
&>.vue-grid-layout {
|
||||||
|
margin-top: -20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,9 +85,6 @@
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
background-color: $--content-right-background-color;
|
background-color: $--content-right-background-color;
|
||||||
|
|
||||||
&>.cn-entity-detail .entity-detail__body>.cn-panel {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
&>.cn-entity-detail .entity-detail__body>.cn-panel2 {
|
&>.cn-entity-detail .entity-detail__body>.cn-panel2 {
|
||||||
.panel-chart {
|
.panel-chart {
|
||||||
.chart-header.panel-chart-block {
|
.chart-header.panel-chart-block {
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
/*---滚动条默认显示样式--*/
|
/*---滚动条默认显示样式--*/
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
background-color: #ddd;
|
background-color: #ececec;
|
||||||
border-radius: 6px;
|
border-radius: 5px;
|
||||||
border: 1px solid #fff;
|
/*border: 1px solid #fff;*/
|
||||||
}
|
}
|
||||||
/*---鼠标点击滚动条显示样式--*/
|
/*---鼠标点击滚动条显示样式--*/
|
||||||
::-webkit-scrollbar-thumb:hover {
|
::-webkit-scrollbar-thumb:hover {
|
||||||
background-color: #c8c8c8;
|
background-color: #ddd;
|
||||||
border-radius: 6px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
/*---滚动条大小--*/
|
/*---滚动条大小--*/
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 14px;
|
width: 8px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
/*---滚动框背景样式--*/
|
/*---滚动框背景样式--*/
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ $--color-monitor: #98AEC5; //全局停用色灰色
|
|||||||
|
|
||||||
$--chart-single-value-icon-background-color: #E8F6FF;
|
$--chart-single-value-icon-background-color: #E8F6FF;
|
||||||
|
|
||||||
$--content-right-background-color: #EFF2F5; //右侧背景色
|
$--content-right-background-color: #fff; //右侧背景色
|
||||||
|
|
||||||
// 空白背景色
|
// 空白背景色
|
||||||
$--background-color-empty: #fffffe;
|
$--background-color-empty: #fffffe;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const routes = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/panel/:typeName',
|
path: '/panel/:typeName',
|
||||||
component: () => import('@/views/charts/Panel')
|
component: () => import('@/views/charts2/Panel')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/user',
|
path: '/user',
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const fromRoute = {
|
|||||||
|
|
||||||
/* panel类别和名称之间的映射 */
|
/* panel类别和名称之间的映射 */
|
||||||
export const panelTypeAndRouteMapping = {
|
export const panelTypeAndRouteMapping = {
|
||||||
trafficSummary: 1,
|
networkOverview: 1,
|
||||||
networkAppPerformance: 2,
|
networkAppPerformance: 2,
|
||||||
dnsServiceInsights: 3,
|
dnsServiceInsights: 3,
|
||||||
ipEntityDetail: 4,
|
ipEntityDetail: 4,
|
||||||
|
|||||||
34
src/views/charts2/Chart.vue
Normal file
34
src/views/charts2/Chart.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<div class="cn-chart" style="background-color: lightgray;height: 100%;">
|
||||||
|
<loading :loading="loading"></loading>
|
||||||
|
<chart-no-data v-if="isNoData"></chart-no-data>
|
||||||
|
<network-overview-line
|
||||||
|
v-if="chart.type === typeMapping.networkOverview.line"
|
||||||
|
></network-overview-line>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Loading from '@/components/common/Loading'
|
||||||
|
import ChartNoData from '@/views/charts/charts/ChartNoData'
|
||||||
|
import { typeMapping } from '@/views/charts2/chart-tools'
|
||||||
|
import NetworkOverviewLine from '@/views/charts2/charts/NetworkOverviewLine';
|
||||||
|
export default {
|
||||||
|
name: 'Chart',
|
||||||
|
components: {
|
||||||
|
Loading,
|
||||||
|
ChartNoData,
|
||||||
|
NetworkOverviewLine
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
chart: Object
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
typeMapping,
|
||||||
|
loading: false,
|
||||||
|
isNoData: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
64
src/views/charts2/ChartList.vue
Normal file
64
src/views/charts2/ChartList.vue
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div class="chart-list" ref="layoutBox">
|
||||||
|
<grid-layout
|
||||||
|
id="gridLayout"
|
||||||
|
ref="layout"
|
||||||
|
v-model:layout="layout"
|
||||||
|
:col-num="24"
|
||||||
|
:is-draggable="!panelLock"
|
||||||
|
:is-resizable="!panelLock"
|
||||||
|
:margin="[20, 20]"
|
||||||
|
:row-height="40"
|
||||||
|
:vertical-compact="true"
|
||||||
|
:use-css-transforms="false"
|
||||||
|
>
|
||||||
|
<grid-item v-for="item in layout"
|
||||||
|
:x="item.x"
|
||||||
|
:y="item.y"
|
||||||
|
:w="item.w"
|
||||||
|
:h="item.h"
|
||||||
|
:i="item.i"
|
||||||
|
:key="item.i">
|
||||||
|
<chart
|
||||||
|
:chart="item"
|
||||||
|
></chart>
|
||||||
|
</grid-item>
|
||||||
|
</grid-layout>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import VueGridLayout from 'vue-grid-layout'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import Chart from '@/views/charts2/Chart'
|
||||||
|
export default {
|
||||||
|
name: 'ChartList',
|
||||||
|
props: {
|
||||||
|
timeFilter: Object,
|
||||||
|
chartList: Array,
|
||||||
|
panelLock: Boolean,
|
||||||
|
entity: Object
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
layout: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
GridLayout: VueGridLayout.GridLayout,
|
||||||
|
GridItem: VueGridLayout.GridItem,
|
||||||
|
Chart
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
chartList (n) {
|
||||||
|
if (!_.isEmpty(n)) {
|
||||||
|
this.layout = [...n]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
118
src/views/charts2/Panel.vue
Normal file
118
src/views/charts2/Panel.vue
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel-box">
|
||||||
|
<div class="panel__header">
|
||||||
|
<div class="panel__title">{{panel.i18n ? $t(panel.i18n) : panel.name}}</div>
|
||||||
|
<div class="panel__time">
|
||||||
|
<date-time-range
|
||||||
|
class="date-time-range"
|
||||||
|
:start-time="timeFilter.startTime"
|
||||||
|
:end-time="timeFilter.endTime"
|
||||||
|
:date-range="timeFilter.dateRangeValue"
|
||||||
|
ref="dateTimeRange"
|
||||||
|
@change="reload"
|
||||||
|
/>
|
||||||
|
<time-refresh
|
||||||
|
class="date-time-range"
|
||||||
|
@change="timeRefreshChange"
|
||||||
|
:end-time="timeFilter.endTime"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<chart-list
|
||||||
|
ref="chartList"
|
||||||
|
:time-filter="timeFilter"
|
||||||
|
:chart-list="chartList"
|
||||||
|
:panel-lock="panelLock"
|
||||||
|
:entity="entity"
|
||||||
|
></chart-list>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { panelTypeAndRouteMapping } from '@/utils/constants'
|
||||||
|
import { getPanelList, getChartList } from '@/utils/api'
|
||||||
|
import { getNowTime } from '@/utils/date-util'
|
||||||
|
import { getTypeCategory } from '@/views/charts/charts/tools'
|
||||||
|
import ChartList from '@/views/charts2/ChartList'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Panel',
|
||||||
|
props: {
|
||||||
|
entity: Object,
|
||||||
|
typeName: String
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ChartList
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
chartList: [], // 普通panel的chart
|
||||||
|
panelLock: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted () {
|
||||||
|
await this.init()
|
||||||
|
},
|
||||||
|
setup (props, ctx) {
|
||||||
|
const panel = ref({})
|
||||||
|
let panelType = 1 // 取得panel的type
|
||||||
|
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 { startTime, endTime } = getNowTime(dateRangeValue)
|
||||||
|
const timeFilter = ref({ startTime, endTime, dateRangeValue })
|
||||||
|
|
||||||
|
return {
|
||||||
|
panelType,
|
||||||
|
panel,
|
||||||
|
timeFilter
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async init () {
|
||||||
|
const panels = await getPanelList({ type: this.panelType })
|
||||||
|
if (panels && panels.length > 0) {
|
||||||
|
this.panel = panels[0]
|
||||||
|
}
|
||||||
|
if (this.panel.id) {
|
||||||
|
if (this.panel.params) {
|
||||||
|
this.panel.params = JSON.parse(this.panel.params)
|
||||||
|
} else {
|
||||||
|
this.panel.params = {}
|
||||||
|
}
|
||||||
|
this.chartList = (await getChartList({ panelId: this.panel.id, pageSize: -1 })).map(chart => {
|
||||||
|
chart.i = chart.id
|
||||||
|
// 递归初始化各属性
|
||||||
|
this.initChartAttr(chart)
|
||||||
|
return chart
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
initChartAttr (chart) {
|
||||||
|
chart.i = chart.id
|
||||||
|
chart.category = getTypeCategory(chart.type)
|
||||||
|
// 初始化params
|
||||||
|
chart.params = chart.params ? JSON.parse(chart.params) : {}
|
||||||
|
chart.firstShow = false
|
||||||
|
if (!this.$_.isEmpty(chart.children)) {
|
||||||
|
chart.children.forEach(c => {
|
||||||
|
this.initChartAttr(c)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
timeRefreshChange (startTime, endTime, dateRangeValue) {
|
||||||
|
|
||||||
|
},
|
||||||
|
reload () {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
9
src/views/charts2/chart-tools.js
Normal file
9
src/views/charts2/chart-tools.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export const typeMapping = {
|
||||||
|
networkOverview: {
|
||||||
|
line: 102,
|
||||||
|
appList: 103,
|
||||||
|
performanceEvent: 302,
|
||||||
|
table: 601,
|
||||||
|
ddosDetection: 701
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/views/charts2/charts/NetworkOverviewLine.vue
Normal file
9
src/views/charts2/charts/NetworkOverviewLine.vue
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<template>
|
||||||
|
呵呵
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'NetworkOverviewLine'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="height: 100%;">
|
||||||
<cn-data-list
|
<cn-data-list
|
||||||
ref="dataList"
|
ref="dataList"
|
||||||
:tableId="tableId"
|
:tableId="tableId"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="height: 100%;">
|
||||||
<cn-data-list
|
<cn-data-list
|
||||||
ref="dataList"
|
ref="dataList"
|
||||||
:tableId="tableId"
|
:tableId="tableId"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="height: 100%;">
|
||||||
<cn-data-list
|
<cn-data-list
|
||||||
ref="dataList"
|
ref="dataList"
|
||||||
:tableId="tableId"
|
:tableId="tableId"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="height: 100%;">
|
||||||
<cn-data-list
|
<cn-data-list
|
||||||
ref="dataList"
|
ref="dataList"
|
||||||
:api="url"
|
:api="url"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="height: 100%;">
|
||||||
<cn-data-list
|
<cn-data-list
|
||||||
ref="dataList"
|
ref="dataList"
|
||||||
:tableId="tableId"
|
:tableId="tableId"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="height: 100%;">
|
||||||
<cn-data-list
|
<cn-data-list
|
||||||
ref="dataList"
|
ref="dataList"
|
||||||
:tableId="tableId"
|
:tableId="tableId"
|
||||||
|
|||||||
Reference in New Issue
Block a user