• 苍穹外卖数据可视化


    1、用户统计

    所谓用户统计,实际上统计的是用户的数量。通过折线图来展示,上面这根蓝色线代表的是用户总量,下边这根绿色线代表的是新增用户数量,是具体到每一天。所以说用户统计主要统计两个数据,一个是总的用户数量,另外一个是新增用户数量

    原型图:

    image-20230102213727736

    业务规则:

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

    接口设计

    根据上述原型图设计接口。

    image-20230102213809414 image-20230102213818334

    VO设计

    根据用户统计接口的返回结果设计VO

    image-20230102211004237
    @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 &gt;= #{begin}
                </if>
                <if test="end != null">
                    and create_time &lt;= #{end}
                </if>
            </where>
    </select>
    
    2、订单统计

    订单统计通过一个折现图来展现,折线图上有两根线,这根蓝色的线代表的是订单总数,而下边这根绿色的线代表的是有效订单数,指的就是状态是已完成的订单就属于有效订单,分别反映的是每一天的数据。上面还有3个数字,分别是订单总数、有效订单、订单完成率,它指的是整个时间区间之内总的数据。

    原型图:

    image-20230107192859270

    业务规则:

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

    接口设计

    根据上述原型图设计接口。

    image-20230107192942872 image-20230107192952958

    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 orderCountList 和每天有效订单数量列表 List 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 &gt;= #{begin}
                </if>
                <if test="end != null">
                    and order_time &lt;= #{end}
                </if>
            </where>
    </select>
    
    3、销量排名Top10

    所谓销量排名,销量指的是商品销售的数量。项目当中的商品主要包含两类:一个是套餐,一个是菜品,所以销量排名其实指的就是菜品和套餐销售的数量排名。通过柱形图来展示销量排名,这些销量是按照降序来排列,并且只需要统计销量排名前十的商品。

    原型图:

    image-20230107203622747

    业务规则:

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

    接口设计

    据上述原型图设计接口。

    image-20230107203720606 image-20230107203730681

    VO设计

    根据销量排名接口的返回结果设计VO

    image-20230107204028895
    @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 nameList,每天销量列表List 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 &gt;= #{beginTime}
                        </if>
                        <if test="endTime != null">
                            and order_time &lt;= #{endTime}
                        </if>
                    </where>
                    group by od.name order by number desc limit 10
        </select>
    
  • 相关阅读:
    IMU激光雷达联合标定
    小白学Python:提取Word中的所有图片,只需要1行代码
    C语言实现基于高效率IP路由查找的内容
    Automated Testing for LLMOps 01:使用CircleCI进行持续集成CI
    【Linux】Linux常用指令
    GO语言学习笔记(与Java的比较学习)(三)
    算法通关村第二关-青铜终于学会链表了
    有哪些关于程序员的笑话?那些年,我们对计算机专业的误解太深了
    经纬度坐标为中心点生成米距离长度半径的圆形面,含java js源码+在线绘制,代码简单零依赖
    力扣labuladong——一刷day40
  • 原文地址:https://blog.csdn.net/weixin_53961667/article/details/139335429