优化逻辑

This commit is contained in:
weitang 2025-05-21 14:45:26 +08:00
parent ac80a4d040
commit 7bc871cac7
5 changed files with 262 additions and 9 deletions

View File

@ -1,5 +1,6 @@
package com.yfd.platform.modules.algorithm.controller;
import cn.hutool.core.util.StrUtil;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.algorithm.domain.AlgorithmClass;
import com.yfd.platform.modules.algorithm.domain.AlgorithmDevice;
@ -53,9 +54,10 @@ public class AlgorithmDeviceController {
@PostMapping("/getAlgorithmDeviceCurve")
@ApiOperation("查询算法部件的参数曲线")
public ResponseResult getAlgorithmDeviceCurve(String algorithmId, String componentId) {
public ResponseResult getAlgorithmDeviceCurve(String algorithmId, String componentId,String type) {
type = StrUtil.isBlank(type) ? "1" : type;
List<Map<String, Object>> algorithmDeviceCurveList = algorithmDeviceService.getAlgorithmDeviceCurve(algorithmId,
componentId);
componentId,type);
return ResponseResult.successData(algorithmDeviceCurveList);
}
}

View File

@ -37,6 +37,6 @@ public interface IAlgorithmDeviceService extends IService<AlgorithmDevice> {
* 参数说明 componentId 部件id
* 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
***********************************/
List<Map<String, Object>> getAlgorithmDeviceCurve(String algorithmId, String componentId);
List<Map<String, Object>> getAlgorithmDeviceCurve(String algorithmId, String componentId,String type);
}

View File

