Răsfoiți Sursa

feat: 实现指标汇聚

weijianghai 2 ani în urmă
părinte
comite
0357c5969c

+ 92 - 0
src/main/java/com/nokia/hb/dao/mapper/PerCfgCellMapper.java

@@ -100,4 +100,96 @@ public interface PerCfgCellMapper extends BaseMapper<PerCfgCell> {
             + " </script>")
     List<Map<String, Object>> others(@Param("indicators") String indicators, @Param("timeType") String timeType,
                                      @Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
+
+    /**
+     * 按地市汇聚
+     *
+     * @param citys      地市
+     * @param timeType   时间类型
+     * @param indicators 指标
+     * @param startTime  开始时间
+     * @param endTime    结束时间
+     * @return {@link List}<{@link Map}<{@link String}, {@link Object}>>
+     */
+    @Select("<script>"
+            + "select ${indicators} from pm_parse.pm_4g_${timeType}_city"
+            + " where sdate <![CDATA[ >= ]]> #{startTime}"
+            + " and sdate <![CDATA[ <= ]]> #{endTime}"
+            + " and city in"
+            + " <foreach open=\"(\" close=\")\" collection=\"citys\" item=\"item\" separator=\",\">"
+            + "   #{item}"
+            + " </foreach>"
+            + " order by sdate desc"
+            + " </script>")
+    List<Map<String, Object>> aggByCity(@Param("citys") Set<String> citys, @Param("timeType") String timeType,
+                                        @Param("indicators") String indicators,
+                                        @Param("startTime") LocalDateTime startTime,
+                                        @Param("endTime") LocalDateTime endTime);
+
+    /**
+     * 按区县汇聚
+     *
+     * @param quxians    区县
+     * @param timeType   时间类型
+     * @param indicators 指标
+     * @param startTime  开始时间
+     * @param endTime    结束时间
+     * @return {@link List}<{@link Map}<{@link String}, {@link Object}>>
+     */
+    @Select("<script>"
+            + "select ${indicators} from pm_parse.pm_4g_${timeType}_qu"
+            + " where sdate <![CDATA[ >= ]]> #{startTime}"
+            + " and sdate <![CDATA[ <= ]]> #{endTime}"
+            + " and quxian in"
+            + " <foreach open=\"(\" close=\")\" collection=\"quxians\" item=\"item\" separator=\",\">"
+            + "   #{item}"
+            + " </foreach>"
+            + " order by sdate desc"
+            + " </script>")
+    List<Map<String, Object>> aggByQuXian(@Param("quxians") Set<String> quxians, @Param("timeType") String timeType,
+                                         @Param("indicators") String indicators,
+                                         @Param("startTime") LocalDateTime startTime,
+                                         @Param("endTime") LocalDateTime endTime);
+
+    /**
+     * 地市为空汇聚
+     *
+     * @param timeType   时间类型
+     * @param indicators 指标
+     * @param startTime  开始时间
+     * @param endTime    结束时间
+     * @return {@link List}<{@link Map}<{@link String}, {@link Object}>>
+     */
+    @Select("<script>"
+            + "select ${indicators} from pm_parse.pm_4g_${timeType}_city"
+            + " where sdate <![CDATA[ >= ]]> #{startTime}"
+            + " and sdate <![CDATA[ <= ]]> #{endTime}"
+            + " and city is null"
+            + " order by sdate desc"
+            + " </script>")
+    List<Map<String, Object>> aggByOtherCity(@Param("timeType") String timeType,
+                                               @Param("indicators") String indicators,
+                                               @Param("startTime") LocalDateTime startTime,
+                                               @Param("endTime") LocalDateTime endTime);
+
+    /**
+     * 区县为空汇聚
+     *
+     * @param timeType   时间类型
+     * @param indicators 指标
+     * @param startTime  开始时间
+     * @param endTime    结束时间
+     * @return {@link List}<{@link Map}<{@link String}, {@link Object}>>
+     */
+    @Select("<script>"
+            + "select ${indicators} from pm_parse.pm_4g_${timeType}_qu"
+            + " where sdate <![CDATA[ >= ]]> #{startTime}"
+            + " and sdate <![CDATA[ <= ]]> #{endTime}"
+            + " and quxian is null"
+            + " order by sdate desc"
+            + " </script>")
+    List<Map<String, Object>> aggByOtherQuXian(@Param("timeType") String timeType,
+                                          @Param("indicators") String indicators,
+                                          @Param("startTime") LocalDateTime startTime,
+                                          @Param("endTime") LocalDateTime endTime);
 }

