说明
该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。
该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。
说明:OverallAuth2.0 是一个简单、易懂、功能强大的权限+可视化流程管理系统。
友情提醒:本篇文章是属于系列文章,看该文章前,建议先看之前文章,可以更好理解项目结构。
qq群:801913255,进群有什么不懂的尽管问,群主都会耐心解答。
有兴趣的朋友,请关注我吧(*^▽^*)。
关注我,学不会你来打我
实现功能
1、系统登录后的可视化面板页面
原本不想写这篇文章,因为它和我们的系统权限、框架没有实质性的关系,但耐不住群友的软磨硬泡,便答应了下来。
我起初的设想,这块功能直接上传到码云上,群友可以根据自己搭建的系统,酌情修改。
安装echarts
npm install echarts --save
搭建面板页面
在panel文件夹,打开index页面,编写布局代码
<template>
<div style="display: flex; height: 1080px">
<div style="width: 80%">
<div
style="height: 25%; display: flex; margin-bottom: 5px"
class="boxStyle"
>
<div style="width: 50%" class="boxStyle">
</div>
<div
style="width: 50%; margin-left: 5px;"
class="boxStyle"
>
2
</div>
</div>
<div style="height: 45% ;margin-bottom: 5px" class="boxStyle">
3
</div>
<div style="height: 28%" class="boxStyle">
4
</div>
</div>
<div
style="width: 20%; margin-left: 5px; display: flow-root"
class="panelContent boxStyle"
>
<div
style="width: 100%; height: 50%; margin-bottom: 5px"
class="boxStyle"
>
特色功能
</div>
<div style="width: 100%; height: 50%" class="boxStyle">关于作者</div>
</div>
</div>
</template>
<script lang="ts" >
import * as echarts from "echarts";
import { defineComponent } from "vue";
export default defineComponent({
props: {
// openPageData: {
// type: Object as PropType<buttonModel>,
// required: true,
// },
},
setup(props, context) {
return {};
},
components: {},
});
</script>
<style scoped>
.panelContent {
font-size: 12px;
justify-content: right;
align-items: center;
}
.boxStyle {
border: 1px solid #00152914;
box-shadow: 0 1px 4px #00152914;
}
</style>
布局样式如下

