找回密码
 立即注册
首页 业界区 业界 (系列十三)Vue3+Echarts搭建超好看的系统面板 ...

(系列十三)Vue3+Echarts搭建超好看的系统面板

各卧唯 2025-6-6 10:20:35
说明

    该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。
    该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。
    说明:OverallAuth2.0 是一个简单、易懂、功能强大的权限+可视化流程管理系统。
友情提醒:本篇文章是属于系列文章,看该文章前,建议先看之前文章,可以更好理解项目结构。
qq群:801913255,进群有什么不懂的尽管问,群主都会耐心解答。
有兴趣的朋友,请关注我吧(*^▽^*)。
1.bmp

关注我,学不会你来打我
实现功能
  1、系统登录后的可视化面板页面
  原本不想写这篇文章,因为它和我们的系统权限、框架没有实质性的关系,但耐不住群友的软磨硬泡,便答应了下来。

  我起初的设想,这块功能直接上传到码云上,群友可以根据自己搭建的系统,酌情修改。
安装echarts
  npm install echarts --save
搭建面板页面
在panel文件夹,打开index页面,编写布局代码
  1. <template>
  2.   
  3.    
  4.       
  5.         
  6.         
  7.         
  8.          2
  9.         
  10.       
  11.       
  12.        3
  13.       
  14.       
  15.         4
  16.       
  17.    
  18.    
  19.       
  20.         特色功能
  21.       
  22.       关于作者
  23.    
  24.   
  25. </template>
  26.    
复制代码
布局样式如下
2.png

填充盒子1的内容
在api文件夹下,创建一个文件夹panel,然后再该文件夹下创建一个echarts.ts的文件,编写如下代码
  1. export const echartsOne = {
  2.     title: {
  3.       text: "系统六芒星图",
  4.     },
  5.     color: ['#67F9D8'],
  6.     //backgroundColor: "#013954",  //背景样式
  7.     radar: {
  8.       // 雷达图的指示器,表示多个变量的标签
  9.       indicator: [
  10.         { name: "好用", max: 5 },
  11.         { name: "易懂", max: 5 },
  12.         { name: "简单", max: 5 },
  13.         { name: "通用", max: 5 },
  14.         { name: "灵活", max: 5 },
  15.         { name: "学习", max: 5 },
  16.       ],
  17.       splitArea: {
  18.         areaStyle: {
  19.           color: ['#adbecf','#77EADF', '#26C3BE', '#64AFE9', '#428BD4','#2177cd'],
  20.           shadowColor: 'rgba(0, 0, 0, 0.2)',
  21.           shadowBlur: 10
  22.         }
  23.       },
  24.       axisName: {
  25.         formatter: '【{value}】',
  26.         color: '#428BD4'
  27.       },
  28.     },
  29.     series: [
  30.       {
  31.         type: "radar",
  32.         // 雷达图的数据
  33.         data: [
  34.           {
  35.             value: [5, 5, 5, 5, 5, 5],
  36.           },
  37.         ],
  38.       },
  39.     ],
  40.   };
复制代码
该代码是echarts的雷达图代码。
回到页面,我们把盒子1里的内容替换成
   然后再setup下添加如下代码
  1.   onMounted(() => {
  2.       GetEchartsOneData();
  3.     });
  4.     function GetEchartsOneData() {
  5.       var myChart = echarts.init(document.getElementById("echarts-one"));
  6.       myChart.setOption(echartsOne);
  7.     }
