Apache ECharts

Apache ECharts介绍:

Apache ECharts 是一款基于 Javascript 的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。

官网地址:https://echarts.apache.org/zh/index.html

Apache ECharts入门程序:

进入官网,按照官方给的步骤:

html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>ECharts</title>
    <!-- 引入刚刚下载的 ECharts 文件 -->
    <script src="echarts.js"></script>
  </head>
  <body>
    <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
      // 基于准备好的dom,初始化echarts实例
      var myChart = echarts.init(document.getElementById('main'));

      // 指定图表的配置项和数据
      var option = {
        title: {
          text: 'ECharts 入门示例'
        },
        tooltip: {},
        legend: {
          data: ['销量']
        },
        xAxis: {
          data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
        },
        yAxis: {},
        series: [
          {
            name: '销量',
            type: 'bar',
            data: [5, 20, 36, 10, 10, 20]
          }
        ]
      };

      // 使用刚指定的配置项和数据显示图表。
      myChart.setOption(option);
    </script>
  </body>
</html>

营业额统计:

业务规则及接口设计:

  • 营业额指订单状态为已完成的订单金额合计
  • 基于可视化报表的折线图展示营业额数据,X轴为日期,Y轴为营业额
  • 根据时间选择区间,展示每天的营业额数据

前端想展示数据,也要设计接口从后端获取数据。

返回数据这一块,因为是前端来展示数据,所以我们提供的数据是要依照前端的规则。

具体代码实现:

Controll层:

java 复制代码
@Autowired
    private ReportService reportService;

    /**
     * 营业额统计
     * @param begin
     * @param end
     * @return
     */
    @GetMapping("/turnoverStatistics")
    @ApiOperation("营业额统计")
    public Result<TurnoverReportVO> turnoverStatistics(
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("营业额统计");
        TurnoverReportVO turnoverReportVO = reportService.turnoverStatistics(begin,end);
        return Result.success(turnoverReportVO);
    }

这里有个小细节,就是查询统计营业额,前端传的参数是日期的起始时间和结束时间,

格式是yyyy-MM-dd这种形式,所以,我们也要用这种形式来进行接收。

@DateTimeFormat(pattern = "yyyy-MM-dd"),就用到了这个方法。

Service层:

java 复制代码
package com.sky.service.impl;

import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.service.ReportService;
import com.sky.vo.TurnoverReportVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.constraints.Min;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ReportServiceImpl implements ReportService {

    @Autowired
    private OrderMapper orderMapper;

    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        //封装TurnoverReportVO的dateList对象
        List<LocalDate> datelist = new ArrayList<>();
        datelist.add(begin);
        while(!begin.equals(end)){
            //将日期加到list集合中
            begin = begin.plusDays(1);
            datelist.add(begin);
        }
        String datejoin = StringUtils.join(datelist, ",");
        //封装TurnoverReportVO的turnoverList对象
        List<Double> turnoverlist = new ArrayList<>();
        for (LocalDate localDate : datelist) {
            //查询date日期对应的营业额数据,营业额是指:状态为"已完成"的订单金额合计
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate,LocalTime.MAX);
            //select sum(amount) from orders where order_time > ? and order_time < ? and status = 5
            Map map = new HashMap();
            map.put("begin",beginTime);
            map.put("end",endTime);
            map.put("status", Orders.COMPLETED);
            Double turnover = orderMapper.TurnoverOfSum(map);
            turnover = turnover==null?0.0:turnover;
            turnoverlist.add(turnover);
        }
        for (Double v : turnoverlist) {
            System.out.println("今日份营业额:"+ v);
        }
        //封装TurnoverReportVO对象
        TurnoverReportVO turnoverReportVO = new TurnoverReportVO();
        turnoverReportVO.setDateList(datejoin);
        turnoverReportVO.setTurnoverList(StringUtils.join(turnoverlist,","));
        return  turnoverReportVO;
    }
}
思路:

我们观察TurnoverReportVO对象里面有两个值,dateList,turnoverList

一个是日期列表,一个是营业额列表。

我们观察前端页面也能看成

横坐标:是日期 纵坐标:是营业额。

所以我们Service层的思路就很简单了

1:封装dateList对象

创建一个LocalDate的列表,然后通过LocalDate提供的库函数plusDay,将日期由begin一直加到end,并且TurnoverReportVO对象中的dateList对象是一个String,所以我们再调用String.utils的方法对这个列表进行逗号分割。

2:封装turnoverList对象

我们已经有了每一天的日期了,我们需要每一天的营业额(当然这里也不一定是每一天的,我们前端界面是可以选择的,有可能是一周,也有可能是一个月)。

这个turnoverList对象的封装就需要查询数据库了

select sum(amout) from orders where order_time > ? and order_time < ? and status = 5

我们创建一个map对象里面有beginTime,endTime,status,然后传到mapper层,查询数据中的数据。

3:最后再封装TurnoverReportVO对象返回。

Mapper层及注解:

