feat: dashboard定义

This commit is contained in:
chenjinsong
2022-07-06 21:08:12 +08:00
parent 05cc86a3f2
commit ebd9727178
21 changed files with 290 additions and 34 deletions

View File

@@ -2,7 +2,7 @@ module.exports = {
plugins: {
autoprefixer: {},
'postcss-plugin-px2rem': {
rootValue: 16,
rootValue: 14,
exclude: /node_modules/i,
minPixelValue: 3,
selectorBlackList: ['.html', 'iconfont', '.ttf', '.css']

View File

@@ -15,36 +15,37 @@
<div id="app"></div>
</body>
<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;}
} /*>=800的设备*/
} !*>=800的设备*!
@media only screen and (min-width: 1024px) {
body,html{font-size: 12px !important;}
} /*>=1024的设备*/
} !*>=1024的设备*!
@media only screen and (min-width: 1280px) {
body,html{font-size: 12px !important;}
}/*>=1280的设备*/
}!*>=1280的设备*!
@media only screen and (min-width: 1366px) {
body,html{font-size: 12px !important; }
}/*>=1366的设备*/
}!*>=1366的设备*!
@media only screen and (min-width: 1440px) {
body,html{font-size: 12px !important;}
}/*>=1440的设备*/
}!*>=1440的设备*!
@media only screen and (min-width: 1680px) {
body,html{font-size: 14px !important;}
}/*>=1680的设备*/
}!*>=1680的设备*!
@media only screen and (min-width: 1920px) {
body,html{font-size: 16px !important;}
}/*>=1920的设备*/
}!*>=1920的设备*!
@media only screen and (min-width: 2560px) {
body,html{font-size: 22px !important;}
}/*>=2560的设备*/
}!*>=2560的设备*!*/
</style>
</html>

View File

@@ -2,14 +2,12 @@
height: calc(100% - 50px);
background-color: $--content-right-background-color;
width: 100%;
&>div {
height: 100%;
}
}
.cn-header {
display: flex;
height: 50px;
border-bottom: 1px solid #e2e5ec;
.header__left {
display: flex;
@@ -18,7 +16,8 @@
.header__left-breadcrumb.el-breadcrumb {
padding-left: 20px;
.header__left-breadcrumb-item.el-breadcrumb-item {
display: inline-block; max-width: 300px;
display: inline-block;
max-width: 300px;
height: 16px;
overflow: hidden;
text-overflow: ellipsis;

View File

@@ -24,7 +24,7 @@
@import './views/detections/detection-list/detection-list';
@import './views/detections/detection-list/row';
@import './views/detections/detection-overview';
@import './views/charts/panel';
// @import './views/charts/panel';
@import 'views/charts/chartIpOpenPortBar';
@import './views/charts/chartTable';
@import './views/charts/chartSingleValue';
@@ -45,5 +45,5 @@
@import './views/report/builtinReport';
@import './components/rightBox/report/builtinReportBox';
@import './views/charts2/panel';
//@import '../chart';

View 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;
}
}
}

View File

@@ -85,9 +85,6 @@
overflow: auto;
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 {
.panel-chart {
.chart-header.panel-chart-block {

View File

@@ -1,17 +1,17 @@
/*---滚动条默认显示样式--*/
::-webkit-scrollbar-thumb {
background-color: #ddd;
border-radius: 6px;
border: 1px solid #fff;
background-color: #ececec;
border-radius: 5px;
/*border: 1px solid #fff;*/
}
/*---鼠标点击滚动条显示样式--*/
::-webkit-scrollbar-thumb:hover {
background-color: #c8c8c8;
border-radius: 6px;
background-color: #ddd;
border-radius: 5px;
}
/*---滚动条大小--*/
::-webkit-scrollbar {
width: 14px;
width: 8px;
height: 14px;
}
/*---滚动框背景样式--*/

View File

@@ -49,7 +49,7 @@ $--color-monitor: #98AEC5; //全局停用色灰色
$--chart-single-value-icon-background-color: #E8F6FF;
$--content-right-background-color: #EFF2F5; //右侧背景色
$--content-right-background-color: #fff; //右侧背景色
// 空白背景色
$--background-color-empty: #fffffe;

View File

@@ -16,7 +16,7 @@ const routes = [
children: [
{
path: '/panel/:typeName',
component: () => import('@/views/charts/Panel')
component: () => import('@/views/charts2/Panel')
},
{
path: '/user',

View File

@@ -42,7 +42,7 @@ export const fromRoute = {
/* panel类别和名称之间的映射 */
export const panelTypeAndRouteMapping = {
trafficSummary: 1,
networkOverview: 1,
networkAppPerformance: 2,
dnsServiceInsights: 3,
ipEntityDetail: 4,

View 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>

View 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
View 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>

View File

@@ -0,0 +1,9 @@
export const typeMapping = {
networkOverview: {
line: 102,
appList: 103,
performanceEvent: 302,
table: 601,
ddosDetection: 701
}
}

View File

@@ -0,0 +1,9 @@
<template>
呵呵
</template>
<script>
export default {
name: 'NetworkOverviewLine'
}
</script>

View File

@@ -1,5 +1,5 @@
<template>
<div>
<div style="height: 100%;">
<cn-data-list
ref="dataList"
:tableId="tableId"

View File

@@ -1,5 +1,5 @@
<template>
<div>
<div style="height: 100%;">
<cn-data-list
ref="dataList"
:tableId="tableId"

View File

@@ -1,5 +1,5 @@
<template>
<div>
<div style="height: 100%;">
<cn-data-list
ref="dataList"
:tableId="tableId"

View File

@@ -1,5 +1,5 @@
<template>
<div>
<div style="height: 100%;">
<cn-data-list
ref="dataList"
:api="url"

View File

@@ -1,5 +1,5 @@
<template>
<div>
<div style="height: 100%;">
<cn-data-list
ref="dataList"
:tableId="tableId"

View File

@@ -1,5 +1,5 @@
<template>
<div>
<div style="height: 100%;">
<cn-data-list
ref="dataList"
:tableId="tableId"