文章目录
- 1、用户统计
- 2、订单统计
- 3、销量排名Top10
 
 
 
1、用户统计
所谓用户统计,实际上统计的是用户的数量。通过折线图来展示,上面这根蓝色线代表的是用户总量,下边这根绿色线代表的是新增用户数量,是具体到每一天。所以说用户统计主要统计两个数据,一个是总的用户数量,另外一个是新增用户数量。
原型图:
 
 
业务规则:
- 基于可视化报表的折线图展示用户数据,X轴为日期,Y轴为用户数
- 根据时间选择区间,展示每天的用户总量和新增用户量数据
接口设计
根据上述原型图设计接口。
 
 
VO设计
根据用户统计接口的返回结果设计VO
 
 
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserReportVO implements Serializable {
    //日期,以逗号分隔,例如:2022-10-01,2022-10-02,2022-10-03
    private String dateList;
    //用户总量,以逗号分隔,例如:200,210,220
    private String totalUserList;
    //新增用户,以逗号分隔,例如:20,21,10
    private String newUserList;
}
根据接口定义,在ReportController中创建userStatistics方法
    /**
     * 用户统计
     * @param begin
     * @param end
     * @return
     */
    @ApiOperation("用户统计")
    @GetMapping("/userStatistics")
    public Result<UserReportVO> userStatistics(
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("营业额统计:{},{}",begin,end);
        //调用业务获取用户统计数据
        UserReportVO userReportVO = reportService.getUserStatistics(begin,end);
        return Result.success(userReportVO);
    }
在ReportService接口中声明getUserStatistics方法
    /**
     * 用户统计数据
     * @param begin
     * @param end
     * @return
     */
    UserReportVO getUserStatistics(LocalDate begin, LocalDate end);
在ReportServiceImpl实现类中实现getUserStatistics方法
    /**
     * 用户统计数据
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
        //目标获取用户统计数据:用户每天总数量,每天新增数量 、 每天日期列表
        //获取每天新增用户数量
            //select count(*) from user where create_time >= 当天最小时间 and create_time <= 当天最大时间
        //获取每天用户总数量
            //select count(*) from user where create_time <= 当天最大时间
        //1、根据开始日期与结束日期生成每天日期集合列表
        List<LocalDate> dateList = getDateList(begin, end);
        //2、定义存储每天新增用户 和 每天新增用户集合
        ArrayList<Integer> createUserList = new ArrayList<>();
        ArrayList<Integer> totalUserList = new ArrayList<>();
        //3、遍历日期列表,每天数据
        for (LocalDate date : dateList) {
            //定义每天最大时间和最小时间
            LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(date,LocalTime.MAX);
            //执行sql
            //将参数封装到map里
            Map<String,Object> map = new HashMap<>();
            //查询总用户
            map.put("endTime",endTime);
            Integer totalUser = userMapper.countByMap(map);
            totalUser = totalUser == null ? 0 : totalUser;
            totalUserList.add(totalUser);
            //查询新增用户,只需要再加一个开始条件
            map.put("beginTime",beginTime);
            Integer createUser = userMapper.countByMap(map);
            createUser = createUser == null ? 0 : createUser;
            createUserList.add(createUser);
        }
        //封装返回数据
        return UserReportVO.builder()
                .dateList(StringUtils.join(dateList,","))
                .totalUserList(StringUtils.join(totalUserList,","))
                .newUserList(StringUtils.join(createUserList,","))
                .build();
    }
在UserMapper接口中声明countByMap方法
	/**
     * 根据动态条件统计用户数量
     * @param map
     * @return
     */
    Integer countByMap(Map map);
在UserMapper.xml文件中编写动态SQL
<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>
2、订单统计
订单统计通过一个折现图来展现,折线图上有两根线,这根蓝色的线代表的是订单总数,而下边这根绿色的线代表的是有效订单数,指的就是状态是已完成的订单就属于有效订单,分别反映的是每一天的数据。上面还有3个数字,分别是订单总数、有效订单、订单完成率,它指的是整个时间区间之内总的数据。
原型图:
 
 
业务规则:
- 有效订单指状态为 “已完成” 的订单
- 基于可视化报表的折线图展示订单数据,X轴为日期,Y轴为订单数量
- 根据时间选择区间,展示每天的订单总数和有效订单数
- 展示所选时间区间内的有效订单数、总订单数、订单完成率,订单完成率 = 有效订单数 / 总订单数 * 100%
接口设计
根据上述原型图设计接口。
 
 
VO设计
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderReportVO implements Serializable {
    //日期,以逗号分隔,例如:2022-10-01,2022-10-02,2022-10-03
    private String dateList;
    //每日订单数,以逗号分隔,例如:260,210,215
    private String orderCountList;
    //每日有效订单数,以逗号分隔,例如:20,21,10
    private String validOrderCountList;
    //订单总数
    private Integer totalOrderCount;
    //有效订单数
    private Integer validOrderCount;
    //订单完成率
    private Double orderCompletionRate;
}
在ReportController中根据订单统计接口创建orderStatistics方法
    @GetMapping("/ordersStatistics")
    @ApiOperation("订单数据统计")
    public Result<OrderReportVO> orderStatistics(
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("订单数量统计{},{}",begin,end);
        //调用业务
        OrderReportVO orderReportVO = reportService.getOrderStatistics(begin,end);
        return Result.success(orderReportVO);
    }