java 复制代码
/**
     * 动态查询营业额
     * @param map
     * @return
     */
    Double TurnoverOfSum(Map map);
java 复制代码
<select id="TurnoverOfSum" resultType="java.lang.Double">
        select sum(amount) from sky_take_out.orders
        <where>
            <if test="begin != null">and order_time &gt; #{begin}</if>
            <if test="end != null">and order_Time &lt; #{end}</if>
            <if test="status != null"> and status = #{status} </if>
        </where>
    </select>

用户统计:

业务规则及接口设计:

业务规则:

  • 基于可视化报表的折线图展示用户数据,X轴为日期,Y轴为用户数
  • 根据时间选择区间,展示每天的用户总量和新增用户量数据

用户统计和上面的不同点就是我们的返回值有三个列表:

  • dateList
  • newUserList
  • totalUserList

具体代码实现:

整体的思路和上面的营业额统计差不多

Controll层:

java 复制代码
/**
     * 用户数量统计
     * @param begin
     * @param end
     * @return
     */
    @GetMapping("/userStatistics")
    @ApiOperation("用户数量统计")
    public Result<UserReportVO> userStatistics(
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
            log.info("用户数量统计");
            UserReportVO userReportVO = reportService.userStatistics(begin,end);
            return Result.success(userReportVO);
    }

Service层:

java 复制代码
    /**
     * 用户数量统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        //封装UserReportVO的dateList对象
        List<LocalDate> dateList = new ArrayList<>();
        while (!begin.equals(end)){
            dateList.add(begin);
            begin = begin.plusDays(1);
        }
        String datejoin = StringUtils.join(dateList, ",");
        //封装UserReportVO的totalUserList对象
        //select count(id) from user where create_time < endTime
        //封装UserReportVO的newUserList对象
        //select count(id) from user where create_time > beginTime and create_time < endTime
        List<Integer> totalUserList =  new ArrayList<>();
        List<Integer> newUserList = new ArrayList<>();
        for (LocalDate date : dateList) {
            LocalDateTime beginTime = LocalDateTime.of(date,LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(date,LocalTime.MAX);
            Map map = new HashMap();
            map.put("end",endTime);
            Integer totalUser = userMapper.UserofSum(map);
            map.put("begin",beginTime);
            Integer newUser = userMapper.UserofSum(map);
            totalUserList.add(totalUser);
            newUserList.add(newUser);
        }
        String totaluserjoin = StringUtils.join(totalUserList, ",");
        String newluserjoin = StringUtils.join(newUserList, ",");
        UserReportVO userReportVO = new UserReportVO();
        userReportVO.setDateList(datejoin);
        userReportVO.setTotalUserList(totaluserjoin);
        userReportVO.setNewUserList(newluserjoin);
        return userReportVO;
    }

这里Service层的业务就是封装三个列表

要想封装这个用户,我们需要去调userMapper

我们想要知道总共的用户的sql是:

//select count(id) from user where create_time < endTime

截至到这个end时间时候的用户数量。

而新增用户的sql是:

//select count(id) from user where create_time > beginTime and create_time < endTime

我们要给这个新增确定一个日期范围。

userMapper及注解:

java 复制代码
Integer UserofSum(Map map);
java 复制代码
<select id="UserofSum" resultType="java.lang.Integer">
        select count(id) from sky_take_out.user
        <where>
            <if test="begin != null">and create_time > #{begin}</if>
            <if test="end != null">and create_time &lt; #{end}</if>
        </where>
    </select>

订单统计:

业务规则及接口设计:

业务规则:

  • 有效订单指状态为 "已完成" 的订单
  • 基于可视化报表的折线图展示订单数据,X轴为日期,Y轴为订单数量
  • 根据时间选择区间,展示每天的订单总数和有效订单数
  • 展示所选时间区间内的有效订单数、总订单数、订单完成率,订单完成率 = 有效订单数 / 总订单数 * 100%

具体的代码实现:

Controll层:

java 复制代码
    /**
     * 订单统计
     * @param begin
     * @param end
     * @return
     */
    @GetMapping("/ordersStatistics")
    @ApiOperation("订单统计")
    public Result<OrderReportVO> orderStatistics(
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("订单统计");
        OrderReportVO orderReportVO = reportService.ordersStatistics(begin,end);
        return Result.success(orderReportVO);
    }

Service层:

