Echarts本质
不管是哪种形式的图形,最本质的东西实际上是数据,它其实是对数据的一种可视化展示。使用Echarts,重点在于研究当前图表所需的数据格式。通常是需要后端提供符合格式要求的动态数据,然后响应给前端来展示图表。
具体返回数据一般由前端来决定,前端展示图表,具体折现图对应数据是什么格式,是有固定的要求的。 所以说,后端需要去适应前端,它需要什么格式的数据,我们就给它返回什么格式的数据。
营业额统计
根据接口设计VO,VO略。
// controller
@GetMapping("/turnoverStatistics")
@ApiOperation("营业额销售统计")
public Result<TurnoverReportVO> turnoverStatistics(
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end
) {
return Result.success(reportService.getTurnover(begin, end));
}
// service
TurnoverReportVO getTurnover(LocalDate beginTime, LocalDate endTime);
// impl
public TurnoverReportVO getTurnover(LocalDate begin, LocalDate end) {
// 当前集合用于存放从begin到end范围内的每天的日期
List<LocalDate> dateList = new ArrayList<>();
dateList.add(begin);
while (!begin.equals(end)) {
// 日期计算,获得指定日期后1天的日期
begin = begin.plusDays(1);
dateList.add(begin);
}
// 存放每天的营业额
List<Double> turnoverList = new ArrayList<>();
// 将集合中每个元素取出
for (LocalDate date : dateList) {
// 获取具体时刻(LocalDate 与 LocalDateTime 表示不同)
LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
Map map = new HashMap();
map.put("status", Orders.COMPLETED); // 状态:已完成
map.put("begin", beginTime);
map.put("end", endTime);
Double turnover = orderMapper.sumByMap(map);
turnover = turnover == null ? 0.0 :turnover; // turnover 如果为空就显示 0.0 不为空就显示自己
turnoverList.add(turnover);
}
// 将集合元素取出进行数据封装
return TurnoverReportVO
.builder()
.dateList(StringUtils.join(dateList,",")) // 注意这里需要使用的是 Apache Commons Lang 的 StringUtils.join
.turnoverList(StringUtils.join(turnoverList,","))
.build();
}
// mapper
Double sumByMap(Map map);
// xml
<select id="sumByMap" resultType="java.lang.Double">
select sum(amount) from orders
<where>
<if test = "status != null">
and status = #{status}
</if>
<if test = "begin != null">
and order_time >= #{begin} <!-- 大于符号的转义字符 -->
</if>
<if test = "end != null">
and order_time <= #{end} <!-- 小于符号的转义字符 -->
</if>
</where>
</select>
用户统计
根据接口设计VO,VO略。
// controller
@GetMapping("/userStatistics")
@ApiOperation("用户数据统计")
public Result<UserReportVO> userStatistics(
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
return Result.success(reportService.getUserStatistics(begin, end));
}
// service
UserReportVO getUserStatistics(LocalDate begin, LocalDate end);
// impl
/**
* 根据时间区间统计用户数量
* @param begin
* @param end
* @return
*/
@Override
public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
List<LocalDate> dateList = new ArrayList<>();
dateList.add(begin);
while (!begin.equals(end)) {
begin = begin.plusDays(1);
dateList.add(begin);
}
List<Integer> newUserList = new ArrayList<>(); // 新增用户数
List<Integer> totalUserList = new ArrayList<>(); // 总用户数
for (LocalDate date : dateList) {
LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
// 新增用户数量 select count(id) from user where create_time > ? and create_time < ?
Integer newUser = getUserCount(beginTime, endTime);
// 总用户数量 select count(id) from user where create_time < ?
Integer totalUser = getUserCount(null, endTime);
newUserList.add(newUser);
totalUserList.add(totalUser);
}
return UserReportVO.builder()
.dateList(StringUtils.join(dateList, ","))
.newUserList(StringUtils.join(newUserList, ","))
.totalUserList(StringUtils.join(totalUserList, ","))
.build();
}
/**
* 根据时间区间统计用户数量
* @param beginTime
* @param endTime
* @return
*/
private Integer getUserCount(LocalDateTime beginTime, LocalDateTime endTime) {
Map map = new HashMap();
map.put("begin", beginTime);
map.put("end", endTime);
return userMapper.countByMap(map);
}
// mapper
Integer countByMap(Map map);
// xml
<select id="countByMap" resultType="java.lang.Integer">
select count(id) from user
<where>
<if test="begin != null">
and create_time >= #{begin}
</if>
<if test="end != null">
and create_time <= #{end}
</if>
</where>
</select>
订单统计
根据接口设计VO,VO略。
// controller
@GetMapping("/ordersStatistics")
@ApiOperation("订单数据统计")
public Result<OrderReportVO> orderStatistics(
@DateTimeFormat(pattern = "yyyy-MM-dd")
LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd")
LocalDate end){
return Result.success(reportService.getOrderStatistics(begin,end));
}
// service
OrderReportVO getOrderStatistics(LocalDate begin, LocalDate end);
// impl
public OrderReportVO getOrderStatistics(LocalDate begin, LocalDate end) {
List<LocalDate> dateList = new ArrayList<>();
dateList.add(begin);
while(!begin.equals(end)) {
begin = begin.plusDays(1);
dateList.add(begin);
}
// 每天订单总数集合
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);
// 查询每天的总订单数 select count(id) from orders where order_time > ? and order_time < ?
Integer orderCount = getOrderCount(beginTime, endTime, null);
// 查询每天的有效订单数 select count(id) from orders where order_time > ? and order_time < ? and status = ?
Integer validOrderCount = getOrderCount(beginTime, endTime, Orders.COMPLETED);
orderCountList.add(orderCount);
validOrderCountList.add(validOrderCount);
}
// 时间区间内的总订单数
Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get(); // 使用stream流,然后将集合里的元素遍历求和
// 时间区间内的总有效订单数
Integer validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();
// 订单完成率
Double orderCompletionRate = 0.0;
if(totalOrderCount != 0) {
orderCompletionRate = validOrderCount.doubleValue() / totalOrderCount;
}
return OrderReportVO.builder()
.dateList(StringUtils.join(orderCountList,","))
.orderCountList(StringUtils.join(orderCountList,","))
.validOrderCountList(StringUtils.join(validOrderCountList, ","))
.totalOrderCount(totalOrderCount)
.validOrderCount(validOrderCount)
.orderCompletionRate(orderCompletionRate)
.build();
}
/**
* 根据时间区间统计指定状态的订单数量
*/
private Integer getOrderCount(LocalDateTime beginTime, LocalDateTime endTime, Integer status) {
Map map = new HashMap();
map.put("status", status);
map.put("begin",beginTime);
map.put("end", endTime);
return orderMapper.countByMap(map);
}
// mapper
Integer countByMap(Map map);
// xml
<select id="countByMap" resultType="java.lang.Integer">
select count(id) from orders
<where>
<if test="status != null">
and status = #{status}
</if>
<if test="begin != null">
and order_time >= #{begin}
</if>
<if test="end != null">
and order_time <= #{end}
</if>
</where>
</select>
销量排名Top10
根据接口设计VO,VO略。
// controller
@GetMapping("/top10")
@ApiOperation("销量排名统计")
public Result<SalesTop10ReportVO> top10(
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
return Result.success(reportService.getSalesTop10(begin,end));
}
// service
SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end);
// impl
public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end) {
LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
List<GoodsSalesDTO> goodsSalesDTOList = orderMapper.getSalesTop10(beginTime, endTime);
// 商品名称列表,以逗号分隔
String nameList = StringUtils.join(goodsSalesDTOList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList()),",");
// 销量列表,以逗号分隔
String numberList = StringUtils.join(goodsSalesDTOList.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList()),",");
return SalesTop10ReportVO.builder()
.nameList(nameList)
.numberList(numberList)
.build();
}
// mapper
List<GoodsSalesDTO> getSalesTop10(LocalDateTime beginTime, LocalDateTime endTime);
// xml
<!--
SELECT od.name AS name, SUM(od.number) AS number
FROM order_detail od
JOIN orders o ON od.order_id = o.id
WHERE o.status = 5
AND o.order_time >= '2024-07-01'
AND o.order_time <= '2025-07-01'
GROUP BY od.name
ORDER BY number DESC
LIMIT 0, 10;
-->
<select id="getSalesTop10" resultType="com.sky.dto.GoodsSalesDTO">
select od.name name,sum(od.number) number from order_detail od ,orders o
where od.order_id = o.id
and o.status = 5
<if test="begin != null">
and order_time >= #{begin}
</if>
<if test="end != null">
and order_time <= #{end}
</if>
group by name
order by number desc
limit 0, 10
</select>