复制代码
注意这里的onMounted钩子函数需要添加引用,echartsOne也需要导入。点击vue的提示即可。
完成以上代码,我们预览看下效果
3.png
照葫芦画瓢,我们开始编写盒子2、3、4的内容
在echarts.ts中添加
  1. //南丁格尔玫瑰图
  2. export const echartsTWO = {
  3.     title: {
  4.         text: "模块访问占比",
  5.     },
  6.     toolbox: {
  7.         show: true,
  8.     },
  9.     legend: {
  10.         bottom: "10",
  11.     },
  12.     // backgroundColor: "#013954",  //背景样式
  13.     series: [
  14.         {
  15.             name: "Nightingale Chart",
  16.             type: "pie",
  17.             radius: [25, 80],
  18.             center: ["50%", "50%"],
  19.             roseType: "area",
  20.             // itemStyle: {
  21.             //   borderRadius: 8,
  22.             // },
  23.             data: [
  24.                 { value: 40, name: "菜单权限" },
  25.                 { value: 38, name: "角色权限" },
  26.                 { value: 32, name: "列权限" },
  27.                 { value: 30, name: "行权限" },
  28.                 { value: 28, name: "按钮权限" },
  29.                 { value: 18, name: "接口权限" },
  30.                 { value: 26, name: "流程" },
  31.                 { value: 22, name: "表单" },
  32.             ],
  33.         },
  34.     ],
  35. };
  36. //中国地图
  37. export const chinaGeoCoordMap = ref({
  38.     黑龙江: [127.9688, 45.368],
  39.     内蒙古: [110.3467, 41.4899],
  40.     吉林: [125.8154, 44.2584],
  41.     北京市: [116.4551, 40.2539],
  42.     辽宁: [123.1238, 42.1216],
  43.     河北: [114.4995, 38.1006],
  44.     天津: [117.4219, 39.4189],
  45.     山西: [112.3352, 37.9413],
  46.     陕西: [109.1162, 34.2004],
  47.     甘肃: [103.5901, 36.3043],
  48.     宁夏: [106.3586, 38.1775],
  49.     青海: [101.4038, 36.8207],
  50.     新疆: [87.9236, 43.5883],
  51.     西藏: [91.11, 29.97],
  52.     四川: [103.9526, 30.7617],
  53.     重庆: [108.384366, 30.439702],
  54.     山东: [117.1582, 36.8701],
  55.     河南: [113.4668, 34.6234],
  56.     江苏: [118.8062, 31.9208],
  57.     安徽: [117.29, 32.0581],
  58.     湖北: [114.3896, 30.6628],
  59.     浙江: [119.5313, 29.8773],
  60.     福建: [119.4543, 25.9222],
  61.     江西: [116.0046, 28.6633],
  62.     湖南: [113.0823, 28.2568],
  63.     贵州: [106.6992, 26.7682],
  64.     云南: [102.9199, 25.4663],
  65.     广东: [113.12244, 23.009505],
  66.     广西: [108.479, 23.1152],
  67.     海南: [110.3893, 19.8516],
  68.     上海: [121.4648, 31.2891],
  69. });
  70. export const chinaDatas = [
  71.     [
  72.         {
  73.             name: "黑龙江",
  74.             value: 0,
  75.         },
  76.     ],
  77.     [
  78.         {
  79.             name: "内蒙古",
  80.             value: 0,
  81.         },
  82.     ],
  83.     [
  84.         {
  85.             name: "吉林",
  86.             value: 0,
  87.         },
  88.     ],
  89.     [
  90.         {
  91.             name: "辽宁",
  92.             value: 0,
  93.         },
  94.     ],
  95.     [
  96.         {
  97.             name: "河北",
  98.             value: 0,
  99.         },
  100.     ],
  101.     [
  102.         {
  103.             name: "天津",
  104.             value: 0,
  105.         },
  106.     ],
  107.     [
  108.         {
  109.             name: "山西",
  110.             value: 0,
  111.         },
  112.     ],
  113.     [
  114.         {
  115.             name: "陕西",
  116.             value: 0,
  117.         },
  118.     ],
  119.     [
  120.         {
  121.             name: "甘肃",
  122.             value: 0,
  123.         },
  124.     ],
  125.     [
  126.         {
  127.             name: "宁夏",
  128.             value: 0,
  129.         },
  130.     ],
  131.     [
  132.         {
  133.             name: "青海",
  134.             value: 0,
  135.         },
  136.     ],
  137.     [
  138.         {
  139.             name: "新疆",
  140.             value: 0,
  141.         },
  142.     ],
  143.     [
  144.         {
  145.             name: "西藏",
  146.             value: 0,
  147.         },
  148.     ],
  149.     [
  150.         {
  151.             name: "四川",
  152.             value: 0,
  153.         },
  154.     ],
  155.     [
  156.         {
  157.             name: "重庆",
  158.             value: 0,
  159.         },
  160.     ],
  161.     [
  162.         {
  163.             name: "山东",
  164.             value: 0,
  165.         },
  166.     ],
  167.     [
  168.         {
  169.             name: "河南",
  170.             value: 0,
  171.         },
  172.     ],
  173.     [
  174.         {
  175.             name: "江苏",
  176.             value: 0,
  177.         },
  178.     ],
  179.     [
  180.         {
  181.             name: "安徽",
  182.             value: 0,
  183.         },
  184.     ],
  185.     [
  186.         {
  187.             name: "湖北",
  188.             value: 0,
  189.         },
  190.     ],
  191.     [
  192.         {
  193.             name: "浙江",
  194.             value: 0,
  195.         },
  196.     ],
  197.     [
  198.         {
  199.             name: "福建",
  200.             value: 0,
  201.         },
  202.     ],
  203.     [
  204.         {
  205.             name: "江西",
  206.             value: 0,
  207.         },
  208.     ],
  209.     [
  210.         {
  211.             name: "湖南",
  212.             value: 0,
  213.         },
  214.     ],
  215.     [
  216.         {
  217.             name: "贵州",
  218.             value: 0,
  219.         },
  220.     ],
  221.     [
  222.         {
  223.             name: "广西",
  224.             value: 0,
  225.         },
  226.     ],
  227.     [
  228.         {
  229.             name: "海南",
  230.             value: 0,
  231.         },
  232.     ],
  233.     [
  234.         {
  235.             name: "上海",
  236.             value: 1,
  237.         },
  238.     ],
  239. ];
  240. var convertData = function (data: string | any[]) {
  241.     var res = [];
  242.     for (var i = 0; i < data.length; i++) {
  243.         var dataItem = data[i];
  244.         var fromCoord = chinaGeoCoordMap.value[dataItem[0].name];
  245.         var toCoord = [103.9526, 30.7617];
  246.         if (fromCoord && toCoord) {
  247.             res.push([
  248.                 {
  249.                     coord: fromCoord,
  250.                     value: dataItem[0].value,
  251.                 },
  252.                 {
  253.                     coord: toCoord,
  254.                 },
  255.             ]);
  256.         }
  257.     }
  258.     return res;
  259. };
  260. export const series: {
  261.     type: string;
  262.     zlevel: number;
  263.     coordinateSystem: string;
  264.     effect: {
  265.         show: boolean;
  266.         period: number; //箭头指向速度,值越小速度越快
  267.         trailLength: number; //特效尾迹长度[0,1]值越大,尾迹越长重
  268.         symbol: string; //箭头图标
  269.         symbolSize: number;
  270.         brushType: string;
  271.         scale: number
  272.     };
  273.     rippleEffect:any;
  274.     label: {},
  275.     symbol: string;
  276.     symbolSize: {},
  277.     itemStyle: {},
  278.     lineStyle: {
  279.         normal: {
  280.             width: number; //尾迹线条宽度
  281.             opacity: number; //尾迹线条透明度
  282.             curveness: number; //尾迹线条曲直度
  283.         };
  284.     };
  285.     data: any
  286. }[] = [];
  287. [["四川", chinaDatas as any]].forEach(function (item, i) {
  288.     series.push(
  289.         {
  290.             type: "lines",
  291.             coordinateSystem: "geo",
  292.             zlevel: 2,
  293.             rippleEffect:[],
  294.             effect: {
  295.                 show: true,
  296.                 period: 4, //箭头指向速度,值越小速度越快
  297.                 trailLength: 0.02, //特效尾迹长度[0,1]值越大,尾迹越长重
  298.                 symbol: "arrow", //箭头图标
  299.                 symbolSize: 5, //图标大小
  300.                 brushType: "",
  301.                 scale: 0
  302.             },
  303.             label: [],
  304.             symbol: "",
  305.             symbolSize: [],
  306.             itemStyle: [],
  307.             lineStyle: {
  308.                 normal: {
  309.                     width: 1, //尾迹线条宽度
  310.                     opacity: 1, //尾迹线条透明度
  311.                     curveness: 0.3, //尾迹线条曲直度
  312.                 },
  313.             },
  314.             data: convertData(item[1]),
  315.         },
  316.         {
  317.             type: "effectScatter",
  318.             coordinateSystem: "geo".toString(),
  319.             zlevel: 2,
  320.             effect:{} as any,
  321.             rippleEffect: {
  322.                 //涟漪特效
  323.                 period: 4, //动画时间,值越小速度越快
  324.                 brushType: "stroke", //波纹绘制方式 stroke, fill
  325.                 scale: 4,
  326.                 show: false,
  327.                 trailLength: 0,
  328.                 symbol: "",
  329.                 symbolSize: 0
  330.             },
  331.             label: {
  332.                 normal: {
  333.                     show: true,
  334.                     position: "right", //显示位置
  335.                     offset: [5, 0], //偏移设置
  336.                     formatter: function (params: { data: { name: any } }) {
  337.                         //圆环显示文字
  338.                         return params.data.name;
  339.                     },
  340.                     fontSize: 13,
  341.                 },
  342.                 emphasis: {
  343.                     show: true,
  344.                 },
  345.             },
  346.             symbol: "circle",
  347.             symbolSize: function (val: number[]) {
  348.                 return 5 + val[2] * 5; //圆环大小
  349.             },
  350.             itemStyle: {
  351.                 normal: {
  352.                     show: false,
  353.                     color: "#f00",
  354.                 },
  355.             },
  356.             lineStyle: {
  357.                 normal: {
  358.                     width: 1, //尾迹线条宽度
  359.                     opacity: 1, //尾迹线条透明度
  360.                     curveness: 0.3, //尾迹线条曲直度
  361.                 },
  362.             },
  363.             data: item[1].map(function (
  364.                 dataItem: {
  365.                     name: any;
  366.                     value: any;
  367.                 }[]
  368.             ) {
  369.                 return {
  370.                     name: dataItem[0].name,
  371.                     value: chinaGeoCoordMap.value[dataItem[0].name].concat([dataItem[0].value]),
  372.                 };
  373.             }),
  374.         },
  375.         //被攻击点
  376.         {
  377.             type: "scatter",
  378.             coordinateSystem: "geo",
  379.             zlevel: 2,
  380.             rippleEffect:{} as any,
  381.             effect: {
  382.                 period: 4,
  383.                 brushType: "stroke",
  384.                 scale: 4,
  385.                 show: false,
  386.                 trailLength: 0,
  387.                 symbol: "",
  388.                 symbolSize: 0
  389.             },
  390.             label: {
  391.                 normal: {
  392.                     show: true,
  393.                     position: "right",
  394.                     //offset:[5, 0],
  395.                     color: "#0f0",
  396.                     formatter: "{b}",
  397.                     textStyle: {
  398.                         color: "#0f0",
  399.                     },
  400.                 },
  401.                 emphasis: {
  402.                     show: true,
  403.                     color: "#f60",
  404.                 },
  405.             },
  406.             symbol: "pin",
  407.             symbolSize: 50,
  408.             itemStyle: [],
  409.             lineStyle: '' as any,
  410.             data: [
  411.                 {
  412.                     name: item[0],
  413.                     value: chinaGeoCoordMap.value[item[0].toString()].concat([10]),
  414.                 },
  415.             ],
  416.         }
  417.     );
  418. });
  419. export const echartsThree = {
  420.     title: {
  421.         text: "各省访问数量",
  422.     },
  423.     tooltip: {
  424.       trigger: "item",
  425.       backgroundColor: "rgba(166, 200, 76, 0.82)",
  426.       borderColor: "#FFFFCC",
  427.       showDelay: 0,
  428.       hideDelay: 0,
  429.       enterable: true,
  430.       transitionDuration: 0,
  431.       extraCssText: "z-index:100",
  432.       formatter: function (
  433.         params: { name: any; value: { [x: string]: any }; seriesIndex: number },
  434.         ticket: any,
  435.         callback: any
  436.       ) {
  437.         //根据业务自己拓展要显示的内容
  438.         var res = "";
  439.         var name = params.name;
  440.         var value = params.value[params.seriesIndex + 1];
  441.         res =
  442.           "<span style='color:#fff;'>" + name + "</span><br/>数据:" + value;
  443.         return res;
  444.       },
  445.     },
  446.     //backgroundColor: "#013954",
  447.     visualMap: {
  448.       //图例值控制
  449.       min: 0,
  450.       max: 1,
  451.       calculable: true,
  452.       show: true,
  453.       color: ["#f44336", "#fc9700", "#ffde00", "#ffde00", "#00eaff"],
  454.       textStyle: {
  455.         color: "#fff",
  456.       },
  457.     },
  458.     geo: {
  459.       map: "china",
  460.       zoom: 1.2,
  461.       label: {
  462.         emphasis: {
  463.           show: false,
  464.         },
  465.       },
  466.       roam: false, //是否允许缩放
  467.       itemStyle: {
  468.         normal: {
  469.           color: "rgba(51, 69, 89, .5)", //地图背景色
  470.           borderColor: "#516a89", //省市边界线00fcff 516a89
  471.           borderWidth: 1,
  472.         },
  473.         emphasis: {
  474.           color: "rgba(37, 43, 61, .5)", //悬浮背景
  475.         },
  476.       },
  477.     },
  478.     series: series,
  479.   };
  480.   //堆叠图
  481.   export const echartsFour = {
  482.     title: {
  483.       text: "系统访问量走势图",
  484.     },
  485.    // backgroundColor: "#6a7985",  //背景样式
  486.     tooltip: {
  487.       trigger: "axis",
  488.       axisPointer: {
  489.         type: "cross",
  490.         label: {
  491.           backgroundColor: "#6a7985",
  492.         },
  493.       },
  494.     },
  495.     legend: {
  496.       data: ["菜单权限", "角色权限", "按钮权限", "行权限", "列权限"],
  497.     },
  498.     toolbox: {
  499.       // feature: {
  500.       //   saveAsImage: {},
  501.       // },
  502.     },
  503.     grid: {
  504.       left: "3%",
  505.       right: "4%",
  506.       bottom: "3%",
  507.       containLabel: true,
  508.     },
  509.     xAxis: [
  510.       {
  511.         type: "category",
  512.         boundaryGap: false,
  513.         data: ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"],
  514.       },
  515.     ],
  516.     yAxis: [
  517.       {
  518.         type: "value",
  519.       },
  520.     ],
  521.     series: [
  522.       {
  523.         name: "菜单权限",
  524.         type: "line",
  525.         stack: "Total",
  526.         areaStyle: {},
  527.         emphasis: {
  528.           focus: "series",
  529.         },
  530.         data: [120, 132, 101, 134, 90, 230, 210],
  531.       },
  532.       {
  533.         name: "角色权限",
  534.         type: "line",
  535.         stack: "Total",
  536.         areaStyle: {},
  537.         emphasis: {
  538.           focus: "series",
  539.         },
  540.         data: [220, 182, 191, 234, 290, 330, 310],
  541.       },
  542.       {
  543.         name: "按钮权限",
  544.         type: "line",
  545.         stack: "Total",
  546.         areaStyle: {},
  547.         emphasis: {
  548.           focus: "series",
  549.         },
  550.         data: [150, 232, 201, 154, 190, 330, 410],
  551.       },
  552.       {
  553.         name: "行权限",
  554.         type: "line",
  555.         stack: "Total",
  556.         areaStyle: {},
  557.         emphasis: {
  558.           focus: "series",
  559.         },
  560.         data: [320, 332, 301, 334, 390, 330, 320],
  561.       },
  562.       {
  563.         name: "列权限",
  564.         type: "line",
  565.         stack: "Total",
  566.         label: {
  567.           show: true,
  568.           position: "top",
  569.         },
  570.         areaStyle: {},
  571.         emphasis: {
  572.           focus: "series",
  573.         },
  574.         data: [820, 932, 901, 934, 1290, 1330, 1320],
  575.       },
  576.     ],
  577.   };
