2024年重庆甘肃安徽等省职业院校技能大赛_大数据应用开发样题解析-模块E:数据可视化

单击以下链接,可跳转到相应的子任务实现部分。

  • 创建Vue工程

  • 后端接口说明

  • 任务1、 用柱状图展示消费额最高的省份

  • 任务2、 用饼状图展示各地区消费能力

  • 任务3、 用玫瑰图展示各地区消费能力

  • 任务4、 用折线图展示每年上架商品数量变化

  • 任务5、 用散点图展示每年上架商品数量的变化

  • 任务6、 用条形图展示平均消费额最高的省份

  • 任务7、 用折柱混合图展示省份平均消费额和地区平均消费额

最终实现的效果如下:

折混图

请注意:本示例为了在一个项目中演示多种不同图表的实现,实现了一个单页面应用程序,通过路由来在不同的图表之间切换。在比赛时,并没有此要求,因此大家也可以每个子任务单独创建一个项目,请求一个接口数据并显示一张图表,从而避免使用单页面应用程序和路由组件导航,这样可以减少复杂度和可能出错的机率。只要最终实现任务需求即可。

任务分析

相对来说,这部分在整个竞赛的各模块中相对比较容易,也是确保得分的模块。该模块主要涉及以下知识点:

  • (1)Vue前端框架。

  • (2)在Vue中实现Ajax请求。

  • (3)前端JavaScript编程(数据处理)。

  • (4)Apache ECharts图表库使用。

前置学习

前端框架vue.js系列教程:

注意:请务必先学习上面的vue.js系列教程,再继续接下来的任务实现。


创建Vue3工程

请按以下步骤实现任务要求。

(1) 创建一个项目存放的专用文件夹,比如,myvue,然后在命令使用cd命令切换到该目录下。

(2) 使用NPM包管理器安装本任务中项目的依赖包。在命令行执行如下安装命令:

在正式比赛中应该不需要自己安装这些依赖包,因为环境不连网,所以需要的模块和包应该已经安装在本地了。比赛时赛方应该已经在环境中创建好了项目的基本框架,大家在此基础上继续

#安装vue
$ npm install vue@next

#安装vue-route依赖包
$ npm install vue-router

#安装echarts依赖包
$ npm install echarts

(3) 创建Vue项目。在myvue目录下,执行如下项目创建命令:

在正式比赛中应该不需要自己从零创建项目。比赛时赛方应该已经在环境中创建好了项目的基本框架,大家在此基础上继续创建页面、编写代码请求和处理数据并显示数据即可。

$ vue create myvue-app

(4) 启动VS Code,打开myvue-app项目文件夹,加载项目文件,然后在项目的src目录下,创建一个views子目录。

(5) 检查项目中是否有echarts.min.js文件(比赛环境中没有安装echarts组件,需要手工导入echarts.min.js文件)。如果没有,将赛方提供的echarts.min.js拷贝到项目的src/assets/目录下。

(6) 打开项目中的vue.config.js文件,增加一项配置(如果没有的话):lintOnSave:false,如下所示:

......
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false
})

接口说明

在以下可视化任务中,涉及到对两个接口的请求。

接口1:获取指定时间范围内的订单数据

http请求方法:POST

请求地址:http://192.168.23.*(地址为可视化接口虚拟机的直连IP):8999/dataVisualization/selectOrderInfo

请求参数:

字段 说明 类型 是否必填
startTime 开始时间 String
endTime 结束时间 String

请求格式:json。示例如下:

{
"startTime":"2020-01-01 00:00:00",
"endTime":"2020-12-30 00:00:00"
}

返回参数说明:

参数 说明
id 主键
finalTotalAmount 总金额
outTradeNo 订单交易编号(第三方支付用)
provinceName 省市名称。例如,北京、天津市、河北省等。
regionName 地区名称。例如,华北、华中等。
userName 用户名

请求成功返回JSON数据包:

{
  "msg": "操作成功",
  "code": 200,
  "data": [
      {
          "id": 78506,
          "finalTotalAmount": 305062.00,
          "outTradeNo": "756847726439369",
          "provinceName": "北京",
          "regionName": "华北",
          "userName": "华馥"
      },
      {
          "id": 78559,
          "finalTotalAmount": 6111.00,
          "outTradeNo": "341957455961748",
          "provinceName": "北京",
          "regionName": "华北",
          "userName": "罗菊兰"
      },
      {
          "id": 78568,
          "finalTotalAmount": 84610.00,
          "outTradeNo": "489992944636772",
          "provinceName": "北京",
          "regionName": "华北",
          "userName": "毛岚"
      },

  ]
}

接口2:查询上架的商品信息

http请求方法:POST

请求地址:http://192.168.23.*(地址为可视化接口虚拟机的直连IP):8999/dataVisualization/selectGoodsInfo

请求参数:无具体参数

请求格式:json,{}。

返回参数说明:

参数 说明
id 编号
price 总金额
skuName 商品名称
year 年份

请求成功返回JSON数据包:

{
  "msg": "操作成功",
  "code": 200,
  "data": [
      {
          "id": ,
          "price": 2220,
          "skuName": "荣耀10青春版 幻彩渐变 2400万AI自拍 全网通版4GB+64GB 渐变蓝 移动联通电信4G全面屏手机 双卡双待",
          "year": "2019"
      },
      {
          "id": 2,
          "price": 3321,
          "skuName": "TCL 55A950C 55英寸32核人工智能 HDR曲面超薄4K电视金属机身(枪色)",
          "year": "2019"
      },
      {
          "id": 3,
          "price": 3100,
          "skuName": "小米(MI)电视 55英寸曲面4K智能WiFi网络液晶电视机4S L55M5-AQ 小米电视4S 55英寸 曲面",
          "year": "2019"
      },
...
  ]
}

