SpringBoot+Vue3实现数据可视化大屏

前端工程的地址:UserManagerFront: 数据可视化前端 (gitee.com)

效果展示,可以展现出来了,样式可能还有一些丑。

后端代码

后端主要是拿到数据并对数据进行处理,按照前端需要的格式进行返回即可。
import com.njitzx.entity.Student;
import com.njitzx.entity.vo.*;
import com.njitzx.mapper.StudentMapper;
import com.njitzx.mapper.TeacherMapper;
import com.njitzx.serivce.StudentService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Map;import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.LinkedHashMap;
@Service
@RequiredArgsConstructor
public class StudentServiceImpl implements StudentService {private final StudentMapper studentMapper;private final TeacherMapper teacherMapper;@Overridepublic CollegeVO getCollege() {List<Student> students = studentMapper.getAll();// 分组并计算每个学院的学生数量Map<String, Long> collect = students.stream() //收集成map集合.collect(Collectors.groupingBy(Student::getCollege, Collectors.counting()));// 根据值进行排序(降序),然后将结果收集到一个新的LinkedHashMap中Map<String, Long> sortedCollect = collect.entrySet().stream().sorted(Entry.<String, Long>comparingByValue().reversed()).collect(Collectors.toMap(Entry::getKey,Entry::getValue,(e1, e2) -> e1,LinkedHashMap::new));// 将排序后的键和值拼接成字符串String college = String.join(",", sortedCollect.keySet());String countList = sortedCollect.values().stream().map(String::valueOf).collect(Collectors.joining(","));return CollegeVO.builder().nameList(college).numberList(countList).build();}@Overridepublic List<GenderVO> getSex() {List<Student> students = studentMapper.getAll();Map<String, Long> collect = students.stream().collect(Collectors.groupingBy(Student::getGender, Collectors.counting()));List<GenderVO> genderVOList = collect.entrySet().stream().map(entry -> {GenderVO vo = new GenderVO();vo.setName(entry.getKey());vo.setValue(entry.getValue());return vo;}).collect(Collectors.toList());return  genderVOList;}@Overridepublic List<ProvinceVO> getProvince() {List<Student> students = studentMapper.getAll();Map<String, Long> collect = students.stream().collect(Collectors.groupingBy(Student::getProvinces, Collectors.counting()));List<ProvinceVO> genderVOList = collect.entrySet().stream().map(entry -> {ProvinceVO vo = new ProvinceVO();vo.setName(entry.getKey());vo.setValue(entry.getValue());return vo;}).collect(Collectors.toList());return  genderVOList;}@Overridepublic NumberVO getnumbwer() {Long l = studentMapper.selectCount();Long r = teacherMapper.selectCount();return  NumberVO.builder().numberStudent(l).numberTeacher(r).build();}@Overridepublic HobbyVO getHobby() {List<Student> students = studentMapper.getAll();// 分组并计算每个学院的学生数量Map<String, Long> collect = students.stream().collect(Collectors.groupingBy(Student::getHobby, Collectors.counting()));// 将排序后的键和值拼接成字符串String name = String.join(",", collect.keySet());String count = collect.values().stream().map(String::valueOf).collect(Collectors.joining(","));return HobbyVO.builder().name(name).count(count).build();}
}

前端

主要是学习前端如何编写的。

vue3编写echarts代码

1.创建一个盒子<div class="panel bar" ref="chart1"> //通过ref 拿到这个盒子
2 导入echarts import * as echarts from 'echarts';3const chart1 = ref(null);  创建dom对象4.创建option配置5 初始化  let instance = echarts.init(chart1.value);6挂载配置到instance上面 instance.setOption(chartOptions);也可以通过document来获取对象,进行初始化和挂载。let initMap = echarts.init(document.querySelector('#hobbyRef'))initMap.setOption(option)
柱状图的配置
```javascript const chartOptions = { //设置距离边框的样式 grid: { left: '0%', right: '0%', top: "20%", bottom: '4%', containLabel: true }, // 设置标题 title: { // 标题 text: '学院人数排名前五', //居中位置 left: 'center', //设置标题的样式 textStyle: { color: '#2f89cf', // 设置标题颜色为红色 fontSize: 18, // 设置字体大小 fontWeight: 'bold' // 设置字体粗细 } }, color: ['#2f89cf'], tooltip: { trigger: 'axis', //坐标轴点上去触发 axisPointer: {type: 'shadow'} }, xAxis: { type: 'category', data: collegeNameList.value, axisTick: { alignWithLabel: true }, //修改 axisLabel: { color: "rgba(255,255,255,.6)", fontSize: 12, // 调大字体大小 interval: 0, // 强制显示所有标签 rotate: 30, // 旋转标签以避免重叠 formatter: function (value) { // 如果名称超过10个字符,显示省略号 return value.length > 10 ? value.slice(0, 10) + '...' : value; } }, axisLine: { show: false, // 如果想要设置单独的线条样式 lineStyle: { color: "rgba(255,255,255,.1)", width: 1, type: "solid" } } }, yAxis: { type: 'value', axisLabel: { color: "rgba(255,255,255,.6)", fontSize: "12" }, // y轴线条样式 axisLine: { lineStyle: { color: "rgba(255,255,255,.1)", // width: 1, // type: "solid" } }, // y 轴分隔线样式 splitLine: { lineStyle: { color: "rgba(255,255,255,.1)" } } }, //配置数据的 series: [{ name: '学生数量', type: 'bar', barWidth: '35%', data: collegeNumberList.value, itemStyle: { barBorderRadius: 5 } }] }; ```

<h4 id="hA9LP">中国地图</h4>
``javascript
import china from '@/json/china.json'  //导入地图的json数据const mockData = ref([])//从后端拿到地图的数据 [{'nane':'北京市','value':500}]
const getmokcData = async () => {const res = await getStudentProvince();mockData.value = res.data.dataawait nextTick(() => {getEcharts3();});
}let initMap = echarts.init(document.querySelector('#mapDom')); //初始化//注册中国地图echarts.registerMap('china', china);//拿到前五的数据let topFiveData = mockData.value.sort((a, b) => b.value - a.value).slice(0, 5);// 将筛选后的数据转换为 ECharts 需要的格式let data = topFiveData.map(i => {let cityPosition = getCityPositionByName(i.name);return {name: i.name,value: cityPosition ? [...cityPosition.value.map(Number), i.value] : [0, 0, i.value]};});
// 创建一个方便查找的字典对象let mockDataMap = mockData.value.reduce((acc, item) => {acc[item.name] = item.value;return acc;}, {});let options = {title: {text: '学生家乡分布',left: 'center',textStyle: {color: '#fa4c27',fontSize: 18,fontWeight: 'bold'}},tooltip: {trigger: 'item',formatter: (params) => {// 从 mockDataMap 中获取对应省份的数据值let count = mockDataMap[params.name] || 0; // 确保显示为0而不是NaNreturn `${params.name}<br/>${count} (学生总数)`;}},//又下角的工具toolbox: {show: true,orient: 'vertical',left: 'right',top: 'center',feature: {dataView: {readOnly: false, title: '数据视图'},restore: {title: '还原'},saveAsImage: {title: '保存为图片', pixelRatio: 2}}},visualMap: {min: 0,max: Math.max(...topFiveData.map(d => d.value)),text: ['High', 'Low'],realtime: false,calculable: true,inRange: {color: ['#e0f7fa', '#80deea', '#0288d1']}},//地图坐标geo: {map: 'china',roam: false,// zoom: 1, // 调整这个值来放大地图label: {show: false},emphasis: {label: {show: false}}},series: [{name: '中国',type: 'map',map: 'china',label: {show: false},data: mockData.value,},{type: 'scatter',coordinateSystem: 'geo',symbol: 'pin',symbolSize: [50, 50],label: {show: true,color: '#fff',formatter(value) {return value.name + value.data.value[2]; // 显示人数},fontSize: 10},itemStyle: {color: '#e30707' // 标记颜色},data: data,}]};initMap.setOption(options);
背景样式
* {margin: 0;padding: 0;box-sizing: border-box;
}li {list-style: none;
}@font-face {font-family: electronicFont;src: url("@/assets/font/DS-DIGIT.TTF");
}.header {position: relative;height: 1.25rem;background: url('@/assets/images/head_bg.png') no-repeat top center;background-color: #0b1341;background-size: 100% 100%;h1 {font-size: 0.475rem;color: #fff;text-align: center;line-height: 1rem;}.showTime {position: absolute;top: 0;right: 0.375rem;line-height: 0.9375rem;font-size: 0.25rem;color: rgba(255, 255, 255, 0.7);}
}.mainbox {font-family: Arial, Helvetica, sans-serif;margin: 0;padding: 0;/*  背景图定位 / 背景图尺寸  cover 完全铺满容器  contain 完整显示在容器内 */background: url('@/assets/images/bg.jpg') no-repeat #000;background-size: cover;/* 行高是字体1.15倍 */line-height: 1.15;
}.mainbox {min-width: 1024px;max-width: 1920px;padding: 0.125rem 0.125rem 0;display: flex;.column {flex: 3;&:nth-child(2) {flex: 5;margin: 0 0.125rem 0.1875rem;overflow: hidden;}}
}.panel {position: relative;height: 3.875rem;border: 1px solid rgba(25, 186, 139, 0.17);background: rgba(255, 255, 255, 0.04) url('@/assets/images/line.png');padding: 0 0.1875rem 0.5rem;margin-bottom: 0.1875rem;&::before {position: absolute;top: 0;left: 0;content: "";width: 10px;height: 10px;border-top: 2px solid #02a6b5;border-left: 2px solid #02a6b5;}&::after {position: absolute;top: 0;right: 0;content: "";width: 10px;height: 10px;border-top: 2px solid #02a6b5;border-right: 2px solid #02a6b5;}.panel-footer {position: absolute;left: 0;bottom: 0;width: 100%;//z-index: 0;&::before {position: absolute;bottom: 0;left: 0;content: "";width: 10px;height: 10px;border-bottom: 2px solid #02a6b5;border-left: 2px solid #02a6b5;}&::after {position: absolute;bottom: 0;right: 0;content: "";width: 10px;height: 10px;border-bottom: 2px solid #02a6b5;border-right: 2px solid #02a6b5;}}//.panel-footer::before, .panel-footer::after {//  z-index: 0; /* 确保伪元素在 panel-footer 下层 *///}h2 {//z-index: 1; /* 确保 panel 在最上层 */height: 0.6rem;line-height: 0.6rem;text-align: center;color: #fff;font-size: 0.25rem;font-weight: 400;a {margin: 0 0.1875rem;color: #fff;text-decoration: underline;}}.chart {height: 3rem;}
}.no {background: rgba(101, 132, 226, 0.1);padding: 0.1875rem;.no-hd {position: relative;border: 1px solid rgba(25, 186, 139, 0.17);&::before {content: "";position: absolute;width: 30px;height: 10px;border-top: 2px solid #02a6b5;border-left: 2px solid #02a6b5;top: 0;left: 0;}&::after {content: "";position: absolute;width: 30px;height: 10px;border-bottom: 2px solid #02a6b5;border-right: 2px solid #02a6b5;right: 0;bottom: 0;}ul {display: flex;li {position: relative;flex: 1;text-align: center;height: 1rem;line-height: 1rem;font-size: 0.875rem;color: #ffeb7b;padding: 0.05rem 0;font-family: electronicFont;font-weight: bold;&:first-child::after {content: "";position: absolute;height: 50%;width: 1px;background: rgba(255, 255, 255, 0.2);right: 0;top: 25%;}}}}.no-bd ul {display: flex;li {flex: 1;height: 0.5rem;line-height: 0.5rem;text-align: center;font-size: 0.225rem;color: rgba(255, 255, 255, 0.7);padding-top: 0.125rem;}}
}.map {position: relative;height: 10.125rem;.chart {position: absolute;top: 0;left: 0;z-index: 5;height: 10.125rem;width: 100%;}.map1,.map2,.map3 {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);width: 6.475rem;height: 6.475rem;background: url('@/assets/images/map.png') no-repeat;background-size: 100% 100%;opacity: 0.3;}.map2 {width: 8.0375rem;height: 8.0375rem;background-image: url('@/assets/images/lbx.png');opacity: 0.6;animation: rotate 15s linear infinite;z-index: 2;}.map3 {width: 7.075rem;height: 7.075rem;background-image: url('@/assets/images/jt.png');animation: rotate1 10s linear infinite;}@keyframes rotate {from {transform: translate(-50%, -50%) rotate(0deg);}to {transform: translate(-50%, -50%) rotate(360deg);}}@keyframes rotate1 {from {transform: translate(-50%, -50%) rotate(0deg);}to {transform: translate(-50%, -50%) rotate(-360deg);}}
}@media screen and (max-width: 1024px) {html {font-size: 42px !important;}
}@media screen and (min-width: 1920px) {html {font-size: 80px !important;}
}

template

整体结构是 flex布局 3 5 3 布局样式。

<template><div class="header"><h1>工程数据分析</h1><div class="showTime"></div></div><!-- 页面主体  一个大的盒子  划分 --><div class="mainbox"><div class="column"><div class="panel bar" ref="chart1"><div class="chart"></div><!--        <h2 style="color: red">学院人数排名前五</h2>--><div class="panel-footer"></div></div><div class="panel line" ref="chart2"><div class="chart"></div><h2>标题</h2><div class="panel-footer"></div></div><div class="panel pie"><h2></h2><div class="panel-footer"></div></div></div><div class="column"><div class="no"><div class="no-hd"><ul><li>{{ stNumber.numberTeacher }}</li><li>{{ stNumber.numberStudent }}</li></ul></div><div class="no-bd"><ul><li>学生人数</li><li>老师人数</li></ul></div></div><!-- 地图模块 --><div class="map"><!-- 放到map中间 --><div class="chart" id="mapDom"></div><div class="map1"></div><div class="map2"></div><div class="map3"></div></div></div><div class="column"><div class="panel bar" ><h2></h2><div class="chart" id="hobbyRef"></div><div class="panel-footer"></div></div><div class="panel line"><h2></h2><div class="panel-footer"></div></div><div class="panel pie"><h2></h2><div class="panel-footer"></div></div></div></div>
</template>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/886268.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3: toRef, reactive, toRefs, toRaw

vue3&#xff1a; toRef, reactive, toRefs, toRaw 扫码或者点击文字后台提问 <template><div>{{ man }}</div><hr><!-- <div>{{ name }}--{{ age }}--{{ like }}</div> --><div><button click"change">修…

《网络硬件设备完全技术宝典》

《网络硬件设备完全技术宝典》 网卡 集线器 交换机 路由器 双绞线 光缆 无线接入点AP 交换机技术与选择策略 冗余链路技术 由于物理链路和网络模块的损坏都将导致网络链路的失败&#xff0c;因此两个设备之间&#xff0c;特别是核心交换机与汇聚交换机之间的单链路…

Win10下使用Anaconda安装GPU版本PyTorch

PyTorch是一个开源机器学习框架&#xff0c;最初来自Meta Ai。如果你想研究人工智能或从事人工智能项目方面的工作&#xff0c;那么在本地机器上使用PyTorch设置开发环境对于许多项目来说都是必不可少的。GPU&#xff08;图形处理单元&#xff09;是一种专用处理器&#xff0c;…

灰狼优化算法

灰狼优化算法&#xff08;Grey Wolf Optimizer&#xff0c;GWO&#xff09;是一种群智能优化算法&#xff0c;由澳大利亚格里菲斯大学学者Mirjalili等人于2014年提出。该算法灵感来源于灰狼群体的捕食行为&#xff0c;通过模拟灰狼的社会等级分层、跟踪、包围和攻击猎物等步骤来…

Chromium 中sqlite数据库操作演示c++

本文主要演示sqlite数据库 增删改查创建数据库以及数据库表的基本操作&#xff0c;仅供学习参考。 一、sqlite数据库操作类封装&#xff1a; sql\database.h sql\database.cc // Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-sty…

Docker部署Kafka集群,增加 SASL_SSL认证,并集成到Spring Boot,无Zookeeper版

1&#xff0c;准备好Kafka 镜像包&#xff1a; bitnami/kafka:3.9.0 镜像资源包 2&#xff0c;准备好kafka.keystore.jks 和 kafka.truststore.jks证书 具体操作可参考&#xff1a; Docker部署Kafka SASL_SSL认证&#xff0c;并集成到Spring Boot-CSDN博客 3&#xff0c;配置…

apipost下载安装教程、脚本详细使用教程

目录 apipost脚本使用教程 缘由&#xff1a; 实现流程&#xff1a; 1、设置接口需要的URL&#xff1a; 2、boby: 3、预执行操作&#xff1a; 4、断言 5、执行结果&#xff1a; 什么是ApiPost&#xff1f; 下载以及安装&#xff1a; apipost使用文档介绍&#xff1a;…

Python Web 应用开发基础知识

Python Web 应用开发基础知识 引言 随着互联网的快速发展&#xff0c;Web 应用程序的需求日益增加。Python 作为一种简单易学且功能强大的编程语言&#xff0c;已经成为 Web 开发中广受欢迎的选择之一。本文将深入探讨 Python Web 开发的基础知识&#xff0c;包括常用框架、基…

SpringBoot多环境+docker集成企业微信会话存档sdk

SpringBoot多环境docker集成企业微信会话存档sdk 文章来自于 https://developer.work.weixin.qq.com/community/article/detail?content_id16529801754907176021 SpringBoot多环境docker集成企业微信会话存档sdk 对于现在基本流行的springboot环境&#xff0c;官方文档真是比…

在openi平台 基于华为顶级深度计算平台 openmind 动手实践

大家可能一直疑问&#xff0c;到底大模型在哪里有用。 本人从事的大模型有几个方向的业务。 基于生成式语言模型的海事航行警告结构化解析。 基于生成式语言模型的航空航行警告结构化解析。 基于生成式生物序列&#xff08;蛋白质、有机物、rna、dna、mrna&#xff09;的多模态…

【论文分享】基于街景图像识别和深度学习的针对不同移动能力老年人的街道步行可达性研究——以南京成贤街社区为例

全球老龄化趋势加剧, 许多城市中老年人数量不断增加&#xff0c;而现有街道和社区基础设施往往未能满足其步行安全和便利需求。本次我们给大家带来一篇SCI论文的全文翻译&#xff0c;该论文通过探讨不同步行能力的老年人对城市步行环境的需求&#xff0c;提供了关于如何改善城市…

Android Osmdroid + 天地图 (二)

Osmdroid 天地图 &#xff08;二&#xff09; 前言正文一、定位监听二、改变地图中心三、添加Marker四、地图点击五、其他配置① 缩放控件② Marker更换图标③ 添加比例尺④ 添加指南针⑤ 添加经纬度网格线⑥ 启用旋转手势⑦ 添加小地图 六、源码 前言 上一篇中我们显示了地图…

CSS基础知识04

文本溢出通常是指在限定的空间内不能容纳所输入的文字&#xff0c;导致文字超出了容器的边界 一、文本溢出 1.1.css属性处理 所用到的属性 属性属性值overflowvisible&#xff1a;默认值&#xff0c;内容不会被修剪&#xff0c;会呈现在元素框之外。hidden&#xff1a;内容会…

gitlab和jenkins连接

一&#xff1a;jenkins 配置 安装gitlab插件 生成密钥 id_rsa 要上传到jenkins&#xff0c;id_rsa.pub要上传到gitlab cat /root/.ssh/id_rsa 复制查看的内容 可以看到已经成功创建出来了对于gitlab的认证凭据 二&#xff1a;配置gitlab cat /root/.ssh/id_rsa.pub 复制查…

Modbus TCP转Modbus ASCII解决方案

Modbus TCP和Modbus ASCII是两种不同的通信协议。Modbus TCP是一种二进制协议&#xff0c;Modbus ASCII是一种基于文本的协议。二者不能直接转换&#xff0c;因为它们的数据表示方式、消息结构、字符编码等都不相同。 如果你需要将Modbus TCP转换为Modbus ASCII&#xff0c;你…

十三、注解配置SpringMVC

文章目录 1. 创建初始化类&#xff0c;代替web.xml2. 创建SpringConfig配置类&#xff0c;代替spring的配置文件3. 创建WebConfig配置类&#xff0c;代替SpringMVC的配置文件4. 测试功能 1. 创建初始化类&#xff0c;代替web.xml 2. 创建SpringConfig配置类&#xff0c;代替spr…

全新升级!立迈胜STMP57系列防水一体化步进伺服电机:IP65+多圈绝对值编码器+EtherCAT通信+内置刹车

在这个科技日新月异的时代&#xff0c;每一步创新都意味着行业的一次飞跃。 回想当初&#xff0c;我们做防水电机的初衷只是因为客户的应用场景涉水&#xff0c;从而定做了IP65防护等级的一体式电机。 后来发现很多客户也有类似的需求&#xff0c;比如机械加工、户外照明、自…

5G CPE:为什么活动会场与商铺的网络成为最新选择

在快节奏的现代社会中&#xff0c;无论是举办一场盛大的活动还是经营一家繁忙的商铺&#xff0c;稳定的网络连接都是不可或缺的基石。然而&#xff0c;面对复杂的布线难题或高昂的商业宽带费用&#xff0c;许多场所往往陷入两难境地。幸运的是&#xff0c;5G CPE&#xff08;Cu…

React-redux 实战案例,自定义useSelector

创建一个新的 React 工程&#xff0c;并配置 Redux 和 Ant Design&#xff0c;你可以按以下步骤操作。我将使用 create-react-app 脚手架工具来快速创建一个基于 TypeScript 的 React 项目 1. 创建新项目 使用 create-react-app 创建一个新的 React 项目&#xff0c;带 TypeS…

【C++】list 类深度解析:探索双向链表的奇妙世界

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 如果你对string&#xff0c;vector还存在疑惑&#xff0c;欢迎阅读我之前的作品 &#xff1a; 之前文章&#x1f525;&#x1…