java 复制代码
/**
     * 订单统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        //封装OrderReportVO的dateList对象
        List<LocalDate> dateList = new ArrayList<>();
        while (!begin.equals(end)){
            dateList.add(begin);
            begin = begin.plusDays(1);
        }
        String datejoin = StringUtils.join(dateList, ",");
        //封装OrderReportVO的orderCountList对象
        //封装OrderReportVO的validOrderCountList对象
        List<Integer> orderCountList = new ArrayList<>();
        List<Integer> validOrderCountList = new ArrayList<>();
        for (LocalDate date : dateList) {
            LocalDateTime beginTime = LocalDateTime.of(date,LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(date,LocalTime.MAX);
            Map map = new HashMap();
            map.put("begin",beginTime);
            map.put("end",endTime);
            Integer totalorders = orderMapper.OrdersofSum(map);
            map.put("status",Orders.COMPLETED);
            Integer validorders = orderMapper.OrdersofSum(map);
            orderCountList.add(totalorders);
            validOrderCountList.add(validorders);
        }
        String totaljoin = StringUtils.join(orderCountList, ",");
        String validjoin = StringUtils.join(validOrderCountList,",");

        //计算时间区间内的订单总数量
        Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();
        //计算时间区间内的有效订单数量
        Integer validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();

        //计算订单完成率
        Double orderCompletionRate  = 0.0;
        if(totalOrderCount!=0){
            orderCompletionRate = validOrderCount.doubleValue()/totalOrderCount.doubleValue();
        }

        OrderReportVO orderReportVO = new OrderReportVO();
        orderReportVO.setDateList(datejoin);
        orderReportVO.setOrderCountList(totaljoin);
        orderReportVO.setValidOrderCountList(validjoin);
        orderReportVO.setTotalOrderCount(totalOrderCount);
        orderReportVO.setValidOrderCount(validOrderCount);
        orderReportVO.setOrderCompletionRate(orderCompletionRate);
        return orderReportVO;
    }

Mapper层及注解:

java 复制代码
     /**
     * 订单统计
     * @param map
     * @return
     */
    Integer OrdersofSum(Map map);
java 复制代码
<select id="OrdersofSum" resultType="java.lang.Integer">
        select count(id) from sky_take_out.orders
            <where>
                <if test="begin != null">and order_time > #{begin}</if>
                <if test="end != null">and order_Time &lt; #{end}</if>
                <if test="status != null">and status=#{status}</if>
            </where>
    </select>

销量排名统计(TOP10):

业务规则及接口设计:

业务规则:

  • 根据时间选择区间,展示销量前10的商品(包括菜品和套餐)
  • 基于可视化报表的柱状图降序展示商品销量
  • 此处的销量为商品销售的份数

具体的代码实现:

Controll层:

java 复制代码
/**
     * TOP10销量统计
     * @param begin
     * @param end
     * @return
     */
    @GetMapping("/top10")
    @ApiOperation("TOP10销量统计")
    public Result<SalesTop10ReportVO> Top10Statostics(
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("TOP10销量统计");
        SalesTop10ReportVO salesTop10ReportVO = reportService.Top10Statostics(begin,end);
        return Result.success(salesTop10ReportVO);
    }

Service层:

java 复制代码
    /**
     * TOP10销量统计
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO Top10Statostics(LocalDate begin, LocalDate end) {
        LocalDateTime beginTime = LocalDateTime.of(begin,LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end,LocalTime.MAX);
        System.out.println("开始时间是:"+beginTime);
        System.out.println("结束时间是:"+endTime);
        List<GoodsSalesDTO> goodsSalesDTOList = orderMapper.GetTop10(beginTime,endTime);
        List<String> names = goodsSalesDTOList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
        String nameList = StringUtils.join(names, ",");
        List<Integer> numbers = goodsSalesDTOList.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());
        String numberList = StringUtils.join(numbers, ",");
        SalesTop10ReportVO salesTop10ReportVO = new SalesTop10ReportVO();
        salesTop10ReportVO.setNameList(nameList);
        salesTop10ReportVO.setNumberList(numberList);
        return salesTop10ReportVO;
    }

这题的从sql语句开始分析比较简单

sql 复制代码
select od.name,sum(od.number) number from order_detail od,orders o
where od.order_id = o.id and o.status = 5 and o.order_time < 2024-05-04 and o.order_time > 2024-05-10
group by od.name
order by number desc
limit 0,10

根据传入的时间范围来获取数据。

Mapper层及注解:

java 复制代码
    /**
     * TOP10销量统计
     * @param beginTime
     * @param endTime
     * @return
     */
    List<GoodsSalesDTO> GetTop10(LocalDateTime beginTime, LocalDateTime endTime);
java 复制代码
<select id="GetTop10" resultType="com.sky.dto.GoodsSalesDTO">
        select od.name,sum(od.number) number
        from sky_take_out.order_detail od,sky_take_out.orders o
        where od.order_id = o.id and o.status = 5
        <if test="beginTime != null">and o.order_time > #{beginTime}</if>
        <if test="endTime != null">and o.order_Time &lt; #{endTime}</if>
        group by od.name
        order by number desc
        limit 0,10
    </select>

结果展示:

相关推荐
bysking23 分钟前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓39 分钟前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_41142 分钟前
无网络安装ionic和运行
前端·npm
理想不理想v43 分钟前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云1 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
微信:137971205871 小时前
web端手机录音
前端
齐 飞1 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
神仙别闹1 小时前
基于tensorflow和flask的本地图片库web图片搜索引擎
前端·flask·tensorflow
aPurpleBerry2 小时前
JS常用数组方法 reduce filter find forEach
javascript
GIS程序媛—椰子2 小时前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js