可以看出,接口返回的数据是一个JSON对象。

子任务一:用柱状图展示消费额最高的省份

任务描述

  1. 编写Vue 工程代码,根据接口,用柱状图展示2020 年消费额最高的5 个省份(不用考虑数据是否合规,直接聚合省份消费额),同时将用于图表展示的数据结构在浏览器的console 中进行打印输出,将图表可视化结果和浏览器console 打印结果分别截图并粘贴至客户端桌面【Release\模块E 提交结果.docx】中对应的任务序号下。

请按以下步骤操作。

(1) 在项目的src/views/目录下,新建一个名为Task01View.vue的文件,编辑代码如下:

<template>
<h2>柱状图</h2>

<div class="left">
  <!-- echarts图表绘制在这里 -->      
  <div id="canvas" style="width: 580px;height:600px;"></div>    
</div>
 
<div class="right">
    <p><pre>{{ items }}</pre></p>  
</div>
</template>

<script>
  // 导入echarts组件
  import * as echarts from '../assets/echarts.min.js'      

  // 请求的RESTful API 接口中(请将IP替换为相应的接口实际地址)
  var url = "http://IP:8999/dataVisualization/selectOrderInfo"
  var params = '{"startTime":"2020-01-01 00:00:00", "endTime":"2020-12-31 23:59:59"}'

  export default {
    name: 'TaskTop',
    data () {
      return {
        items: ''
      }
    },
    mounted () {
        // 根据准备好的dom初始化echarts实例
        var myChart = echarts.init(document.getElementById('canvas'));

        // 使用刚才指定的配置项和数据显示图表
        myChart.setOption({
          title: {
            text: '用柱状图展示2020年消费额最高的5个省份',
            subtext: '2020年',
            left: 'center'
          },
          tooltip: {},
          legend: {
            data: ['销售额'],   // 要和series.name一致
            x:'right',
            y:'top'              
          },
          xAxis: {
            type: 'category',
            data: []     // **** ajax请求回来的数据要填充到这里
          },
          yAxis: {
            type: 'value'
          },
          series: [
            {
              name: '销售额',
              type: 'bar',
              data: []   // **** ajax请求回来的数据要填充到这里
            }
          ]
        });
        // fetch请求
        fetch(url, {
              method: "post",   // POST请求
              headers: {'content-type': 'application/json;charset=UTF-8'},
              body: params       // 参数
            }
          )
              .then((response) => {
                // 取出响应中的json数据 *
                return response.json();
              })
              .then((data) => {                  
                // 从返回的json数据中,抽取x轴值列表和y轴值列表
                var jsObj = getXY(data.data);

                // 将用于图表展示的数据结构在浏览器的console 中进行打印输出
                console.log(jsObj)

                // 设置响应数据显示在右侧,便于观察
                // this.items = JSON.stringify(data,null,"\t\t\t");
                this.items = jsObj

                // 刷新echarts数据
                var option = myChart.getOption();
                option.xAxis[0].data = jsObj.x;
                option.series[0].data = jsObj.y;
                myChart.setOption(option);
              })
              .catch(error => {   // 请求失败处理
                  console.log(error);
              })
              .then(() => {
                this.loading = false;
              });
    }
  }

  // 分别抽取x轴数据和y轴数据
  function getXY(jsArray){
    // 准备存储数据的结构
    var dataMap = new Map();

    for (var index in jsArray){     // 这里遍历的是索引          
        var jsObj = jsArray[index]   // 根据索引获得对象
        var provinceName = jsObj.provinceName;   // 订单所属省份          
        var finalTotalAmount = jsObj.finalTotalAmount; // 订单金额
        // 如果有该省份,则累加金额
        if(dataMap.has(provinceName)){
          dataMap.set(provinceName, dataMap.get(provinceName) + finalTotalAmount)
        }
        // 如果没有,则说明是该省第一个订单
        else{
          dataMap.set(provinceName, finalTotalAmount)
        }
    }

    // 先转为数组,再按金额排序,然后取前5个
    var top5Arr = Array.from(dataMap).sort((a,b) => b[1] - a[1]).slice(0,5)

    // 遍历top5Arr,取x轴值(省份名称)和y轴值(该省总金额)        
    var xs = [];     // 存储x轴数据
    var ys = [];     // 存储y轴数据
    for (var [key, value] of top5Arr) {
      xs.push(key); // 省份值,放入x轴
      ys.push(value);// 金额值,放入y轴
    }

    // 以json对象形式返回
    return {"x":xs,"y":ys};
  }

</script>

(2) 修改主组件App.vue,添加导航链接和渲染组件,代码如下:

<template>
<div class="menu">
  <h3>请选择分析结果</h3>
  <ul>
      <!--使用 router-link 组件进行导航 -->
      <li><router-link to="/">首页</router-link></li>
      <li><router-link to="/task01">任务1:用柱状图展示消费额最高的省份</router-link></li>
  </ul>
</div>

<div class="graph">
    <!-- 渲染在这里 -->
    <router-view></router-view>
</div>
</template>

(3) 修改入口文件main.js,导入路由组件文件并指定路由映射,主要修改部分如下:

// 程序入口文件
...

// 1. 定义路由组件.  
import Home from "./views/HomeView.vue"
import Task01 from "./views/Task01View.vue"

// 2. 定义一些路由映射
const routes = [
  { path: '/', component: Home },
  { path: '/task01', component: Task01 },
]

...

(4) 执行Vue应用程序。

在VS Code编辑器下方的“终端”窗口中,执行如下命令,启动开发服务器:

$ npm run serve

打开浏览器,访问http://localhost:8080/,点击左侧的链接,就可以看到在右侧显示相应的柱状图。

子任务二:用饼状图展示各地区消费能力