+ 3 - 1
src/main/java/com/nokia/hb/pojo/dto/RenderTableDto.java

@@ -8,7 +8,9 @@ import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-import javax.validation.constraints.*;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Past;
 import java.time.LocalDateTime;
 import java.util.Set;
 

+ 6 - 1
src/main/java/com/nokia/hb/pojo/enums/SearchTypeEnum.java

@@ -11,5 +11,10 @@ public enum SearchTypeEnum {
     /**
      * eci
      */
-    ECI;
+    ECI,
+    /**
+     * 汇聚
+     */
+    AGG,
+    ;
 }

+ 85 - 30
src/main/java/com/nokia/hb/service/PmService.java

@@ -1,6 +1,7 @@
 package com.nokia.hb.service;
 
 import com.nokia.common.R;
+import com.nokia.common.exception.BizException;
 import com.nokia.hb.dao.entity.PerCfgIndicator;
 import com.nokia.hb.dao.mapper.PerCfgCellMapper;
 import com.nokia.hb.dao.mapper.PerCfgIndicatorMapper;
@@ -35,23 +36,10 @@ public class PmService {
         indicatorSet.add("eci");
         indicatorSet.add("sdate");
         String indicators = String.join(",", indicatorSet);
+        List<Col> cols = getCols(indicatorSet);
         // 按地市查询
         if (SearchTypeEnum.AREA.equals(dto.getSearchType())) {
-            // 获取拥有的城市权限
-            Map<String, String> areas = (Map<String, String>) session.getAttribute("areas");
-            // 地区权限校验
-            for (String t : dto.getLteCitys()) {
-                if (!areas.containsKey(t)) {
-                    log.debug("没有权限的city: {}", t);
-                    return R.error("没有" + t + "的权限");
-                }
-            }
-            for (String t : dto.getNblteCitys()) {
-                if (!areas.containsKey(t)) {
-                    log.debug("没有权限的city: {}", t);
-                    return R.error("没有" + t + "的权限");
-                }
-            }
+            checkAreaPermission(dto, session);
             if (!CollectionUtils.isEmpty(dto.getLteQuxians())) {
                 List<Map<String, Object>> l = perCfgCellMapper.searchByCity(NetTypeEnum.LTE.name(), dto.getLteCitys(),
                         dto.getLteQuxians(), indicators, dto.getTimeType().name().toLowerCase(), dto.getStartTime(),
@@ -71,30 +59,75 @@ public class PmService {
             }
         }
         // 按eci查询
-        if (SearchTypeEnum.ECI.equals(dto.getSearchType())) {
+        else if (SearchTypeEnum.ECI.equals(dto.getSearchType())) {
             String[] conditionArray = dto.getCondition().split(",");
             Set<String> conditions = Stream.of(conditionArray).collect(Collectors.toSet());
             list = perCfgCellMapper.searchByEci(conditions, indicators, dto.getTimeType().name().toLowerCase(),
                     dto.getStartTime(), dto.getEndTime());
         }
-        if (CollectionUtils.isEmpty(list)) {
-            return R.ok(new RetData(new ArrayList<>(), new ArrayList<>()));
-        }
-        Map<String, String> ezMap = initZnEnMap();
-        List<Col> cols = new ArrayList<>();
-        Set<String> headers = list.get(0).keySet();
-        ezMap.forEach((k, v) -> {
-            if (headers.contains(k)) {
-                Col col = new Col();
-                col.setField(k);
-                col.setTitle(v);
-                col.setWidth(getWidth(v));
-                cols.add(col);
+        // 汇聚查询
+        else if (SearchTypeEnum.AGG.equals(dto.getSearchType())) {
+            checkAreaPermission(dto, session);
+            indicatorSet.remove("eci");
+            indicatorSet.add("city");
+            if (!CollectionUtils.isEmpty(dto.getLteCitys()) || !CollectionUtils.isEmpty(dto.getNblteCitys())) {
+                indicators = String.join(",", indicatorSet);
+                List<Map<String, Object>> l = perCfgCellMapper.aggByCity(Stream.concat(dto.getLteCitys().stream(),
+                                dto.getNblteCitys().stream()).collect(Collectors.toSet()),
+                        dto.getTimeType().name(), indicators, dto.getStartTime(), dto.getEndTime());
+                list.addAll(l);
             }
-        });
+            if (Boolean.TRUE.equals(dto.getIncludeOther())) {
+                indicators = String.join(",", indicatorSet);
+                List<Map<String, Object>> l = perCfgCellMapper.aggByOtherCity(dto.getTimeType().name().toLowerCase(),
+                        indicators, dto.getStartTime(), dto.getEndTime());
+                list.addAll(l);
+            }
+            indicatorSet.remove("city");
+            indicatorSet.add("quxian");
+            if (!CollectionUtils.isEmpty(dto.getLteQuxians()) || !CollectionUtils.isEmpty(dto.getNblteQuxians())) {
+                indicators = String.join(",", indicatorSet);
+                List<Map<String, Object>> l2 = perCfgCellMapper.aggByQuXian(Stream.concat(dto.getLteQuxians().stream(),
+                                dto.getNblteQuxians().stream()).collect(Collectors.toSet()),
+                        dto.getTimeType().name().toLowerCase(), indicators, dto.getStartTime(), dto.getEndTime());
+                list.addAll(l2);
+            }
+            if (Boolean.TRUE.equals(dto.getIncludeOther())) {
+                indicators = String.join(",", indicatorSet);
+                List<Map<String, Object>> l = perCfgCellMapper.aggByOtherQuXian(dto.getTimeType().name().toLowerCase(),
+                        indicators, dto.getStartTime(), dto.getEndTime());
+                list.addAll(l);
+            }
+            indicatorSet.add("city");
+            cols = getCols(indicatorSet);
+        }
         return R.ok(new RetData(cols, list));
     }
 
+    /**
+     * 检查区域权限
+     *
+     * @param dto     dto
+     * @param session 会话
+     */
+    private void checkAreaPermission(RenderTableDto dto, HttpSession session) {
+        // 获取拥有的城市权限
+        Map<String, String> areas = (Map<String, String>) session.getAttribute("areas");
+        // 地区权限校验
+        for (String t : dto.getLteCitys()) {
+            if (!areas.containsKey(t)) {
+                log.debug("没有权限的city: {}", t);
+                throw new BizException("没有" + t + "的权限");
+            }
+        }
+        for (String t : dto.getNblteCitys()) {
+            if (!areas.containsKey(t)) {
+                log.debug("没有权限的city: {}", t);
+                throw new BizException("没有" + t + "的权限");
+            }
+        }
+    }
+
     /**
      * 指标字段中英文map
      *
@@ -103,6 +136,7 @@ public class PmService {
     public Map<String, String> initZnEnMap() {
         Map<String, String> m = new LinkedHashMap<>();
         m.put("cellname", "小区中文名");
+        m.put("province", "省");
         m.put("city", "地市");
         m.put("quxian", "区县");
         m.put("vendor", "厂家");
@@ -119,4 +153,25 @@ public class PmService {
         int width = length * 15;
         return Math.max(width, 200);
     }
+
+    /**
+     * 得到表头
+     *
+     * @param headers 头
+     * @return {@link List}<{@link Col}>
+     */
+    List<Col> getCols(Set<String> headers) {
+        List<Col> cols = new ArrayList<>();
+        Map<String, String> ezMap = initZnEnMap();
+        ezMap.forEach((k, v) -> {
+            if (headers.contains(k)) {
+                Col col = new Col();
+                col.setField(k);
+                col.setTitle(v);
+                col.setWidth(getWidth(v));
+                cols.add(col);
+            }
+        });
+        return cols;
+    }
 }

+ 0 - 3
src/main/resources/application.yml

@@ -2,9 +2,6 @@ server:
   port: 9003
   servlet:
     context-path: /
-    session:
-      cookie:
-        http-only: true
   tomcat:
     uri-encoding: UTF-8
     max-threads: 800

+ 52 - 47
src/main/resources/templates/template.html

@@ -129,9 +129,9 @@
         <div class="grid-demo">
             <div class="row layui-form row2">
                 <div style="width:100%;float: left;">
-                    <div class="c1 label"> 粒度:</div>
+                    <div class="c1 label"> 时间粒度:</div>
                     <div class="timeTypeDiv c1" style="width: 10%;">
-                        <select name="timeType" id="timeType" lay-filter="timeType" onchange="console.log('555555555555555555')">
+                        <select name="timeType" id="timeType" lay-filter="timeType">
                             <option value="QUATER" selected>15分钟</option>
                             <option value="HOUR">小时</option>
                             <option value="DAY">天</option>
@@ -149,6 +149,7 @@
                 <div style="width:100%;float: left;">
                     <div class="column" id="searchType" style="width:auto;float: left;">
                         <input type="radio" name="where" value="AREA" title="按地市查询" lay-filter="where" checked>
+                        <input type="radio" name="where" value="AGG" title="按地市汇聚查询" lay-filter="where">
                         <input type="radio" name="where" value="ECI" title="按eci查询" lay-filter="where" >
                     </div>
                     <div style="width:70%;float: left;">
@@ -169,17 +170,17 @@
     const host = window.location.host
     const username = window.sessionStorage.getItem('userName')
     const socket = new WebSocket(`ws://${host}/ws?username=${username}`);
-    socket.onopen = (event) => {
-        console.log(event)
-    }
+    // socket.onopen = (event) => {
+    //     console.log(event)
+    // }
 
     socket.onclose = (event) => {
-        console.log(event)
+        // console.log(event)
         logout()
     }
 
     socket.onerror = (event) => {
-        console.log(event)
+        // console.log(event)
         logout()
     }
 
@@ -228,11 +229,11 @@
             });
             let dateArray = '';
             let timeType = $('#timeType').val()
-            console.log('timeType: ', timeType);
+            // console.log('timeType: ', timeType);
             let date = new Date();
-            if(timeType == 'QUATER'){ 
+            if(timeType === 'QUATER'){
                 dateArray= formatDate(date) + ' ' + '00:00:00' + ' - ' + formatDate(date) + ' ' + '00:15:00';
-                console.log('dateArray: ', dateArray);
+                // console.log('dateArray: ', dateArray);
             }
             
             initTreeCity(tree)
@@ -246,7 +247,7 @@
             //    console.log('ooooo')
                 // handleChange(data.value)
                 form.render('select'); // 渲染select,固定写法
-                if(data.value == 'QUATER'){ 
+                if(data.value === 'QUATER'){
                     dateArray= formatDate(date) + ' ' + '00:00:00' + ' - ' + formatDate(date) + ' ' + '00:15:00';
                     // console.log('dateArray: ', dateArray);
                     laydate.render({
@@ -255,11 +256,11 @@
                         range: true,
                         value: dateArray,
                         ready: function(date){
-                            console.log(date); //得到初始的日期时间对象:{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
+                            // console.log(date); //得到初始的日期时间对象:{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
                         },
                     });
                 }
-                if(data.value == 'HOUR'){ 
+                if(data.value === 'HOUR'){
                     // console.log('xiaoshi')
                     dateArray= formatDate(date) + ' ' + '00:00:00' + ' - ' + formatDate(date) + ' ' + '01:00:00';
                     // console.log('dateArray: ', dateArray);
@@ -269,11 +270,11 @@
                         range: true,
                         value: dateArray,
                         ready: function(date){
-                            console.log(date); //得到初始的日期时间对象:{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
+                            // console.log(date); //得到初始的日期时间对象:{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
                         },
                     });
                 }
-                if(data.value == 'DAY'){ 
+                if(data.value === 'DAY'){
                     // console.log('xiaoshi')
                     dateArray= formatDate(date) + ' ' + '00:00:00' + ' - ' + formatDate(date) + ' ' + '23:59:59';
                     // console.log('dateArray: ', dateArray);
@@ -283,7 +284,7 @@
                         range: true,
                         value: dateArray,
                         ready: function(date){
-                            console.log(date); //得到初始的日期时间对象:{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
+                            // console.log(date); //得到初始的日期时间对象:{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
                         },
                     });
                 }
@@ -295,10 +296,10 @@
                 range: true,
                 value: dateArray,
                 ready: function(date){
-                    console.log(date); //得到初始的日期时间对象:{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
+                    // console.log(date); //得到初始的日期时间对象:{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
                 },
                 change: function(value, date){
-                    console.log('date: ', date);
+                    // console.log('date: ', date);
 
                 }
             });
