22. SpringBoot+Vue实现Echarts数据报表(柱状图、饼图、折线图)
Echarts 官网:https://echarts.apache.org/examples/zh/index.html#chart-type-line
Vue 安装 Echarts
npm i echarts -S
完整示例代码:

静态图表的 Vue 代码示例
<template>
<div>
<el-row :gutter="10">
<el-col :span="12">
<el-card>
<div style="width: 100%; height: 400px" id="line"></div>
</el-card>
</el-col>
<el-col :span="12">
<el-card>
<div style="width: 100%; height: 400px" id="bar"></div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="10" style="margin: 10px 0">
<el-col :span="12">
<el-card>
<div style="width: 100%; height: 400px" id="pie"></div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import * as echarts from 'echarts'
const option = {
title: {
text: '订单销售的趋势图',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
name: '金额',
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
smooth: true
},
{
name: '库存',
data: [356, 987, 457, 768, 390, 680, 1920],
type: 'line',
smooth: true
}
]
}
const option1 = {
title: {
text: '订单销售的柱状图',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
data: ['水果', '零食', '饮料', '奶制品', '生活用品']
},
yAxis: {
type: 'value'
},
series: [
{
name: '金额',
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'bar',
smooth: true
},
{
name: '销量',
data: [100, 200, 204, 209, 590, 698, 700],
type: 'bar',
smooth: true
}
]
}
const option2 = {
title: {
text: '订单销售统计',
subtext: '比例图',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: 'Access From',
type: 'pie',
center: ['50%', '60%'],
radius: '50%',
data: [
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' },
{ value: 484, name: 'Union Ads' },
{ value: 300, name: 'Video Ads' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
export default {
name: "Charts",
data() {
return {}
},
mounted() { // 等待页面的元素全部加载完成之后再初始化
// 折线图
let linetDom = document.getElementById('line');
let lineChart = echarts.init(linetDom);
lineChart.setOption(option)
// 柱状图
let barDom = document.getElementById('bar');
let barChart = echarts.init(barDom);
barChart.setOption(option1)
// 饼图
let pieDom = document.getElementById('pie');
let pieChart = echarts.init(pieDom);
pieChart.setOption(option2)
},
methods: {}
}
</script>
<style scoped>
</style>
orders 表结构
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '订单编号',
`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '订单名称',
`money` decimal(10,2) DEFAULT NULL COMMENT '订单金额',
`userid` int(11) DEFAULT NULL COMMENT '用户ID',
`category` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '订单分类',
`date` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '订单日期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单表';
Order.java
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Orders {
@TableId(type = IdType.AUTO)
private Integer id;
private String no;
private String name;
private BigDecimal money;
private Integer userid;
private String category;
private String date;
@TableField(exist = false)
private String user;
}
OrdersController.java
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.springboot.common.HoneyLogs;
import com.example.springboot.common.LogType;
import com.example.springboot.common.Result;
import com.example.springboot.entity.Orders;
import com.example.springboot.entity.User;
import com.example.springboot.service.OrdersService;
import com.example.springboot.service.UserService;
import com.example.springboot.utils.TokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/orders")
public class OrdersController {
@Autowired
OrdersService ordersService;
@Autowired
UserService userService;
/**
* 新增信息
*/
@HoneyLogs(operation = "订单", type = LogType.ADD)
@PostMapping("/add")
public Result add(@RequestBody Orders orders) {
User currentUser = TokenUtils.getCurrentUser(); // 获取到当前登录的用户信息
orders.setUserid(currentUser.getId());
orders.setDate(DateUtil.today()); // 2023-10-08
orders.setNo(IdUtil.fastSimpleUUID());
ordersService.save(orders);
return Result.success();
}
/**
* 修改信息
*/
@HoneyLogs(operation = "订单", type = LogType.UPDATE)
@PutMapping("/update")
public Result update(@RequestBody Orders orders) {
ordersService.updateById(orders);
return Result.success();
}
/**
* 删除信息
*/
@HoneyLogs(operation = "订单", type = LogType.DELETE)
@DeleteMapping("/delete/{id}")
public Result delete(@PathVariable Integer id) {
ordersService.removeById(id);
return Result.success();
}
/**
* 批量删除信息
*/
@HoneyLogs(operation = "订单", type = LogType.BATCH_DELETE)
@DeleteMapping("/delete/batch")
public Result batchDelete(@RequestBody List<Integer> ids) {
ordersService.removeBatchByIds(ids);
return Result.success();
}
/**
* 查询全部信息
*/
@GetMapping("/selectAll")
public Result selectAll() {
List<Orders> ordersList = ordersService.list(new QueryWrapper<Orders>().orderByDesc("id"));
return Result.success(ordersList);
}
/**
* 根据ID查询信息
*/
@GetMapping("/selectById/{id}")
public Result selectById(@PathVariable Integer id) {
Orders orders = ordersService.getById(id);
User user = userService.getById(orders.getUserid());
if (user != null) {
orders.setUser(user.getName());
}
return Result.success(orders);
}
/**
* 多条件模糊查询信息
* pageNum 当前的页码
* pageSize 每页查询的个数
*/
@GetMapping("/selectByPage")
public Result selectByPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize,
@RequestParam String name) {
QueryWrapper<Orders> queryWrapper = new QueryWrapper<Orders>().orderByDesc("id"); // 默认倒序,让最新的数据在最上面
queryWrapper.like(StrUtil.isNotBlank(name), "name", name);
Page<Orders> page = ordersService.page(new Page<>(pageNum, pageSize), queryWrapper);
List<Orders> records = page.getRecords();
for (Orders record : records) {
Integer authorid = record.getUserid();
User user = userService.getById(authorid);
if (user != null) {
record.setUser(user.getName());
}
}
return Result.success(page);
}
}
WebController 统计数据方法
/**
* 获取统计图数据
* @return 动态数据
*/
@GetMapping("/charts")
public Result charts() {
// 包装折线图的数据
List<Orders> list = ordersService.list();
Set<String> dates = list.stream().map(Orders::getDate).collect(Collectors.toSet());
List<String> dateList = CollUtil.newArrayList(dates);
dateList.sort(Comparator.naturalOrder());
List<Dict> lineList = new ArrayList<>();
for (String date : dateList) {
// 统计当前日期的所有金额总数和
BigDecimal sum = list.stream().filter(orders -> orders.getDate().equals(date)).map(Orders::getMoney)
.reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
Dict dict = Dict.create();
Dict line = dict.set("date", date).set("value", sum);
lineList.add(line);
}
// 柱状图数据
List<Dict> barList = new ArrayList<>();
Set<String> categories = list.stream().map(Orders::getCategory).collect(Collectors.toSet());
for (String cate : categories) {
// 统计当前日期的所有金额总数和
BigDecimal sum = list.stream().filter(orders -> orders.getCategory().equals(cate)).map(Orders::getMoney)
.reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
Dict dict = Dict.create();
Dict bar = dict.set("name", cate).set("value", sum);
barList.add(bar);
}
// 包装所有数据
Dict res = Dict.create().set("line", lineList).set("bar", barList);
return Result.success(res);
}
动态图表 Vue
<template>
<div>
<el-row :gutter="10">
<el-col :span="12">
<el-card>
<div style="width: 100%; height: 400px" id="line"></div>
</el-card>
</el-col>
<el-col :span="12">
<el-card>
<div style="width: 100%; height: 400px" id="bar"></div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="10" style="margin: 10px 0">
<el-col :span="12">
<el-card>
<div style="width: 100%; height: 400px" id="pie"></div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import * as echarts from 'echarts'
const option = {
title: {
text: '订单销售的趋势图',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
data: []
},
yAxis: {
type: 'value'
},
series: [
{
name: '金额',
data: [],
type: 'line',
smooth: true
},
]
}
const option1 = {
title: {
text: '订单销售的柱状图',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
data: []
},
yAxis: {
type: 'value'
},
series: [
{
name: '金额',
data: [],
type: 'bar',
smooth: true
}
]
}
const option2 = {
title: {
text: '订单销售统计',
subtext: '比例图',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '金额',
type: 'pie',
center: ['50%', '60%'],
radius: '50%',
data: [],
label: {
show: true,
formatter(param) {
return param.name + ' (' + param.percent + '%)';
}
},
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
export default {
name: "Charts",
data() {
return {}
},
mounted() { // 等待页面的元素全部加载完成之后再初始化
// 折线图
let linetDom = document.getElementById('line');
let lineChart = echarts.init(linetDom);
// 柱状图
let barDom = document.getElementById('bar');
let barChart = echarts.init(barDom);
barChart.setOption(option1)
// 饼图
let pieDom = document.getElementById('pie');
let pieChart = echarts.init(pieDom);
pieChart.setOption(option2)
this.$request.get('/charts').then(res => {
// 折线
option.xAxis.data = res.data?.line?.map(v => v.date) || []
option.series[0].data = res.data?.line?.map(v => v.value) || []
lineChart.setOption(option)
// 柱状图
option1.xAxis.data = res.data?.bar?.map(v => v.name) || []
option1.series[0].data = res.data?.bar?.map(v => v.value) || []
barChart.setOption(option1)
// 饼图
option2.series[0].data = res.data?.bar || []
pieChart.setOption(option2)
})
},
methods: {}
}
</script>
<style scoped>
</style>