任务描述

  1. 编写Vue 工程代码,根据接口,用饼状图展示2020 年各地区的消费总额占比(不用考虑数据是否合规,直接聚合地区消费额),同时将用于图表展示的数据结构在浏览器的console 中进行打印输出,将图表可视化结果和浏览器console 打印结果分别截图并粘贴至客户端桌面【Release\模块E 提交结果.docx】中对应的任务序号下。

请按以下步骤操作。

(1) 在项目的src/views/目录下,新建一个名为Task02View.vue的文件,编辑代码如下:

<template>
<h2>柱状图</h2>

<div class="left">
  <!-- echarts图表绘制在这里 -->      
  <div id="canvas" style="width: 580px;height:600px;"></div>    
</div>
 
<div class="right">
    <p><pre>{{ items }}</pre></p>  
</div>
</template>

<script>
  // 导入echarts组件
  import * as echarts from '../assets/echarts.min.js'      

  // 请求的RESTful API 接口中(请将IP替换为你接口实际地址)
  var url = "http://IP:8999/dataVisualization/selectOrderInfo"
  var params = '{"startTime":"2020-01-01 00:00:00", "endTime":"2020-12-31 23:59:59"}'

  export default {
    name: 'TaskTop',
    data () {
      return {
        items: ''
      }
    },
    mounted () {
        // 根据准备好的dom初始化echarts实例
        var myChart = echarts.init(document.getElementById('canvas'));

        // 使用刚才指定的配置项和数据显示图表
        myChart.setOption({
          title: {
            text: '用饼状图展示各地区消费能力',
            subtext: '2020年',
            left: 'center'
          },
          tooltip: {trigger: 'item'},
          legend: {
            orient: 'vertical',
            data: ['消费金额'],   // 要和series.name一致
            x:'left',
            y:'top'              
          },
          series: [
            {
              name: '消费金额',
              type: 'pie',
              radius: '60%',
              data: [],   // **** ajax请求回来的数据要填充到这里        
              emphasis: {
                itemStyle: {
                  shadowBlur: 10,
                  shadowOffsetX: 0,
                  shadowColor: 'rgba(0, 0, 0, 0.5)'
                }
              }
            }
          ]
        });

        // fetch请求
        fetch(url, {
              method: "post",
              headers: {'content-type': 'application/json'},
              body: params
            }
          )
              .then((response) => {
                // 取出响应中的json数据 *
                return response.json();
              })
              .then((data) => {                  
                // 从返回的json数据中,抽取x轴值列表和y轴值列表
                var jsObj = getXY(data.data);

                // 设置响应数据显示在右侧,便于观察
                // this.items = JSON.stringify(data,null,"\t\t\t");
                this.items = jsObj

                // 将用于图表展示的数据结构在浏览器的console 中进行打印输出
                console.log(jsObj)

                // 刷新echarts数据
                var option = myChart.getOption();
                option.series[0].data = jsObj;
                myChart.setOption(option);
              })
              .catch(error => {   // 请求失败处理
                  console.log(error);
              })
              .then(() => {
                this.loading = false;
              });
    }
  }

  // 分别抽取x轴数据和y轴数据
  function getXY(jsArray){
    var dataMap = new Map();
    for (var index in jsArray){     // 这里遍历的是索引          
        var jsObj = jsArray[index]   // 根据索引获得对象 {id: 78506, finalTotalAmount: 305062, outTradeNo: '756847726439369', provinceName: '北京', regionName: '华北', userName:'华馥'}
        var regionName = jsObj.regionName;   // 订单所属地区          
        var finalTotalAmount = jsObj.finalTotalAmount; // 订单金额
        // 如果有该地区,则累加金额
        if(dataMap.has(regionName)){
          dataMap.set(regionName, dataMap.get(regionName) + finalTotalAmount)
        }
        // 如果没有,则说明是该地区第一个订单
        else{
          dataMap.set(regionName, finalTotalAmount)
        }
    }

    // 遍历Map,取x轴值(地区名称)和y轴值(该地区总金额)  
    var data = []            
    for (var [key, value] of dataMap) {
      var obj = new Object();     // js对象  
      obj.value = value;
      obj.name = key;
      data.push(obj);
    }

    // 以json对象形式返回
    return data;   // [{name:"华北",value:123123},...]
  }


</script>

(2) 修改主组件App.vue,添加导航链接和渲染组件,代码如下:

<template>
<div class="menu">
  <h3>请选择分析结果</h3>
  <ul>
      <!--使用 router-link 组件进行导航 -->
      <li><router-link to="/">首页</router-link></li>
      <li><router-link to="/task01">任务1:用柱状图展示消费额最高的省份</router-link></li>
      <li><router-link to="/task02">任务2:用饼状图展示各地区消费能力</router-link></li>
  </ul>
</div>

<div class="graph">
    <!-- 渲染在这里 -->
    <router-view></router-view>
</div>
</template>

(3) 修改入口文件main.js,导入路由组件文件并指定路由映射,主要修改部分如下:

// 程序入口文件
...

// 1. 定义路由组件.  
import Home from "./views/HomeView.vue"
import Task01 from "./views/Task01View.vue"
import Task02 from "./views/Task02View.vue"

// 2. 定义一些路由映射
const routes = [
  { path: '/', component: Home },
  { path: '/task01', component: Task01 },
  { path: '/task02', component: Task02 },
]

...

(4) 执行Vue应用程序。

在VS Code编辑器下方的“终端”窗口中,执行如下命令,启动开发服务器:

$ npm run serve

打开浏览器,访问http://localhost:8080/,点击左侧的链接,就可以看到在右侧显示相应的饼状图。

子任务三:用玫瑰图展示各地区消费能力

