数据可视化大屏电商数据展示平台开发实录(Echarts柱图曲线图、mysql筛选统计语句、时间计算、大数据量统计)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
简介: 数据可视化大屏电商数据展示平台开发实录(Echarts柱图曲线图、mysql筛选统计语句、时间计算、大数据量统计)

一、前言

作为地区销售部门,有很多指标需要跟踪。从收入或订单数量等高级指标,到客户反馈等更详细的信息,作为部门的领导,可能需要花费大量的时间从数据堆中找出每次需要的不同数据。客户的销售基本上都是通过线上或者手机端完成的,统一存储在Mysql数据库中。

作为数据可视化开发,客户的基本面已经完成了在数据收集、数据清洗和数据过滤。接下来的主要工作是数据筛选和统计、数据格式化输入即可。


二、项目介绍

项目是某奶品在华东区线下销售的数据统计平台,主要呈现每日奶品销售的信息数据。如销售总金额、区域销售排行、产品品类销售排行、24小时销售量和销售额、不同网点的销售趋势等等。


从需求上可以分析得出,大屏一是要满足数据展示类,二是要满足决策者实时操作比对不同时间节点的销售数据,和后端数据进行交互,三是实时数据,顾名思义指的就是数据在实时传输,产生了数据就要立即展示出来。


三、项目展示

四、项目经验分享

电商数据展示,主要的数据指标,昨日、今日、7日、30日、本月、上月等多维度环比的展示,这对mysql语句的熟练掌握和实际应用有很大的挑战。也正是该项目的顺利完成,让自己对mysql有了更深度的认识。

4.1 翻牌器

4.1.1 翻牌器-今日实时交易

作为当日交易总金额,是整个大屏最为关注的点睛之处。因此,采用了numberAnimate翻牌器效果,实时刷新数据,一目了解掌握大局。

4.1.2.翻牌器后端统计SUM函数的使用

使用数据表中的当天记录和mysql内置函数CURDATE(),进行条件筛选判断,date_format(a.paid_at,'%Y-%m-%d') = CURDATE()

  public function getToday()
    {
        $sql = "select SUM(a.should_paid) AS totalPays,a.uniacid,b.uniacid,b.dpopen from " . $db->table('orders') . " AS a, " . $db->table('set_basic') . " AS b where a.status <> '-128'";// AND a.status <> '-126'
        $sql .= " AND date_format(a.paid_at,'%Y-%m-%d') = CURDATE() AND a.uniacid = b.uniacid";
        $row = $db->queryall($sql);
        $res["data"] = $row;
        die(json_encode_lockdata($res));
    }


4.2 不同时间指标的数据

MySql内部的时间计算

不同的时间指标对应不同的计算方式,充分利用mysql内置函数进行计算。通过数据可视化大屏前端点击切换时间指标来动态获取具体的时间数据指标。


昨天 :TO_DAYS(CURDATE()) - TO_DAYS(date_format(a.paid_at,'%Y-%m-%d')) = 1

今天 : date_format(a.paid_at,'%Y-%m-%d') = CURDATE();

近7天:DATE_SUB(CURDATE(), INTERVAL 6 DAY) <= date(a.paid_at)

本月:date_format(a.paid_at,'%Y-%m') = date_format(CURDATE(),'%Y-%m')

上月:date_format(a.paid_at,'%Y-%m') = date_format(DATE_SUB(CURDATE(), INTERVAL 1 MONTH),'%Y-%m')

