扇区架次数动态展示

打开前端Vue项目:kongguan_web,完成前端src/components/echart/SectorFlightChart.vue页面设计,使用ECharts插件实现柱状图和饼状图

  • 在src/components目录下创建echart目录,完成src/components/echart/SectorFlightChart.vue 的页面div设计:
<template xmlns:el-col="http://www.w3.org/1999/html">
  <div class="home">
    <div id="barFlightChart" class="chart" />
  </div>
</template>
... 接下文 ...
  • 初始化数据,代码如下:
... 接上文 ...
<script>
  import {findATCTime} from "../../api/chartdata/chartdata";

  export default {
    name: "SectorFlightChart",
    data() {
      return {
        sectorData: [],
        barChartData: [],
        barChartAxis: [],
        sectorCharData: [],
        sectorCharOneData: [],
        sectorChartAxis: ['K', 'S', 'E', 'P', 'G'],

        chartOption: {},
        myChart: {},
      }
    },
     mounted() {
      this.initChart();
      this.loadData();
    },
... 接下文 ...
  • 初始化ECharts,代码如下:
... 接上文 ...
    methods: {
      initChart() {
        this.myChart = this.$echarts.init(document.getElementById("barFlightChart"));
        this.chartOption = {
          baseOption: {
            timeline: {
              axisType: 'category',
              // realtime: false,
              // loop: false,
              autoPlay: true,
              // currentIndex: 2,
              playInterval: 1000,
              // controlStyle: {
              //     position: 'left'
              // },
              lineStyle: {color: "#bcc9d7", width: 1},
              controlStyle: {showPlayBtn: !1, showPrevBtn: !1, showNextBtn: !1},
              checkpointStyle: {color: "#f19326", symbol: "circle", symbolSize: 10, borderWidth: 0},
              itemStyle: {normal: {color: "#419ae7"}},
            },
            title: {
              text: "扇区架次数动态循环展示",
              subtext: "",
              top:18,
              left: 26,
              textStyle: {
                color: "#000000"
              },
            },
            tooltip: {
              trigger: "item",
              padding: 10,
              backgroundColor: "#222",
              borderColor: "#777",
              borderWidth: 1,
            },
            angleAxis: {
              type: "category",
              axisTick: {show: !1},
              axisLine: {show: !0, lineStyle: {color: "#d2dde7"}},
              axisLabel: {color: "#d2dde7"},
              data: ["G区", "K区", "E区", "P区", "S区"],
              z: 10
            },
            radiusAxis: {
              min: 0,
              axisLine: {show: !1, lineStyle: {color: "#000", opacity: .3}},
              axisLabel: {show: !1, color: "#000"},
              axisTick: {show: !1},
              splitLine: {lineStyle: {color: "#d2dde7"}},
              splitArea: {show: !1, areaStyle: {color: "rgb(1, 10, 63)", opacity: .8}}
            },
            grid: {left: "10%", right: "50%", top: "10%", bottom: "9%", containLabel: !1},
            polar: {center: ["75%", "45%"], radius: "50%"},
            xAxis: [{
              type: 'value',
              boundaryGap: [0, 0.01],
              splitLine: {
                show: false
              },
              show: false,
              axisLine: {   //横轴样式
                lineStyle: {},
              },
              position:'top'
            }],
            yAxis: [{
              type: 'category',
              data: this.barChartAxis,
              inverse:true,
              axisLine: {   //纵轴样式
                lineStyle: {
                  color: '#73777d'
                }
              },
              axisLabel: {
                rotate: -45
              }
            }],
            series: [{
              type: "bar",
              coordinateSystem: "polar",
              name: "扇区",
              center: ["75%", "45%"],
              stack: "a",
              itemStyle: {
                normal: {
                  color: function (t) {
                    return ["#51b8f9", "#7d92ff", "#5fccc3", "#f19326", "#f258b6"][t.dataIndex]
                  }, label: {show: !0, position: "top", formatter: "{b}\n{c}"}
                }
              }
            }, {
              name: "本日架次数",
              type: "bar",
              barWidth: 8,
              radius: 90,
              avoidLabelOverlap: !1,
              label: {
                normal: {show: !1, position: "outside", formatter: "{c}"},
                emphasis: {show: !0, textStyle: {fontSize: "12", fontWeight: "normal"}}
              },
              labelLine: {normal: {show: !1}},
              itemStyle: {normal: {color: "#51b8f9"}, emphasis: {color: "#f19326"}}
            }]
          }
        }
        this.myChart.setOption(this.chartOption);
      },
... 接下文 ...
  • 加载整理数据,然后拼装ECharts专用的options对象,代码如下:
  //加载数据
      loadData() {
        findATCTime().then(data => {
          if (data.isSuccess) {
            this.formatData(data.result);
          } else {
            this.$message.error("数据获取失败");
          }
        });
      },
      //整理数据
      formatData(data) {
        let timeLineData = [];
        let barDataArr = [];
        let pieDataArr = [];
        let optionArr = [];
        for (let i = 0; i < data.length; i++) {
          let dayItemData = data[i];
          timeLineData.push(i + 1);
          let dayFlightSum = 0;
          let dayFlightDetail = [];
          for (let j = 0; j < dayItemData.length; j++) {
            dayFlightDetail.push(dayItemData[j][this.sectorChartAxis[j]]);
            dayFlightSum = dayFlightSum + parseInt(dayItemData[j][this.sectorChartAxis[j]]);
          }
          pieDataArr.push(dayFlightDetail);
          barDataArr.push(dayFlightSum);
        }
        //拼装 echart专用的options对象
        for (let i = 0; i < timeLineData.length; i++) {
          optionArr.push({
            series: [{data: pieDataArr[i]}, {data: barDataArr}],
            yAxis: [{data: timeLineData, nameTextStyle: {fontSize: 4, align: "center"},axisLabel:{formatter:'第{value}天'}}]
          })
        }
        this.chartOption.baseOption.timeline.data = timeLineData;
        this.chartOption.options = optionArr;
        this.refreshChart();
      }
      refreshChart() {
        this.myChart.setOption(this.chartOption);
      }
    }
  }