任务描述

  1. 编写Vue 工程代码,根据接口,用基础南丁格尔玫瑰图展示2020 年各地区的消费总额占比,同时将用于图表展示的数据结构在浏览器的console 中进行打印输出,将图表可视化结果和浏览器console 打印结果分别截图并粘贴至客户端桌面【Release\模块E 提交结果.docx】中对应的任务序号下。

实现与子任务二的饼状图完全一致,仅修改echarts图表外观即可。如下:

          // 使用刚才指定的配置项和数据显示图表
        myChart.setOption({
          title: {
            text: '用饼状图展示各地区消费能力',
            subtext: '2020年',
            left: 'center'
          },
          tooltip: {
            trigger: 'item',
            formatter: '{a}
{b} : {c} ({d}%)'
          },
          legend: {
            orient: 'vertical',
            data: ['消费金额'],   // 要和series.name一致
            x:'left',
            y:'top'              
          },
          series: [
            {
              name: '消费金额',
              type: 'pie',
              radius: [20, 200],
              center: ['50%', '50%'],
              roseType: 'area',
              itemStyle: {
                borderRadius: 8
              },
              data: [],   // **** ajax请求回来的数据要填充到这里        
              emphasis: {
                itemStyle: {
                  shadowBlur: 10,
                  shadowOffsetX: 0,
                  shadowColor: 'rgba(0, 0, 0, 0.5)'
                }
              }
            }
          ]
        });

子任务四:用折线图展示每年上架商品数量变化

任务描述

  1. 编写Vue 工程代码,根据接口,用折线图展示每年上架商品数量的变化情况(商品出现一次即累加1,不用考虑商品重复出现),同时将用于图表展示的数据结构在浏览器的console 中进行打印输出,将图表可视化结果和浏览器console打印结果分别截图并粘贴至客户端桌面【Release\模块E 提交结果.docx】中对应的任务序号下。

请按以下步骤操作。

(1) 在项目的src/views/目录下,新建一个名为Task04View.vue的文件,编辑代码如下:

<template>
<h2>折线图</h2>

<div class="left">
  <!-- echarts图表绘制在这里 -->      
  <div id="canvas" style="width: 580px;height:600px;"></div>    
</div>
 
<div class="right">
    <p><pre>{{ items }}</pre></p>  
</div>
</template>

<script>
  import * as echarts from '../assets/echarts.min.js'      

  // 请求的RESTful API 接口中(请将IP替换为实际接口地址)
  var url = "http://IP:8999/dataVisualization/selectGoodsInfo"

  export default {
    name: 'TaskTop',
    data () {
      return {
        items: ''
      }
    },
    mounted () {
        // 根据准备好的dom初始化echarts实例
        var myChart = echarts.init(document.getElementById('canvas'));

        // 使用刚才指定的配置项和数据显示图表
        myChart.setOption({
          title: {
            text: '用折线图展示每年上架商品数量的变化',
            left: 'center'
          },
          tooltip: {},
          legend: {
            data: ['上架商品数量'],   // 要和series.name一致
            x:'right',
            y:'top'              
          },
          xAxis: {
            type: 'category',
            data: []
          },
          yAxis: {
            type: 'value',
            // scale: true
          },
          series: [
            {
              name: '上架商品数量',
              symbolSize: 15,
              type: 'line',
              data: [],   // **** ajax请求回来的数据要填充到这里
              // symbolSize: function(value) {
              //   return value[1]/1000;
              // },
              itemStyle: {
                color: 'green'
              }
            }
          ]
        });
        // fetch请求
        fetch(url, {method: "post",headers: {'content-type': 'application/json'}})
              .then((response) => {
                // 取出响应中的json数据 *
                return response.json();
              })
              .then((data) => {
                // 从返回的json数据中,抽取x轴值列表和y轴值列表
                var jsObj = getXY(data.data);

                // 将用于图表展示的数据结构在浏览器的console中进行打印输出
                console.log(jsObj)

                // 设置响应数据显示在右侧,便于观察
                // this.items = JSON.stringify(data,null,"\t\t\t");
                this.items = jsObj

                // 刷新echarts数据
                var option = myChart.getOption();
                option.xAxis[0].data = jsObj.x;   // 设置option中x轴的数据
                option.series[0].data = jsObj.y;   // 设置option中y轴的数据
                myChart.setOption(option);
              })
              .catch(error => {   // 请求失败处理
                  console.log(error);
              })
              .then(() => {
                this.loading = false;
              });
    }
  }

  // 分别抽取x轴数据和y轴数据
  function getXY(jsArray){
    var dataMap = new Map();   // 定义map,存储{年份,数量}
    for (var index in jsArray){     // 这里遍历的是索引          
        var jsObj = jsArray[index]   // 根据索引获得对象 {id: 1, price: 2220, skuName: '荣耀10青春版...', year: 2019}
        var year = jsObj.year;   // 上架商品年份          
        // 如果有该年份,则累加数量
        if(dataMap.has(year)){
          dataMap.set(year, dataMap.get(year) + 1); // 一条数据,一个商品
        }
        // 如果没有,则说明是该年第一个商品
        else{
          dataMap.set(year, 1);     // 一条数据,一个商品
        }
    }

    // 先转为数组,再按年排序
    var dataArr = Array.from(dataMap).sort((a,b) => a[0] - b[0])

    // 遍历dataArr,取x轴值(年份)和y轴值(上架商品数量)        
    var xs = [];     // 存储x轴数据
    var ys = [];     // 存储y轴数据
    for (var [key, value] of dataArr) {
      xs.push(key); // 年份值,放入x轴
      ys.push(value);// 上架商品数量值,放入y轴
    }

    // 以json对象形式返回
    return {"x":xs,"y":ys};
  }

</script>

(2) 修改主组件App.vue,添加导航链接和渲染组件,代码如下:

<template>
<div class="menu">
  <h3>请选择分析结果</h3>
  <ul>
      <!--使用 router-link 组件进行导航 -->
      <li><router-link to="/">首页</router-link></li>
      <li><router-link to="/task01">任务1:用柱状图展示消费额最高的省份</router-link></li>
      <li><router-link to="/task02">任务2:用饼状图展示各地区消费能力</router-link></li>
      <li><router-link to="/task04">任务4:用折线图展示每年上架商品数量的变化</router-link></li>
  </ul>
</div>

<div class="graph">
    <!-- 渲染在这里 -->
    <router-view></router-view>
</div>
</template>

(3) 修改入口文件main.js,导入路由组件文件并指定路由映射,主要修改部分如下:

// 程序入口文件
...

// 1. 定义路由组件.  
import Home from "./views/HomeView.vue"
import Task01 from "./views/Task01View.vue"
import Task02 from "./views/Task02View.vue"
import Task04 from "./views/Task04View.vue"

// 2. 定义一些路由映射
const routes = [
  { path: '/', component: Home },
  { path: '/task01', component: Task01 },
  { path: '/task02', component: Task02 },
  { path: '/task04', component: Task04 },
]

...

(4) 执行Vue应用程序。

在VS Code编辑器下方的“终端”窗口中,执行如下命令,启动开发服务器:

$ npm run serve

打开浏览器,访问http://localhost:8080/,点击左侧的链接,就可以看到在右侧显示相应的折线图。

子任务五:用散点图展示每年上架商品数量的变化

任务描述

  1. 编写Vue 工程代码,根据接口,用基础散点图展示每年上架商品数量的变化情况,同时将用于图表展示的数据结构在浏览器的console 中进行打印输出,将图表可视化结果和浏览器console 打印结果分别截图并粘贴至客户端桌面【Release\模块E 提交结果.docx】中对应的任务序号下。

实现与子任务四类似,仅需修改echarts图表的类型和统计结果数据类型即可。

<template>
<h2>折线图</h2>

<div class="left">
  <!-- echarts图表绘制在这里 -->      
  <div id="canvas" style="width: 580px;height:600px;"></div>    
</div>
 
<div class="right">
    <p><pre>{{ items }}</pre></p>  
</div>
</template>

<script>
  import * as echarts from '../assets/echarts.min.js'      

  // 请求的RESTful API 接口中(请将IP替换为实际接口地址)
  var url = "http://IP:8999/dataVisualization/selectGoodsInfo"

  export default {
    name: 'TaskTop',
    data () {
      return {
        items: ''
      }
    },
    mounted () {
        // 根据准备好的dom初始化echarts实例
        var myChart = echarts.init(document.getElementById('canvas'));

        // 使用刚才指定的配置项和数据显示图表
        myChart.setOption({
          title: {
            text: '用折线图展示每年上架商品数量的变化',
            left: 'center'
          },
          tooltip: {},
          legend: {
            data: ['上架商品数量'],   // 要和series.name一致
            x:'right',
            y:'top'              
          },
          xAxis: {
            type: 'value',
            scale: true
          },
          yAxis: {
            type: 'value',
            // scale: true
          },
          series: [
            {
              name: '上架商品数量',
              symbolSize: 15,
              type: 'scatter',
              data: [],   // **** ajax请求回来的数据要填充到这里
              // symbolSize: function(value) {
              //   return value[1]/1000;
              // },
              itemStyle: {
                color: 'green'
              }
            }
          ]
        });
        // fetch请求
        fetch(url, {method: "post",headers: {'content-type': 'application/json'}})
              .then((response) => {
                // 取出响应中的json数据 *
                return response.json();
              })
              .then((data) => {
                // 从返回的json数据中,抽取x轴值列表和y轴值列表
                var jsObj = getXY(data.data);

                // 将用于图表展示的数据结构在浏览器的console中进行打印输出
                console.log(jsObj)

                // 设置响应数据显示在右侧,便于观察
                // this.items = JSON.stringify(data,null,"\t\t\t");
                this.items = jsObj

                // 刷新echarts数据
                var option = myChart.getOption();
                option.series[0].data = jsObj.y;   // 设置option中的数据
                myChart.setOption(option);
              })
              .catch(error => {   // 请求失败处理
                  console.log(error);
              })
              .then(() => {
                this.loading = false;
              });
    }
  }

  // 分别抽取x轴数据和y轴数据
  function getXY(jsArray){
    var dataMap = new Map();   // 定义map,存储{年份,数量}
    for (var index in jsArray){     // 这里遍历的是索引          
        var jsObj = jsArray[index]   // 根据索引获得对象 {id: 1, price: 2220, skuName: '荣耀10青春版...', year: 2019}
        var year = jsObj.year;   // 上架商品年份          
        // 如果有该年份,则累加数量
        if(dataMap.has(year)){
          dataMap.set(year, dataMap.get(year) + 1); // 一条数据,一个商品
        }
        // 如果没有,则说明是该年第一个商品
        else{
          dataMap.set(year, 1);     // 一条数据,一个商品
        }
    }

    // 先转为数组,再按年排序
    var dataArr = Array.from(dataMap).sort((a,b) => a[0] - b[0])

    // 遍历dataArr,取x轴值(年份)和y轴值(上架商品数量)        
    var axisData = [];     // 存储数据
    for (var [key, value] of dataArr) {
      var itemArr = [key, value];   // 组织数据
      axisData.push(itemArr);       // 放入数组
    }

    // 返回
    return axisData;
  }

</script>

子任务六:用条形图展示平均消费额最高的省份

任务描述

  1. 编写Vue工程代码,根据接口,用条形图展示2020年平均消费额(四舍五入保留两位小数)最高的5个省份,同时将用于图表展示的数据结构在浏览器的console中进行打印输出,将图表可视化结果和浏览器console打印结果分别截图并粘贴至客户端桌面【Release\任务E提交结果.docx】中对应的任务序号下。