复制代码
在页面添加
把盒子2所在的地方替换成把盒子3所在的地方替换成把盒子4所在的地方替换成
  1. onMounted(() => {
  2.       GetEchartsOneData();
  3.       GetEchartsTwoData();
  4.       GetEchartsThreeData();
  5.       GetEchartsFourData();
  6.     });
  7.     //六芒星图
  8.     function GetEchartsOneData() {
  9.       var myChart = echarts.init(document.getElementById("echarts-one"));
  10.       myChart.setOption(echartsOne);
  11.     }
  12.     //南丁格尔玫瑰图
  13.     function GetEchartsTwoData() {
  14.       var myChart = echarts.init(document.getElementById("echarts-tow"));
  15.       myChart.setOption(echartsTWO);
  16.     }
  17.     //中国地图
  18.     function GetEchartsThreeData() {
  19.       var myChart = echarts.init(document.getElementById("echarts-three"));
  20.       echarts.registerMap("china", chinaJson as any); //注册可用的地图
  21.       myChart.setOption(echartsThree);
  22.     }
  23.     //堆叠图
  24.     function GetEchartsFourData() {
  25.       var myChart = echarts.init(document.getElementById("echarts-four"));
  26.       myChart.setOption(echartsFour);
  27.     }
复制代码
特别注意
  1、在添加中国地图时,需要下载一个中国地图的json包,放在项目中(我是放在和echarts.ts同级目录下)。下载地址:https://datav.aliyun.com/portal/school/atlas/area_selector
  2、在tsconfig.json文件中需要添加"resolveJsonModule": true,的配置,该配置可以让系统允许导入json。
预览

兼容性调整
  对应echarts来说,每个图表,它是固定的,就算设置的是百分比,也不随着窗体的大小而自适应屏幕,如下图

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

关注我:一个全栈多端的宝藏博主,定时分享技术文章,不定时分享开源项目。关注我,带你认识不一样的程序世界

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册