feat: panel布局、单值图、line图等

This commit is contained in:
chenjinsong
2021-06-20 13:31:55 +08:00
parent dd94703db0
commit 5a02d866b8
25 changed files with 856 additions and 52 deletions

View File

@@ -22,7 +22,7 @@
"sass-loader": "^8.0.2",
"sass-resources-loader": "^2.2.1",
"vue": "^3.0.0",
"vue-grid-layout": "^2.3.12",
"vue-grid-layout": "^3.0.0-beta1",
"vue-i18n": "^9.1.6",
"vue-router": "^4.0.8",
"vuex": "^4.0.1"

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: "cn-icon"; /* Project id 2614877 */
src: url('iconfont.woff2?t=1624000421294') format('woff2'),
url('iconfont.woff?t=1624000421294') format('woff'),
url('iconfont.ttf?t=1624000421294') format('truetype');
src: url('iconfont.woff2?t=1624011302849') format('woff2'),
url('iconfont.woff?t=1624011302849') format('woff'),
url('iconfont.ttf?t=1624011302849') format('truetype');
}
.cn-icon {
@@ -13,11 +13,11 @@
-moz-osx-font-smoothing: grayscale;
}
.cn-icon-view1:before {
.cn-icon-view:before {
content: "\e702";
}
.cn-icon-more3:before {
.cn-icon-more-arrow-down:before {
content: "\e739";
}
@@ -29,7 +29,7 @@
content: "\e68f";
}
.cn-icon-more1:before {
.cn-icon-more-dark:before {
content: "\e677";
}
@@ -41,11 +41,11 @@
content: "\e738";
}
.cn-icon-xiangshang:before {
.cn-icon-arrow-up:before {
content: "\e732";
}
.cn-icon-xiangxia:before {
.cn-icon-arrow-down:before {
content: "\e737";
}
@@ -105,7 +105,7 @@
content: "\e728";
}
.cn-icon-more:before {
.cn-icon-more-light:before {
content: "\e729";
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -25,7 +25,6 @@
height: 60px;
padding: 0 20px;
border-bottom: 1px solid $--right-box-border-color;
box-sizing: border-box;
.header__title {
font-size: 16px;
@@ -231,7 +230,6 @@
border: none;
border-radius: 4px;
outline: none;
box-sizing: border-box;
font-size: 14px;
cursor: pointer;
transition: background-color linear .2s, color linear .1s;
@@ -302,7 +300,6 @@
height: 100%;
transform: translateY(-50%);
justify-content: space-between;
box-sizing: border-box;
}
.form-item--end-with-btn { // 末尾留出btn宽度空间的form item

View File

@@ -2,7 +2,6 @@
.list-page {
height: 100%;
width: 100%;
box-sizing: border-box;
background-color: #f6f6f6;
.main-list {
@@ -45,7 +44,7 @@
height: 44px;
background-color: white;
border: 1px solid #E6EAED;
box-sizing: border-box;
}
.top-tool-right {
@@ -135,7 +134,7 @@
color: #666666;
font-size: 14px;
text-align: center;
box-sizing: border-box;
line-height: 40px;
&.sub-list-tab--active {
@@ -157,7 +156,7 @@
background-color: #e6eaed;
position: absolute;
z-index: 1;
box-sizing: border-box;
user-select: none;
color: #5f6368;
cursor: ns-resize;
@@ -189,7 +188,7 @@
position: relative;
padding: 0 20px;
width: 100%;
box-sizing: border-box;
flex: auto;
height: calc(100% - 58px);
@@ -231,7 +230,6 @@
height: 49px;
border-bottom: 1px solid $--right-box-border-color;
background-color: white;
box-sizing: content-box;
}
thead {
color: #333;
@@ -358,7 +356,7 @@
left: 270px !important;
margin-top: -3px !important;
box-shadow: none;
box-sizing: border-box;
border-radius: 0;
border-color: #c7c7c7;

View File

@@ -56,9 +56,9 @@ $--color-warning: $--color-primary; //全局警告橙色
$--color-suspended: #9e9c98; //全局停用色灰色
$--color-monitor: #98AEC5; //全局停用色灰色
$global-text-color-active: $--color-primary; // 全局文字active字色
$--chart-single-value-icon-background-color: #E8F6FF;
$content-right-background-color: #f9f9f9; //右侧背景色
$--content-right-background-color: #EFF2F5; //右侧背景色
/** 改变 icon 字体路径变量并引入element-ui变量文件 **/
$--font-path: '~element-plus/lib/theme-chalk/fonts';
@import "~element-plus/packages/theme-chalk/src/index";

View File

@@ -0,0 +1,49 @@
<template>
<div class="cn-chart cn-chart__single-value" :class="singleValueClass(type)">
<div class="single-value__icon"><i class="el-icon-apple"></i></div>
<div class="single-value__content" v-if="type === 51">
<div class="content__data">11112</div>
<div class="content__title">嘻嘻</div>
</div>
<div class="single-value__content" v-if="type === 53">
<div class="content__title">嘻嘻</div>
<div class="content__data">11112</div>
</div>
</div>
</template>
<script>
export default {
name: 'ChartSingleValue',
props: {
type: Number
},
computed: {
singleValueClass () {
return function (type) {
let c
switch (type) {
case 51: {
c = 'cn-chart__single-value--icon-left'
break
}
case 52: {
c = 'cn-chart__single-value--chart'
break
}
case 53: {
c = 'cn-chart__single-value--icon-right'
break
}
default: break
}
return c
}
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,48 @@
<template>
<div class="cn-chart cn-chart__table">
<div class="cn-chart__header">
<div class="header__title">
<slot name="title"></slot>
</div>
<div class="header__operations">
<slot name="operations"></slot>
</div>
</div>
<div class="cn-chart__body">
<el-table
:data="tableData"
style="width: 100%"
>
<el-table-column
type="index"
label="#"
>
</el-table-column>
<el-table-column
v-for="(c, i) in tableColumns"
:key="i"
:prop="c"
>
<template #header>{{c}}</template>
<template #default="{ row }">{{row[c]}}</template>
</el-table-column>
</el-table>
</div>
<div class="cn-chart__footer">
</div>
</div>
</template>
<script>
export default {
name: 'ChartTable',
props: {
tableColumns: Array,
tableData: Array
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,40 @@
<template>
<div class="cn-chart cn-chart__echarts">
<div class="cn-chart__header" v-if="layout.indexOf(layoutConstant.HEADER) > -1">
<div class="header__title">
<slot name="title"></slot>
</div>
<div class="header__operations">
<slot name="operations"></slot>
</div>
</div>
<div class="cn-chart__body">
<slot></slot>
</div>
<div class="cn-chart__footer" v-if="layout.indexOf(layoutConstant.FOOTER) > -1">
<slot name="footer"></slot>
</div>
</div>
</template>
<script>
import { layoutConstant } from '@/components/charts/chart-options'
export default {
name: 'EchartsFrame',
props: {
layout: Array
},
setup () {
return {
layoutConstant
}
},
mounted () {
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,186 @@
/**
* @author 陈劲松
* @date 2021/6/16
* @description chart option和一些工具
*/
import { calculateTextWidth } from '@/utils/tools'
const timeData = [["1988/10/4",89],["1988/10/5",95],["1988/10/6",94],["1988/10/7",86],["1988/10/8",95],["1988/10/9",93],["1988/10/10",88],["1988/10/11",80],["1988/10/12",89],["1988/10/13",83],["1988/10/14",85],["1988/10/15",83],["1988/10/16",73],["1988/10/17",79],["1988/10/18",82],["1988/10/19",77],["1988/10/20",80],["1988/10/21",75],["1988/10/22",79],["1988/10/23",75],["1988/10/24",83],["1988/10/25",85],["1988/10/26",77],["1988/10/27",74],["1988/10/28",70],["1988/10/29",80],["1988/10/30",71],["1988/10/31",73],["1988/11/1",77],["1988/11/2",78],["1988/11/3",81],["1988/11/4",89],["1988/11/5",79],["1988/11/6",76],["1988/11/7",80],["1988/11/8",77],["1988/11/9",72],["1988/11/10",68],["1988/11/11",58],["1988/11/12",54],["1988/11/13",50],["1988/11/14",41],["1988/11/15",36],["1988/11/16",43],["1988/11/17",45],["1988/11/18",54],["1988/11/19",49],["1988/11/20",45],["1988/11/21",42],["1988/11/22",41],["1988/11/23",33],["1988/11/24",23],["1988/11/25",19],["1988/11/26",18],["1988/11/27",13],["1988/11/28",4],["1988/11/29",4],["1988/11/30",-4],["1988/12/1",-4],["1988/12/2",0],["1988/12/3",4],["1988/12/4",-2],["1988/12/5",-11],["1988/12/6",-2],["1988/12/7",-1],["1988/12/8",3],["1988/12/9",6],["1988/12/10",10],["1988/12/11",10],["1988/12/12",14],["1988/12/13",10],["1988/12/14",7],["1988/12/15",1],["1988/12/16",0],["1988/12/17",1],["1988/12/18",2],["1988/12/19",-6],["1988/12/20",3],["1988/12/21",9],["1988/12/22",3],["1988/12/23",4],["1988/12/24",12],["1988/12/25",8],["1988/12/26",0],["1988/12/27",-8],["1988/12/28",-10],["1988/12/29",-13],["1988/12/30",-10],["1988/12/31",-13],["1989/1/1",-3],["1989/1/2",5],["1989/1/3",-5],["1989/1/4",-9],["1989/1/5",1],["1989/1/6",5],["1989/1/7",-1],["1989/1/8",4],["1989/1/9",9],["1989/1/10",-1],["1989/1/11",6],["1989/1/12",1],["1989/1/13",11],["1989/1/14",11],["1989/1/15",7],["1989/1/16",1],["1989/1/17",0],["1989/1/18",-5],["1989/1/19",-9],["1989/1/20",-8],["1989/1/21",-12],["1989/1/22",-6],["1989/1/23",-6],["1989/1/24",-9],["1989/1/25",-13],["1989/1/26",-23],["1989/1/27",-25],["1989/1/28",-21],["1989/1/29",-21],["1989/1/30",-22],["1989/1/31",-31],["1989/2/1",-23],["1989/2/2",-17],["1989/2/3",-19],["1989/2/4",-26],["1989/2/5",-28],["1989/2/6",-24],["1989/2/7",-26],["1989/2/8",-33],["1989/2/9",-30],["1989/2/10",-39],["1989/2/11",-37],["1989/2/12",-36],["1989/2/13",-32],["1989/2/14",-39],["1989/2/15",-30],["1989/2/16",-28],["1989/2/17",-19],["1989/2/18",-19],["1989/2/19",-20],["1989/2/20",-17],["1989/2/21",-26],["1989/2/22",-26],["1989/2/23",-32],["1989/2/24",-35],["1989/2/25",-44],["1989/2/26",-44],["1989/2/27",-48],["1989/2/28",-46],["1989/3/1",-53],["1989/3/2",-57],["1989/3/3",-50],["1989/3/4",-44],["1989/3/5",-43],["1989/3/6",-48],["1989/3/7",-58],["1989/3/8",-67],["1989/3/9",-58],["1989/3/10",-53],["1989/3/11",-52],["1989/3/12",-59],["1989/3/13",-67],["1989/3/14",-59],["1989/3/15",-51],["1989/3/16",-49],["1989/3/17",-40],["1989/3/18",-39],["1989/3/19",-48],["1989/3/20",-48],["1989/3/21",-52],["1989/3/22",-47],["1989/3/23",-53],["1989/3/24",-46],["1989/3/25",-53],["1989/3/26",-57],["1989/3/27",-67],["1989/3/28",-65],["1989/3/29",-68],["1989/3/30",-62],["1989/3/31",-53],["1989/4/1",-46],["1989/4/2",-42],["1989/4/3",-40],["1989/4/4",-45],["1989/4/5",-42],["1989/4/6",-47],["1989/4/7",-46],["1989/4/8",-55],["1989/4/9",-60],["1989/4/10",-55],["1989/4/11",-45],["1989/4/12",-50],["1989/4/13",-40],["1989/4/14",-48],["1989/4/15",-53],["1989/4/16",-51],["1989/4/17",-46],["1989/4/18",-43],["1989/4/19",-38],["1989/4/20",-44]]
const timeData2 = [["1988/10/4",69],["1988/10/5",65],["1988/10/6",64],["1988/10/7",66],["1988/10/8",65],["1988/10/9",63],["1988/10/10",68],["1988/10/11",60],["1988/10/12",69],["1988/10/13",63],["1988/10/14",65],["1988/10/15",63],["1988/10/16",73],["1988/10/17",79],["1988/10/18",62],["1988/10/19",77],["1988/10/20",60],["1988/10/21",75],["1988/10/22",79],["1988/10/23",75],["1988/10/24",63],["1988/10/25",65],["1988/10/26",77],["1988/10/27",74],["1988/10/28",70],["1988/10/29",60],["1988/10/30",71],["1988/10/31",73],["1988/11/1",77],["1988/11/2",78],["1988/11/3",61],["1988/11/4",69],["1988/11/5",79],["1988/11/6",76],["1988/11/7",60],["1988/11/8",77],["1988/11/9",72],["1988/11/10",68],["1988/11/11",58],["1988/11/12",54],["1988/11/13",50],["1988/11/14",41],["1988/11/15",36],["1988/11/16",43],["1988/11/17",45],["1988/11/18",54],["1988/11/19",49],["1988/11/20",45],["1988/11/21",42],["1988/11/22",41],["1988/11/23",33],["1988/11/24",23],["1988/11/25",19],["1988/11/26",18],["1988/11/27",13],["1988/11/28",4],["1988/11/29",4],["1988/11/30",-4],["1988/12/1",-4],["1988/12/2",0],["1988/12/3",4],["1988/12/4",-2],["1988/12/5",-11],["1988/12/6",-2],["1988/12/7",-1],["1988/12/8",3],["1988/12/9",6],["1988/12/10",10],["1988/12/11",10],["1988/12/12",14],["1988/12/13",10],["1988/12/14",7],["1988/12/15",1],["1988/12/16",0],["1988/12/17",1],["1988/12/18",2],["1988/12/19",-6],["1988/12/20",3],["1988/12/21",9],["1988/12/22",3],["1988/12/23",4],["1988/12/24",12],["1988/12/25",6],["1988/12/26",0],["1988/12/27",-8],["1988/12/28",-10],["1988/12/29",-13],["1988/12/30",-10],["1988/12/31",-13],["1989/1/1",-3],["1989/1/2",5],["1989/1/3",-5],["1989/1/4",-9],["1989/1/5",1],["1989/1/6",5],["1989/1/7",-1],["1989/1/8",4],["1989/1/9",9],["1989/1/10",-1],["1989/1/11",6],["1989/1/12",1],["1989/1/13",11],["1989/1/14",11],["1989/1/15",7],["1989/1/16",1],["1989/1/17",0],["1989/1/18",-5],["1989/1/19",-9],["1989/1/20",-8],["1989/1/21",-12],["1989/1/22",-6],["1989/1/23",-6],["1989/1/24",-9],["1989/1/25",-13],["1989/1/26",-23],["1989/1/27",-25],["1989/1/28",-21],["1989/1/29",-21],["1989/1/30",-22],["1989/1/31",-31],["1989/2/1",-23],["1989/2/2",-17],["1989/2/3",-19],["1989/2/4",-26],["1989/2/5",-28],["1989/2/6",-24],["1989/2/7",-26],["1989/2/8",-33],["1989/2/9",-30],["1989/2/10",-39],["1989/2/11",-37],["1989/2/12",-36],["1989/2/13",-32],["1989/2/14",-39],["1989/2/15",-30],["1989/2/16",-28],["1989/2/17",-19],["1989/2/18",-19],["1989/2/19",-20],["1989/2/20",-17],["1989/2/21",-26],["1989/2/22",-26],["1989/2/23",-32],["1989/2/24",-35],["1989/2/25",-44],["1989/2/26",-44],["1989/2/27",-48],["1989/2/28",-46],["1989/3/1",-53],["1989/3/2",-57],["1989/3/3",-50],["1989/3/4",-44],["1989/3/5",-43],["1989/3/6",-48],["1989/3/7",-58],["1989/3/8",-67],["1989/3/9",-58],["1989/3/10",-53],["1989/3/11",-52],["1989/3/12",-59],["1989/3/13",-67],["1989/3/14",-59],["1989/3/15",-51],["1989/3/16",-49],["1989/3/17",-40],["1989/3/18",-39],["1989/3/19",-48],["1989/3/20",-48],["1989/3/21",-52],["1989/3/22",-47],["1989/3/23",-53],["1989/3/24",-46],["1989/3/25",-53],["1989/3/26",-57],["1989/3/27",-67],["1989/3/28",-65],["1989/3/29",-68],["1989/3/30",-62],["1989/3/31",-53],["1989/4/1",-46],["1989/4/2",-42],["1989/4/3",-40],["1989/4/4",-45],["1989/4/5",-42],["1989/4/6",-47],["1989/4/7",-46],["1989/4/8",-55],["1989/4/9",-60],["1989/4/10",-55],["1989/4/11",-45],["1989/4/12",-50],["1989/4/13",-40],["1989/4/14",-48],["1989/4/15",-53],["1989/4/16",-51],["1989/4/17",-46],["1989/4/18",-43],["1989/4/19",-38],["1989/4/20",-44]]
const timeData3 = [["1988/10/4",49],["1988/10/5",45],["1988/10/6",44],["1988/10/7",46],["1988/10/8",45],["1988/10/9",43],["1988/10/10",48],["1988/10/11",40],["1988/10/12",49],["1988/10/13",43],["1988/10/14",45],["1988/10/15",43],["1988/10/16",73],["1988/10/17",79],["1988/10/18",42],["1988/10/19",77],["1988/10/20",40],["1988/10/21",75],["1988/10/22",79],["1988/10/23",75],["1988/10/24",63],["1988/10/25",65],["1988/10/26",77],["1988/10/27",74],["1988/10/28",70],["1988/10/29",60],["1988/10/30",71],["1988/10/31",73],["1988/11/1",77],["1988/11/2",78],["1988/11/3",61],["1988/11/4",69],["1988/11/5",79],["1988/11/6",76],["1988/11/7",60],["1988/11/8",77],["1988/11/9",72],["1988/11/10",68],["1988/11/11",58],["1988/11/12",54],["1988/11/13",50],["1988/11/14",41],["1988/11/15",36],["1988/11/16",43],["1988/11/17",45],["1988/11/18",54],["1988/11/19",49],["1988/11/20",45],["1988/11/21",42],["1988/11/22",41],["1988/11/23",33],["1988/11/24",23],["1988/11/25",19],["1988/11/26",18],["1988/11/27",13],["1988/11/28",4],["1988/11/29",4],["1988/11/30",-4],["1988/12/1",-4],["1988/12/2",0],["1988/12/3",4],["1988/12/4",-2],["1988/12/5",-11],["1988/12/6",-2],["1988/12/7",-1],["1988/12/8",3],["1988/12/9",6],["1988/12/10",10],["1988/12/11",10],["1988/12/12",14],["1988/12/13",10],["1988/12/14",7],["1988/12/15",1],["1988/12/16",0],["1988/12/17",1],["1988/12/18",2],["1988/12/19",-6],["1988/12/20",3],["1988/12/21",9],["1988/12/22",3],["1988/12/23",4],["1988/12/24",12],["1988/12/25",6],["1988/12/26",0],["1988/12/27",-8],["1988/12/28",-10],["1988/12/29",-13],["1988/12/30",-10],["1988/12/31",-13],["1989/1/1",-3],["1989/1/2",5],["1989/1/3",-5],["1989/1/4",-9],["1989/1/5",1],["1989/1/6",5],["1989/1/7",-1],["1989/1/8",4],["1989/1/9",9],["1989/1/10",-1],["1989/1/11",6],["1989/1/12",1],["1989/1/13",11],["1989/1/14",11],["1989/1/15",7],["1989/1/16",1],["1989/1/17",0],["1989/1/18",-5],["1989/1/19",-9],["1989/1/20",-8],["1989/1/21",-12],["1989/1/22",-6],["1989/1/23",-6],["1989/1/24",-9],["1989/1/25",-13],["1989/1/26",-23],["1989/1/27",-25],["1989/1/28",-21],["1989/1/29",-21],["1989/1/30",-22],["1989/1/31",-31],["1989/2/1",-23],["1989/2/2",-17],["1989/2/3",-19],["1989/2/4",-26],["1989/2/5",-28],["1989/2/6",-24],["1989/2/7",-26],["1989/2/8",-33],["1989/2/9",-30],["1989/2/10",-39],["1989/2/11",-37],["1989/2/12",-36],["1989/2/13",-32],["1989/2/14",-39],["1989/2/15",-30],["1989/2/16",-28],["1989/2/17",-19],["1989/2/18",-19],["1989/2/19",-20],["1989/2/20",-17],["1989/2/21",-26],["1989/2/22",-26],["1989/2/23",-32],["1989/2/24",-35],["1989/2/25",-44],["1989/2/26",-44],["1989/2/27",-48],["1989/2/28",-46],["1989/3/1",-53],["1989/3/2",-57],["1989/3/3",-50],["1989/3/4",-44],["1989/3/5",-43],["1989/3/6",-48],["1989/3/7",-58],["1989/3/8",-67],["1989/3/9",-58],["1989/3/10",-53],["1989/3/11",-52],["1989/3/12",-59],["1989/3/13",-67],["1989/3/14",-59],["1989/3/15",-51],["1989/3/16",-49],["1989/3/17",-40],["1989/3/18",-39],["1989/3/19",-48],["1989/3/20",-48],["1989/3/21",-52],["1989/3/22",-47],["1989/3/23",-53],["1989/3/24",-46],["1989/3/25",-53],["1989/3/26",-57],["1989/3/27",-67],["1989/3/28",-65],["1989/3/29",-68],["1989/3/30",-62],["1989/3/31",-53],["1989/4/1",-46],["1989/4/2",-42],["1989/4/3",-40],["1989/4/4",-45],["1989/4/5",-42],["1989/4/6",-47],["1989/4/7",-46],["1989/4/8",-55],["1989/4/9",-60],["1989/4/10",-55],["1989/4/11",-45],["1989/4/12",-50],["1989/4/13",-40],["1989/4/14",-48],["1989/4/15",-53],["1989/4/16",-51],["1989/4/17",-46],["1989/4/18",-43],["1989/4/19",-38],["1989/4/20",-44]]
const line = {
xAxis: {
type: 'time'
},
yAxis: {
type: 'value'
},
grid: {
left: 55,
bottom: 45,
top: 30
},
legend: {
show: true,
right: 30,
top: 'top',
orient: 'horizontal',
icon: 'circle',
itemGap: 20,
itemWidth: 10,
textStyle: {
padding: [0, 0, 0, 5],
fontSize: 14
}
},
axisLabel: {
fontSize: 14
},
series: [
{
name: 'a',
type: 'line',
smooth: true,
symbol: 'none',
data: timeData
},
{
name: 'b',
type: 'line',
smooth: true,
symbol: 'none',
data: timeData2
}
]
}
const lineStack = {
xAxis: {
type: 'time'
},
yAxis: {
type: 'value'
},
grid: {
left: 55,
bottom: 45,
top: 10,
right: 180
},
legend: {
show: true,
right: 30,
top: 'middle',
orient: 'vertical',
icon: 'circle',
itemGap: 20,
itemWidth: 10,
formatter: function (name) {
const width = calculateTextWidth(name)
if (width <= 110) {
return name
} else {
const index = name.length / (width / 110.0) - 3
return name.substring(0, index) + '...'
}
},
textStyle: {
padding: [0, 0, 0, 5],
fontSize: 14
}
},
axisLabel: {
fontSize: 14
},
series: [
{
name: 'a',
type: 'line',
stack: 'value',
areaStyle: {},
symbol: 'none',
data: timeData
},
{
name: 'bbbbbbbbbbbbbbb aerapo',
type: 'line',
stack: 'value',
areaStyle: {},
symbol: 'none',
data: timeData2
},
{
name: 'c',
type: 'line',
stack: 'value',
areaStyle: {},
symbol: 'none',
data: timeData3
}
]
}
const typeOptionMappings = [
{ value: 11, option: line }, // 常规折线图
{ value: 13, option: lineStack }, // 常规折线图
{ value: 91, option: line }, // tab容器
{ value: 92, option: line }, // tab页
{ value: 93, option: line } // 大标题
]
const typeCategory = {
TABLE: 'table',
ECHARTS: 'echarts',
TITLE: 'title',
SINGLE: 'singleValue'
}
export function getTypeCategory (type) {
if (isEcharts(type)) {
return typeCategory.ECHARTS
} else if (isTable(type)) {
return typeCategory.TABLE
} else if (isSingleValue(type)) {
return typeCategory.SINGLE
} else if (isTitle(type)) {
return typeCategory.TITLE
}
}
/* 饼图柱状图等 */
export function isEcharts (type) {
return type <= 50
}
/* 带统计的折线图 */
export function isEchartsWithStatistics (type) {
return type === 12
}
/* 单值 */
export function isSingleValue (type) {
return type >= 51 && type <= 60
}
/* 带折线图的单值 */
export function isSingleValueWithEcharts (type) {
return type === 52
}
/* table */
export function isTable (type) {
return type >= 61 && type <= 70
}
/* title、tab等 */
export function isTitle (type) {
return type >= 91
}
export function getOption (type) {
const mapping = typeOptionMappings.find(m => m.value === type)
return mapping && mapping.option ? mapping.option : null
}
export const layoutConstant = {
HEADER: 'header',
FOOTER: 'footer'
}
export function getLayout (type) {
const layout = []
if (!isSingleValue(type) && !isTitle(type)) {
layout.push(layoutConstant.HEADER)
}
if (type === 12 || type === 31) {
layout.push(layoutConstant.FOOTER)
}
return layout
}
export const heightUnit = 150

View File

@@ -0,0 +1,207 @@
.cn-panel {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: repeat(auto-fill, 50px);
grid-gap: 10px;
padding: 20px;
height: 100%;
width: 100%;
.cn-chart {
background-color: #FFFFFF;
border: 1px solid #E7EAED;
box-shadow: 0 2px 4px 0 rgba(51,51,51,0.02);
border-radius: 2px;
height: 100%;
width: 100%;
}
.cn-chart__echarts, .cn-chart__table {
display: flex;
flex-direction: column;
.cn-chart__header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px 10px 18px;
height: 50px;
font-size: 16px;
color: #333333;
font-weight: bold;
.header__operations {
.cn-icon-more-light {
color: #999;
}
}
}
.cn-chart__body {
flex: auto;
.chart-drawing {
height: 100%;
width: 100%;
}
}
}
.cn-chart__single-value.cn-chart__single-value--icon-left {
display: flex;
justify-content: center;
align-items: center;
.single-value__icon {
position: relative;
margin-right: 7.5%;
width: 72px;
height: 72px;
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
font-size: 28px;
color: $--color-primary;
}
}
.single-value__content {
display: flex;
flex-direction: column;
.content__data {
padding-bottom: 7%;
font-size: 24px;
color: #333333;
font-weight: bold;
}
.content__title {
font-size: 16px;
color: #666666;
}
}
}
.cn-chart__single-value.cn-chart__single-value--icon-right {
display: flex;
flex-direction: row-reverse;
justify-content: space-around;
align-items: center;
.single-value__icon {
background-color: $--chart-single-value-icon-background-color;
border-radius: 50%;
position: relative;
margin-right: 7.5%;
margin-bottom: 6%;
width: 56px;
height: 56px;
i {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
font-size: 24px;
color: $--color-primary;
}
}
.single-value__content {
display: flex;
height: 100%;
flex-direction: column;
.content__title {
display: flex;
align-items: center;
height: 50%;
font-size: 16px;
color: #666666;
}
.content__data {
display: flex;
padding-top: 5%;
height: 50%;
flex: auto;
font-size: 24px;
color: #333333;
font-weight: bold;
}
}
}
.cn-chart__table {
.cn-chart__header {
border-bottom: 1px solid $--content-right-background-color;
.header__operations {
display: grid;
justify-content: end;
align-items: center;
grid-template-rows: 30px;
grid-template-columns: repeat(5, auto);
grid-column-gap: 10px;
.header__operation.header__operation--table {
display: flex;
align-items: center;
height: 22px;
color: $--color-primary;
border: 1px solid $--color-primary;
border-radius: $--border-radius-primary;
.option__button {
display: flex;
align-items: center;
height: 100%;
padding: 0 5px;
cursor: pointer;
background-color: white;
transition: all linear .2s;
}
.option__button:hover {
background-color: #EFF2F5;
}
.option__button.icon-group-item:first-of-type:not(:last-of-type) {
padding: 0 5px 0 0;
}
.option__button.icon-group-item:last-of-type:not(:first-of-type) {
padding: 0 0 0 5px;
}
.icon-group-divide {
height: 14px;
width: 1px;
background-color: $--color-primary;
}
i {
font-size: 12px;
}
}
}
}
.cn-chart__body {
flex: auto;
overflow-y: auto;
.el-table {
padding: 0 10px;
&:before {
height: 0;
}
thead {
color: #333;
}
th.is-leaf, td {
border-bottom: none;
}
th {
padding-bottom: 5px;
}
td {
padding: 7px 0;
color: #333;
}
}
}
}
}

View File

@@ -26,12 +26,9 @@
min-width: 20px;
height: 20px;
line-height: 20px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
text-align: center;
border: 1px solid rgba(154,154,154,0.20);
border-radius: 2px;
border-radius: 2px;
}
:deep(.el-pagination .el-pager li.btn-quicknext), :deep( .el-pager li.btn-quickprev) {
line-height: 20px;
@@ -40,20 +37,20 @@
line-height: 20px;
}
:deep( .el-pagination .el-pager .more) {
background-color: $content-right-background-color;
background-color: $--content-right-background-color;
}
.btn-next, .btn-prev {
background-color: $content-right-background-color !important;
background-color: $--content-right-background-color !important;
}
.pagination input {
background-color: $content-right-background-color !important;
background-color: $--content-right-background-color !important;
}
:deep(.el-pager li.number){
font-family: NotoSansSC-Regular;
color: #666666;
letter-spacing: 0;
font-weight:normal;
background-color: $content-right-background-color;
background-color: $--content-right-background-color;
}
:deep( .el-pager li.number.active){
font-family: NotoSansSC-Regular;
@@ -62,7 +59,7 @@
}
:deep( .el-pagination .el-pager li.active) {
background-color: $global-text-color-active;
background-color: $--color-primary;
border-radius: 2px;
border-radius: 2px;
}

View File

@@ -1,6 +1,9 @@
<template>
<div class="cn-container">
<router-view :key="routerKey"/>
<!-- 临时文本dom用来计算文本长度 -->
<span class="temp-dom temp-dom--12"></span>
<span class="temp-dom temp-dom--14"></span>
</div>
</template>
@@ -22,10 +25,22 @@ export default {
<style lang="scss">
.cn-container {
height: calc(100% - 50px);
background-color: #f6f6f6;
background-color: $--content-right-background-color;
width: 100%;
&>div {
height: 100%;
}
.temp-dom {
visibility: hidden;
font-size: 14px;
position: fixed;
}
.temp-dom--12 {
font-size: 12px;
}
.temp-dom--14 {
font-size: 14px;
}
}
</style>

View File

@@ -1,10 +1,10 @@
<template>
<div class="cn-home">
<left-menu @refresh="refresh"></left-menu>
<div ref="body" class="cn-body">
<main ref="body" class="cn-body">
<cn-header></cn-header>
<cn-container v-if="containerShow" ref="container"></cn-container>
</div>
</main>
</div>
</template>

View File

@@ -205,12 +205,10 @@ export default {
padding: 13px 0 0 18px !important;
height: 50px;
border-right: 1px solid #202F3F;
box-sizing: border-box;
background-color: #182534 !important;
.logo {
display: flex;
box-sizing: border-box;
img {
box-shadow: 0 0 2px 0 rgba(0,0,0,0.50);

View File

@@ -59,7 +59,7 @@
<button class="table-operation-item" @click="tableOperation(['edit', scope.row])"><i class="cn-icon cn-icon-view1"></i></button>
<el-dropdown size="medium" trigger="hover" @command="tableOperation">
<div class="table-operation-item table-operation-item--more">
<i class="cn-icon cn-icon-more3"></i>
<i class="cn-icon cn-icon-more-arrow-down"></i>
</div>
<template #dropdown>
<el-dropdown-menu >

View File

@@ -63,10 +63,10 @@
</template>
<template #default="scope">
<div class="table-operation-items">
<button class="table-operation-item" @click="tableOperation(['edit', scope.row])"><i class="cn-icon cn-icon-view1"></i></button>
<button class="table-operation-item" @click="tableOperation(['edit', scope.row])"><i class="cn-icon cn-icon-view"></i></button>
<el-dropdown size="medium" trigger="hover" @command="tableOperation">
<div class="table-operation-item table-operation-item--more">
<i class="cn-icon cn-icon-more3"></i>
<i class="cn-icon cn-icon-more-arrow-down"></i>
</div>
<template #dropdown>
<el-dropdown-menu >

View File

@@ -8,7 +8,7 @@ import commonMixin from '@/mixins/common'
import { cancelWithChange, clickOutside } from '@/utils/tools'
import i18n from '@/i18n'
import '@/assets/css/main.scss' // 样式入口
// import VueGridLayout from 'vue-grid-layout'
import ElementPlus from 'element-plus'
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc' // dependent on utc plugin
@@ -27,6 +27,7 @@ app.use(router)
app.use(store)
app.use(ElementPlus)
app.use(i18n)
// app.use(VueGridLayout)
app.use(_)
app.directive('has', hasPermission) // 注册指令

View File

@@ -9,15 +9,22 @@ export const api = {
panel: '/visual/panel',
chart: '/visual/chart'
}
/* panel */
export async function getPanelList (params) {
return await getData(api.panel, params, true)
}
export async function getPanel (url, params) {
return await getData(api.panel, params)
export async function getPanel (id) {
return await getData(`${api.chart}/${id}`)
}
/* chart */
export async function getChartList (params) {
return await getData(api.chart, params, true)
}
export async function getChart (id) {
return await getData(`${api.chart}/${id}`)
}
export async function getData (url, params, isQueryList) {
export async function getData (url, params = {}, isQueryList) {
const request = new Promise((resolve, reject) => {
get(url, params).then(response => {
if (response.code === 200) {

View File

@@ -369,3 +369,10 @@ export function isEqual (o1, o2) {
}
return isEqualForInner(o1, o2)
}
/* 计算文本的实际width而不是length */
export function calculateTextWidth (text, fontSize = 14) {
const html = document.querySelector(`.temp-dom--${fontSize}`)
html.innerText = text
return html.offsetWidth
}

220
src/views/charts/Chart.vue Normal file
View File

@@ -0,0 +1,220 @@
<template>
<echarts-frame
v-if="isEcharts"
:layout="layout"
:style="computePosition"
>
<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">
<i class="cn-icon cn-icon-more-light"></i>
</template>
<template #default>
<div class="chart-drawing" :id="`chart${chartInfo.id}`"></div>
</template>
<template #footer v-if="layout.indexOf(layoutConstant.FOOTER) > -1"></template>
</echarts-frame>
<single-value
v-else-if="isSingleValue"
:type="chartInfo.type"
:style="computePosition"
>
</single-value>
<chart-table
v-else-if="isTable"
:table-columns="tableColumns"
:table-data="tableData"
:style="computePosition"
>
<template #title>{{chartInfo.i18n ? $t(chartInfo.i18n) : chartInfo.name}}</template>
<template #operations>
<div class="header__operation header__operation--table">
<span class="option__button"><i class="cn-icon cn-icon-download"></i></span>
</div>
<div class="header__operation header__operation--table"><i class="cn-icon cn-icon-download"></i></div>
<div class="header__operation header__operation--table"><i class="cn-icon cn-icon-download"></i></div>
<div class="header__operation header__operation--table">
<span class="option__button"><i class="cn-icon cn-icon-style"></i></span>
<div class="icon-group-divide"></div>
<span class="option__button"><i class="cn-icon cn-icon-dropdown"></i></span>
</div>
<div class="header__operation header__operation--table">
<span class="option__button"><i class="cn-icon cn-icon-full-screen"></i></span>
</div>
</template>
</chart-table>
</template>
<script>
import * as echarts from 'echarts'
import { isEcharts, isSingleValue, isTable, getOption, getTypeCategory, getLayout, layoutConstant, heightUnit } from '@/components/charts/chart-options'
import EchartsFrame from '@/components/charts/EchartsFrame'
import SingleValue from '@/components/charts/ChartSingleValue'
import Table from '@/components/charts/ChartTable'
import { get } from '@/utils/http'
let myChart // echarts实例
export default {
name: 'Chart',
props: {
chart: Object // 图表对象包括id、name、type等数据
},
components: {
EchartsFrame,
SingleValue,
'chart-table': Table
},
data () {
return {
tableColumns: [],
tableData: []
}
},
methods: {
initChart () {
const now = new Date().getTime()
const params = this.chartInfo.params ? JSON.parse(this.chartInfo.params) : null
if (this.isEcharts) {
myChart = echarts.init(document.getElementById(`chart${this.chartInfo.id}`))
myChart.setOption(this.chartOption)
this.$nextTick(() => {
myChart.resize()
})
} else if (this.isTable) {
if (params) {
const tableColumns = new Set()
tableResponse.data.forEach(d => {
Object.keys(d).forEach(k => {
tableColumns.add(k)
})
})
this.tableColumns = Array.from(tableColumns)
this.tableData = tableResponse.data
/* get(params.url, { startTime: now - 3600000, endTime: now, order: params.order ? params.order : null, limit: params.limit ? params.limit : null }).then(response => {
if (response.code === 200) {
const tableColumns = new Set()
response.data.forEach(d => {
Object.keys(d).forEach(k => {
tableColumns.add(k)
})
})
this.tableColumns = tableColumns
this.tableData = response.data
console.info(this.tableColumns, this.tableData)
}
}) */
}
}
}
},
computed: {
computePosition () {
const gridColumn = `${this.chartInfo.x} / ${this.chartInfo.x + this.chartInfo.w}`
const gridRow = `${this.chartInfo.y} / ${this.chartInfo.y + this.chartInfo.h}`
return {
gridColumn,
gridRow
}
}
},
mounted () {
this.initChart()
},
setup (props) {
const chartInfo = JSON.parse(JSON.stringify(props.chart))
chartInfo.category = getTypeCategory(props.chart.type)
return {
chartInfo,
layoutConstant,
chartOption: getOption(props.chart.type),
isEcharts: isEcharts(props.chart.type),
isSingleValue: isSingleValue(props.chart.type),
isTable: isTable(props.chart.type),
layout: getLayout(props.chart.type)
}
}
}
const tableResponse = JSON.parse(`{
"status": 200,
"success": true,
"message": "OK",
"statistics": {
"elapsed": 2111,
"rows_read": 1750155,
"result_size": 872,
"result_rows": 10
},
"data": [{
"ip": "192.168.32.107",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.108",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.109",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.110",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.111",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.112",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.113",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.114",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.115",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.116",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.117",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.118",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
},{
"ip": "192.168.32.119",
"sessions": "229112",
"packets": "245823",
"bytes": "17974141"
}
]
}`)
</script>
<style>
</style>

View File

@@ -1,38 +1,73 @@
<template>
<div>{{panel}}</div>
<div class="cn-panel">
<chart v-for="(chart, index) in chartList" :key="index" :chart="chart"></chart>
<!-- <grid-layout v-model:layout="chartList"
:col-num="12"
:row-height="30"
:is-draggable="draggable"
:is-resizable="resizable"
:vertical-compact="compact"
:use-css-transforms="true"
>
<grid-item v-for="item in chartList" :key="item.i"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
>
<span class="text">{{ item.i }}</span>
</grid-item>
</grid-layout>-->
</div>
</template>
<script>
import { useRoute } from 'vue-router'
import { ref } from 'vue'
import { panelTypeAndRouteMapping } from '@/utils/constants'
import { api, getPanelList } from '@/utils/api'
import { api, getPanelList, getChartList } from '@/utils/api'
import Chart from './Chart'
export default {
name: 'Panel',
components: {
Chart
},
data () {
return {
panel: {}
}
},
methods: {
},
async mounted () {
const panels = await getPanelList({ type: this.panelType })
if (panels && panels.length > 0) {
this.panel = panels[0]
}
if (this.panel.id) {
this.chartList = (await getChartList({ panelId: this.panel.id })).map(chart => {
chart.i = chart.id
return chart
})
}
},
setup () {
// 取得panel的type
let panelType = 1
const chartList = ref([])
const panel = ref({})
let panelType = 1 // 取得panel的type
const { params } = useRoute()
panelTypeAndRouteMapping[params.typeName] && (panelType = panelTypeAndRouteMapping[params.typeName])
return {
panelType,
chartList,
panel,
api
}
}
}
</script>
<style>
<style lang="scss">
@import '~@/components/charts/panel.scss';
</style>