1.监测点异常统计报表调整

This commit is contained in:
wr
2026-01-28 11:26:52 +08:00
parent 2a5a5087ad
commit 3f77d30cfd
4 changed files with 259 additions and 16 deletions

View File

@@ -8,6 +8,8 @@ import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* @version 1.0.0
@@ -72,7 +74,7 @@ public class DataVerifyExcel implements Serializable {
@ColumnWidth(20)
@ExcelProperty(value = "总指标异常时间")
@Excel(name = "")
@Excel(name = "指标异常时间")
private Integer allTime;
@ColumnWidth(20)
@@ -191,4 +193,33 @@ public class DataVerifyExcel implements Serializable {
private Integer riseTime;
// 字段名 ↔ Excel列名 映射
public static final Map<String, String> FIELD_COLUMN_MAP = new HashMap<>();
static {
// 按代码中字段顺序整理,确保一一对应
FIELD_COLUMN_MAP.put("freqTime", "频率");
FIELD_COLUMN_MAP.put("freqDevTime", "频率偏差");
FIELD_COLUMN_MAP.put("vRmsTime", "相电压有效值");
FIELD_COLUMN_MAP.put("vPosTime", "正序电压");
FIELD_COLUMN_MAP.put("vNegTime", "负序电压");
FIELD_COLUMN_MAP.put("vZeroTime", "零序电压");
FIELD_COLUMN_MAP.put("vUnbalanceTime", "电压不平衡度");
FIELD_COLUMN_MAP.put("rmsLvrTime", "线电压有效值");
FIELD_COLUMN_MAP.put("vuDevTime", "电压正偏差");
FIELD_COLUMN_MAP.put("vlDevTime", "电压负偏差");
FIELD_COLUMN_MAP.put("vThdTime", "电压总谐波畸变率");
FIELD_COLUMN_MAP.put("vTime", "相电压基波有效值");
FIELD_COLUMN_MAP.put("iRmsTime", "电流有效值");
FIELD_COLUMN_MAP.put("pltTime", "长时闪变");
FIELD_COLUMN_MAP.put("vInharmTime", "间谐波电压含有率");
FIELD_COLUMN_MAP.put("vHarmTime", "谐波电压含有率");
FIELD_COLUMN_MAP.put("pfTime", "功率因数");
FIELD_COLUMN_MAP.put("vPhasicTime", "谐波电压相角");
FIELD_COLUMN_MAP.put("v1PhasicTime", "谐波电压基波相角");
FIELD_COLUMN_MAP.put("flucTime", "电压波动");
FIELD_COLUMN_MAP.put("pstTime", "短时闪变");
FIELD_COLUMN_MAP.put("dipTime", "电压暂降");
FIELD_COLUMN_MAP.put("riseTime", "电压暂升");
}
}

View File

@@ -0,0 +1,206 @@
package com.njcn.device.pq.utils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.njcn.device.pq.pojo.vo.dataClean.DataVerifyExcel;
import org.apache.poi.ss.usermodel.Sheet;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.*;
/**
* 修复版按数据量动态排序Excel列解决列挤在一行的问题
* 关键改动:表头构建方式 + 列宽匹配逻辑
*/
public class FixedDynamicExcelExport {
public static void main(String[] args) throws Exception {
// 1. 模拟测试数据(相电压数据量最多,频率次之,频率偏差最少)
List<DataVerifyExcel> dataList = EasyExcel.read("F:\\usr\\response.xlsx")
.head(DataVerifyExcel.class)
.doReadAllSync();
// 2. 导出Excel替换为你的本地路径比如桌面
dataList.sort(Comparator.comparing((DataVerifyExcel item) -> item.getCity() + "_" + item.getStationName()+"_"+item.getDevName())
.thenComparing(DataVerifyExcel::getAllTime, Comparator.reverseOrder())
);
exportExcelByDataSize(dataList, "D:/dynamic_excel_fixed.xlsx");
System.out.println("导出完成!打开桌面的「测试导出.xlsx」查看效果");
}
/**
* 核心方法按数据量排序导出Excel
*/
public static void exportExcelByDataSize(List<DataVerifyExcel> dataList, String outputPath) throws Exception {
// 步骤1统计每个字段的有效数据量
Map<String, Integer> fieldCount = countValidData(dataList);
// 步骤2按数据量降序排序字段名
List<String> sortedFields = sortFields(fieldCount);
// 步骤3构建正确的动态表头
List<List<String>> head = buildCorrectHead(sortedFields);
// 步骤4构建对应顺序的行数据
List<List<Object>> data = buildRowData(dataList, sortedFields);
// 步骤5导出Excel含列宽设置
try (FileOutputStream out = new FileOutputStream(outputPath)) {
EasyExcel.write(out)
.head(head)
.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
.registerWriteHandler(new FreezeHeaderHandler()) // 用修复后的表头
.sheet("数据统计")
.doWrite(data);
}
}
public static void exportExcelByDataSize(List<DataVerifyExcel> dataList, OutputStream outputStream) {
// 步骤1统计每个字段的有效数据量
Map<String, Integer> fieldCount = countValidData(dataList);
// 步骤2按数据量降序排序字段名
List<String> sortedFields = sortFields(fieldCount);
// 步骤3构建正确的动态表头
List<List<String>> head = buildCorrectHead(sortedFields);
// 步骤4构建对应顺序的行数据
List<List<Object>> data = buildRowData(dataList, sortedFields);
// 步骤5导出Excel含列宽设置
EasyExcel.write(outputStream)
.head(head)
.registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
.registerWriteHandler(new FreezeHeaderHandler()) // 用修复后的表头
.sheet("数据统计")
.doWrite(data);
}
public static class FreezeHeaderHandler implements SheetWriteHandler {
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
// 表格创建前无需操作
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
Sheet sheet = writeSheetHolder.getSheet();
// freezePane(c, r)c=冻结列数r=冻结行数这里r=1表示冻结第1行表头c=0表示不冻结列
// 比如 freezePane(1, 1) 表示冻结第一列+第一行
sheet.createFreezePane(0, 1);
}
}
// ★ 修复点1构建正确的表头每个列名独立成List
private static List<List<String>> buildCorrectHead(List<String> allFields) {
List<List<String>> head = new ArrayList<>();
head.add(Collections.singletonList("供电公司"));
head.add(Collections.singletonList("所属变电站"));
head.add(Collections.singletonList("终端名称"));
head.add(Collections.singletonList("监测点名称"));
head.add(Collections.singletonList("IP"));
head.add(Collections.singletonList("干扰源类型"));
head.add(Collections.singletonList("监测对象名称"));
head.add(Collections.singletonList("电网侧变电站"));
head.add(Collections.singletonList("厂商"));
head.add(Collections.singletonList("总指标异常时间"));
List<String> sortedFields = allFields.subList(10, allFields.size());
for (String field : sortedFields) {
// 每个列名单独封装成ListEasyExcel才能识别为不同列
head.add(Collections.singletonList(DataVerifyExcel.FIELD_COLUMN_MAP.get(field)));
}
return head;
}
// 统计有效数据量(无改动,保留)
private static Map<String, Integer> countValidData(List<DataVerifyExcel> dataList) {
// 1. 初始化计数字典反射自动提取所有Time结尾的Integer字段初始值0
Map<String, Integer> countMap = initCountMap();
// 2. 判空,避免空指针异常
if (dataList == null || dataList.isEmpty()) {
return countMap;
}
// 3. 获取DataStatistic类的所有字段
Field[] fields = DataVerifyExcel.class.getDeclaredFields();
try {
// 4. 遍历每个数据对象
for (DataVerifyExcel data : dataList) {
// 5. 遍历每个字段,累加数值
for (Field field : fields) {
// 过滤条件Integer类型 + 以Time结尾
if (field.getType() == Integer.class && field.getName().endsWith("Time") ) {
if(!field.getName().equals("allTime")){
// 设置可访问私有字段
field.setAccessible(true);
// 获取当前对象的该字段值
Integer value = (Integer) field.get(data);
// 非空则累加
if (value != null) {
String fieldName = field.getName();
countMap.put(fieldName, countMap.get(fieldName) + value);
}
}
}
}
}
} catch (IllegalAccessException e) {
// 捕获反射访问异常,便于排查问题
throw new RuntimeException("统计字段时反射访问失败", e);
}
return countMap;
}
// 反射初始化计数字典(复用之前的逻辑)
private static Map<String, Integer> initCountMap() {
Map<String, Integer> countMap = new HashMap<>();
Field[] fields = DataVerifyExcel.class.getDeclaredFields();
for (Field field : fields) {
if (field.getType() == Integer.class && field.getName().endsWith("Time")) {
if(!field.getName().equals("allTime")){
countMap.put(field.getName(), 0);
}
}
}
return countMap;
}
// 按数据量排序字段(无改动,保留)
private static List<String> sortFields(Map<String, Integer> fieldCount) {
List<String> fields = new ArrayList<>(fieldCount.keySet());
fields.sort((f1, f2) -> fieldCount.get(f2) - fieldCount.get(f1)); // 降序
List<String> fieldAlls=new ArrayList<>();
fieldAlls.add("city");
fieldAlls.add("stationName");
fieldAlls.add("devName");
fieldAlls.add("lineName");
fieldAlls.add("ip");
fieldAlls.add("loadType");
fieldAlls.add("objName");
fieldAlls.add("powerSubstationName");
fieldAlls.add("manufacturer");
fieldAlls.add("allTime");
fieldAlls.addAll(fields);
return fieldAlls;
}
// 构建行数据(无改动,保留)
private static List<List<Object>> buildRowData(List<DataVerifyExcel> dataList, List<String> sortedFields) {
List<List<Object>> rows = new ArrayList<>();
for (DataVerifyExcel data : dataList) {
List<Object> row = new ArrayList<>();
for (String field : sortedFields) {
try {
Field f = DataVerifyExcel.class.getDeclaredField(field);
f.setAccessible(true);
row.add(f.get(data));
} catch (Exception e) {
throw new RuntimeException("导出异常数据转换异常:"+e);
}
}
rows.add(row);
}
return rows;
}
}