近30天: DATE_SUB(CURDATE(), INTERVAL 29 DAY) <= date(a.paid_at)

  public function getOrders()
    {
        global $db, $res;
        dbc();
        /*间隔时间天数,-1昨天,0-当日;7-近7日;30-近30天;
         * 过滤$days,如果无参数,默认为当日
         * */
        @$CR_days = $_POST['days'];
        if ($CR_days == "") {
            $CR_days = "0";
        }
        $sql = "select COUNT(a.id) AS transTotal,SUM(a.should_paid) AS totalPays,a.paid_at,a.uniacid,b.uniacid,b.dpopen from " . $db->table('orders') . " AS a, " . $db->table('set_basic') . " AS b where a.status <> '-128' AND a.uniacid = b.uniacid";//AND a.status <> '-126'
        /*判断日期间隔*/
        switch ($CR_days) {
            case -1;
                $sql .= "  AND TO_DAYS(CURDATE()) - TO_DAYS(date_format(a.paid_at,'%Y-%m-%d')) = 1";
                break;
            case 0;
                $sql .= "  AND date_format(a.paid_at,'%Y-%m-%d') = CURDATE()";
                break;
            case 7;
                $sql .= "  AND DATE_SUB(CURDATE(), INTERVAL 6 DAY) <= date(a.paid_at)";
                break;
            case 2;//本月,修改 BY jieji007,2020-08-31
                $sql .= "  AND date_format(a.paid_at,'%Y-%m') = date_format(CURDATE(),'%Y-%m')";
                break;
            case 3;//上月,修改 BY jieji007,2020-08-31
                $sql .= "  AND date_format(a.paid_at,'%Y-%m') = date_format(DATE_SUB(CURDATE(), INTERVAL 1 MONTH),'%Y-%m')";
                break;
            case 30;
                $sql .= "  AND DATE_SUB(CURDATE(), INTERVAL 29 DAY) <= date(a.paid_at)";
                break;
            default:
                $sql .= "  AND date_format(a.paid_at,'%Y-%m-%d') = CURDATE()";
        }
        $row = $db->queryall($sql);
        $res["data"] = $row;
        die(json_encode_lockdata($res));
    }


4.3 实时交易播报

实时交易播报,开发难点在于需要多次跨表查询。

  • 获取当日交易的站点及名称;
  • 获取对应站点团长的数量;
  • 获取对应站点团长的数量;
  • 获取对应的站点会员数量;

    联表查询后,再次循环不同的数据表,方便生成json数据,传送至前端。


MySql联表查询和内部遍历循环

public function getTransMaster()
    {
        global $db, $res;
        dbc();
        //获取当日交易的站点及名称;
        $sql = "select a.uniacid,SUM(a.should_paid) AS totalPays,COUNT(a.id) AS transTotal,MAX(a.paid_at) AS paid_at,b.uniacid,b.name,b.dpopen from " . $db->table('orders');
        $sql .= " AS a, " . $db->table('set_basic') . " AS b";
        $sql .= " WHERE date_format(a.paid_at,'%Y-%m-%d') = CURDATE() AND a.uniacid = b.uniacid AND b.dpopen = 1";
        $sql .= " GROUP BY a.uniacid ORDER BY totalPays DESC LIMIT 15";
        $row = $db->queryall($sql);
        //获取对应站点团长的数量;
        foreach ($row as $k => $v) {
            $sql_l = "select uniacid,IFNULL(COUNT(id),0) AS leaderTotal,server,legitimate,created_at from " . $db->table('leader');
            $sql_l .= " WHERE date_format(created_at,'%Y-%m-%d') = CURDATE() AND uniacid =" . $v['uniacid'];//server = 1 AND legitimate = 1 AND
            $sql_l .= " GROUP BY uniacid";
            $row[$k]["leaderTotal"] = $db->queryall($sql_l);
        }
        //获取对应的站点会员数量;
        foreach ($row as $k => $v) {
            $sql_m = "select COUNT(id) AS memberTotal,created_at,uniacid,legitimate from " . $db->table('member');
            $sql_m .= " WHERE legitimate = 1 AND date_format(created_at,'%Y-%m-%d') = CURDATE() AND uniacid =" . $v['uniacid'];
            $sql_m .= " GROUP BY uniacid";
            $row[$k]["memberTotal"] = $db->queryall($sql_m);
        }
        $res["data"] = $row;
        die(json_encode_lockdata($res));
    }


4.4 每日交易量

准确的表述,应该是近30日的交易量/交易额柱图。方便决策者迅速有效的发现每日销售数据的差异,快速做出反应,进行销售问题的反馈和解决。


4.4.1.近30日交易量/交易额API

为防止日统计无效,使用到了ifnull(COUNT(a.id),0) AS totalTrans函数;