请按以下步骤操作。

(1) 在项目的src/views/目录下,新建一个名为Task06View.vue的文件,编辑代码如下:

<template>
<h2>条形图</h2>

<div class="left">
  <!-- echarts图表绘制在这里 -->      
  <div id="canvas" style="width: 580px;height:600px;"></div>    
</div>
 
<div class="right">
    <p><pre>{{ items }}</pre></p>  
</div>
</template>

<script>
  import * as echarts from '../assets/echarts.min.js'    

  // 请求的RESTful API 接口中(请替换为你自己的IP)
  var url = "http://IP:8999/dataVisualization/selectOrderInfo"
  var params = '{"startTime":"2020-01-01 00:00:00", "endTime":"2020-12-31 23:59:59"}'

  export default {
    name: 'TaskTop',
    data () {
      return {
        items: ''
      }
    },
    mounted () {
        // 根据准备好的dom初始化echarts实例
        var myChart = echarts.init(document.getElementById('canvas'));

        // 使用刚才指定的配置项和数据显示图表
        myChart.setOption({
          title: {
            text: '用条形图展示平均消费额最高的省份',
            subtext: '2020年',
            left: 'center'
          },
          tooltip: {trigger: 'axis'},
          legend: {
            data: ['平均消费额'],   // 要和series.name一致
            x:'right',
            y:'top'              
          },
          xAxis: {
            type: 'value'
          },
          yAxis: {
            type: 'category',
            data: []     // **** ajax请求回来的数据要填充到这里
          },
          series: [
            {
              name: '平均消费额',
              type: 'bar',
              data: []   // **** ajax请求回来的数据要填充到这里
            }
          ]
        });
        // fetch请求
        fetch(url, {
              method: "post",
              headers: {'content-type': 'application/json'},
              body: params
            }
          )
              .then((response) => {
                // 取出响应中的json数据 *
                return response.json();
              })
              .then((data) => {                
                // 从返回的json数据中,抽取x轴值列表和y轴值列表
                var jsObj = getXY(data.data);

                // 将用于图表展示的数据结构在浏览器的console中进行打印输出
                console.log(jsObj)

                // 设置响应数据显示在右侧,便于观察
                // this.items = JSON.stringify(data,null,"\t\t\t");
                this.items = jsObj

                // 刷新echarts数据
                var option = myChart.getOption();
                option.yAxis[0].data = jsObj.x;
                option.series[0].data = jsObj.y;
                myChart.setOption(option);
              })
              .catch(error => {   // 请求失败处理
                  console.log(error);
              })
              .then(() => {
                this.loading = false;
              });
    }
  }

  // 分别抽取x轴数据和y轴数据
  function getXY(jsArray){
    // 存储每个省及其总金额、总订单数
    var dataMap = new Map();  

    for (var index in jsArray){     // 这里遍历的是索引          
        var jsObj = jsArray[index]   // 根据索引获得对象
        var provinceName = jsObj.provinceName;   // 订单所属省份          
        var finalTotalAmount = jsObj.finalTotalAmount; // 订单金额

        // 构造一个对象,存储某省份的累加金额和累加订单数(以便计算平均金额)
        var obj = new Object();

        // 如果有该省份,则累加金额和数量
        if(dataMap.has(provinceName)){        
          var accOjb = dataMap.get(provinceName);   // 获得原来累加的对象    
          obj.totalAmount = accOjb.totalAmount + finalTotalAmount;   // 累加金额
          obj.totalNum = accOjb.totalNum + 1;   // 总订单数。一条订单计数1
        }
        // 如果没有,则说明是该省第一个订单
        else{
          obj.totalAmount = finalTotalAmount;   // 累加金额
          obj.totalNum = 1;   // 总订单数。一条订单计数1
        }
        dataMap.set(provinceName, obj);       // 将更新后的obj存入map
    }

    // 计算每个省的平均消费额
    var avgMap = new Map();
    for (var [province, accObj] of dataMap) {
      var avgConsumAmount = Math.round((accObj.totalAmount / accObj.totalNum) * 100) / 100; // 保留两位小数
      avgMap.set(province, avgConsumAmount);   // {省份,平均消费金额}
    }

    // 先转为数组,再按金额排序,然后取前5个
    var top5Arr = Array.from(avgMap).sort((a,b) => b[1] - a[1]).slice(0,5)

    // 遍历top5Arr,取x轴值(省份名称)和y轴值(该省总金额)  
    var xs = [];     // 存储x轴数据
    var ys = [];     // 存储y轴数据
    for (var [key, value] of top5Arr) {
      xs.unshift(key); // 省份值,放入x轴
      ys.unshift(value);// 平均消费金额,放入y轴
    }

    // 以json对象形式返回
    return {"x":xs,"y":ys};
  }

</script>

(2) 修改主组件App.vue,添加导航链接和渲染组件,代码如下:

<template>
<div class="menu">
  <h3>请选择分析结果</h3>
  <ul>
      <!--使用 router-link 组件进行导航 -->
      <li><router-link to="/">首页</router-link></li>
      <li><router-link to="/task01">任务1:用柱状图展示消费额最高的省份</router-link></li>
      <li><router-link to="/task02">任务2:用饼状图展示各地区消费能力</router-link></li>
      <li><router-link to="/task04">任务4:用散点图展示每年上架商品数量的变化</router-link></li>
      <li><router-link to="/task06">任务6:用条形图展示平均消费额最高的省份</router-link></li>
  </ul>
</div>

<div class="graph">
    <!-- 渲染在这里 -->
    <router-view></router-view>
</div>
</template>