@@ -470,7 +471,7 @@
                 "indicators": [...indicators],
                 "timeType": timeType,
                 "startTime": startTime,
-                "endTime": endTime
+                "endTime": endTime,
             })
             $.ajax({
                 type: "POST",
@@ -526,15 +527,20 @@
                 alert('请填写eci')
                 return;
             }
-            if (searchType === 'AREA' && tree.getChecked('Id1').length === 0) {
+            if ((searchType === 'AREA' || searchType === 'AGG') && tree.getChecked('Id1').length === 0) {
                 alert('请选择地市')
                 return;
             }
+            const timeType = $('#timeType').val()
+            if (searchType === 'AGG' && !(timeType === 'DAY' || timeType === 'HOUR')) {
+                alert('汇聚只有天和小时粒度')
+                return
+            }
             const checkData1 = tree.getChecked('Id1')?.[0]?.children;
             let lte
             let nblte
             let includeOther = false
-            checkData1.forEach?.(t => {
+            checkData1?.forEach?.(t => {
                 if (t?.id === 'LTE') {
                     lte = t
                 }
@@ -545,21 +551,21 @@
                     includeOther = true
                 }
             })
-            console.log(lte)
-            console.log(nblte)
+            // console.log(lte)
+            // console.log(nblte)
             const lteQuxians = new Set()
             let lteCitys = new Set()
-            lte?.children.forEach?.(eee => {
+            lte?.children?.forEach?.(eee => {
                 lteCitys.add(eee.title)
-                eee?.children.forEach?.(ee => {
+                eee?.children?.forEach?.(ee => {
                     lteQuxians.add(ee.title)
                 })
             })
             const nblteQuxians = new Set()
             let nblteCitys = new Set()
-            nblte?.children.forEach?.(eee => {
+            nblte?.children?.forEach?.(eee => {
                 nblteCitys.add(eee.title)
-                eee?.children.forEach?.(ee => {
+                eee?.children?.forEach?.(ee => {
                     nblteQuxians.add(ee.title)
                 })
             })
@@ -573,12 +579,11 @@
                 checkData2= tree.getChecked('Id4')?.[0]?.children ;
             }
             const indicators = new Set();
-            checkData2.forEach(eee => {
-                eee.children.forEach(ee => {
+            checkData2?.forEach?.(eee => {
+                eee.children?.forEach?.(ee => {
                     indicators.add(ee.id)
                 })
             });
-            let timeType = $('#timeType').val()
             let sdate = $('#time1').val()
             const [startTime, endTime] = sdate.split(' - ')
             renderTable(includeOther, condition, searchType, table, lteCitys, lteQuxians, nblteCitys, nblteQuxians,
@@ -613,8 +618,8 @@
                         return
                     }
                     const indicators = new Set()
-                    checkedData.forEach(eee => {
-                        eee.children.forEach(ee => {
+                    checkedData?.forEach?.(eee => {
+                        eee.children?.forEach?.(ee => {
                             indicators.add(ee.id)
                         })
                     });
@@ -644,24 +649,25 @@
         // 修改指标模板
         var templateId;
         function editTemplate() {
-            console.log('xiugai')
+            // console.log('xiugai')
             const checkedData = tree?.getChecked('Id3')?.[0]?.children
-            console.log('checkedData: ', checkedData);
-            if(!checkedData || checkedData.length <= 0){
+            // console.log('checkedData: ', checkedData);
+            if (!checkedData || checkedData.length <= 0) {
                 alert('请选择要修改的指标模板!')
                 return
-            }else if(checkedData.length > 1){
+            }
+            if (checkedData.length > 1) {
                 alert('请选择一个要修改的指标模板!')
                 return
-            }else{
-                layer.open({
+            }
+            layer.open({
                 type: 1,
-                title:"修改指标模板",
+                title: "修改指标模板",
                 content: $("#add-template"),
                 area: ['600px', '600px'],
                 btn: ['确定'],
                 shadeClose: true,
-                success: function(layero, index){
+                success: function (layero, index) {
                     let data = checkedData[0].id;
                     $.ajax({
                         type: "POST",
@@ -673,10 +679,10 @@
                                 templateId = r.data.id;
                                 $('#templateName').val(r.data.templateName);
                                 let arr = [];
-                                r.data.list.map(item=>{
+                                r.data.list.map(item => {
                                     arr.push(item.id)
                                 })
-                                console.log('arr: ', arr);
+                                // console.log('arr: ', arr);
                                 tree.setChecked('Id2', arr)
                                 return
                             }
@@ -684,7 +690,7 @@
                         }
                     });
                 },
-                yes: function(index, layero){
+                yes: function (index, layero) {
                     const templateName = $('#templateName').val()
                     if (!templateName || templateName.length <= 0) {
                         alert('请输入模板名称!')
@@ -696,8 +702,8 @@
                         return
                     }
                     const indicators = new Set()
-                    checkedData.forEach(eee => {
-                        eee.children.forEach(ee => {
+                    checkedData?.forEach?.(eee => {
+                        eee.children?.forEach?.(ee => {
                             indicators.add(ee.id)
                         })
                     });
@@ -723,7 +729,6 @@
                     });
                 },
             });
-            }
         }
 
         // 删除指标模板
@@ -734,7 +739,7 @@
                 return
             }
             const ids = new Set()
-            checkedData.forEach(t => {
+            checkedData?.forEach?.(t => {
                 ids.add(t.id)
             });
             const dataJson = JSON.stringify({