日期格式化DATE_FORMAT(a.paid_at,'%Y-%m-%d'),便于Echarts的图表的展示;


   //近30日交易量;
    public function getEveryDay()
    {
        global $db, $res;
        dbc();
        $sql = "select DATE_FORMAT(a.paid_at,'%Y-%m-%d') as dataKey,ifnull(COUNT(a.id),0) AS totalTrans,ifnull(SUM(a.should_paid),0) AS totalPays,b.uniacid,b.dpopen from " . $db->table('orders') . " AS a, " . $db->table('set_basic') . " AS b WHERE a.status <> '-128' AND a.uniacid = b.uniacid";// AND a.status <> '-126'
        if (@$_COOKIE['Controller'] == "-1") {
            $sql .= "  AND a.uniacid = " . $_COOKIE['uniacid'];
        } else {
            $sql .= " AND b.dpopen = 1";
        }
        $sql .= " GROUP BY DATE_FORMAT(a.paid_at,'%Y-%m-%d') ORDER BY a.paid_at DESC LIMIT 30";
        $row = $db->queryall($sql);
        $res["data"] = $row;
        die(json_encode_lockdata($res));
    }


4.4.1.近30日交易量/交易额Echarts

//柱状图
function getBar(dataName, dataList1, dataList2) {
    var myChart = echarts.init(document.getElementById("trans"));
    var option = {
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                lineStyle: {
                    color: '#57617B'
                }
            }
        },
        dataZoom: [{
            show: false,
            start: 0,
            end: 50,
            type: "inside",
        }],
        legend: {
            data: [
                {"name": "交易量"},
                {"name": "交易额"}
            ],
            top: '2%',
            icon: 'circle',
            textStyle: {
                "color": "rgba(255,255,255,0.9)"
            }
        },
        xAxis: [
            {
                "type": "category",
                data: dataName,
                axisLine: {lineStyle: {color: "rgba(255,255,255,.1)"}},
                inverse: true,
                axisLabel: {
                    textStyle: {color: "rgba(255,255,255,.6)", fontSize: '12'}
                }
            }
        ],
        yAxis: [
            {
                type: "value",
                axisLabel: {show: true},
                axisLine: {lineStyle: {color: 'rgba(255,255,255,.4)'}},
                splitLine: {show: true, lineStyle: {color: "rgba(255,255,255,.2)"}}
            },
            {
                type: "value",
                show: true,
                axisLabel: {show: true},
                axisLine: {lineStyle: {color: 'rgba(255,255,255,.4)'}},
                splitLine: {show: true, lineStyle: {color: "rgba(255,255,255,0)"}}
            }
        ],
        grid: {
            top: '13%',
            right: '2%',
            left: '2%',
            bottom: '5%',
            containLabel: true
        },
        series: [
            {
                name: "交易量",
                type: "bar",
                data: dataList1,
                barWidth: '50%',
                yAxisIndex: 1,
                itemStyle: {
                    normal: {
                        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
                            offset: 0,
                            color: '#39e7d7'
                        }, {
                            offset: 1,
                            color: '#10A7DB'
                        }], false),
                        barBorderRadius: [2, 2, 0, 0],
                        shadowColor: 'rgba(0,255,225,1)',
                        shadowBlur: 4
                    }
                }
            },
            {
                name: "交易额",
                type: 'line',
                smooth: true,
                symbol: 'circle',
                symbolSize: 5,
                //showSymbol: false,
                yAxisIndex: 0,
                data: dataList2,
                lineStyle: {
                    normal: {
                        width: 2
                    },
                },
                itemStyle: {
                    color: '#cdba00',
                    borderColor: 'rgba(0,136,212,0.2)',
                    borderWidth: 12
                }
            }
        ]
    };
    myChart.setOption(option);
    window.addEventListener("resize", function () {
        myChart.resize();
    });
}


4.5 24小时销售额/销售量折线图

4.5.1.GROUP BY 条件

  • 筛选条件 TO_DAYS(CURDATE()) - TO_DAYS(date_format(a.paid_at,'%Y-%m-%d')) = 1
  • 分组统计规则 GROUP BY DATE_FORMAT(a.paid_at,'%Y-%m-%d %H')