</script>
  • 页面样式,代码如下:
<style scoped>
  .home {
    height: 700px;
    overflow: auto;
    background-color: #ffffff;
    border: 1px solid #ebedf2;
    border-radius: 10px;
    box-shadow: 3px 3px 3px 3px #ebedf2;
  }
  .home::-webkit-scrollbar {
    display: none;
  }
  .chart {
    height: 680px;
  }
</style>
  • 加载数据时,会调用src/api/chartdata/chartdata.js中定义的findATCTime方法,向服务端发送GET请求,获取扇区架次数动态统计,chartdata.js的完整代码如下:
import request from '../../utils/request'
const baseUrl = "/api"
/**
 * 扇区架次数动态统计
 */
export function findATCTime() {
  return request({
    url: baseUrl + "/atc/findATCTime",
    method: "GET"
  })
}
/**
 * 获取各个扇区通话饱和度
 */
export function findCallSaturation() {
  return request({
    url: baseUrl + "/callSaturation/findCallSaturation",
    method: "GET"
  })
}
export function annualWarningStatisticsByCategory() {
  return request({
    url: baseUrl + "/warnFlightHistory/annualWarningStatisticsByCategory",
    method: "GET"
  })
}
export function getAirPortCount() {
  return request({
    url: baseUrl + "/company/getAirPortCount",
    method: "GET"
  })
}
/**
 * 获取从青岛起飞航班数前十的航线
 * @returns {AxiosPromise}
 */
export function findByLimit() {
  return request({
    url: baseUrl + "/airLine/findByLimit",
    method: "GET"
  })
}

2、后端的实现,打开后端项目:BigData-KongGuan

  • 编写实体类com/qrsoft/entity/Atc.java(前面任务时,已经创建过)
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("atc_number")
public class Atc implements Serializable {
	@TableId(value = "id",type = IdType.AUTO)
	private Integer id;

	@TableField(value = "ACID")
	private String acId;

	@TableField(value = "ATC_TIME")
	private String atcTime;

	@TableField(value = "EXECUTE_DATE")
	private String executeDate;

	@TableField(value = "PLAN_SECTOR_NAME")
	private String planSectorName;

	@TableField(exist = false)
	private String count;
}
  • 编写数据访问类com/qrsoft/mapper/AtcMapper.java,添加findATCTime()方法和findATCTime2()方法,AtcMapper类的完整代码如下:
import com.qrsoft.entity.Atc;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface AtcMapper extends BaseMapper<Atc> {
    @Select("select PLAN_SECTOR_NAME,COUNT(*) as count from atc_number GROUP BY PLAN_SECTOR_NAME;")
    List<Atc> findSectorSortie();

    @Select("select EXECUTE_DATE from atc_number group by EXECUTE_DATE order by EXECUTE_DATE desc limit 19;")
    List<String> findATCTime();

    @Select("select PLAN_SECTOR_NAME,count(*) as count from atc_number where EXECUTE_DATE = #{executeTime} and PLAN_SECTOR_NAME = #{sectorName}")
    Atc findATCTime2(String executeTime,String sectorName);
}
  • 编写Service类com/qrsoft/service/AtcService.java,添加findATCTime()方法,AtcService类的完整代码如下:
package com.qrsoft.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qrsoft.common.Result;
import com.qrsoft.common.ResultConstants;
import com.qrsoft.entity.Atc;
import com.qrsoft.entity.MultiRadar;
import com.qrsoft.mapper.AtcMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Service
public class AtcService extends ServiceImpl<AtcMapper, Atc> {
    @Autowired
    private MultiRadarService multiRadarService;

    /**
     * 查询所有扇区航班架次
     */
    public Result findSectorSortie() {
        List<Atc> sectorSortie = baseMapper.findSectorSortie();
        return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS, sectorSortie);
    }

    /**
     * 根据扇区号查询架次
     * @param planSectorName
     */
    public Result findLocusCount(String planSectorName) {
        QueryWrapper<MultiRadar> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("section",planSectorName);
        int count = multiRadarService.count(queryWrapper);
        return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS, count);
    }

    /**
     * 扇区架次数动态统计(饼状图)
     */
    public Result findATCTime() {
        List<String> sectorName = new ArrayList<>();
        sectorName.add("K");
        sectorName.add("S");
        sectorName.add("E");
        sectorName.add("P");
        sectorName.add("G");
        List<String> executeTime = baseMapper.findATCTime();

        List list = new ArrayList();
        for (int i = 0; executeTime.size() > i; i++) {
            ArrayList<Object> objects = new ArrayList<>();
            for (int j = 0; sectorName.size() > j; j++) {
                Atc atcTime2 = baseMapper.findATCTime2(executeTime.get(i), sectorName.get(j));
                HashMap<String, Object> map = new HashMap<>();
                if (atcTime2.getPlanSectorName() != null) {
                    map.put(atcTime2.getPlanSectorName(), atcTime2.getCount());
                }else {
                    map.put(sectorName.get(j),0);
                }
                objects.add(map);
            }
            list.add(objects);
        }
        return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS, list);
    }
}
  • 编写扇区操作的控制器类com/qrsoft/controller/AtcController.java,添加findATCTime()方法,AtcController类的完整代码如下:
package com.qrsoft.controller;

import com.qrsoft.common.Result;
import com.qrsoft.service.AtcService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Api(tags = "扇区操作类")
@RestController
@RequestMapping("/api/atc")
public class AtcController {
    @Autowired
    private AtcService service;
    /**
     * 获取各扇区航班数
     */
    @ApiOperation(value = "获取各扇区航班数")
    @GetMapping("/findSectorSortie")
    public Result findSectorSortie(){
        return service.findSectorSortie();
    }

    /**
     * 根据扇区名称获取该扇区航班数
     * @param planSectorName
     */
    @ApiOperation(value = "根据扇区名称获取该扇区航班数")
    @GetMapping("/findLocusCount")
    public Result findLocusCount(@RequestParam String planSectorName){
        return service.findLocusCount(planSectorName);
    }

    /**
     * 扇区架次数动态统计(饼状图)
     */
    @ApiOperation(value = "扇区架次数动态统计(饼状图)")
    @GetMapping("/findATCTime")
    public Result findATCTime(){
        return service.findATCTime();
    }
}

3、实现前端的报表展示

  • 回顾前面已经完成的src/components/echart/SectorFlightChart.vue页面,在页面中绑定数据的核心代码为:
  //加载数据
      loadData() {
        findATCTime().then(data => {
          if (data.isSuccess) {
            this.formatData(data.result);
          } else {
            this.$message.error("数据获取失败");
          }
        });
      },
      //整理数据
      formatData(data) {
        let timeLineData = [];
        let barDataArr = [];
        let pieDataArr = [];
        let optionArr = [];
        for (let i = 0; i < data.length; i++) {
          let dayItemData = data[i];
          timeLineData.push(i + 1);
          let dayFlightSum = 0;
          let dayFlightDetail = [];
          for (let j = 0; j < dayItemData.length; j++) {
            dayFlightDetail.push(dayItemData[j][this.sectorChartAxis[j]]);
            dayFlightSum = dayFlightSum + parseInt(dayItemData[j][this.sectorChartAxis[j]]);
          }
          pieDataArr.push(dayFlightDetail);
          barDataArr.push(dayFlightSum);
        }

        //拼装 echart专用的options对象
        for (let i = 0; i < timeLineData.length; i++) {
          optionArr.push({
            series: [{data: pieDataArr[i]}, {data: barDataArr}],
            yAxis: [{data: timeLineData, nameTextStyle: {fontSize: 4, align: "center"},axisLabel:{formatter:'第{value}天'}}]
          })
        }

        this.chartOption.baseOption.timeline.data = timeLineData;
        this.chartOption.options = optionArr;
        this.refreshChart();
      }
,
      //重新绑定数据
      refreshChart() {
        this.myChart.setOption(this.chartOption);
      }
  • 在src/views/Home/Index.vue引入SectorFlightChart组件,代码如下:
... 略 ...

  import AirLine from "../../components/AirLine";
  import Section from "../../components/Section";
  import Delay from "../../components/Delay";
  import WarnStatistice from "../../components/WarnStatistice";
  import SectorFlightChart from "../../components/echart/SectorFlightChart";

  import {hasPermission} from "../../utils/permission";

  export default {
    data() {
      return {
      };
    },
    mounted() {
    },
    components: {AirLine,Section,Delay,WarnStatistice,SectorFlightChart},
    methods: {
      isShow(permission){
        return hasPermission(permission);   
      }
    }

... 略 ...
  • 在src/views/Home/Index.vue添加“扇区架次动态展示”组件,代码如下:
<el-row :gutter="30" v-show="isShow('/section/detail')">
    <el-col :span="16" align="center">
      <SectorFlightChart/>
    </el-col>

    // ... 略 ...
</el-row>

注意:在上面代码中【 v-show="isShow('/section/detail')" 】属性的作用是判断当前登录的用户是否有权限显示当前内容,如果当前登录的用户没有权限,则不会显示当前内容,新用户的权限需要到MySQL数据库中进行设置。

这里有两种方式,可以显示当前内容:

1)去掉【 v-show="isShow('/section/detail')" 】属性,即不判断是否有权限显示。

2)需要使用有权限的用户登录才能显示,或到数据库中分配权限。

参照任务“动态航线图”进行设置。

例如我们前面使用的用户admin,该用户没有权限显示,所以使用admin用户登录系统时是不会显示当前内容的,如果要进行权限设置,可以进入MySQL安装节点(node3节点),然后进入数据库,为admin用户授权。

[root@node3 ~]# mysql -uroot -p123456
mysql> use kongguan;

先查看角色表中,“管理员”的ID:

修改sys_auth表,添加一个【/section/detail】权限:

mysql> insert into sys_auth(auth_name,auth_code,menu_url) values('show detail','/section/detail','/section/detail');

修改role_auth表,将权限授权给“管理员”角色:

mysql>insert into role_auth(role_id,auth_id) values(3,198);

  • src/views/Home/Index.vue的完整代码如下:
<template>
  <div class="index">
   <el-row :gutter="30" v-show="isShow('/flight/airline')">
      <el-col :span=24 align="center">
        <AirLine/>
      </el-col>
    </el-row> 
    <el-row :gutter="30"  v-show="isShow('/flight/section')">
      <el-col :span="24" align="center">
        <Section/>
      </el-col>
    </el-row>
    <el-row :gutter="30" v-show="isShow('/flight/delay')">
      <el-col :span="16" align="center">
        <Delay/>
      </el-col>
      <el-col :span="8" align="center">
        <year-warning-chart/>
      </el-col>
    </el-row>
    <el-row :gutter="30" v-show="isShow('/section/warning')">
      <el-col :span="12" align="center">
        <air-port-count-chart/>
      </el-col>
      <el-col :span="12" align="center">
        <WarnStatistice/>
      </el-col>
    </el-row>
    <el-row :gutter="30" v-show="isShow('/section/detail')">
      <el-col :span="16" align="center">
        <SectorFlightChart/>
      </el-col>
      <el-col :span="8" align="center">
        <sector-call-chart/>
      </el-col>
    </el-row>
  </div>
</template>

<script>
  import AirLine from "../../components/AirLine";
  import Section from "../../components/Section";
  import WarnStatistice from "../../components/WarnStatistice";
  import Delay from "../../components/Delay";

  import {hasPermission} from "../../utils/permission";

  import SectorFlightChart from "../../components/echart/SectorFlightChart";

  export default {
    data() {
      return {
      };
    },

    mounted() {
    },
    components: {AirLine, Section, WarnStatistice, Delay,SectorFlightChart},
    methods: {
      isShow(permission){
        return hasPermission(permission);
      }
    }
  };
</script>

<style scoped>
  .index {
    height: 100%;
    overflow: auto;
    padding-left: 44px;
    padding-right: 44px
  }
  .index::-webkit-scrollbar {
    display: none;
  }
  .caseClass {
    background: url('../../assets/images/index-bg.png') no-repeat;
    background-size: cover;
    margin-top: 20px;
    height: 284px;
  }
  .el-button {
    background: transparent;
  }
</style>
  • 确保Hadoop、Spark、Kafka、Redis、MySQL等服务均已经正常启动,如果没有正常启动,请参照前面的安装部署任务,完成这些服务的启动。

例如:查看MySQL是否正常启动。

  • 启动后端项目 BigData-KongGuan

  • 启动前端项目 kongguan_web

  • 报表的最终展示效果如下图所示:

  • 30
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值