|
|
|
|
@ -1,14 +1,16 @@
|
|
|
|
|
package com.os.ems.record.controller;
|
|
|
|
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
import java.text.ParseException;
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
|
|
|
|
|
import com.os.common.exception.ServiceException;
|
|
|
|
|
|
|
|
|
|
import com.os.common.core.page.PageDomain;
|
|
|
|
|
import com.os.common.core.page.TableSupport;
|
|
|
|
|
import org.checkerframework.checker.units.qual.A;
|
|
|
|
|
import org.springframework.format.annotation.DateTimeFormat;
|
|
|
|
|
import com.os.common.utils.StringUtils;
|
|
|
|
|
import org.springframework.security.access.prepost.PreAuthorize;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
|
@ -23,7 +25,7 @@ import com.os.common.core.page.TableDataInfo;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 物联网数据Controller
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @author zch
|
|
|
|
|
* @date 2025-04-28
|
|
|
|
|
*/
|
|
|
|
|
@ -34,6 +36,9 @@ public class RecordIotenvInstantController extends BaseController
|
|
|
|
|
@Autowired
|
|
|
|
|
private IRecordIotenvInstantService recordIotenvInstantService;
|
|
|
|
|
|
|
|
|
|
/** 最大导出记录数限制(10万条) */
|
|
|
|
|
private static final int MAX_EXPORT_RECORDS = 100000;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 查询物联网数据列表
|
|
|
|
|
*/
|
|
|
|
|
@ -48,15 +53,196 @@ public class RecordIotenvInstantController extends BaseController
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 导出物联网数据列表
|
|
|
|
|
* 导出物联网数据列表(支持按日期分表查询、多设备批量导出、动态列导出)
|
|
|
|
|
*/
|
|
|
|
|
@Log(title = "物联网数据", businessType = BusinessType.EXPORT)
|
|
|
|
|
@PostMapping("/export")
|
|
|
|
|
public void export(HttpServletResponse response, RecordIotenvInstant recordIotenvInstant)throws ParseException
|
|
|
|
|
public void export(HttpServletResponse response, RecordIotenvInstant recordIotenvInstant) throws ParseException
|
|
|
|
|
{
|
|
|
|
|
List<RecordIotenvInstant> list = recordIotenvInstantService.selectRecordIotenvInstantList(recordIotenvInstant);
|
|
|
|
|
// 校验时间范围参数
|
|
|
|
|
Map<String, Object> params = recordIotenvInstant.getParams();
|
|
|
|
|
if (params == null || params.get("beginRecordTime") == null || params.get("endRecordTime") == null) {
|
|
|
|
|
throw new ServiceException("导出失败:请选择记录时间范围");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 解析设备类型参数(用于动态导出列和数据过滤)
|
|
|
|
|
Set<Integer> monitorTypes = parseMonitorTypes(params);
|
|
|
|
|
|
|
|
|
|
// 使用专用导出方法(性能优化:移除ORDER BY,支持多设备批量导出)
|
|
|
|
|
List<RecordIotenvInstant> list = recordIotenvInstantService.selectRecordIotenvInstantListForExport(recordIotenvInstant);
|
|
|
|
|
|
|
|
|
|
// 根据设备类型过滤无效数据(零值和超范围值)
|
|
|
|
|
list = filterInvalidData(list, monitorTypes);
|
|
|
|
|
|
|
|
|
|
// 添加数据量检查,防止导出数据量过大导致内存溢出
|
|
|
|
|
if (list.size() > MAX_EXPORT_RECORDS) {
|
|
|
|
|
throw new ServiceException("导出数据量过大(" + list.size() + "条),请缩小时间范围或减少设备数量");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据设备类型动态选择导出列
|
|
|
|
|
String[] includeColumns = getExportColumnsByType(monitorTypes);
|
|
|
|
|
ExcelUtil<RecordIotenvInstant> util = new ExcelUtil<RecordIotenvInstant>(RecordIotenvInstant.class);
|
|
|
|
|
util.exportExcel(response, list, "物联网数据数据");
|
|
|
|
|
// 使用showColumn方法指定需要导出的列
|
|
|
|
|
util.showColumn(includeColumns);
|
|
|
|
|
util.exportExcel(response, list, "物联网数据");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析设备类型参数
|
|
|
|
|
*/
|
|
|
|
|
private Set<Integer> parseMonitorTypes(Map<String, Object> params) {
|
|
|
|
|
Set<Integer> types = new HashSet<>();
|
|
|
|
|
Object monitorTypesObj = params.get("monitorTypes");
|
|
|
|
|
if (monitorTypesObj != null && StringUtils.isNotEmpty(monitorTypesObj.toString())) {
|
|
|
|
|
String[] typeStrs = monitorTypesObj.toString().split(",");
|
|
|
|
|
for (String typeStr : typeStrs) {
|
|
|
|
|
try {
|
|
|
|
|
types.add(Integer.parseInt(typeStr.trim()));
|
|
|
|
|
} catch (NumberFormatException ignored) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return types;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据设备类型过滤无效数据
|
|
|
|
|
* 过滤规则(使用OR关系,满足任一类型的有效性即保留):
|
|
|
|
|
* 1. 温度设备(type=5):温度>0且<=79
|
|
|
|
|
* 2. 温湿度设备(type=6):温度或湿度任一>0且<=79
|
|
|
|
|
* 3. 噪声设备(type=7):噪声>0且<=79
|
|
|
|
|
* 4. 振动设备(type=10):振动相关字段任一>0
|
|
|
|
|
*/
|
|
|
|
|
private List<RecordIotenvInstant> filterInvalidData(List<RecordIotenvInstant> list, Set<Integer> monitorTypes) {
|
|
|
|
|
if (monitorTypes.isEmpty()) {
|
|
|
|
|
// 未指定类型时,保留有任何有效数据的记录
|
|
|
|
|
return list.stream().filter(this::hasValidData).collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 单一类型:严格按该类型过滤
|
|
|
|
|
if (monitorTypes.size() == 1) {
|
|
|
|
|
Integer type = monitorTypes.iterator().next();
|
|
|
|
|
return list.stream().filter(record -> isValidForType(record, type)).collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 多类型:使用OR关系,满足任一选中类型的有效性即保留
|
|
|
|
|
return list.stream().filter(record -> {
|
|
|
|
|
for (Integer type : monitorTypes) {
|
|
|
|
|
if (isValidForType(record, type)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}).collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 判断记录对于指定类型是否有效 */
|
|
|
|
|
private boolean isValidForType(RecordIotenvInstant record, Integer type) {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 5: // 温度设备
|
|
|
|
|
return isValidTemperature(record.getTemperature());
|
|
|
|
|
case 6: // 温湿度设备
|
|
|
|
|
return isValidTemperature(record.getTemperature()) || isValidHumidity(record.getHumidity());
|
|
|
|
|
case 7: // 噪声设备
|
|
|
|
|
return isValidNoise(record.getNoise());
|
|
|
|
|
case 10: // 振动设备
|
|
|
|
|
return hasValidVibrationData(record);
|
|
|
|
|
default:
|
|
|
|
|
return hasValidData(record);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 判断温度是否有效:>0且<=79 */
|
|
|
|
|
private boolean isValidTemperature(BigDecimal temperature) {
|
|
|
|
|
return temperature != null && temperature.compareTo(BigDecimal.ZERO) > 0 && temperature.compareTo(new BigDecimal("79")) <= 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 判断湿度是否有效:>0且<=79 */
|
|
|
|
|
private boolean isValidHumidity(BigDecimal humidity) {
|
|
|
|
|
return humidity != null && humidity.compareTo(BigDecimal.ZERO) > 0 && humidity.compareTo(new BigDecimal("79")) <= 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 判断噪声是否有效:>0且<=79 */
|
|
|
|
|
private boolean isValidNoise(BigDecimal noise) {
|
|
|
|
|
return noise != null && noise.compareTo(BigDecimal.ZERO) > 0 && noise.compareTo(new BigDecimal("79")) <= 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 判断是否有有效的振动数据 */
|
|
|
|
|
private boolean hasValidVibrationData(RecordIotenvInstant record) {
|
|
|
|
|
return (record.getVibrationSpeed() != null && record.getVibrationSpeed().compareTo(BigDecimal.ZERO) > 0) ||
|
|
|
|
|
(record.getVibrationDisplacement() != null && record.getVibrationDisplacement().compareTo(BigDecimal.ZERO) > 0) ||
|
|
|
|
|
(record.getVibrationAcceleration() != null && record.getVibrationAcceleration().compareTo(BigDecimal.ZERO) > 0) ||
|
|
|
|
|
(record.getVibrationTemp() != null && record.getVibrationTemp().compareTo(BigDecimal.ZERO) > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 判断记录是否有任何有效数据 */
|
|
|
|
|
private boolean hasValidData(RecordIotenvInstant record) {
|
|
|
|
|
return isValidTemperature(record.getTemperature()) ||
|
|
|
|
|
isValidHumidity(record.getHumidity()) ||
|
|
|
|
|
isValidNoise(record.getNoise()) ||
|
|
|
|
|
hasValidVibrationData(record);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据设备类型获取导出列
|
|
|
|
|
* 列顺序:设备编号、设备名称、能源类型数据列、记录时间
|
|
|
|
|
* type=5: 温度设备 -> 设备编号、设备名称、温度、记录时间
|
|
|
|
|
* type=6: 温湿度设备 -> 设备编号、设备名称、温度、湿度、记录时间
|
|
|
|
|
* type=7: 噪声设备 -> 设备编号、设备名称、噪声、记录时间
|
|
|
|
|
* type=10: 振动设备 -> 设备编号、设备名称、振动速度、振动位移、振动加速度、振动温度、记录时间
|
|
|
|
|
* 混合类型: 导出所有列
|
|
|
|
|
*/
|
|
|
|
|
private String[] getExportColumnsByType(Set<Integer> monitorTypes) {
|
|
|
|
|
List<String> columns = new ArrayList<>();
|
|
|
|
|
// 固定列:设备编号、设备名称
|
|
|
|
|
columns.add("monitorCode");
|
|
|
|
|
columns.add("monitorName");
|
|
|
|
|
|
|
|
|
|
if (monitorTypes.isEmpty() || monitorTypes.size() > 1) {
|
|
|
|
|
// 混合类型或未指定:导出所有数据列
|
|
|
|
|
columns.add("temperature");
|
|
|
|
|
columns.add("humidity");
|
|
|
|
|
columns.add("noise");
|
|
|
|
|
columns.add("vibrationSpeed");
|
|
|
|
|
columns.add("vibrationDisplacement");
|
|
|
|
|
columns.add("vibrationAcceleration");
|
|
|
|
|
columns.add("vibrationTemp");
|
|
|
|
|
} else {
|
|
|
|
|
// 单一类型:只导出对应的列
|
|
|
|
|
Integer type = monitorTypes.iterator().next();
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 5: // 温度设备
|
|
|
|
|
columns.add("temperature");
|
|
|
|
|
break;
|
|
|
|
|
case 6: // 温湿度设备
|
|
|
|
|
columns.add("temperature");
|
|
|
|
|
columns.add("humidity");
|
|
|
|
|
break;
|
|
|
|
|
case 7: // 噪声设备
|
|
|
|
|
columns.add("noise");
|
|
|
|
|
break;
|
|
|
|
|
case 10: // 振动设备
|
|
|
|
|
columns.add("vibrationSpeed");
|
|
|
|
|
columns.add("vibrationDisplacement");
|
|
|
|
|
columns.add("vibrationAcceleration");
|
|
|
|
|
columns.add("vibrationTemp");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// 其他类型:导出所有列
|
|
|
|
|
columns.add("temperature");
|
|
|
|
|
columns.add("humidity");
|
|
|
|
|
columns.add("noise");
|
|
|
|
|
columns.add("vibrationSpeed");
|
|
|
|
|
columns.add("vibrationDisplacement");
|
|
|
|
|
columns.add("vibrationAcceleration");
|
|
|
|
|
columns.add("vibrationTemp");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 固定列:记录时间
|
|
|
|
|
columns.add("recodeTime");
|
|
|
|
|
return columns.toArray(new String[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|