在ReportService中根据订单统计接口
    /**
     * 订单统计数据
     * @param begin
     * @param end
     * @return
     */
    OrderReportVO getOrderStatistics(LocalDate begin, LocalDate end);
实现Service
    /**
     * 订单统计数据
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO getOrderStatistics(LocalDate begin, LocalDate end) {
        //订单统计:日期列表dateList,每天订单数量列表
        //1、根据开始日期与结束日期生成列表
        List<LocalDate> dateList = getDateList(begin, end);
        //2、定义每天订单总数量 List<Integer> orderCountList 和每天有效订单数量列表 List<Integer> validOrderCountList
        List<Integer> orderCountList = new ArrayList<>();
        List<Integer> validOrderCountList = new ArrayList<>();
        //3、遍历日期列表dateList
        for (LocalDate date : dateList) {
            //生成当天最大时间和最小时间
            LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
            Map<String, Object> map = new HashMap<>();
            //获取当天订单
            map.put("beginTime",beginTime);
            map.put("endTime",endTime);
            Integer orderCount = orderMapper.orderCountByToday(map);
            orderCount = orderCount == null?0:orderCount;
            orderCountList.add(orderCount);
            //获取有效订单
            map.put("status", Orders.COMPLETED);
            Integer validOrder = orderMapper.orderCountByToday(map);
            validOrder = validOrder == null?0:validOrder;
            validOrderCountList.add(validOrder);
        }
        //4、计算所有天订单总数量和有效订单总数量
        Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();
        Integer validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();
        Double orderCompletionRate = 0.0;
        //5、计算完成率
        if (totalOrderCount != 0){
            orderCompletionRate = validOrderCount.doubleValue() / totalOrderCount;
        }
        //6、封装数据返回
        return OrderReportVO.builder()
                .dateList(StringUtils.join(dateList,","))
                .orderCountList(StringUtils.join(orderCountList,","))
                .validOrderCountList(StringUtils.join(validOrderCountList,","))
                .totalOrderCount(totalOrderCount)
                .validOrderCount(validOrderCount)
                .orderCompletionRate(orderCompletionRate)
                .build();
    }
mapper层实现
    /**
     * 获取订单数
     * @param map
     * @return
     */
    Integer orderCountByToday(Map<String, Object> map);
<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>
3、销量排名Top10
所谓销量排名,销量指的是商品销售的数量。项目当中的商品主要包含两类:一个是套餐,一个是菜品,所以销量排名其实指的就是菜品和套餐销售的数量排名。通过柱形图来展示销量排名,这些销量是按照降序来排列,并且只需要统计销量排名前十的商品。
原型图:
 
 
业务规则:
- 根据时间选择区间,展示销量前10的商品(包括菜品和套餐)
- 基于可视化报表的柱状图降序展示商品销量
- 此处的销量为商品销售的份数
接口设计
据上述原型图设计接口。
 
 
VO设计
根据销量排名接口的返回结果设计VO
 
 
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SalesTop10ReportVO implements Serializable {
    //商品名称列表,以逗号分隔,例如:鱼香肉丝,宫保鸡丁,水煮鱼
    private String nameList;
    //销量列表,以逗号分隔,例如:260,215,200
    private String numberList;
}
Controller层
在ReportController中根据销量排名接口创建top10方法
    @ApiOperation("销售top10统计")
    @GetMapping("/top10")
    public Result<SalesTop10ReportVO> salesTop10Statistics(
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
            @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){
        log.info("销售前10排名{},{}",begin,end);
        SalesTop10ReportVO salesTop10ReportVO = reportService.getSalesTop10(begin,end);
        return Result.success(salesTop10ReportVO);
    }
Service层接口
    /**
     * 销售前10统计
     * @param begin
     * @param end
     * @return
     */
    SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end);
接口实现类
    /**
     * 销售前10统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end) {
        //目标:top10统计:商品名称列表 List<String> nameList,每天销量列表List<Integer> numberList
        //获取最大和最小时间
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        //查询top商品和销量
        List<GoodsSalesDTO> goodsSalesDTOS = orderMapper.getTop10(beginTime,endTime);
        //获取商品名称列表集合
        List<String> nameList = goodsSalesDTOS.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
        //获取销量列表集合
        List<Integer> numberList = goodsSalesDTOS.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());
        return SalesTop10ReportVO.builder()
                .nameList(StringUtils.join(nameList,","))
                .numberList(StringUtils.join(numberList,","))
                .build();
    }
mapper层
    /**
     * 获取top10
     * @param beginTime
     * @param endTime
     * @return
     */
    List<GoodsSalesDTO> getTop10(LocalDateTime beginTime, LocalDateTime endTime);
    <select id="getTop10" resultType="com.sky.dto.GoodsSalesDTO">
        select od.name,sum(od.number) number from orders o
            inner join order_detail od on o.id = od.order_id
                <where>
                    <if test="beginTime != null">
                        and order_time >= #{beginTime}
                    </if>
                    <if test="endTime != null">
                        and order_time <= #{endTime}
                    </if>
                </where>
                group by od.name order by number desc limit 10
    </select>



