@ -10,6 +10,7 @@ import com.yfd.platform.modules.algorithm.service.IAlgorithmDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.modules.auxcontrol.domain.DeviceSignal;
import com.yfd.platform.modules.auxcontrol.domain.DeviceWorkData;
import com.yfd.platform.modules.auxcontrol.domain.TimeConfig;
import com.yfd.platform.modules.auxcontrol.mapper.DeviceSignalMapper;
import com.yfd.platform.modules.auxcontrol.service.IDeviceWorkDataService;
import com.yfd.platform.modules.basedata.domain.SubstationDevice;
@ -83,7 +84,7 @@ public class AlgorithmDeviceServiceImpl extends ServiceImpl<AlgorithmDeviceMappe
* 返回值说明: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
***********************************/
@Override
public List<Map<String, Object>> getAlgorithmDeviceCurve(String algorithmId, String componentId) {
public List<Map<String, Object>> getAlgorithmDeviceCurve(String algorithmId, String componentId,String type) {
List<Map<String, Object>> list = algorithmDeviceMapper.getAlgorithmDeviceType(algorithmId, componentId);
Map<String, List<String>> groupedDevices = list.stream()
.filter(map -> map.containsKey("sourceType") && map.get("sourceType") != null)
@ -115,7 +116,8 @@ public class AlgorithmDeviceServiceImpl extends ServiceImpl<AlgorithmDeviceMappe
for (String signalId : signalIdList) {
List<DeviceWorkData> deviceWorkDataGroup = collect.getOrDefault(signalId, Collections.emptyList());
Map<String, Object> map = processSignalData(deviceWorkDataGroup, signalId);
// Map<String, Object> map = processSignalData(deviceWorkDataGroup, signalId);
Map<String, Object> map = processDeviceData(deviceWorkDataGroup, signalId,type);
deviceDataList.add(map);
}
@ -124,6 +126,106 @@ public class AlgorithmDeviceServiceImpl extends ServiceImpl<AlgorithmDeviceMappe
return deviceDataList;
}
public Map<String, Object> processDeviceData(List<DeviceWorkData> deviceWorkDataList, String signalId,
String type) {
// 根据类型生成时间槽和配置参数
TimeConfig config = generateTimeConfig(type);
// 按时间单位分组数据
Map<LocalDateTime, String> timeDataMap = groupDataByTimeUnit(deviceWorkDataList, config.getTruncateUnit());
// 构建xAxis和series数据
List<String> xAxisData = new ArrayList<>();
List<Double> seriesData = new ArrayList<>();
for (LocalDateTime slot : config.getTimeSlots()) {
xAxisData.add(slot.format(config.getFormatter()));
String value = timeDataMap.getOrDefault(slot, "0");
seriesData.add(NumberUtil.parseDouble(NumberUtil.isNumber(value) ? value : "0"));
}
// 构建ECharts数据结构
return buildEChartsResult(xAxisData, seriesData, signalId);
}
/**
* 按时间单位分组数据
*/
private Map<LocalDateTime, String> groupDataByTimeUnit(List<DeviceWorkData> dataList, ChronoUnit unit) {
Map<LocalDateTime, String> map = new HashMap<>();
for (DeviceWorkData data : dataList) {
LocalDateTime key = data.getStartTime().truncatedTo(unit);
map.put(key, data.getValue());
}
return map;
}
/**
* 构建ECharts结果
*/
private Map<String, Object> buildEChartsResult(List<String> xAxisData, List<Double> seriesData, String signalId) {
Map<String, Object> result = new HashMap<>();
// xAxis配置
Map<String, Object> xAxis = new HashMap<>();
xAxis.put("type", "category");
xAxis.put("data", xAxisData);
result.put("xAxis", xAxis);
// yAxis配置
Map<String, Object> yAxis = new HashMap<>();
yAxis.put("type", "value");
result.put("yAxis", yAxis);
// 系列数据配置
DeviceSignal deviceSignal = deviceSignalMapper.selectById(signalId);
String seriesName = deviceSignal != null ? deviceSignal.getSignalName() : "";
List<Map<String, Object>> seriesList = new ArrayList<>();
Map<String, Object> series = new HashMap<>();
series.put("name", seriesName);
series.put("type", "line");
series.put("step", "start");
series.put("data", seriesData);
seriesList.add(series);
result.put("series", seriesList);
return result;
}
/**
* 生成时间配置
*/
private TimeConfig generateTimeConfig(String type) {
List<LocalDateTime> timeSlots = new ArrayList<>();
DateTimeFormatter formatter;
ChronoUnit truncateUnit;
if ("2".equals(type)) {
// 类型2过去24小时每小时一个点
LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.HOURS);
LocalDateTime startTime = now.minusHours(23);
for (int i = 0; i < 24; i++) {
timeSlots.add(startTime.plusHours(i));
}
formatter = DateTimeFormatter.ofPattern("HH时");
truncateUnit = ChronoUnit.HOURS;
} else {
// 默认类型1过去60分钟每分钟一个点
LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES);
LocalDateTime startTime = now.minusMinutes(59);
for (int i = 0; i < 60; i++) {
timeSlots.add(startTime.plusMinutes(i));
}
formatter = DateTimeFormatter.ofPattern("HH时mm分");
truncateUnit = ChronoUnit.MINUTES;
}
return new TimeConfig(timeSlots, formatter, truncateUnit);
}
/**********************************
* 用途说明: 绘制信号ECharts折线图
* 参数说明 deviceWorkDataList 信号数据

View File

@ -2,15 +2,18 @@ package com.yfd.platform.modules.patroltask.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.beanit.iec61850bean.BdaBoolean;
import com.beanit.iec61850bean.BdaTimestamp;
import com.yfd.platform.component.WebSocketServer;
import com.yfd.platform.component.iec104.common.BasicInstruction104;
import com.yfd.platform.component.iec104.server.master.BootNettyClientChannel;
import com.yfd.platform.component.iec104.server.master.BootNettyClientChannelCache;
import com.yfd.platform.component.utils.OptimizedThreadPool;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.auxcontrol.domain.AnalogData;
import com.yfd.platform.modules.auxcontrol.mapper.DeviceSignalMapper;
@ -26,12 +29,19 @@ import com.yfd.platform.modules.patroltask.service.ITaskTodoService;
import com.yfd.platform.utils.SecurityUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.*;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.FileInputStream;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@ -67,6 +77,8 @@ public class AlarmLogController {
@Resource
private TaskResultMapper taskResultMapper;
public static Map<String, String> status = new ConcurrentHashMap<>();
@GetMapping("/getAlarmLogList")
@ApiOperation("查询报警信息")
public ResponseResult getAlarmLogList(String stationId) {
@ -334,4 +346,141 @@ public class AlarmLogController {
return ResponseResult.success();
}
@PostMapping("/sendExcelData")
@ApiOperation("批量发送excel数据")
public ResponseResult sendExcelData(String fileName) throws Exception {
boolean sendExcelData = status.containsKey("sendExcelData");
if (sendExcelData) {
return ResponseResult.error("当前发送数据进程还没结束");
}
status.put("sendExcelData", "1");
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(()->{
try {
processExcelWithSending("D:\\riis\\video\\excel\\" + fileName);
} catch (Exception e) {
e.printStackTrace();
}
});
executorService.shutdown();
return ResponseResult.success();
}
public void processExcelWithSending(String filePath) throws Exception {
try (FileInputStream file = new FileInputStream(filePath);
Workbook workbook = WorkbookFactory.create(file)) {
Sheet sheet = workbook.getSheetAt(1);
Row headerRow = sheet.getRow(1); // 英文注释行
// 获取列名映射列索引 -> 英文列名
Map<Integer, String> columnNames = getColumnNames(headerRow);
// 从数据行开始遍历第三行
for (int rowIndex = 2; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
Row dataRow = sheet.getRow(rowIndex);
if (dataRow == null) {
continue;
}
Map<String, String> payload = buildPayload(columnNames, dataRow);
System.out.println(payload.toString());
if (!payload.isEmpty()) {
for (String address : payload.keySet()) {
String value = payload.get(address);
// 发送数据
//更新信号数据值
deviceSignalMapper.updateDeviceSignalValue_yc(address, value, getCurrentTime());
//插入历史数据
deviceWorkDataService.insertData("IEC61850", null, address, value, getCurrentTime());
//执行报警处理
alarmLogService.doAlaramRecord("IEC61850", "yc", null, address, value);
}
// 等待5秒
waitForNextRequest();
}
}
}
status.remove("sendExcelData");
}
// 获取列名映射列索引 -> 英文列名
private static Map<Integer, String> getColumnNames(Row headerRow) {
Map<Integer, String> map = new LinkedHashMap<>();
if (headerRow != null) {
for (int i = 0; i < headerRow.getLastCellNum(); i++) {
Cell cell = headerRow.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
String trimName = cell.toString().trim();
if (StrUtil.isNotBlank(trimName)) {
map.put(i, trimName);
}
}
}
return map;
}
// 构建请求负载
private static Map<String, String> buildPayload(Map<Integer, String> columnNames, Row dataRow) {
Map<String, String> payload = new LinkedHashMap<>();
columnNames.forEach((colIndex, colName) -> {
Cell cell = dataRow.getCell(colIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
Object parseCellValue = parseCellValue(cell);
String value = parseCellValue == null ? "0" : parseCellValue.toString();
payload.put(colName, value);
});
return payload;
}
private static Object parseCellValue(Cell cell) {
// 获取公式计算器需要从Workbook获取
FormulaEvaluator evaluator = cell.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator();
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue().trim();
case NUMERIC:
return org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell) ?
cell.getLocalDateTimeCellValue() :
cell.getNumericCellValue();
case BOOLEAN:
return cell.getBooleanCellValue();
case FORMULA: {
// 计算公式的实际值
CellValue cellValue = evaluator.evaluate(cell);
return convertCellValue(cellValue);
}
default:
return null;
}
}
// 转换计算结果类型的方法
private static Object convertCellValue(CellValue cellValue) {
switch (cellValue.getCellType()) {
case NUMERIC:
return cellValue.getNumberValue();
case STRING:
return cellValue.getStringValue();
case BOOLEAN:
return cellValue.getBooleanValue();
default:
return null;
}
}
// 等待间隔
private static void waitForNextRequest() {
try {
TimeUnit.SECONDS.sleep(60); // 5秒间隔
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Data sending interrupted", e);
}
}
}

View File

@ -40,7 +40,7 @@
signal_id=#{signalId}
AND start_time >= NOW() - INTERVAL 1 HOUR
ORDER BY
start_time DESC
start_time
</select>
<!-- <select id="getDeviceWorkData" resultType="java.util.Map">-->
<!-- SELECT-->
@ -110,6 +110,6 @@
</foreach>
AND start_time >= NOW() - INTERVAL 1 HOUR
ORDER BY
start_time DESC
start_time
</select>
</mapper>