(3) 修改入口文件main.js,导入路由组件文件并指定路由映射,主要修改部分如下:

// 程序入口文件
...

// 1. 定义路由组件.  
import Home from "./views/HomeView.vue"
import Task01 from "./views/Task01View.vue"
import Task02 from "./views/Task02View.vue"
import Task04 from "./views/Task04View.vue"
import Task06 from "./views/Task06View.vue"

// 2. 定义一些路由映射
const routes = [
  { path: '/', component: Home },
  { path: '/task01', component: Task01 },
  { path: '/task02', component: Task02 },
  { path: '/task04', component: Task04 },
  { path: '/task06', component: Task06 },
]

...

(4) 执行Vue应用程序。

在VS Code编辑器下方的“终端”窗口中,执行如下命令,启动开发服务器:

$ npm run serve

打开浏览器,访问http://localhost:8080/,点击左侧的链接,就可以看到在右侧显示相应的条形图。

子任务七:用折柱混合图展示省份平均消费额和地区平均消费额

任务描述

  1. 编写Vue工程代码,根据接口,用折柱混合图展示2020年各省份平均消费额(四舍五入保留两位小数)和地区平均消费额(四舍五入保留两位小数)的对比情况,柱状图展示平均消费额最高的5个省份,折线图展示这5个省所在的地区的平均消费额变化,同时将用于图表展示的数据结构在浏览器的console中进行打印输出,将图表可视化结果和浏览器console打印结果分别截图并粘贴至客户端桌面【Release\任务E提交结果.docx】中对应的任务序号下。

请按以下步骤操作。

(1) 在项目的src/views/目录下,新建一个名为Task07View.vue的文件,编辑代码如下:

<template>
<h2>折柱混合图</h2>

<div class="left">
  <!-- echarts图表绘制在这里 -->      
  <div id="canvas" style="width: 580px;height:500px;"></div>    
</div>
 
<div class="right">
    <p><pre>{{ items }}</pre></p>  
</div>
</template>

<script>
  import * as echarts from '../assets/echarts.min.js'      

  // 请求的RESTful API 接口中(请替换为你自己的IP)
  var url = "http://IP:8999/dataVisualization/selectOrderInfo"
  var params = '{"startTime":"2020-01-01 00:00:00", "endTime":"2020-12-31 23:59:59"}'

  export default {
    name: 'TaskTop',
    data () {
      return {
        items: ''
      }
    },
    mounted () {
        // 根据准备好的dom初始化echarts实例
        var myChart = echarts.init(document.getElementById('canvas'));

        // 使用刚才指定的配置项和数据显示图表
        myChart.setOption({
          title: {
            text: '用折柱混合图展示省份平均消费额和地区平均消费额',
            subtext: '2020年',
            left: 'center'
          },
          tooltip: {
            trigger:'axis',
            formatter: '{b0}<br />{a0}: {c0}<br />{a1}: {c1}'
          },
          legend: {
            data: ['省平均消费额','地区平均消费额'],   // 要和series.name一致
            x:'center',
            y:'bottom'              
          },
          xAxis: {
            type: 'category',
            data: []     // **** ajax请求回来的数据要填充到这里
          },
          yAxis: [
            {
              type: 'value',
              name: '省平均消费额',
            },
            {
              type: 'value',
              name: '地区平均消费额',
          }],
          series: [
            {
              name: '省平均消费额',
              type: 'bar',
              barWidth : '50%',
              data: []   // **** ajax请求回来的数据要填充到这里
            },{
                name: '地区平均消费额',
                type: 'line',
                smooth:true,
                data: []   // **** ajax请求回来的数据要填充到这里
            }
          ]
        });
        // fetch请求
        fetch(url, {
              method: "post",
              headers: {'content-type': 'application/json'},
              body: params
            }
          )
              .then((response) => {
                // 取出响应中的json数据 *
                return response.json();
              })
              .then((data) => {  
                // 从返回的json数据中,抽取数据
                var jsObj = getAvgConsumption(data.data);

                // 将用于图表展示的数据结构在浏览器的console中进行打印输出
                console.log(jsObj)

                // 设置响应数据显示在右侧,便于观察
                // this.items = JSON.stringify(data,null,"\t\t\t");
                this.items = jsObj

                // 刷新echarts数据
                var option = myChart.getOption();
                option.xAxis[0].data = jsObj.a;     // 省份名称
                option.series[0].data = jsObj.b;   // 省份平均消费top5
                option.series[1].data = jsObj.c;   // 所属地区的平均消费额
                myChart.setOption(option);
              })
              .catch(error => {   // 请求失败处理
                  console.log(error);
              })
              .then(() => {
                this.loading = false;
              });
    }
  }

  // 汇总统计各省和地区的平均消费金额,并构造在echarts中显示的数据
  function getAvgConsumption(jsArray){
    // 各个省的平均消费金额
    var mapByProvince = getAvgConsumptionByProvince(jsArray);

    // 各个地区的平均消费金额
    var mapByRegion = getAvgConsumptionByArea(jsArray);      

    // top 5
    // 先转为数组,再按金额排序,然后取前5个
    var top5Arr = Array.from(mapByProvince).sort((a,b) => b[1].avgConsumAmount - a[1].avgConsumAmount).slice(0,5)

    // 遍历top5Arr,需要返回 省份名称数组,各省份平均消费额数组,各地区平均消费额数组  
    var provinces = []; // 存储省份名称
    var avgByPorvinces = [];     // 存储各省份平均消费额
    var avgByRegions = [];       // 存储各地区平均消费额
    for (var [key, value] of top5Arr) {
      provinces.push(key); // 放入省份名称
      avgByPorvinces.push(value.avgConsumAmount); // 放入各省份平均消费额
      // 该省所属地区的平均消费额
      avgByRegions.push(mapByRegion.get(value.regionName)); // 根据地区名,获取该地区的平均消费额
    }

    // 以对象形式返回
    return {a:provinces, b:avgByPorvinces, c:avgByRegions};
  }

  // 统计各个省的平均消费金额
  function getAvgConsumptionByProvince(jsArray){
    // 存储每个省及其总金额、总订单数
    var dataMap = new Map();  

    for (var index in jsArray){     // 这里遍历的是索引          
        var jsObj = jsArray[index]   // 根据索引获得对象
        var provinceName = jsObj.provinceName;   // 订单所属省份          
        var finalTotalAmount = jsObj.finalTotalAmount; // 订单金额
        var regionName = jsObj.regionName;   // 订单所属地区

        // 构造一个对象,存储某省份的累加金额和累加订单数(以便计算平均金额)
        var obj = new Object();

        // 如果有该省份,则累加金额和数量
        if(dataMap.has(provinceName)){        
          var accOjb = dataMap.get(provinceName);   // 获得原来累加的对象    
          obj.totalAmount = accOjb.totalAmount + finalTotalAmount;   // 累加金额
          obj.totalNum = accOjb.totalNum + 1;   // 总订单数。一条订单计数1
          obj.regionName = regionName;   // 所在地区
        }
        // 如果没有,则说明是该省第一个订单
        else{
          obj.totalAmount = finalTotalAmount;   // 累加金额
          obj.totalNum = 1;   // 总订单数。一条订单计数1
          obj.regionName = regionName;   // 所在地区
        }
        dataMap.set(provinceName, obj);       // 将更新后的obj存入map
    }

    // 计算每个省的平均消费额
    var avgMap = new Map();
    for (var [province, accObj] of dataMap) {
      var avgConsumAmount = Math.round((accObj.totalAmount / accObj.totalNum) * 100) / 100; // 保留两位小数
      avgMap.set(province, {avgConsumAmount: avgConsumAmount, regionName: accObj.regionName});   // {省份,{平均消费金额,所属省份}}
    }

    return avgMap;
  }

  // 统计各个地区的平均消费金额
  function getAvgConsumptionByArea(jsArray){
    // 存储每个省及其总金额、总订单数
    var dataMap = new Map();  

    for (var index in jsArray){     // 这里遍历的是索引          
        var jsObj = jsArray[index]   // 根据索引获得对象
        var regionName = jsObj.regionName;   // 订单所属地区          
        var finalTotalAmount = jsObj.finalTotalAmount; // 订单金额

        // 构造一个对象,存储某地区的累加金额和累加订单数(以便计算平均金额)
        var obj = new Object();

        // 如果有该省份,则累加金额和数量
        if(dataMap.has(regionName)){        
          var accOjb = dataMap.get(regionName);   // 获得原来累加的对象    
          obj.totalAmount = accOjb.totalAmount + finalTotalAmount;   // 累加金额
          obj.totalNum = accOjb.totalNum + 1;   // 总订单数。一条订单计数1
        }
        // 如果没有,则说明是该地区第一个订单
        else{
          obj.totalAmount = finalTotalAmount;   // 累加金额
          obj.totalNum = 1;   // 总订单数。一条订单计数1
        }
        dataMap.set(regionName, obj);       // 将更新后的obj存入map
    }

    // 计算每个地区的平均消费额
    var avgMap = new Map();
    for (var [region, accObj] of dataMap) {
      var avgConsumAmount = Math.round((accObj.totalAmount / accObj.totalNum) * 100) / 100; // 保留两位小数
      avgMap.set(region, avgConsumAmount);   // {省份,平均消费金额}
    }

    return avgMap;
  }

