db2 null转0_项目小结(一):用电监控实现数据库查询竖向转横向

前言:

微信公众号:潇雷
当努力到一定程度,幸运自与你不期而遇。

需求

1、实现对电能采集设备各类数据的汇总展示,数据库中的点为每隔15分钟一个值,界面设计如下:

e5afc73899c52b92d30801527394cecc.png

而数据库中的内容:
0efc8304c6811ea1c9bb49aec6d0af4b.png

其中的DataPoint的分钟点,对应的每15分钟一个点。

2、电量的实现要用柱状图来表示:后面一个点的数据减去前面一个点的数据算后面那个点的值,还要考虑空值的存在。第一个点的值减去前天最后一个点的值,暂时需求定为如果一个点没有数据则后面那个点就不去相减。

3、最后计算出来的值都要乘个系数。

需求难点分析

1、正如上面数据库中的数据所展示的,每个分钟点一个数据,而到展示端变成每个分钟点的数据横向展示,而且会出现断点数据的存在。那么这时候的实现就比较麻烦了,这就是数据库竖向转横向问题

2、电量相减的点考虑循环判断去做。

3、前端用Vue+elementui+echarts来实现。

功能实现

1、前端展示:

1.1、单选框和多选框

 1<template>
2  <el-radio v-model="radio" label="1">备选项el-radio>
3  <el-radio v-model="radio" label="2">备选项el-radio>
4template>
5
6<script> 7  export default { 8    data () { 9      return {10        radio: '1'11      };12    }13  }14script>

这是elementui的案例。
关于radio单选框问题需要注意的点:

  • 注意外层包个div,写样式

  • lable的值必须和v-model相等才能显示值

  • 鼠标点击某个值,v-model的值则会与当前label的值相等。

实现思路:页面初始化时查询所有设备(并网点),传参的时候传入并网点id,单选电压、电流、功率、电量的时候,每个label的值不同,后面多选框的展示与这个label值相等则展示出来。
例如:

 1
2              <div v-if="radio2==100" style="padding-top: 20px;margin-left: 50px">
3                 <el-checkbox-group v-model="checkList">
4                    <el-checkbox  label="101" >Uael-checkbox>
5                    <el-checkbox  label="102" >Ubel-checkbox>
6                    <el-checkbox  label="103" >Ucel-checkbox>
7                    <el-checkbox  label="111" >Uabel-checkbox>
8                    <el-checkbox  label="112" >Ubcel-checkbox>
9                    <el-checkbox  label="113" >Ucael-checkbox>
10                el-checkbox-group>
11              div>

1.2 前端的这个表格需要自己来画,每隔15分钟作为一列的话共有96个,用代码生成:

 1time() {
2              let h1 = "",
3                  m1 = "",
4                  h = "",
5                  m = "",
6                  timestr = "",
7                  arr = [],
8                  seg = 15
9              for (let i = 15; i 1455; i++) {
10                  if (seg % 15 == 0) {
11                      h1 = parseInt(i / 60)
12                      h = h1 10 ? "0" + h1 : h1
13                      m1 = parseInt(i % 60)
14                      m = m1 10 ? "0" + m1 : m1
15                      timestr = h + ":" + m
16                      arr.push(timestr)
17                  }
18                  seg++;
19              }
20              this.$data.initArr = arr
21          },

1.3 结合echarts使用

echarts常用于大数据可视化展示,必须要准备dom节点来创建,每个echarts实例独占一个Dom节点。

  • echarts的legend(显示框)和series(x轴)的data必须按顺序一一对应,因此如果有丢失数据的话,就用null来占位。

  • div外部dom的大小定义后,grid元素相当于padding,控制内部间距。

  • 点击效果:点击legend后隐藏该条曲线。代码如下:

 1/点击效果:点击legend后隐藏
2              this.$data.chart.on('legendselectchanged', function(params) {
3                  var option = this.getOption();
4                  var select_key = Object.keys(params.selected);
5                  var select_value = Object.values(params.selected);
6                  var n = 0;
7                  select_value.map(res => {
8                      if (!res) {
9                          n++;
10                      }
11                  });
12                  console.log('n', n)
13                  if (n == select_value.length) {
14                      option.legend[0].selected[params.name] = true;
15                  }
16                  this.setOption(option)
17
18              });
  • 遇到的一个问题:legend标题显示返回后总是显示在同一个位置,那是因为返回多条数据的时候返回的都是同个位置,因此,返回第一条数据后,后面的数据的位置都应该有变化。(解决经验)

 1 var x=200;
2              this.$data.option.legend=tableData.map(i=>{
3                  x=x+100;
4                  var arr=[];
5                  for(var key in i){
6                      arr.push(i[key])
7                  }
8                  return{
9                      data:arr,
10                      orient: "horizontal",
11                      icon:"circle",
12                      paddingLeft:50,
13                      left:x
14                  }
15              })