填充盒子1的内容
在api文件夹下,创建一个文件夹panel,然后再该文件夹下创建一个echarts.ts的文件,编写如下代码
export const echartsOne = {
title: {
text: "系统六芒星图",
},
color: ['#67F9D8'],
//backgroundColor: "#013954", //背景样式
radar: {
// 雷达图的指示器,表示多个变量的标签
indicator: [
{ name: "好用", max: 5 },
{ name: "易懂", max: 5 },
{ name: "简单", max: 5 },
{ name: "通用", max: 5 },
{ name: "灵活", max: 5 },
{ name: "学习", max: 5 },
],
splitArea: {
areaStyle: {
color: ['#adbecf','#77EADF', '#26C3BE', '#64AFE9', '#428BD4','#2177cd'],
shadowColor: 'rgba(0, 0, 0, 0.2)',
shadowBlur: 10
}
},
axisName: {
formatter: '【{value}】',
color: '#428BD4'
},
},
series: [
{
type: "radar",
// 雷达图的数据
data: [
{
value: [5, 5, 5, 5, 5, 5],
},
],
},
],
};
该代码是echarts的雷达图代码。
回到页面,我们把盒子1里的内容替换成
<div id="echarts-one" style="width: 100%; height: 100%"></div>
然后再setup下添加如下代码
onMounted(() => {
GetEchartsOneData();
});
function GetEchartsOneData() {
var myChart = echarts.init(document.getElementById("echarts-one"));
myChart.setOption(echartsOne);
}
注意这里的onMounted钩子函数需要添加引用,echartsOne也需要导入。点击vue的提示即可。
完成以上代码,我们预览看下效果
照葫芦画瓢,我们开始编写盒子2、3、4的内容
在echarts.ts中添加
//南丁格尔玫瑰图
export const echartsTWO = {
title: {
text: "模块访问占比",
},
toolbox: {
show: true,
},
legend: {
bottom: "10",
},
// backgroundColor: "#013954", //背景样式
series: [
{
name: "Nightingale Chart",
type: "pie",
radius: [25, 80],
center: ["50%", "50%"],
roseType: "area",
// itemStyle: {
// borderRadius: 8,
// },
data: [
{ value: 40, name: "菜单权限" },
{ value: 38, name: "角色权限" },
{ value: 32, name: "列权限" },
{ value: 30, name: "行权限" },
{ value: 28, name: "按钮权限" },
{ value: 18, name: "接口权限" },
{ value: 26, name: "流程" },
{ value: 22, name: "表单" },
],
},
],
};
//中国地图
export const chinaGeoCoordMap = ref<any>({
黑龙江: [127.9688, 45.368],
内蒙古: [110.3467, 41.4899],
吉林: [125.8154, 44.2584],
北京市: [116.4551, 40.2539],
辽宁: [123.1238, 42.1216],
河北: [114.4995, 38.1006],
天津: [117.4219, 39.4189],
山西: [112.3352, 37.9413],
陕西: [109.1162, 34.2004],
甘肃: [103.5901, 36.3043],
宁夏: [106.3586, 38.1775],
青海: [101.4038, 36.8207],
新疆: [87.9236, 43.5883],
西藏: [91.11, 29.97],
四川: [103.9526, 30.7617],
重庆: [108.384366, 30.439702],
山东: [117.1582, 36.8701],
河南: [113.4668, 34.6234],
江苏: [118.8062, 31.9208],
安徽: [117.29, 32.0581],
湖北: [114.3896, 30.6628],
浙江: [119.5313, 29.8773],
福建: [119.4543, 25.9222],
江西: [116.0046, 28.6633],
湖南: [113.0823, 28.2568],
贵州: [106.6992, 26.7682],
云南: [102.9199, 25.4663],
广东: [113.12244, 23.009505],
广西: [108.479, 23.1152],
海南: [110.3893, 19.8516],
上海: [121.4648, 31.2891],
});
export const chinaDatas = [
[
{
name: "黑龙江",
value: 0,
},
],
[
{
name: "内蒙古",
value: 0,
},
],
[
{
name: "吉林",
value: 0,
},
],
[
{
name: "辽宁",
value: 0,
},
],
[
{
name: "河北",
value: 0,
},
],
[
{
name: "天津",
value: 0,
},
],
[
{
name: "山西",
value: 0,
},
],
[
{
name: "陕西",
value: 0,
},
],
[
{
name: "甘肃",
value: 0,
},
],
[
{
name: "宁夏",
value: 0,
},
],
[
{
name: "青海",
value: 0,
},
],
[
{
name: "新疆",
value: 0,
},
],
[
{
name: "西藏",
value: 0,
},
],
[
{
name: "四川",
value: 0,
},
],
[
{
name: "重庆",
value: 0,
},
],
[
{
name: "山东",
value: 0,
},
],
[
{
name: "河南",
value: 0,
},
],
[
{
name: "江苏",
value: 0,
},
],
[
{
name: "安徽",
value: 0,
},
],
[
{
name: "湖北",
value: 0,
},
],
[
{
name: "浙江",
value: 0,
},
],
[
{
name: "福建",
value: 0,
},
],
[
{
name: "江西",
value: 0,
},
],
[
{
name: "湖南",
value: 0,
},
],
[
{
name: "贵州",
value: 0,
},
],
[
{
name: "广西",
value: 0,
},
],
[
{
name: "海南",
value: 0,
},
],
[
{
name: "上海",
value: 1,
},
],
];
var convertData = function (data: string | any[]) {
var res = [];
for (var i = 0; i < data.length; i++) {
var dataItem = data[i];
var fromCoord = chinaGeoCoordMap.value[dataItem[0].name];
var toCoord = [103.9526, 30.7617];
if (fromCoord && toCoord) {
res.push([
{
coord: fromCoord,
value: dataItem[0].value,
},
{
coord: toCoord,
},
]);
}
}
return res;
};
export const series: {
type: string;
zlevel: number;
coordinateSystem: string;
effect: {
show: boolean;
period: number; //箭头指向速度,值越小速度越快
trailLength: number; //特效尾迹长度[0,1]值越大,尾迹越长重
symbol: string; //箭头图标
symbolSize: number;
brushType: string;
scale: number
};
rippleEffect:any;
label: {},
symbol: string;
symbolSize: {},
itemStyle: {},
lineStyle: {
normal: {
width: number; //尾迹线条宽度
opacity: number; //尾迹线条透明度
curveness: number; //尾迹线条曲直度
};
};
data: any
}[] = [];
[["四川", chinaDatas as any]].forEach(function (item, i) {
series.push(
{
type: "lines",
coordinateSystem: "geo",
zlevel: 2,
rippleEffect:[],
effect: {
show: true,
period: 4, //箭头指向速度,值越小速度越快
trailLength: 0.02, //特效尾迹长度[0,1]值越大,尾迹越长重
symbol: "arrow", //箭头图标
symbolSize: 5, //图标大小
brushType: "",
scale: 0
},
label: [],
symbol: "",
symbolSize: [],
itemStyle: [],
lineStyle: {
normal: {
width: 1, //尾迹线条宽度
opacity: 1, //尾迹线条透明度
curveness: 0.3, //尾迹线条曲直度
},
},
data: convertData(item[1]),
},
{
type: "effectScatter",
coordinateSystem: "geo".toString(),
zlevel: 2,
effect:{} as any,
rippleEffect: {
//涟漪特效
period: 4, //动画时间,值越小速度越快
brushType: "stroke", //波纹绘制方式 stroke, fill
scale: 4,
show: false,
trailLength: 0,
symbol: "",
symbolSize: 0
},
label: {
normal: {
show: true,
position: "right", //显示位置
offset: [5, 0], //偏移设置
formatter: function (params: { data: { name: any } }) {
//圆环显示文字
return params.data.name;
},
fontSize: 13,
},
emphasis: {
show: true,
},
},
symbol: "circle",
symbolSize: function (val: number[]) {
return 5 + val[2] * 5; //圆环大小
},
itemStyle: {
normal: {
show: false,
color: "#f00",
},
},
lineStyle: {
normal: {
width: 1, //尾迹线条宽度
opacity: 1, //尾迹线条透明度
curveness: 0.3, //尾迹线条曲直度
},
},
data: item[1].map(function (
dataItem: {
name: any;
value: any;
}[]
) {
return {
name: dataItem[0].name,
value: chinaGeoCoordMap.value[dataItem[0].name].concat([dataItem[0].value]),
};
}),
},
//被攻击点
{
type: "scatter",
coordinateSystem: "geo",
zlevel: 2,
rippleEffect:{} as any,
effect: {
period: 4,
brushType: "stroke",
scale: 4,
show: false,
trailLength: 0,
symbol: "",
symbolSize: 0
},
label: {
normal: {
show: true,
position: "right",
//offset:[5, 0],
color: "#0f0",
formatter: "{b}",
textStyle: {
color: "#0f0",
},
},
emphasis: {
show: true,
color: "#f60",
},
},
symbol: "pin",
symbolSize: 50,
itemStyle: [],
lineStyle: '' as any,
data: [
{
name: item[0],
value: chinaGeoCoordMap.value[item[0].toString()].concat([10]),
},
],
}
);
});
export const echartsThree = {
title: {
text: "各省访问数量",
},
tooltip: {
trigger: "item",
backgroundColor: "rgba(166, 200, 76, 0.82)",
borderColor: "#FFFFCC",
showDelay: 0,
hideDelay: 0,
enterable: true,
transitionDuration: 0,
extraCssText: "z-index:100",
formatter: function (
params: { name: any; value: { [x: string]: any }; seriesIndex: number },
ticket: any,
callback: any
) {
//根据业务自己拓展要显示的内容
var res = "";
var name = params.name;
var value = params.value[params.seriesIndex + 1];
res =
"<span style='color:#fff;'>" + name + "</span><br/>数据:" + value;
return res;
},
},
//backgroundColor: "#013954",
visualMap: {
//图例值控制
min: 0,
max: 1,
calculable: true,
show: true,
color: ["#f44336", "#fc9700", "#ffde00", "#ffde00", "#00eaff"],
textStyle: {
color: "#fff",
},
},
geo: {
map: "china",
zoom: 1.2,
label: {
emphasis: {
show: false,
},
},
roam: false, //是否允许缩放
itemStyle: {
normal: {
color: "rgba(51, 69, 89, .5)", //地图背景色
borderColor: "#516a89", //省市边界线00fcff 516a89
borderWidth: 1,
},
emphasis: {
color: "rgba(37, 43, 61, .5)", //悬浮背景
},
},
},
series: series,
};
//堆叠图
export const echartsFour = {
title: {
text: "系统访问量走势图",
},
// backgroundColor: "#6a7985", //背景样式
tooltip: {
trigger: "axis",
axisPointer: {
type: "cross",
label: {
backgroundColor: "#6a7985",
},
},
},
legend: {
data: ["菜单权限", "角色权限", "按钮权限", "行权限", "列权限"],
},
toolbox: {
// feature: {
// saveAsImage: {},
// },
},
grid: {
left: "3%",
right: "4%",
bottom: "3%",
containLabel: true,
},
xAxis: [
{
type: "category",
boundaryGap: false,
data: ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"],
},
],
yAxis: [
{
type: "value",
},
],
series: [
{
name: "菜单权限",
type: "line",
stack: "Total",
areaStyle: {},
emphasis: {
focus: "series",
},
data: [120, 132, 101, 134, 90, 230, 210],
},
{
name: "角色权限",
type: "line",
stack: "Total",
areaStyle: {},
emphasis: {
focus: "series",
},
data: [220, 182, 191, 234, 290, 330, 310],
},
{
name: "按钮权限",
type: "line",
stack: "Total",
areaStyle: {},
emphasis: {
focus: "series",
},
data: [150, 232, 201, 154, 190, 330, 410],
},
{
name: "行权限",
type: "line",
stack: "Total",
areaStyle: {},
emphasis: {
focus: "series",
},
data: [320, 332, 301, 334, 390, 330, 320],
},
{
name: "列权限",
type: "line",
stack: "Total",
label: {
show: true,
position: "top",
},
areaStyle: {},
emphasis: {
focus: "series",
},
data: [820, 932, 901, 934, 1290, 1330, 1320],
},
],
};
在页面添加
把盒子2所在的地方替换成<div id="echarts-tow" style="width: 100%; height: 100%"></div>
把盒子3所在的地方替换成<div id="echarts-three" style="width: 100%; height: 100%"></div>
把盒子4所在的地方替换成<div id="echarts-four" style="width: 100%; height: 100%"></div>
onMounted(() => {
GetEchartsOneData();
GetEchartsTwoData();
GetEchartsThreeData();
GetEchartsFourData();
});
//六芒星图
function GetEchartsOneData() {
var myChart = echarts.init(document.getElementById("echarts-one"));
myChart.setOption(echartsOne);
}
//南丁格尔玫瑰图
function GetEchartsTwoData() {
var myChart = echarts.init(document.getElementById("echarts-tow"));
myChart.setOption(echartsTWO);
}
//中国地图
function GetEchartsThreeData() {
var myChart = echarts.init(document.getElementById("echarts-three"));
echarts.registerMap("china", chinaJson as any); //注册可用的地图
myChart.setOption(echartsThree);
}
//堆叠图
function GetEchartsFourData() {
var myChart = echarts.init(document.getElementById("echarts-four"));
myChart.setOption(echartsFour);
}
特别注意
1、在添加中国地图时,需要下载一个中国地图的json包,放在项目中(我是放在和echarts.ts同级目录下)。下载地址:https://datav.aliyun.com/portal/school/atlas/area_selector
2、在tsconfig.json文件中需要添加"resolveJsonModule": true,的配置,该配置可以让系统允许导入json。
预览
兼容性调整
对应echarts来说,每个图表,它是固定的,就算设置的是百分比,也不随着窗体的大小而自适应屏幕,如下图

要解决以上问题,我们只需要添加一个方法即可
//图标兼容性调整
function resizeEchart(myChart:any)
{
//监听窗口大小变化(适用于一个页面多个图形)
window.addEventListener('resize',()=>{myChart.resize();})
}
然后再myChart.setOption()方法后面添加resizeEchart(myChart);即可解决兼容性问题,如图
//堆叠图
function GetEchartsFourData() {
var myChart = echarts.init(document.getElementById("echarts-four"));
myChart.setOption(echartsFour);
resizeEchart(myChart);
}
结语
我们的OverallAuth2.0项目也正式迈入功能开发阶段,可能文章内容逐渐开始复杂化,如果你感兴趣的话,也有跟着博主从0到1搭建权限管理系统的兴趣。
那么请加qq群:801913255,进群有什么不懂的尽管问,群主都会耐心解答。
****后端WebApi预览地址:http://139.155.137.144:8880/swagger/index.html
前端vue 预览地址:http://139.155.137.144:8881
关注公众号:发送【权限】,获取前后端代码
有兴趣的朋友,请关注我微信公众号吧(*^▽^*)。
关注我:一个全栈多端的宝藏博主,定时分享技术文章,不定时分享开源项目。关注我,带你认识不一样的程序世界