public function getTwentyFour()
    {
        global $db, $res;
        dbc();
        //最近24小时记录;
        $sql = "select RIGHT(DATE_FORMAT(a.paid_at,'%Y-%m-%d %H'),2) as dataKey,ifnull(COUNT(a.id),0) AS totalTrans,ifnull(SUM(a.should_paid),0) AS totalPays,b.uniacid,b.dpopen from " . $db->table('orders') . " AS a, " . $db->table('set_basic') . " AS b WHERE a.paid_at <> '' AND DATE_FORMAT(a.paid_at,'%Y-%m-%d') = CURDATE()";
        $sql .= " AND a.status <> '-128' AND a.uniacid = b.uniacid AND b.dpopen = 1";//AND a.status <> '-126'
        $sql .= " GROUP BY DATE_FORMAT(a.paid_at,'%Y-%m-%d %H')";
        $row = $db->queryall($sql);
        $res["data"] = $row;
        //上24小时记录;
        $sql_p = "select RIGHT(DATE_FORMAT(a.paid_at,'%Y-%m-%d %H'),2) as dataKey,ifnull(COUNT(a.id),0) AS totalTrans,ifnull(SUM(a.should_paid),0) AS totalPays,b.uniacid,b.dpopen from " . $db->table('orders') . " AS a, " . $db->table('set_basic') . " AS b WHERE a.paid_at <> '' AND TO_DAYS(CURDATE()) - TO_DAYS(date_format(a.paid_at,'%Y-%m-%d')) = 1";
        $sql_p .= " GROUP BY DATE_FORMAT(a.paid_at,'%Y-%m-%d %H')";
        $row_p = $db->queryall($sql_p);
        $res["pdata"] = $row_p;
        die(json_encode_lockdata($res));
    }


4.5.2.近24小时/上24小时

//折线图
function getLine(dataName, dataList1, dataList2) {
    var myChart = echarts.init(document.getElementById('twentyFour'));
    var option = {
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                lineStyle: {
                    color: '#57617B'
                }
            }
        },
        legend: {
            data: ['近24小时', '上24小时'],
            y: 'top',
            textStyle: {
                color: "#fff"
            },
            itemGap: 20,
        },
        grid: {
            top: '15%',
            right: '2%',
            left: '2%',
            bottom: '5%',
            containLabel: true
        },
        xAxis: [{
            type: 'category',
            boundaryGap: false,
            interval: 0,
            axisLabel: {
                show: true,
                textStyle: {
                    color: 'rgba(255,255,255,.6)'
                }
            },
            axisLine: {
                lineStyle: {
                    color: 'rgba(255,255,255,.1)'
                }
            },
            data: dataName
        }],
        yAxis: [{
            axisLabel: {
                show: true,
                textStyle: {
                    color: 'rgba(255,255,255,.6)'
                }
            },
            axisLine: {
                lineStyle: {
                    color: 'rgba(255,255,255,.1)'
                }
            },
            splitLine: {
                lineStyle: {
                    color: 'rgba(255,255,255,.1)'
                }
            }
        }],
        series: [{
            name: '近24小时',
            type: 'line',
            connectNulls: true,
            smooth: true,
            symbol: 'circle',
            symbolSize: 3,
            showSymbol: true,
            lineStyle: {
                normal: {
                    width: 2
                }
            },
            areaStyle: {
                normal: {
                    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
                        offset: 0,
                        color: 'rgba(24, 163, 64, 0.3)'
                    }, {
                        offset: 0.8,
                        color: 'rgba(24, 163, 64, 0)'
                    }], false),
                    shadowColor: 'rgba(0, 0, 0, 0.1)',
                    shadowBlur: 10
                }
            },
            itemStyle: {
                normal: {
                    color: '#cdba00',
                    borderColor: 'rgba(137,189,2,0.27)',
                    borderWidth: 12
                }
            },
            data: dataList1
        }, {
            name: '上24小时',
            type: 'line',
            connectNulls: true,
            smooth: true,
            symbol: 'circle',
            symbolSize: 3,
            showSymbol: true,
            lineStyle: {
                normal: {
                    width: 2
                }
            },
            areaStyle: {
                normal: {
                    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
                        offset: 0,
                        color: 'rgba(39, 122,206, 0.3)'
                    }, {
                        offset: 0.8,
                        color: 'rgba(39, 122,206, 0)'
                    }], false),
                    shadowColor: 'rgba(0, 0, 0, 0.1)',
                    shadowBlur: 10
                }
            },
            itemStyle: {
                normal: {
                    color: '#277ace',
                    borderColor: 'rgba(0,136,212,0.2)',
                    borderWidth: 12
                }
            },
            data: dataList2
        }]
    };
    myChart.setOption(option);
    window.addEventListener("resize", function () {
        myChart.resize();
    });
}


4.6 筛选时间切换封装函数

4.6.1.获取当天日期