View File

@@ -51,6 +51,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.njcn.device.pq.utils.FixedDynamicExcelExport.exportExcelByDataSize;
/**
* <p>
* 服务实现类
@@ -392,14 +394,16 @@ public class PqDataVerifyBakServiceImpl extends ServiceImpl<PqDataVerifyBakMappe
dataVerifyExcel.setManufacturer(areaLineInfoVO.getManufacturer());
}
}
Set<String> excludeColumnFiledNames = new HashSet<>(1);
excludeColumnFiledNames.add("lineId");
dataVerifyExcels.sort(Comparator.comparing((DataVerifyExcel item) -> item.getCity() + "_" + item.getStationName()+"_"+item.getDevName())
.thenComparing(DataVerifyExcel::getAllTime, Comparator.reverseOrder())
dataVerifyExcels.sort(Comparator
.comparing(DataVerifyExcel::getAllTime, Comparator.reverseOrder())
.thenComparing((DataVerifyExcel item) -> item.getCity() + "_" + item.getStationName()+"_"+item.getDevName())
);
EasyExcel.write(response.getOutputStream(), DataVerifyExcel.class)
.excludeColumnFiledNames(excludeColumnFiledNames).sheet("sheet")
.doWrite(dataVerifyExcels);
exportExcelByDataSize(dataVerifyExcels,response.getOutputStream());
// Set<String> excludeColumnFiledNames = new HashSet<>(1);
// excludeColumnFiledNames.add("lineId");
// EasyExcel.write(response.getOutputStream(), DataVerifyExcel.class)
// .excludeColumnFiledNames(excludeColumnFiledNames).sheet("sheet")
// .doWrite(dataVerifyExcels);
}

View File

@@ -148,7 +148,7 @@
<select id="getMonthFlow" resultType="com.njcn.device.pq.pojo.vo.LineFlowMealDetailVO">
select t.*,
(t.statisValue)/t.flowMeal flowProportion
(t.statisValue / t.flowMeal) as flowProportion
from (
SELECT
a.id id,
@@ -158,8 +158,6 @@
gd.name electricPowerCompany,
b.IP DeviceIP,
b.id deviceId,
-- ifnull(d.flow, (select flow from cld_flow_meal where type = 0 and flag = 1)) + ifnull(d1.flow, 0) flowMeal,
-- ifnull(convert(m.Actual_Value/1024/1024,decimal(7,2)),0) statisValue
COALESCE(d.flow, (SELECT flow FROM cld_flow_meal WHERE type = 0 AND flag = 1)) + COALESCE(d1.flow, 0) AS flowMeal,
COALESCE(CAST(m.Actual_Value / 1024 / 1024 AS DECIMAL(7, 2)), 0) AS statisValue
FROM pq_line a
@@ -170,16 +168,20 @@
LEFT JOIN cld_dev_meal c ON b.id = c.line_id
LEFT JOIN cld_flow_meal d ON c.Base_Meal_Id = d.id
LEFT JOIN cld_flow_meal d1 ON c.Ream_Meal_Id = d1.id
WHERE a.id IN
<where>
a.id IN
<foreach item="item" collection="devs" separator="," open="(" close=")">
#{item}
</foreach>
AND
m.Time_Id between #{startTime} and #{endTime}
AND
<if test="startTime != null and endTime != null">
AND
m.Time_Id between #{startTime} and #{endTime}
</if>
AND
b.Run_Flag != 2
</where>
) t
ORDER BY flowProportion DESC
ORDER BY flowProportion DESC ;
</select>
<select id="getMonthFlowNew" resultType="com.njcn.device.pq.pojo.vo.LineFlowMealDetailVO">