</script>

(2) 修改主组件App.vue,添加导航链接和渲染组件,代码如下:

<template>
<div class="menu">
  <h3>请选择分析结果</h3>
  <ul>
      <!--使用 router-link 组件进行导航 -->
      <li><router-link to="/">首页</router-link></li>
      <li><router-link to="/task01">任务1:用柱状图展示消费额最高的省份</router-link></li>
      <li><router-link to="/task02">任务2:用饼状图展示各地区消费能力</router-link></li>
      <li><router-link to="/task04">任务4:用折线图展示每年上架商品数量的变化</router-link></li>
      <li><router-link to="/task06">任务6:用条形图展示平均消费额最高的省份</router-link></li>
      <li><router-link to="/task07">任务7:用折柱混合图展示省份平均消费额和地区平均消费额</router-link></li>
  </ul>
</div>

<div class="graph">
    <!-- 渲染在这里 -->
    <router-view></router-view>
</div>
</template>

(3) 修改入口文件main.js,导入路由组件文件并指定路由映射,主要修改部分如下:

// 程序入口文件
...

// 1. 定义路由组件.  
import Home from "./views/HomeView.vue"
import Task01 from "./views/Task01View.vue"
import Task02 from "./views/Task02View.vue"
import Task04 from "./views/Task04View.vue"
import Task06 from "./views/Task06View.vue"
import Task07 from "./views/Task07View.vue"

// 2. 定义一些路由映射
const routes = [
  { path: '/', component: Home },
  { path: '/task01', component: Task01 },
  { path: '/task02', component: Task02 },
  { path: '/task04', component: Task04 },
  { path: '/task06', component: Task06 },
  { path: '/task07', component: Task07 },
]

...

(4) 执行Vue应用程序。

在VS Code编辑器下方的“终端”窗口中,执行如下命令,启动开发服务器:

$ npm run serve

打开浏览器,访问http://localhost:8080/,点击左侧的链接,就可以看到在右侧显示相应的折柱混合图。

© 版权声明
THE END
喜欢就支持一下吧
点赞258赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

夸夸
夸夸
还有吗!没看够!
取消
昵称表情代码图片

    暂无评论内容