项目小结(1):用电监控实现数据库查询竖向转横向

微信扫一扫,分享到朋友圈

项目小结(1):用电监控实现数据库查询竖向转横向

前言:

当努力到一定程度,幸运自与你不期而遇。

需求

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

而数据库中的内容:

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

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

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

需求难点分析

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

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

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

功能实现

1、前端展示:

1.1、单选框和多选框

<template>
<el-radio v-model="radio" label="1">备选项</el-radio>
<el-radio v-model="radio" label="2">备选项</el-radio>
</template>
<script>
export default {
data () {
return {
radio: '1'
};
}
}
</script>
复制代码

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

  • 注意外层包个div,写样式
  • lable的值必须和v-model相等才能显示值
  • 鼠标点击某个值,v-model的值则会与当前label的值相等。

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

<!--电压-->
<div v-if="radio2==100">
<el-checkbox-group v-model="checkList">
<el-checkbox  label="101" >Ua</el-checkbox>
<el-checkbox  label="102" >Ub</el-checkbox>
<el-checkbox  label="103" >Uc</el-checkbox>
<el-checkbox  label="111" >Uab</el-checkbox>
<el-checkbox  label="112" >Ubc</el-checkbox>
<el-checkbox  label="113" >Uca</el-checkbox>
</el-checkbox-group>
</div>
复制代码

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

time() {
let h1 = "",
m1 = "",
h = "",
m = "",
timestr = "",
arr = [],
seg = 15
for (let i = 15; i < 1455; i++) {
if (seg % 15 == 0) {
h1 = parseInt(i / 60)
h = h1 < 10 ? "0" + h1 : h1
m1 = parseInt(i % 60)
m = m1 < 10 ? "0" + m1 : m1
timestr = h + ":" + m
arr.push(timestr)
}
seg++;
}
this.$data.initArr = arr
},
复制代码

1.3 结合echarts使用

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

  • echarts的legend(显示框)和series(x轴)的data必须按顺序一一对应,因此如果有丢失数据的话,就用null来占位。
  • div外部dom的大小定义后,grid元素相当于padding,控制内部间距。
  • 点击效果:点击legend后隐藏该条曲线。代码如下:
/点击效果:点击legend后隐藏
this.$data.chart.on('legendselectchanged', function(params) {
var option = this.getOption();
var select_key = Object.keys(params.selected);
var select_value = Object.values(params.selected);
var n = 0;
select_value.map(res => {
if (!res) {
n++;
}
});
console.log('n', n)
if (n == select_value.length) {
option.legend[0].selected[params.name] = true;
}
this.setOption(option)
});
复制代码
  • 遇到的一个问题:legend标题显示返回后总是显示在同一个位置,那是因为返回多条数据的时候返回的都是同个位置,因此,返回第一条数据后,后面的数据的位置都应该有变化。( 解决经验
var x=200;
this.$data.option.legend=tableData.map(i=>{
x=x+100;
var arr=[];
for(var key in i){
arr.push(i[key])
}
return{
data:arr,
orient: "horizontal",
icon:"circle",
paddingLeft:50,
left:x
}
})
复制代码

1.4 一个新颖点

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

<el-table-column
:prop="`timeArr.${item}`"
v-for="item in initArr"
:key="item"
:label="item">
</el-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进行解析遍历。这就是实现思路。

代码实现:

获取基准数组:

/**
* 按15分钟分割datapoint 输出为: [0:15 0:30 0:45 1:00...24:00]
**/
public static ArrayList getSegArr(){
String h="",m="",timestr="";
int seg=15;
int h1,m1;
ArrayList<Object> list = new ArrayList<>();
for (int i=15;i<1455;i++){
if(seg%15==0){
h1=(i/60);
h = h1<10?"0"+h1:h1+"";
m1=(i%60);
m = m1<10?"0"+m1:m1+"";
timestr = h+":"+m;
list.add(timestr);
}
seg++;
}
return list;
}
复制代码

思路实现:

if (cdElectrictyPowerVO.getDataType().intValue()==CdMonitorConst.MONITOR_CONST_POWER_HAVE_A.getStatus()){
if(cdElectrictyDataVO.getDataName()==null){
cdElectrictyDataVO.setDataName(CdMonitorConst.MONITOR_CONST_POWER_HAVE_A.getName());
}
if(cdElectrictyDataVO.getDevName()==null){
cdElectrictyDataVO.setDevName(cdElectrictyPowerVO.getMpntName());
}
if(cdElectrictyDataVO.getDateTime()==null){
cdElectrictyDataVO.setDateTime(cdElectrictyPowerVO.getDataDate());
}
//如果当前的datapoint和基准数组的datapoint相等,则将key和value重写put进map,相同key自动重写,空值的value默认为null
if(DataPointSegUtil.dataPointToTime(cdElectrictyPowerVO.getDataPoint()).equals(segArr.get(i))){
timeMap.put(DataPointSegUtil.dataPointToTime(cdElectrictyPowerVO.getDataPoint()),cdElectrictyPowerVO.getPower().multiply(new BigDecimal(cdElectrictyPtCtVO.getPt())).multiply(new BigDecimal(cdElectrictyPtCtVO.getCt())));
}
}
复制代码

2、计算两点的差值。

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

if(!ObjectUtil.isEmpty(cdElectrictyDataVO2)) {
for (int i = 1; i < segArr.size() - 1; i++) {
BigDecimal bigDecimal = new BigDecimal(timeMap2.get(segArr.get(i)).toString());
BigDecimal bigDecimal2 = new BigDecimal(timeMap2.get(segArr.get(i - 1)).toString());
BigDecimal bigDecimal3 = new BigDecimal(-1);
//只有两个值都不相等才能进来
if (!bigDecimal.equals(bigDecimal3) && !bigDecimal2.equals(bigDecimal3)) {
BigDecimal subtract = bigDecimal.subtract(bigDecimal2);
timeMap2New.put(segArr.get(i) + "", subtract.multiply(new BigDecimal(cdElectrictyPtCtVO.getPt())).multiply(new BigDecimal(cdElectrictyPtCtVO.getCt())));
}else{
timeMap2New.put(segArr.get(i)+"",null);
}
}
}
复制代码

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

微信扫一扫,分享到朋友圈

项目小结(1):用电监控实现数据库查询竖向转横向

荣耀推出“共享笔记本电脑”:叫外卖就能送到家

上一篇

C++雾中风景15:聊聊让人抓狂的Name Mangling

下一篇

你也可能喜欢

项目小结(1):用电监控实现数据库查询竖向转横向

长按储存图像,分享给朋友