function getDate(days) {
    //定义今日标准时间;
    var d = new Date();
    var nowYear = d.getFullYear().toString();//今年
    var nowMonth = timeAdd0((d.getMonth() + 1).toString());//当月
    var nowDay = timeAdd0(d.getDate().toString());//当日
    var now = nowYear + "-" + nowMonth + "-" + nowDay;//今日标准时间; 2020-09-02
    //日期计算;
    var startDate = new Date(Date.parse(now.replace(/-/g, '/'))); //将开始时间由字符串格式转换为日期格式
    var value = startDate.getTime();  //将开始时间转为毫秒
    value += days * (24 * 3600 * 1000); //将天数转换成毫秒后与开始时间相加得到结束时间的毫秒数
    var d2 = new Date(value);    //将得到的毫秒数转换为日期
    var nowYear2 = d2.getFullYear().toString();//今年
    var nowMonth2 = timeAdd0((d2.getMonth() + 1).toString());//当月
    var nowDay2 = timeAdd0(d2.getDate().toString());//当日
    var endDate = nowYear2 + "-" + nowMonth2 + "-" + nowDay2;
    return endDate;
}


4.6.2.获取当月日期

//获取当月;
function getMonths(mons, today) {
    var d = new Date();
    var nowYear = d.getFullYear().toString();//今年
    var nowMonth = timeAdd0((d.getMonth() + 1 + Number(mons)).toString());//当月
    var nowDay = timeAdd0(d.getDate().toString());//当日
    if (today == "0") {
        var now = nowYear + "-" + nowMonth + "-" + nowDay;//今日标准时间; 2020-09-02
    } else {
        var now = nowYear + "-" + nowMonth + "-" + "01";//今日标准时间; 2020-09-02
    }
    return now;
}

4.6.3.获取上月日期

//获取上月;
function getLastMonths(mons, today) {
    var d = new Date();
    var nowYear = d.getFullYear().toString();//今年
    var nowMonth = timeAdd0((d.getMonth() + 1 + Number(mons)).toString());//当月
    if (today == "1") {
        var now = nowYear + "-" + nowMonth + "-" + "01";//今日标准时间; 2020-09-02
    }
    if (today == "30") {
        var now = nowYear + "-" + nowMonth + "-" + mGetDate(Number(mons));//今日标准时间; 2020-09-02
    }
    return now;
}


4.6.3.获取当前月份天数

//获取当前月份天数:
function mGetDate(mons) {
    var date = new Date();
    var year = date.getFullYear();
    var month = date.getMonth() + 1 + Number(mons);
    var d = new Date(year, month, 0);
    return d.getDate();
}

总结

该项目是初期入门数据可视化大屏的作品,严格意义上,是在懵懂的状态下完成的开发。随时开发作品的不断增加,对项目销售的了解、开发过程的深入、大数据量的学习,回头再看,总有些可以精进的地方。

@漏刻有时


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
JSON JavaScript 定位技术
vue中使用echarts实现省市地图绘制,根据数据显示省市天气图标及温度信息
vue中使用echarts实现省市地图绘制,根据数据显示省市天气图标及温度信息
142 1
|
30天前
|
安全 关系型数据库 MySQL
如何将数据从MySQL同步到其他系统
【10月更文挑战第17天】如何将数据从MySQL同步到其他系统
168 0
|
1月前
|
SQL 前端开发 关系型数据库
全表数据核对 ,行数据核对,列数据核对,Mysql 8.0 实例(sample database classicmodels _No.3 )
全表数据核对 ,行数据核对,列数据核对,Mysql 8.0 实例(sample database classicmodels _No.3 )
49 0
全表数据核对 ,行数据核对,列数据核对,Mysql 8.0 实例(sample database classicmodels _No.3 )
|
1月前
|
关系型数据库 MySQL 数据库
mysql 里创建表并插入数据
【10月更文挑战第5天】
121 1
|
1月前
|
分布式计算 关系型数据库 MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
50 3
|
12天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
119 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
12天前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
在项目中,为了解决Redis与Mysql的数据一致性问题,我们采用了多种策略:对于低一致性要求的数据,不做特别处理;时效性数据通过设置缓存过期时间来减少不一致风险;高一致性但时效性要求不高的数据,利用MQ异步同步确保最终一致性;而对一致性和时效性都有高要求的数据,则采用分布式事务(如Seata TCC模式)来保障。
47 14
|
15天前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
46 9
|
26天前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
|
23天前
|
SQL 关系型数据库 MySQL
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
42 1
下一篇
无影云桌面