1.4 一个新颖点

这个点是我对于搞后端的人来说做前端可能真的有点难,就是在前端生成一个时间数组后,如何在table表格里面把这些值给遍历出来。我试了几种都不能表示出来这个时间数组,最后问我师傅,他成功的试了出来。因此记录下来:在prop里面加个单引号,然后通过$获取,至于原因我还不知道。

1       table-column2                        :prop="`timeArr.${item}`"3                        v-for="item in initArr"4                        :key="item"5                        :label="item">6              table-column>
2、后端及数据库实现

难点分析:

2.1、解决数据库查询数据竖向转横向

思路:

可以在sql通过case when来实现,但是查询后96个点的查询时间为7s左右,因此不考虑,后面觉得在代码角度来转变更快。这块之前并没有做过,因此思路还是很重要的。虚拟一个基准数组,这样就有这些坐标点的key,保证了这些key与前端的key相等,就不会说断点问题,另外遍历这个查询结果,如果数据库的时间点与基准数组的key相等,则把这个key的value更新为当前时间点的数据。用linkedhashMap来表现,因为它有序,map相同key会不断重写,没有被重写的key的value为null,最后返回一个map的key-value列,封装成实体给前端,前端就可以对这个类中的map进行解析遍历。这就是实现思路。

代码实现:

获取基准数组:

 1 /** 2     * 按15分钟分割datapoint 输出为: [0:15 0:30 0:45 1:00...24:00] 3    **/
4    public static ArrayList getSegArr(){
5        String h="",m="",timestr="";
6        int seg=15;
7        int h1,m1;
8        ArrayList list = new ArrayList<>(); 9        for (int i=15;i<1455;i++){10            if(seg%15==0){11                h1=(i/60);12                h = h1<10?"0"+h1:h1+"";13                m1=(i%60);14                m = m1<10?"0"+m1:m1+"";15                timestr = h+":"+m;16                list.add(timestr);17            }18            seg++;19        }20        return list;21    }

思路实现:

 1                if (cdElectrictyPowerVO.getDataType().intValue()==CdMonitorConst.MONITOR_CONST_POWER_HAVE_A.getStatus()){
2                    if(cdElectrictyDataVO.getDataName()==null){
3                        cdElectrictyDataVO.setDataName(CdMonitorConst.MONITOR_CONST_POWER_HAVE_A.getName());
4                    }
5                    if(cdElectrictyDataVO.getDevName()==null){
6                        cdElectrictyDataVO.setDevName(cdElectrictyPowerVO.getMpntName());
7                    }
8                    if(cdElectrictyDataVO.getDateTime()==null){
9                        cdElectrictyDataVO.setDateTime(cdElectrictyPowerVO.getDataDate());
10                    }
11                    //如果当前的datapoint和基准数组的datapoint相等,则将key和value重写put进map,相同key自动重写,空值的value默认为null
12                    if(DataPointSegUtil.dataPointToTime(cdElectrictyPowerVO.getDataPoint()).equals(segArr.get(i))){
13                        timeMap.put(DataPointSegUtil.dataPointToTime(cdElectrictyPowerVO.getDataPoint()),cdElectrictyPowerVO.getPower().multiply(new BigDecimal(cdElectrictyPtCtVO.getPt())).multiply(new BigDecimal(cdElectrictyPtCtVO.getCt())));
14                    }
15                }

2、计算两点的差值。

这块的比较需要用到bigDecimal,商业计算一般都用这个,因为它本质是用String类转的,不存在精确度丢失问题。第一点的数据提前塞进去。后面的从第二个点开始塞。

 1if(!ObjectUtil.isEmpty(cdElectrictyDataVO2)) {
2            for (int i = 1; i 1; i++) {
3                BigDecimal bigDecimal = new BigDecimal(timeMap2.get(segArr.get(i)).toString());
4                BigDecimal bigDecimal2 = new BigDecimal(timeMap2.get(segArr.get(i - 1)).toString());
5                BigDecimal bigDecimal3 = new BigDecimal(-1);
6                //只有两个值都不相等才能进来
7                if (!bigDecimal.equals(bigDecimal3) && !bigDecimal2.equals(bigDecimal3)) {
8                    BigDecimal subtract = bigDecimal.subtract(bigDecimal2);
9                    timeMap2New.put(segArr.get(i) + "", subtract.multiply(new BigDecimal(cdElectrictyPtCtVO.getPt())).multiply(new BigDecimal(cdElectrictyPtCtVO.getCt())));
10                }else{
11                    timeMap2New.put(segArr.get(i)+"",null);
12                }
13            }
14        }

展现

以上这就是这个需求前后端解决的完整思路,页面效果如下:

ac906e29ac2d3778eb4848f22a40fe17.png
ac6f119942d69b1d057d5035f4775987.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值