CN-38 feat: 添加 chart type 31

This commit is contained in:
zhangyu
2021-06-23 15:57:34 +08:00
parent 407e1c9c9f
commit becfb5b120
23 changed files with 334 additions and 51 deletions

View File

@@ -8,26 +8,27 @@
<slot name="operations"></slot>
</div>
</div>
<div class="cn-chart__body">
<div class="cn-chart__body" :class="{'pie-with-table': isPieWithTable}">
<slot></slot>
</div>
<div class="cn-chart__footer" v-if="layout.indexOf(layoutConstant.FOOTER) > -1">
<div class="cn-chart__footer" v-if="layout.indexOf(layoutConstant.FOOTER) > -1" :class="{'pie-with-table': isPieWithTable}">
<slot name="footer"></slot>
</div>
</div>
</template>
<script>
import { layoutConstant } from '@/components/charts/chart-options'
import { layoutConstant, isEchartsWithTable } from '@/components/charts/chart-options'
export default {
name: 'EchartsFrame',
props: {
layout: Array
layout: Array,
chartInfo: {}
},
setup () {
setup (props) {
return {
layoutConstant
layoutConstant,
isPieWithTable: isEchartsWithTable(props.chartInfo.type)
}
},
mounted () {
@@ -35,6 +36,9 @@ export default {
}
</script>
<style>
</style>
<style scoped>
.cn-panel .cn-chart__echarts .pie-with-table{
flex: 1;
padding: 10px;
}
</style>

View File

@@ -0,0 +1,103 @@
<template>
<el-table
v-loading="loading"
class="pie-table"
:data="tableData"
style="width: 100%;border: 1px solid #E7EAED"
:size="'mini'"
:height="'100%'">
<el-table-column type="expand" :min-width="'5%'">
<template #default="props">
<el-table
class="expand-table"
:data=" props.row.children"
style="width: 100%;"
:show-header="false"
:size="'mini'"
:height="'100%'">
<el-table-column
min-width="5%">
</el-table-column>
<el-table-column
v-for="(item, index) in tableTitles"
:key="index"
:min-width="item.width"
:label="item.label"
:prop="item.prop">
</el-table-column>
</el-table>
</template>
</el-table-column>
<el-table-column
v-for="(item, index) in tableTitles"
:key="index"
:min-width="item.width"
:label="item.label"
:prop="item.prop">
</el-table-column>
</el-table>
</template>
<script>
export default {
name: 'PieTable',
props: {
tableData: Array
},
watch: {
tableData: {
deep: true,
immediate: true,
handler (n) {
console.log(n)
}
}
},
data () {
return {
loading: false,
tableTitles: [
{
label: this.$t('chart.pieTable.domain'),
prop: 'domain',
width: '20%'
},
{
label: this.$t('chart.pieTable.sessions'),
prop: 'sessions',
width: '25%'
},
{
label: this.$t('chart.pieTable.packets'),
prop: 'packets',
width: '25%'
},
{
label: this.$t('chart.pieTable.bytes'),
prop: 'bytes',
width: '25%'
}
]
}
}
}
</script>
<style scoped>
/deep/ .el-table__expanded-cell[class*=cell]{
padding: 0;
}
.expand-table /deep/ .el-table__body .el-table__row:last-of-type td{
border: none;
}
.pie-table{
font-family: Roboto-Medium;
font-size: 14px;
color: #333333;
font-weight: 500;
}
.expand-table{
font-weight: 400;
color: #606266;
}
</style>

View File

@@ -15,16 +15,105 @@ const pieData = [
{ value: 4, name: 'sessions' },
{ value: 5, name: 'fqdn_category_name' },
{ value: 1, name: 'uniq_domain1' },
{ value: 2, name: 'bytes2' },
{ value: 3, name: 'packets3' },
{ value: 4, name: 'sessions4' },
{ value: 5, name: 'fqdn_category_name5' },
{ value: 1, name: 'uniq_domain6' },
{ value: 2, name: 'bytes7' },
{ value: 3, name: 'packets8' },
{ value: 4, name: 'sessions9' },
{ value: 5, name: 'fqdn_category_name10' }
{ value: 2, name: 'bytes1' },
{ value: 3, name: 'packets1' },
{ value: 4, name: 'sessions1' },
{ value: 5, name: 'fqdn_category_name1' }
// { value: 1, name: 'uniq_domain2' },
// { value: 2, name: 'bytes2' },
// { value: 3, name: 'packets2' },
// { value: 4, name: 'sessions2' },
// { value: 5, name: 'fqdn_category_name2' },
// { value: 1, name: 'uniq_domain3' },
// { value: 2, name: 'bytes3' },
// { value: 3, name: 'packets3' },
// { value: 4, name: 'sessions3' },
// { value: 5, name: 'fqdn_category_name3' },
// { value: 1, name: 'uniq_domain4' },
// { value: 2, name: 'bytes4' },
// { value: 3, name: 'packets4' },
// { value: 4, name: 'sessions4' },
// { value: 5, name: 'fqdn_category_name4' }
]
export const pieTableDatas = [
{
domain: '12306.com',
bytes: '170537133646',
packets: '123454646',
sessions: '26682',
children: [
{
domain: '192.168.36.120',
bytes: '170537133646',
packets: '123454646',
sessions: '26682'
},
{
domain: '192.168.36.120',
bytes: '170537133646',
packets: '123454646',
sessions: '26682'
},
{
domain: '192.168.36.120',
bytes: '170537133646',
packets: '123454646',
sessions: '26682'
}
]
},
{
domain: '12306.com',
bytes: '170537133646',
packets: '123454646',
sessions: '26682',
children: [
{
domain: '192.168.36.120',
bytes: '170537133646',
packets: '123454646',
sessions: '26682'
},
{
domain: '192.168.36.120',
bytes: '170537133646',
packets: '123454646',
sessions: '26682'
},
{
domain: '192.168.36.120',
bytes: '170537133646',
packets: '123454646',
sessions: '26682'
}
]
},
{
domain: '12306.com',
bytes: '170537133646',
packets: '123454646',
sessions: '26682',
children: [
{
domain: '192.168.36.120',
bytes: '170537133646',
packets: '123454646',
sessions: '26682'
},
{
domain: '192.168.36.120',
bytes: '170537133646',
packets: '123454646',
sessions: '26682'
},
{
domain: '192.168.36.120',
bytes: '170537133646',
packets: '123454646',
sessions: '26682'
}
]
}]
const line = {
xAxis: {
type: 'time'
@@ -141,18 +230,21 @@ const pieWithTable = {
},
legend: {
orient: 'vertical',
right: '0%',
type: 'plain',
right: '5%',
top: '30%',
height: '50%',
width: '40%',
icon: 'circle',
itemWidth: 10, // 设置宽度
itemHeight: 10, // 设置高度
itemGap: 20
},
series: [
{
type: 'pie',
radius: ['50%', '80%'],
center: ['30%', '50%'],
center: ['25%', '50%'],
data: pieData,
emphasis: {
itemStyle: {

View File

@@ -208,7 +208,7 @@ export default {
this.pageSize = this.postPageSizes[0]
this.resetPageSizes()
} else {
const pageSize = localStorage.getItem('nz-pageSize-' + localStorage.getItem('nz-username') + '-' + this.tableId)
const pageSize = localStorage.getItem('cn-pageSize-' + localStorage.getItem('cn-username') + '-' + this.tableId)
if (pageSize != 'undefined' && pageSize != null) {
this.pageSize = parseInt(pageSize)
}

View File

@@ -98,7 +98,7 @@ export default {
const myEndTime = ref(props.endTime)
const timeArr = ref([myStartTime.value, myEndTime.value])
const address = localStorage.getItem('cn-sys-timezone')
const utc = localStorage.getItem('timezone-offset')
const utc = localStorage.getItem('cn-timezone-offset')
const rangeHistory = ref(localStorage.getItem('date-range-history') ? JSON.parse(localStorage.getItem('date-range-history')) : [])
const dateRangeValue = ref(60)
dateRangeValue.value = 60

View File

@@ -112,7 +112,8 @@ export default {
methods: {
jump (route) {
if (route === this.route) {
this.refresh()
// this.refresh()
return
}
this.$router.push({
path: route,

View File

@@ -20,8 +20,8 @@
<el-form-item :label="$t('config.roles.permission')">
<!--<div class="tree-option">
<button type="button" class="nz-btn nz-btn-size-small-new nz-btn-style-light-new option-btn" style="margin-left: 0px;" @click="expandAllOrNone" :class="{'btn-active':expandAllFlag}">展开/收缩</button>
<button type="button" class="nz-btn nz-btn-size-small-new nz-btn-style-light-new option-btn" @click="selectAllOrNone" :class="{'btn-active':selectAllFlag}"><span ><i class="cn-icon cn-icon-delete"></i></span></button>
<button type="button" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new option-btn" style="margin-left: 0px;" @click="expandAllOrNone" :class="{'btn-active':expandAllFlag}">展开/收缩</button>
<button type="button" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new option-btn" @click="selectAllOrNone" :class="{'btn-active':selectAllFlag}"><span ><i class="cn-icon cn-icon-delete"></i></span></button>
</div>-->
<el-tree :data="menus" :default-expand-all="expandAllFlag" :props="{label:labelFormatter}" @check-change="selectChange" class="tree-border" node-key="id" ref="menuTree" show-checkbox id="role-box-input-menus">
<template #default="{ data }">

View File

@@ -19,17 +19,17 @@
</div>
</div>
<div class="custom-bottom-btns">
<button v-if="isCancel" :id="tableId+'-element-set-none'" class="nz-btn nz-btn-size-small-new nz-btn-style-light-new is-cancel" type="button" @click="batchHandler(false)">
<button 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)">
<span class="top-tool-btn-txt">{{$t('overall.clear')}}</span>
</button>
<button v-if="!isCancel" :id="tableId+'-element-set-all'" class="nz-btn nz-btn-size-small-new nz-btn-style-light-new" type="button" @click="batchHandler(true)">
<button 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)">
<span class="top-tool-btn-txt">{{$t('overall.all')}}</span>
</button>
<div>
<button :id="tableId+'-element-set-esc'" class="nz-btn nz-btn-size-small-new nz-btn-style-light-new" type="button" @click="esc">
<button :id="tableId+'-element-set-esc'" class="cn-btn cn-btn-size-small-new cn-btn-style-light-new" type="button" @click="esc">
<span class="top-tool-btn-txt">{{$t('overall.esc')}}</span>
</button>
<button :id="tableId+'-element-set-save'" class="nz-btn nz-btn-size-small-new nz-btn-style-normal-new" type="button" @click="save">
<button :id="tableId+'-element-set-save'" class="cn-btn cn-btn-size-small-new cn-btn-style-normal-new" type="button" @click="save">
<span class="top-tool-btn-txt">{{$t('overall.save')}}</span>
</button>
</div>
@@ -51,9 +51,9 @@ export default {
}
},
created () {
const localStorageTitle = JSON.parse(localStorage.getItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.tableId))
const localStorageTitle = JSON.parse(localStorage.getItem('cn-tableTitle-' + localStorage.getItem('cn-username') + '-' + this.tableId))
if (localStorageTitle) {
localStorage.setItem('nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.tableId, JSON.stringify(localStorageTitle))
localStorage.setItem('cn-tableTitle-' + localStorage.getItem('cn-username') + '-' + this.tableId, JSON.stringify(localStorageTitle))
}
},
watch: {
@@ -93,7 +93,7 @@ export default {
save () {
this.$emit('update', this.custom)
localStorage.setItem(
'nz-tableTitle-' + localStorage.getItem('nz-username') + '-' + this.tableId,
'cn-tableTitle-' + localStorage.getItem('cn-username') + '-' + this.tableId,
JSON.stringify(this.custom)
)
this.esc()

View File

@@ -17,7 +17,7 @@
width="55">
</el-table-column>
<el-table-column
v-for="(item, index) in customTableTitle"
v-for="(item, index) in customTableTitles"
:key="`col-${index}`"
:fixed="item.fixed"
:label="item.label"

View File

@@ -16,7 +16,7 @@
width="55">
</el-table-column>
<el-table-column
v-for="(item, index) in customTableTitle"
v-for="(item, index) in customTableTitles"
:key="`col-${index}`"
:fixed="item.fixed"
:label="item.label"

View File

@@ -16,7 +16,7 @@
width="55">
</el-table-column>
<el-table-column
v-for="(item, index) in customTableTitle"
v-for="(item, index) in customTableTitles"
:key="`col-${index}`"
:fixed="item.fixed"
:label="item.label"
@@ -102,7 +102,6 @@ export default {
label: this.$t('config.user.name'),
prop: 'name',
show: true,
width: 150,
sortable: 'custom'
}, {
label: this.$t('config.user.username'),

View File

@@ -258,6 +258,14 @@ const cn = {
},
response: '响应'
}
},
chart: {
pieTable: {
domain: '域名',
bytes: '字节数',
packets: '包数',
sessions: '会话数'
}
}
}

View File

@@ -259,6 +259,14 @@ const en = {
logout: 'logout'
}
}
},
chart: {
pieTable: {
domain: 'Domain',
bytes: 'Bytes',
packets: 'Packets',
sessions: 'Sessions'
}
}
}
export default en

View File

@@ -1,10 +1,15 @@
import { createI18n } from 'vue-i18n'
import { storageKey } from '@/utils/constants'
import { getI18n } from '@/utils/api'
import cn from './cn'
import en from './en'
const i18n = createI18n({
locale: localStorage.getItem(storageKey.language) || 'en',
messages: {}
messages: {
cn: cn,
en: en
}
})
export async function loadI18n () {
const items = await getI18n()

View File

@@ -42,7 +42,7 @@ export default {
utcTimeToSysTime (str) { // utc 0 到系统设置的时区
let date = ''
if (isNaN(str)) {
date = window.$dayJs(str).valueOf() + localStorage.getItem('timezone-local-offset') * 60 * 60 * 1000
date = window.$dayJs(str).valueOf() + localStorage.getItem('cn-timezone-local-offset') * 60 * 60 * 1000
} else {
date = str
}

View File

@@ -17,9 +17,24 @@ export default {
type: String
}
},
computed: {
customTableTitles () {
return this.customTableTitle.filter(item => item.show)
}
},
watch: {
customTableTitle (n) {
if (n) {
setTimeout(() => {
this.$refs.dataTable.doLayout()
}, 100)
}
}
},
data () {
return {
operationWidth: '165' // 操作列宽
operationWidth: '165', // 操作列宽
show: true
}
},
methods: {

View File

@@ -51,8 +51,8 @@ const user = {
localStorage.setItem('cn-sys-logo', res.data.systemLogo)
}
localStorage.setItem('cn-sys-timezone', res.data.timezone)
localStorage.setItem('timezone-offset', dayjs.tz().utcOffset() / 60)
localStorage.setItem('timezone-local-offset', dayjs().utcOffset() / 60)
localStorage.setItem('cn-timezone-offset', dayjs.tz().utcOffset() / 60)
localStorage.setItem('cn-timezone-local-offset', dayjs().utcOffset() / 60)
post('/sys/user/permissions', { token: res.data.token }).then(res => {
const menuList = sortByOrderNum(res.data.menus)
store.commit('setMenuList', menuList)

View File

@@ -246,7 +246,7 @@ export const tableSort = {
export const cancelWithChange = {
mounted (el, binding) {
if (!binding.value || !binding.value.object) return
const unsavedChange = localStorage.getItem('nz-unsaved-change')
const unsavedChange = localStorage.getItem('cn-unsaved-change')
const oldValue = JSON.parse(JSON.stringify(binding.value.object))
function domClick (e) {
const newValue = JSON.parse(JSON.stringify(binding.value.object))

View File

@@ -4,6 +4,7 @@
v-if="isEcharts"
:layout="layout"
:style="computePosition"
:chartInfo="chartInfo"
>
<template #title v-if="layout.indexOf(layoutConstant.HEADER) > -1">{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</template>
<template #operations v-if="layout.indexOf(layoutConstant.HEADER) > -1">
@@ -12,9 +13,12 @@
<template #default>
<div class="chart-drawing" :id="`chart${chartInfo.id}`"></div>
</template>
<template #footer v-if="layout.indexOf(layoutConstant.FOOTER) > -1">
<template #footer v-if="layout.indexOf(layoutConstant.FOOTER) > -1" :class="{}">
<!-- 带Table的饼图展示Table -->
<template v-if="isEchartsWithTable">
<div style="height: 100%">
<PieTable :tableData="pieTableData" ref="pieTable"/>
</div>
</template>
</template>
</echarts-frame>
@@ -80,10 +84,11 @@
<script>
import * as echarts from 'echarts'
import { isEcharts, isSingleValue, isTable, getOption, getTypeCategory, getLayout, layoutConstant, heightUnit, isEchartsWithTable } from '@/components/charts/chart-options'
import { isEcharts, isSingleValue, isTable, getOption, getTypeCategory, getLayout, layoutConstant, heightUnit, isEchartsWithTable, pieTableDatas } from '@/components/charts/chart-options'
import EchartsFrame from '@/components/charts/EchartsFrame'
import SingleValue from '@/components/charts/ChartSingleValue'
import Table from '@/components/charts/ChartTable'
import PieTable from '@/components/charts/PieTable'
import ChartTablePagination from '@/components/charts/ChartTablePagination'
import { chartTableDefaultPageSize, chartTableTopOptions } from '@/utils/constants'
import { get } from '@/utils/http'
@@ -93,13 +98,20 @@ let myChart // echarts实例
export default {
name: 'Chart',
props: {
chart: Object // 图表对象包括id、name、type等数据
chart: Object, // 图表对象包括id、name、type等数据
startTime: {
type: Number
},
endTime: {
type: Number
}
},
components: {
EchartsFrame,
SingleValue,
ChartTablePagination,
'chart-table': Table
'chart-table': Table,
PieTable
},
data () {
return {
@@ -110,16 +122,46 @@ export default {
tableColumns: [], // table字段
tableData: [], // table的所有数据
currentPageData: [] // table当前页的数据
}
},
pieTableData: []
}
},
methods: {
initChart () {
const now = new Date().getTime()
const self = this
const now = this.dayJs.tz().valueOf()
const params = this.chartInfo.params ? JSON.parse(this.chartInfo.params) : null
console.log(params)
if (this.isEcharts) {
myChart = echarts.init(document.getElementById(`chart${this.chartInfo.id}`))
myChart.setOption(this.chartOption)
if (this.isEchartsWithTable) {
if (this.chartOption.series[0].data.length > 10) { // pieWithTable 图例超过10个改为滚动显示
this.chartOption.legend.type = 'scroll'
myChart.setOption(this.chartOption)
}
if (params.url.split('?').length > 1) {
params.url = params.url.split('?')[0]
}
if (params.urlTable.split('?').length > 1) {
params.urlTable = params.urlTable.split('?')[0]
}
/* get(params.url, { startTime: now - 3600000, endTime: now, order: params.order ? params.order : null, limit: params.limit ? params.limit : '20' }).then(response => {
console.log(response)
}) */
// 获取pieTable的 table数据
/* get(params.urlTable, { startTime: this.startTime, endTime: this.endTime, fqdnCategoryName: echartParams.name }).then(response => {
console.log(response)
}) */
self.pieTableData = pieTableDatas
myChart.on('click', function (echartParams) {
console.log(echartParams)
/* get(params.urlTable, { startTime: this.startTime, endTime: this.endTime, fqdnCategoryName: echartParams.name }).then(response => {
console.log(response)
}) */
self.pieTableData = pieTableDatas
})
}
this.$nextTick(() => {
myChart.resize()
})
@@ -169,6 +211,7 @@ export default {
},
mounted () {
this.initChart()
console.log(this.layout)
},
setup (props) {
const chartInfo = JSON.parse(JSON.stringify(props.chart))

View File

@@ -5,7 +5,7 @@
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="endTime"/>
<DateTimeRange class="date-time-range" :start-time="startTime" :end-time="endTime" ref="dateTimeRange" @change="reload"/>
</div>
<chart v-for="(chart, index) in chartList" :key="index" :chart="chart"></chart>
<chart v-for="(chart, index) in chartList" :key="index" :chart="chart" :start-time="startTime" :end-time="endTime"></chart>
<!-- <grid-layout v-model:layout="chartList"
:col-num="12"
:row-height="30"
@@ -52,14 +52,16 @@ export default {
},
async mounted () {
const panels = await getPanelList({ type: this.panelType })
console.log(panels)
if (panels && panels.length > 0) {
this.panel = panels[0]
}
if (this.panel.id) {
this.chartList = (await getChartList({ panelId: this.panel.id })).map(chart => {
this.chartList = (await getChartList({ panelId: this.panel.id })).map(chart => { // 记得改回mao
chart.i = chart.id
return chart
})
console.log(this.chartList)
}
},
setup (props, ctx) {

View File

@@ -3,6 +3,7 @@
<cn-data-list
ref="dataList"
:api="url"
:tableId="tableId"
:layout="['searchInput', 'elementSet']"
v-model:custom-table-title="tools.customTableTitle"
:from="fromRoute.operationLog"

View File

@@ -2,6 +2,7 @@
<div>
<cn-data-list
ref="dataList"
:tableId="tableId"
v-model:custom-table-title="tools.customTableTitle"
:api="url"
:from="fromRoute.roles"

View File

@@ -2,6 +2,7 @@
<div>
<cn-data-list
ref="dataList"
:tableId="tableId"
v-model:custom-table-title="tools.customTableTitle"
:api="url"
:from="fromRoute.user"