From 38f910fccd3f4ee505627cf56382c9175620da03 Mon Sep 17 00:00:00 2001
From: yexb <553699424@qq.com>
Date: Mon, 18 May 2026 08:45:05 +0800
Subject: [PATCH] =?UTF-8?q?feat(event):=20=E6=B7=BB=E5=8A=A0=E6=9A=82?=
=?UTF-8?q?=E6=80=81=E4=BA=8B=E4=BB=B6=E6=B3=A2=E5=BD=A2=E6=9F=A5=E7=9C=8B?=
=?UTF-8?q?=E4=B8=8E=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 getTransientEventWave 接口用于查看暂态事件波形
- 新增 exportTransientEventWaves 接口用于批量导出暂态事件波形
- 添加 EventWaveExportParam 参数类支持波形导出
- 在 EventListMapper 中增加 selectTransientDetailsByIds 查询方法
- 更新事件列表查询参数支持毫秒级时间格式
- 移除事件描述模糊查询条件优化查询性能
- 添加波形导出相关的常量和工具类集成
---
AGENTS.md | 3 +
entrance/src/main/resources/application.yml | 10 +
event/event-list/pom.xml | 21 +
...va => EventMillisecondTimeSerializer.java} | 6 +-
.../controller/EventListController.java | 19 +
.../eventlist/mapper/EventListMapper.java | 2 +
.../mapper/mapping/EventListMapper.xml | 13 +-
.../pojo/param/EventListQueryParam.java | 7 +-
.../pojo/param/EventWaveExportParam.java | 19 +
.../event/eventlist/pojo/vo/EventListVO.java | 45 +-
.../eventlist/service/EventListService.java | 6 +
.../service/impl/EventListServiceImpl.java | 471 +++++++++++++++++-
.../service/impl/EventWavePathResolver.java | 81 +++
.../service/impl/EventListTimeFormatTest.java | 44 ++
.../impl/EventWavePathResolverTest.java | 40 ++
.../component/SteadyTrendFieldResolver.java | 24 +-
.../controller/SteadyDataViewController.java | 12 -
.../datavie/mapper/SteadyDataViewMapper.java | 7 -
.../mapper/mapping/SteadyDataViewMapper.xml | 33 --
.../pojo/param/SteadyDataViewQueryParam.java | 49 --
.../pojo/param/SteadyTrendQueryParam.java | 3 -
.../service/SteadyDataViewService.java | 4 -
.../impl/SteadyDataViewServiceImpl.java | 120 -----
.../impl/SteadyDataViewTrendServiceImpl.java | 1 -
.../SteadyInfluxQueryComponentTest.java | 51 --
.../SteadyTrendFieldResolverTest.java | 28 +-
.../SteadyDataViewControllerTest.java | 19 +
.../pojo/param/SteadyTrendQueryParamTest.java | 19 +
...teadyDataViewIndicatorServiceImplTest.java | 27 -
.../SteadyDataViewTrendServiceImplTest.java | 123 -----
.../cfg/controller/SysConfigController.java | 61 +++
.../system/cfg/mapper/SysConfigMapper.java | 10 +
.../cfg/mapper/mapping/SysConfigMapper.xml | 5 +
.../system/cfg/pojo/param/SysConfigParam.java | 26 +
.../gather/system/cfg/pojo/po/SysConfig.java | 36 ++
.../system/cfg/service/ISysConfigService.java | 33 ++
.../service/impl/SysConfigServiceImpl.java | 59 +++
.../service/impl/DictDataServiceImpl.java | 3 +-
.../service/impl/DictTypeServiceImpl.java | 3 +-
.../service/impl/SysLogAuditServiceImpl.java | 3 +-
.../njcn/gather/system/log/util/CSVUtil.java | 5 +-
.../system/pojo/constant/DictConst.java | 5 +
.../system/util/ExportFileNameUtil.java | 32 ++
.../main/resources/sql/system/sys-config.sql | 34 ++
.../DiskMonitorNotificationComponent.java | 3 +-
.../disk/util/GeneratedFileNameUtil.java | 32 ++
.../component/AddDataTableRegistryTest.java | 28 --
.../AddDataTaskStatusHolderTest.java | 33 --
.../AddDataTemplateRegistryTest.java | 33 --
.../AddDataTimeSlotCalculatorTest.java | 61 ---
.../component/AddDataValueGeneratorTest.java | 32 --
.../mapper/mapping/AddLedgerLineMapper.xml | 2 +
.../pojo/vo/AddLedgerLinePathVO.java | 2 +
.../sql/add-ledger/add-ledger-dict-init.sql | 224 ---------
.../component/AddLedgerTreeBuilderTest.java | 43 --
.../util/AddLedgerLineNoUtilTest.java | 33 --
tools/mms-mapping/README.md | 2 +-
.../mapping/component/FileStorageService.java | 3 +-
.../component/IcdToXmlResponseConverter.java | 7 +-
.../component/JsonToXmlConversionService.java | 8 +-
.../component/RuleBasedXmlMappingService.java | 8 +-
.../mapping/utils/GeneratedFileNameUtil.java | 33 ++
.../debug/GetIcdMmsJsonDebugRunner.java | 232 ---------
.../component/WaveFileComponentTestMain.java | 265 ----------
.../wave/component/WaveFileComponentTest.java | 22 -
.../component/WaveVectorComponentTest.java | 73 ---
.../service/impl/WaveServiceImplTest.java | 162 ------
67 files changed, 1203 insertions(+), 1760 deletions(-)
rename event/event-list/src/main/java/com/njcn/gather/event/eventlist/config/{EventSecondTimeSerializer.java => EventMillisecondTimeSerializer.java} (74%)
create mode 100644 event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/param/EventWaveExportParam.java
create mode 100644 event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/impl/EventWavePathResolver.java
create mode 100644 event/event-list/src/test/java/com/njcn/gather/event/eventlist/service/impl/EventListTimeFormatTest.java
create mode 100644 event/event-list/src/test/java/com/njcn/gather/event/eventlist/service/impl/EventWavePathResolverTest.java
delete mode 100644 steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/pojo/param/SteadyDataViewQueryParam.java
delete mode 100644 steady/steady-DataView/src/test/java/com/njcn/gather/steady/datavie/component/SteadyInfluxQueryComponentTest.java
create mode 100644 steady/steady-DataView/src/test/java/com/njcn/gather/steady/datavie/controller/SteadyDataViewControllerTest.java
create mode 100644 steady/steady-DataView/src/test/java/com/njcn/gather/steady/datavie/pojo/param/SteadyTrendQueryParamTest.java
delete mode 100644 steady/steady-DataView/src/test/java/com/njcn/gather/steady/datavie/service/impl/SteadyDataViewIndicatorServiceImplTest.java
delete mode 100644 steady/steady-DataView/src/test/java/com/njcn/gather/steady/datavie/service/impl/SteadyDataViewTrendServiceImplTest.java
create mode 100644 system/src/main/java/com/njcn/gather/system/cfg/controller/SysConfigController.java
create mode 100644 system/src/main/java/com/njcn/gather/system/cfg/mapper/SysConfigMapper.java
create mode 100644 system/src/main/java/com/njcn/gather/system/cfg/mapper/mapping/SysConfigMapper.xml
create mode 100644 system/src/main/java/com/njcn/gather/system/cfg/pojo/param/SysConfigParam.java
create mode 100644 system/src/main/java/com/njcn/gather/system/cfg/pojo/po/SysConfig.java
create mode 100644 system/src/main/java/com/njcn/gather/system/cfg/service/ISysConfigService.java
create mode 100644 system/src/main/java/com/njcn/gather/system/cfg/service/impl/SysConfigServiceImpl.java
create mode 100644 system/src/main/java/com/njcn/gather/system/util/ExportFileNameUtil.java
create mode 100644 system/src/main/resources/sql/system/sys-config.sql
create mode 100644 systemmonitor/disk-monitor/src/main/java/com/njcn/gather/systemmonitor/disk/util/GeneratedFileNameUtil.java
delete mode 100644 tools/add-data/src/test/java/com/njcn/gather/tool/adddata/component/AddDataTableRegistryTest.java
delete mode 100644 tools/add-data/src/test/java/com/njcn/gather/tool/adddata/component/AddDataTaskStatusHolderTest.java
delete mode 100644 tools/add-data/src/test/java/com/njcn/gather/tool/adddata/component/AddDataTemplateRegistryTest.java
delete mode 100644 tools/add-data/src/test/java/com/njcn/gather/tool/adddata/component/AddDataTimeSlotCalculatorTest.java
delete mode 100644 tools/add-data/src/test/java/com/njcn/gather/tool/adddata/component/AddDataValueGeneratorTest.java
delete mode 100644 tools/add-ledger/src/main/resources/sql/add-ledger/add-ledger-dict-init.sql
delete mode 100644 tools/add-ledger/src/test/java/com/njcn/gather/tool/addledger/component/AddLedgerTreeBuilderTest.java
delete mode 100644 tools/add-ledger/src/test/java/com/njcn/gather/tool/addledger/util/AddLedgerLineNoUtilTest.java
create mode 100644 tools/mms-mapping/src/main/java/com/njcn/gather/icd/mapping/utils/GeneratedFileNameUtil.java
delete mode 100644 tools/mms-mapping/src/test/java/com/njcn/gather/icd/mapping/debug/GetIcdMmsJsonDebugRunner.java
delete mode 100644 tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/component/WaveFileComponentTestMain.java
delete mode 100644 tools/wave-tool/src/test/java/com/njcn/gather/tool/wave/component/WaveFileComponentTest.java
delete mode 100644 tools/wave-tool/src/test/java/com/njcn/gather/tool/wave/component/WaveVectorComponentTest.java
delete mode 100644 tools/wave-tool/src/test/java/com/njcn/gather/tool/wave/service/impl/WaveServiceImplTest.java
diff --git a/AGENTS.md b/AGENTS.md
index 709a9c5..eaf69db 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -18,6 +18,7 @@
- 只清理自己造成的问题:可以删除因本次修改而产生的未使用 `import`、变量或方法;不要删除仓库中原本就存在的死代码,除非用户明确要求。
- 先定义验证方式:执行方案里要写清楚“改哪里、怎么判断改对了”;默认通过代码路径、配置一致性和受影响范围检查进行验证。
- 除非用户明确要求,否则不执行任何 `mvn` 编译、打包、测试或其他构建命令。
+- 所有导出或生成文件名统一追加日期,格式为“原文件名 + `_` + `yyyyMMdd` + 原扩展名”,例如 `暂态事件列表_20260516.xlsx`;新增下载导出、临时生成或落盘保存文件时,优先复用目标模块已有文件名工具,不要在业务代码中散落手写日期拼接。
## 项目结构与模块划分
`CN_Tool` 是一个 Maven 多模块后端项目,根目录的 [`pom.xml`](C:/code/gitea/cn_tool/CN_Tool/pom.xml) 聚合了 `entrance`、`system`、`user`、`detection` 和 `tools`。
@@ -40,6 +41,8 @@ Java 源码位于 `src/main/java`,配置文件位于 `src/main/resources`,My
- 不要假设运行时存在自动数据库迁移;如果代码依赖新表、新字段或新索引,必须同步补齐对应 SQL 与文档说明。
- SQL 脚本应放在目标模块的 `src/main/resources/sql/...` 下,并保持可审阅、可单独执行、语义清晰。
- 变更缓存、日志、审计相关逻辑时,优先沿用现有机制,不要绕开现有登录上下文、缓存约定和审计字段填充方式。
+- 涉及 `sys_dict_type`、`sys_dict_data` 的字典类型编码、字典数据编码或固定字典数据 ID 时,必须统一维护在 `system/src/main/java/com/njcn/gather/system/pojo/constant/DictConst.java`;后续新增使用点也要先补常量再引用,不要在业务代码、SQL 或文档中散落硬编码。
+- 新增或保留字典初始化 SQL 前,必须先确认对应字典类型在后端代码、配置或明确页面契约中确实被使用;未使用的字典类型和字典数据不要写入 `sys_dict_type`、`sys_dict_data` 初始化脚本。
## 注释与编码
- 新增或修改代码时,关键字段、关键分支、关键约束和非直观实现应补充简洁中文注释。
diff --git a/entrance/src/main/resources/application.yml b/entrance/src/main/resources/application.yml
index b9b7cf4..3120866 100644
--- a/entrance/src/main/resources/application.yml
+++ b/entrance/src/main/resources/application.yml
@@ -48,6 +48,16 @@ socket:
webSocket:
port: 7777
+steady:
+ influxdb:
+ url: http://192.168.1.103:18086
+ database: pqsbase
+ username: admin
+ password: ${STEADY_INFLUXDB_PASSWORD:}
+ ssl: false
+ connect-timeout-ms: 5000
+ read-timeout-ms: 30000
+
log:
homeDir: D:\logs
commonLevel: info
diff --git a/event/event-list/pom.xml b/event/event-list/pom.xml
index 0ddb213..4ef095b 100644
--- a/event/event-list/pom.xml
+++ b/event/event-list/pom.xml
@@ -35,5 +35,26 @@
add-ledger
1.0.0
+
+ com.njcn.gather
+ system
+ 1.0.0
+
+
+ com.njcn.gather
+ wave-tool
+ 1.0.0
+
+
+ org.apache.poi
+ poi-ooxml
+ 4.1.2
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
diff --git a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/config/EventSecondTimeSerializer.java b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/config/EventMillisecondTimeSerializer.java
similarity index 74%
rename from event/event-list/src/main/java/com/njcn/gather/event/eventlist/config/EventSecondTimeSerializer.java
rename to event/event-list/src/main/java/com/njcn/gather/event/eventlist/config/EventMillisecondTimeSerializer.java
index 261e4e8..fde1d2b 100644
--- a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/config/EventSecondTimeSerializer.java
+++ b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/config/EventMillisecondTimeSerializer.java
@@ -9,11 +9,11 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
- * 暂态事件时间字段按秒输出,避免接口响应携带毫秒。
+ * 暂态事件时间字段按毫秒输出,保持与数据库 datetime(3) 精度一致。
*/
-public class EventSecondTimeSerializer extends JsonSerializer {
+public class EventMillisecondTimeSerializer extends JsonSerializer {
- private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+ private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
diff --git a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/controller/EventListController.java b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/controller/EventListController.java
index a370836..c9ba281 100644
--- a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/controller/EventListController.java
+++ b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/controller/EventListController.java
@@ -8,8 +8,10 @@ import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.LogUtil;
import com.njcn.gather.event.eventlist.pojo.param.EventListQueryParam;
+import com.njcn.gather.event.eventlist.pojo.param.EventWaveExportParam;
import com.njcn.gather.event.eventlist.pojo.vo.EventListVO;
import com.njcn.gather.event.eventlist.service.EventListService;
+import com.njcn.gather.tool.wave.pojo.vo.WaveComtradeResultVO;
import com.njcn.web.controller.BaseController;
import com.njcn.web.utils.HttpResultUtil;
import io.swagger.annotations.Api;
@@ -64,4 +66,21 @@ public class EventListController extends BaseController {
public void exportTransientEvents(@RequestBody EventListQueryParam param) {
eventListService.exportTransientEvents(param);
}
+
+ @OperateInfo(info = LogEnum.BUSINESS_COMMON)
+ @ApiOperation("查看暂态事件波形")
+ @GetMapping("/transient/{eventId}/wave")
+ public HttpResult getTransientEventWave(@PathVariable("eventId") String eventId) {
+ String methodDescribe = getMethodDescribe("getTransientEventWave");
+ LogUtil.njcnDebug(log, "{},开始查看暂态事件波形,eventId={}", methodDescribe, eventId);
+ WaveComtradeResultVO result = eventListService.getTransientEventWave(eventId);
+ return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
+ }
+
+ @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.DOWNLOAD)
+ @ApiOperation("导出选中暂态事件波形")
+ @PostMapping("/transient/wave/export")
+ public void exportTransientEventWaves(@RequestBody EventWaveExportParam param) {
+ eventListService.exportTransientEventWaves(param);
+ }
}
diff --git a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/mapper/EventListMapper.java b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/mapper/EventListMapper.java
index c3909fb..6eb21ac 100644
--- a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/mapper/EventListMapper.java
+++ b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/mapper/EventListMapper.java
@@ -18,4 +18,6 @@ public interface EventListMapper extends BaseMapper {
List selectTransientExportList(@Param("param") EventListQueryParam param, @Param("limit") Integer limit);
MpEventDetailPO selectTransientDetail(@Param("eventId") String eventId);
+
+ List selectTransientDetailsByIds(@Param("eventIds") List eventIds);
}
diff --git a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/mapper/mapping/EventListMapper.xml b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/mapper/mapping/EventListMapper.xml
index 891bd90..bedeef5 100644
--- a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/mapper/mapping/EventListMapper.xml
+++ b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/mapper/mapping/EventListMapper.xml
@@ -47,9 +47,6 @@
AND phase = #{param.phase}
-
- AND event_describe LIKE CONCAT('%', #{param.eventDescribe}, '%')
-
AND duration >= #{param.durationMin}
@@ -101,4 +98,14 @@
WHERE event_id = #{eventId}
LIMIT 1
+
+
diff --git a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/param/EventListQueryParam.java b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/param/EventListQueryParam.java
index cfb2f82..f67e944 100644
--- a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/param/EventListQueryParam.java
+++ b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/param/EventListQueryParam.java
@@ -18,10 +18,10 @@ import java.util.List;
@ApiModel("暂态事件列表查询参数")
public class EventListQueryParam extends BaseParam {
- @ApiModelProperty("发生时刻开始,格式 yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty("发生时刻开始,格式 yyyy-MM-dd HH:mm:ss.SSS,兼容 yyyy-MM-dd HH:mm:ss")
private String startTimeStart;
- @ApiModelProperty("发生时刻结束,格式 yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty("发生时刻结束,格式 yyyy-MM-dd HH:mm:ss.SSS,兼容 yyyy-MM-dd HH:mm:ss")
private String startTimeEnd;
@ApiModelProperty("事件类型")
@@ -30,9 +30,6 @@ public class EventListQueryParam extends BaseParam {
@ApiModelProperty("相别")
private String phase;
- @ApiModelProperty("事件描述关键字")
- private String eventDescribe;
-
@ApiModelProperty("持续时间下限,单位秒")
private BigDecimal durationMin;
diff --git a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/param/EventWaveExportParam.java b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/param/EventWaveExportParam.java
new file mode 100644
index 0000000..94d94df
--- /dev/null
+++ b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/param/EventWaveExportParam.java
@@ -0,0 +1,19 @@
+package com.njcn.gather.event.eventlist.pojo.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 事件波形批量导出参数。
+ */
+@Data
+@ApiModel("事件波形批量导出参数")
+public class EventWaveExportParam {
+
+ @ApiModelProperty("页面勾选的事件 ID 列表")
+ private List eventIds = new ArrayList();
+}
diff --git a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/vo/EventListVO.java b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/vo/EventListVO.java
index 82dbd6a..87de897 100644
--- a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/vo/EventListVO.java
+++ b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/pojo/vo/EventListVO.java
@@ -2,11 +2,12 @@ package com.njcn.gather.event.eventlist.pojo.vo;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
-import com.njcn.gather.event.eventlist.config.EventSecondTimeSerializer;
+import com.njcn.gather.event.eventlist.config.EventMillisecondTimeSerializer;
import lombok.Data;
import java.io.Serializable;
@@ -25,10 +26,11 @@ public class EventListVO implements Serializable {
private String measurementPointId;
- private String eventType;
-
- @Excel(name = "设备名称", width = 25)
- private String equipmentName;
+ @Excel(name = "发生时刻", width = 25, exportFormat = "yyyy-MM-dd HH:mm:ss.SSS")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
+ @JsonDeserialize(using = LocalDateTimeDeserializer.class)
+ @JsonSerialize(using = EventMillisecondTimeSerializer.class)
+ private LocalDateTime startTime;
@Excel(name = "工程名称", width = 25)
private String engineeringName;
@@ -36,29 +38,32 @@ public class EventListVO implements Serializable {
@Excel(name = "项目名称", width = 25)
private String projectName;
- @Excel(name = "发生时刻", width = 25, exportFormat = "yyyy-MM-dd HH:mm:ss")
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- @JsonDeserialize(using = LocalDateTimeDeserializer.class)
- @JsonSerialize(using = EventSecondTimeSerializer.class)
- private LocalDateTime startTime;
+ @Excel(name = "设备名称", width = 25)
+ private String equipmentName;
+
+ private String mac;
@Excel(name = "监测点名称", width = 25)
private String lineName;
- @Excel(name = "事件描述", width = 25)
- private String eventDescribe;
-
- @Excel(name = "事件发生位置", width = 18)
- private String sagsource;
-
- @Excel(name = "相别", width = 15)
- private String phase;
+ @Excel(name = "暂降/暂升幅值(%)", width = 20)
+ private BigDecimal featureAmplitude;
@Excel(name = "持续时间(s)", width = 18)
private BigDecimal duration;
- @Excel(name = "暂降/暂升幅值(%)", width = 20)
- private BigDecimal featureAmplitude;
+ @Excel(name = "事件类型", width = 18)
+ private String eventType;
+
+ @Excel(name = "相别", width = 15)
+ private String phase;
+
+ @Excel(name = "事件描述", width = 25)
+ @JsonProperty("event_describe")
+ private String eventDescribe;
+
+ @Excel(name = "事件发生位置", width = 18)
+ private String sagsource;
private String wavePath;
diff --git a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/EventListService.java b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/EventListService.java
index 74267ba..ece1426 100644
--- a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/EventListService.java
+++ b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/EventListService.java
@@ -2,7 +2,9 @@ package com.njcn.gather.event.eventlist.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.gather.event.eventlist.pojo.param.EventListQueryParam;
+import com.njcn.gather.event.eventlist.pojo.param.EventWaveExportParam;
import com.njcn.gather.event.eventlist.pojo.vo.EventListVO;
+import com.njcn.gather.tool.wave.pojo.vo.WaveComtradeResultVO;
/**
* 事件列表服务。
@@ -14,4 +16,8 @@ public interface EventListService {
EventListVO getTransientEventDetail(String eventId);
void exportTransientEvents(EventListQueryParam param);
+
+ WaveComtradeResultVO getTransientEventWave(String eventId);
+
+ void exportTransientEventWaves(EventWaveExportParam param);
}
diff --git a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/impl/EventListServiceImpl.java b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/impl/EventListServiceImpl.java
index 7446e82..56440b9 100644
--- a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/impl/EventListServiceImpl.java
+++ b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/impl/EventListServiceImpl.java
@@ -1,30 +1,61 @@
package com.njcn.gather.event.eventlist.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.gather.event.eventlist.mapper.EventListMapper;
import com.njcn.gather.event.eventlist.pojo.param.EventListQueryParam;
+import com.njcn.gather.event.eventlist.pojo.param.EventWaveExportParam;
import com.njcn.gather.event.eventlist.pojo.po.MpEventDetailPO;
import com.njcn.gather.event.eventlist.pojo.vo.EventListVO;
import com.njcn.gather.event.eventlist.service.EventListService;
+import com.njcn.gather.system.cfg.service.ISysConfigService;
+import com.njcn.gather.system.dictionary.pojo.po.DictData;
+import com.njcn.gather.system.dictionary.pojo.po.DictType;
+import com.njcn.gather.system.dictionary.service.IDictDataService;
+import com.njcn.gather.system.dictionary.service.IDictTypeService;
+import com.njcn.gather.system.pojo.constant.DictConst;
+import com.njcn.gather.system.util.ExportFileNameUtil;
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLinePathQueryParam;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
import com.njcn.gather.tool.addledger.service.AddLedgerService;
+import com.njcn.gather.tool.wave.pojo.param.WaveComtradeParseParam;
+import com.njcn.gather.tool.wave.pojo.vo.WaveComtradeResultVO;
+import com.njcn.gather.tool.wave.service.WaveService;
import com.njcn.web.factory.PageFactory;
import com.njcn.web.utils.ExcelUtil;
+import com.njcn.web.utils.HttpServletUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
/**
* 事件列表服务实现。
@@ -37,8 +68,12 @@ public class EventListServiceImpl implements EventListService {
private static final int LEDGER_LINE_QUERY_LIMIT = 1000;
private static final int EVENT_LINE_ID_QUERY_LIMIT = 1000;
private static final int EXPORT_LIMIT = 5000;
+ private static final int WAVE_EXPORT_LIMIT = 500;
private static final String EMPTY_TEXT = "-";
- private static final DateTimeFormatter OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+ private static final String WAVE_EXPORT_SUCCESS = "成功";
+ private static final String WAVE_EXPORT_FAIL = "失败";
+ private static final BigDecimal PERCENT_BASE = new BigDecimal("100");
+ private static final DateTimeFormatter OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
private static final DateTimeFormatter[] INPUT_FORMATTERS = new DateTimeFormatter[]{
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"),
@@ -48,6 +83,10 @@ public class EventListServiceImpl implements EventListService {
private final EventListMapper eventListMapper;
private final AddLedgerService addLedgerService;
+ private final ISysConfigService sysConfigService;
+ private final IDictTypeService dictTypeService;
+ private final IDictDataService dictDataService;
+ private final WaveService waveService;
@Override
public Page pageTransientEvents(EventListQueryParam param) {
@@ -89,10 +128,298 @@ public class EventListServiceImpl implements EventListService {
throw new BusinessException(CommonResponseEnum.FAIL, "导出数据超过 5000 条,请缩小查询条件");
}
exportRecords = buildEventList(eventDetails);
+ fillExportEventTypeNames(exportRecords);
} else {
exportRecords = Collections.emptyList();
}
- ExcelUtil.exportExcel("暂态事件列表.xlsx", "暂态事件列表", EventListVO.class, exportRecords);
+ ExcelUtil.exportExcel(ExportFileNameUtil.appendToday("暂态事件列表.xlsx"), "暂态事件列表", EventListVO.class, exportRecords);
+ }
+
+ @Override
+ public WaveComtradeResultVO getTransientEventWave(String eventId) {
+ MpEventDetailPO eventDetail = requireEventDetail(eventId);
+ AddLedgerLinePathVO linePath = requireLinePath(eventDetail);
+ EventWavePathResolver.WaveFilePath waveFilePath = resolveWaveFilePath(eventDetail, linePath);
+ if (!Files.exists(waveFilePath.getCfgPath())) {
+ throw new BusinessException(CommonResponseEnum.FAIL, "cfg 波形文件不存在");
+ }
+ if (!Files.exists(waveFilePath.getDatPath())) {
+ throw new BusinessException(CommonResponseEnum.FAIL, "dat 波形文件不存在");
+ }
+ WaveComtradeParseParam parseParam = new WaveComtradeParseParam();
+ parseParam.setMonitorName(defaultText(linePath.getLineName()));
+ try (InputStream cfgInputStream = new FileInputStream(waveFilePath.getCfgPath().toFile());
+ InputStream datInputStream = new FileInputStream(waveFilePath.getDatPath().toFile())) {
+ return waveService.parseComtrade(cfgInputStream, datInputStream, parseParam);
+ } catch (IOException ex) {
+ log.error("读取暂态事件波形文件失败,eventId={}", eventDetail.getEventId(), ex);
+ throw new BusinessException(CommonResponseEnum.FAIL, "读取波形文件失败");
+ }
+ }
+
+ @Override
+ public void exportTransientEventWaves(EventWaveExportParam param) {
+ List eventIds = normalizeExportEventIds(param);
+ List exportItems = buildWaveExportItems(eventIds);
+ writeWaveExportZip(exportItems);
+ }
+
+ private MpEventDetailPO requireEventDetail(String eventId) {
+ String normalizedEventId = trimToNull(eventId);
+ if (normalizedEventId == null) {
+ throw new BusinessException(CommonResponseEnum.FAIL, "事件 ID 不能为空");
+ }
+ MpEventDetailPO eventDetail = eventListMapper.selectTransientDetail(normalizedEventId);
+ if (eventDetail == null) {
+ throw new BusinessException(CommonResponseEnum.FAIL, "暂态事件不存在");
+ }
+ return eventDetail;
+ }
+
+ private AddLedgerLinePathVO requireLinePath(MpEventDetailPO eventDetail) {
+ List lineIds = new ArrayList();
+ lineIds.add(eventDetail.getMeasurementPointId());
+ Map linePathMap = addLedgerService.listLinePathByLineIds(lineIds);
+ AddLedgerLinePathVO linePath = linePathMap.get(eventDetail.getMeasurementPointId());
+ if (linePath == null) {
+ throw new BusinessException(CommonResponseEnum.FAIL, "监测点台账不存在或已删除");
+ }
+ return linePath;
+ }
+
+ private List normalizeExportEventIds(EventWaveExportParam param) {
+ List eventIds = normalizeIds(param == null ? null : param.getEventIds());
+ if (eventIds.isEmpty()) {
+ throw new BusinessException(CommonResponseEnum.FAIL, "请选择需要导出的事件");
+ }
+ if (eventIds.size() > WAVE_EXPORT_LIMIT) {
+ throw new BusinessException(CommonResponseEnum.FAIL, "波形导出事件数量不能超过 500 条");
+ }
+ return eventIds;
+ }
+
+ private List buildWaveExportItems(List eventIds) {
+ List eventDetails = eventListMapper.selectTransientDetailsByIds(eventIds);
+ Map eventMap = new LinkedHashMap();
+ List lineIds = new ArrayList();
+ for (MpEventDetailPO eventDetail : eventDetails) {
+ eventMap.put(eventDetail.getEventId(), eventDetail);
+ String lineId = trimToNull(eventDetail.getMeasurementPointId());
+ if (lineId != null && !lineIds.contains(lineId)) {
+ lineIds.add(lineId);
+ }
+ }
+ Map linePathMap = addLedgerService.listLinePathByLineIds(lineIds);
+ List exportItems = new ArrayList();
+ for (String eventId : eventIds) {
+ WaveExportItem item = new WaveExportItem();
+ item.setEventId(eventId);
+ MpEventDetailPO eventDetail = eventMap.get(eventId);
+ item.setEventDetail(eventDetail);
+ if (eventDetail == null) {
+ item.fail("事件不存在");
+ exportItems.add(item);
+ continue;
+ }
+ AddLedgerLinePathVO linePath = linePathMap.get(eventDetail.getMeasurementPointId());
+ item.setLinePath(linePath);
+ item.setEventVO(buildEventVO(eventDetail, linePath));
+ fillWaveExportFileState(item);
+ exportItems.add(item);
+ }
+ return exportItems;
+ }
+
+ private void fillWaveExportFileState(WaveExportItem item) {
+ MpEventDetailPO eventDetail = item.getEventDetail();
+ if (item.getLinePath() == null) {
+ item.fail("监测点台账不存在或已删除");
+ return;
+ }
+ if (eventDetail.getFileFlag() == null || eventDetail.getFileFlag() != 1) {
+ item.fail("波形文件未招");
+ return;
+ }
+ try {
+ EventWavePathResolver.WaveFilePath waveFilePath = resolveWaveFilePath(eventDetail, item.getLinePath());
+ item.setWaveFilePath(waveFilePath);
+ boolean cfgExists = Files.exists(waveFilePath.getCfgPath());
+ boolean datExists = Files.exists(waveFilePath.getDatPath());
+ if (cfgExists && datExists) {
+ item.success();
+ return;
+ }
+ if (!cfgExists && !datExists) {
+ item.fail("cfg/dat 文件不存在");
+ } else if (!cfgExists) {
+ item.fail("cfg 文件不存在");
+ } else {
+ item.fail("dat 文件不存在");
+ }
+ } catch (BusinessException ex) {
+ item.fail(ex.getMessage());
+ }
+ }
+
+ private EventWavePathResolver.WaveFilePath resolveWaveFilePath(MpEventDetailPO eventDetail, AddLedgerLinePathVO linePath) {
+ try {
+ return EventWavePathResolver.resolve(sysConfigService.getWaveStoragePath(), linePath.getEquipmentMac(), eventDetail.getWavePath());
+ } catch (IllegalArgumentException ex) {
+ throw new BusinessException(CommonResponseEnum.FAIL, ex.getMessage());
+ }
+ }
+
+ private void writeWaveExportZip(List exportItems) {
+ HttpServletResponse response = HttpServletUtil.getResponse();
+ try {
+ String fileName = URLEncoder.encode(ExportFileNameUtil.appendToday("选中事件波形导出.zip"), "UTF-8");
+ response.reset();
+ response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
+ response.setContentType("application/zip;charset=UTF-8");
+ try (ServletOutputStream outputStream = response.getOutputStream();
+ ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
+ writeZipEntry(zipOutputStream, ExportFileNameUtil.appendToday("选中事件日志.xlsx"), buildWaveExportWorkbook(exportItems));
+ for (int i = 0; i < exportItems.size(); i++) {
+ WaveExportItem item = exportItems.get(i);
+ EventWavePathResolver.WaveFilePath waveFilePath = item.getWaveFilePath();
+ if (waveFilePath == null) {
+ continue;
+ }
+ String folder = buildZipFolderName(i + 1, item.getEventId());
+ writeWaveFileIfExists(zipOutputStream, folder + "/" + waveFilePath.getCfgPath().getFileName(), waveFilePath.getCfgPath());
+ writeWaveFileIfExists(zipOutputStream, folder + "/" + waveFilePath.getDatPath().getFileName(), waveFilePath.getDatPath());
+ }
+ zipOutputStream.flush();
+ }
+ } catch (IOException ex) {
+ log.error("导出暂态事件波形失败", ex);
+ throw new BusinessException(CommonResponseEnum.FAIL, "导出波形文件失败");
+ }
+ }
+
+ private byte[] buildWaveExportWorkbook(List exportItems) throws IOException {
+ XSSFWorkbook workbook = new XSSFWorkbook();
+ try {
+ writeEventLogSheet(workbook, exportItems);
+ writeWaveFileSheet(workbook, exportItems);
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ workbook.write(outputStream);
+ return outputStream.toByteArray();
+ } finally {
+ workbook.close();
+ }
+ }
+
+ private void writeEventLogSheet(XSSFWorkbook workbook, List exportItems) {
+ XSSFSheet sheet = workbook.createSheet("选中事件列表");
+ String[] headers = new String[]{"发生时刻", "工程名称", "项目名称", "设备名称", "监测点名称", "暂降/暂升幅值(%)",
+ "持续时间(s)", "事件类型", "相别", "事件描述", "事件发生位置"};
+ int[] columnWidths = new int[]{25, 25, 25, 25, 25, 20, 18, 18, 15, 25, 18};
+ writeHeader(sheet, headers, createHeaderStyle(workbook));
+ Map eventTypeNameMap = buildEventTypeNameMap();
+ int rowIndex = 1;
+ for (WaveExportItem item : exportItems) {
+ EventListVO vo = item.getEventVO();
+ if (vo == null) {
+ continue;
+ }
+ Row row = sheet.createRow(rowIndex++);
+ writeCells(row, new Object[]{formatDateTime(vo.getStartTime()), vo.getEngineeringName(), vo.getProjectName(),
+ vo.getEquipmentName(), vo.getLineName(), vo.getFeatureAmplitude(), vo.getDuration(),
+ translateEventType(vo.getEventType(), eventTypeNameMap), vo.getPhase(), vo.getEventDescribe(),
+ vo.getSagsource()});
+ }
+ applyColumnWidth(sheet, columnWidths);
+ }
+
+ private void writeWaveFileSheet(XSSFWorkbook workbook, List exportItems) {
+ XSSFSheet sheet = workbook.createSheet("波形文件清单");
+ String[] headers = new String[]{"事件ID", "设备MAC", "wavePath", "cfg文件路径", "dat文件路径", "导出状态", "失败原因"};
+ writeHeader(sheet, headers, createHeaderStyle(workbook));
+ int rowIndex = 1;
+ for (WaveExportItem item : exportItems) {
+ EventWavePathResolver.WaveFilePath waveFilePath = item.getWaveFilePath();
+ Row row = sheet.createRow(rowIndex++);
+ writeCells(row, new Object[]{item.getEventId(),
+ item.getLinePath() == null ? EMPTY_TEXT : item.getLinePath().getEquipmentMac(),
+ item.getEventDetail() == null ? EMPTY_TEXT : item.getEventDetail().getWavePath(),
+ waveFilePath == null ? EMPTY_TEXT : waveFilePath.getCfgPath().toString(),
+ waveFilePath == null ? EMPTY_TEXT : waveFilePath.getDatPath().toString(),
+ item.getStatus(), defaultText(item.getFailReason())});
+ }
+ applyColumnWidth(sheet, headers.length);
+ }
+
+ private CellStyle createHeaderStyle(XSSFWorkbook workbook) {
+ CellStyle style = workbook.createCellStyle();
+ Font font = workbook.createFont();
+ font.setBold(true);
+ style.setFont(font);
+ return style;
+ }
+
+ private void writeHeader(XSSFSheet sheet, String[] headers, CellStyle style) {
+ Row row = sheet.createRow(0);
+ for (int i = 0; i < headers.length; i++) {
+ Cell cell = row.createCell(i);
+ cell.setCellValue(headers[i]);
+ cell.setCellStyle(style);
+ }
+ }
+
+ private void writeCells(Row row, Object[] values) {
+ for (int i = 0; i < values.length; i++) {
+ Cell cell = row.createCell(i);
+ Object value = values[i];
+ cell.setCellValue(value == null ? "" : String.valueOf(value));
+ }
+ }
+
+ private void applyColumnWidth(XSSFSheet sheet, int columnCount) {
+ for (int i = 0; i < columnCount; i++) {
+ sheet.setColumnWidth(i, 20 * 256);
+ }
+ }
+
+ private void applyColumnWidth(XSSFSheet sheet, int[] columnWidths) {
+ for (int i = 0; i < columnWidths.length; i++) {
+ sheet.setColumnWidth(i, columnWidths[i] * 256);
+ }
+ }
+
+ private void writeZipEntry(ZipOutputStream zipOutputStream, String entryName, byte[] content) throws IOException {
+ ZipEntry zipEntry = new ZipEntry(entryName);
+ zipOutputStream.putNextEntry(zipEntry);
+ zipOutputStream.write(content);
+ zipOutputStream.closeEntry();
+ }
+
+ private void writeWaveFileIfExists(ZipOutputStream zipOutputStream, String entryName, Path filePath) throws IOException {
+ if (!Files.exists(filePath)) {
+ return;
+ }
+ zipOutputStream.putNextEntry(new ZipEntry(entryName));
+ try (InputStream inputStream = new FileInputStream(filePath.toFile())) {
+ byte[] buffer = new byte[8192];
+ int length;
+ while ((length = inputStream.read(buffer)) != -1) {
+ zipOutputStream.write(buffer, 0, length);
+ }
+ }
+ zipOutputStream.closeEntry();
+ }
+
+ private String buildZipFolderName(int index, String eventId) {
+ return index + "_" + sanitizeZipSegment(eventId);
+ }
+
+ private String sanitizeZipSegment(String value) {
+ String text = trimToNull(value);
+ return text == null ? "unknown" : text.replaceAll("[\\\\/:*?\"<>|]", "_");
+ }
+
+ private String formatDateTime(LocalDateTime value) {
+ return value == null ? EMPTY_TEXT : OUTPUT_FORMATTER.format(value);
}
private List buildEventList(List eventDetails) {
@@ -121,15 +448,16 @@ public class EventListServiceImpl implements EventListService {
vo.setMeasurementPointId(eventDetail.getMeasurementPointId());
vo.setEventType(eventDetail.getEventType());
vo.setEquipmentName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getEquipmentName()));
+ vo.setMac(linePath == null ? EMPTY_TEXT : defaultText(linePath.getEquipmentMac()));
vo.setEngineeringName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getEngineeringName()));
vo.setProjectName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getProjectName()));
vo.setStartTime(eventDetail.getStartTime());
vo.setLineName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getLineName()));
- vo.setEventDescribe(defaultText(eventDetail.getEventDescribe(), eventDetail.getEventType()));
+ vo.setEventDescribe(trimToNull(eventDetail.getEventDescribe()));
vo.setSagsource(defaultText(eventDetail.getSagsource()));
vo.setPhase(defaultText(eventDetail.getPhase()));
vo.setDuration(eventDetail.getDuration());
- vo.setFeatureAmplitude(eventDetail.getFeatureAmplitude());
+ vo.setFeatureAmplitude(toPercent(eventDetail.getFeatureAmplitude()));
vo.setWavePath(eventDetail.getWavePath());
vo.setFileFlag(eventDetail.getFileFlag());
vo.setDealFlag(eventDetail.getDealFlag());
@@ -155,11 +483,12 @@ public class EventListServiceImpl implements EventListService {
validateRange(queryParam.getFeatureAmplitudeMin(), queryParam.getFeatureAmplitudeMax(), "幅值下限不能大于上限");
validateFlag(queryParam.getFileFlag(), "波形文件状态只能是 0 或 1");
validateDealFlag(queryParam.getDealFlag());
+ queryParam.setFeatureAmplitudeMin(fromPercent(queryParam.getFeatureAmplitudeMin()));
+ queryParam.setFeatureAmplitudeMax(fromPercent(queryParam.getFeatureAmplitudeMax()));
queryParam.setStartTimeStart(OUTPUT_FORMATTER.format(startTime));
queryParam.setStartTimeEnd(OUTPUT_FORMATTER.format(endTime));
queryParam.setEventType(trimToNull(queryParam.getEventType()));
queryParam.setPhase(trimToNull(queryParam.getPhase()));
- queryParam.setEventDescribe(trimToNull(queryParam.getEventDescribe()));
queryParam.setEngineeringName(trimToNull(queryParam.getEngineeringName()));
queryParam.setProjectName(trimToNull(queryParam.getProjectName()));
queryParam.setEquipmentName(trimToNull(queryParam.getEquipmentName()));
@@ -222,10 +551,10 @@ public class EventListServiceImpl implements EventListService {
try {
return LocalDateTime.parse(text, formatter);
} catch (DateTimeParseException ignored) {
- // 尝试下一个前端可能传入的时间格式。
+ // 尝试下一种前端可能传入的时间格式。
}
}
- throw new BusinessException(CommonResponseEnum.FAIL, "时间格式不正确,仅支持 yyyy-MM-dd HH:mm:ss");
+ throw new BusinessException(CommonResponseEnum.FAIL, "时间格式不正确,仅支持 yyyy-MM-dd HH:mm:ss 或 yyyy-MM-dd HH:mm:ss.SSS");
}
private List normalizeIds(List ids) {
@@ -255,6 +584,59 @@ public class EventListServiceImpl implements EventListService {
}
}
+ private BigDecimal toPercent(BigDecimal value) {
+ return value == null ? null : value.multiply(PERCENT_BASE);
+ }
+
+ private BigDecimal fromPercent(BigDecimal value) {
+ return value == null ? null : value.divide(PERCENT_BASE);
+ }
+
+ private void fillExportEventTypeNames(List exportRecords) {
+ Map eventTypeNameMap = buildEventTypeNameMap();
+ for (EventListVO record : exportRecords) {
+ record.setEventType(translateEventType(record.getEventType(), eventTypeNameMap));
+ }
+ }
+
+ private Map buildEventTypeNameMap() {
+ DictType dictType = dictTypeService.getByCode(DictConst.EVENT_TYPE_DICT);
+ if (dictType == null) {
+ dictType = dictTypeService.lambdaQuery()
+ .eq(DictType::getName, DictConst.EVENT_TYPE_DICT)
+ .eq(DictType::getState, DataStateEnum.ENABLE.getCode())
+ .orderByAsc(DictType::getSort)
+ .orderByDesc(DictType::getId)
+ .last("LIMIT 1")
+ .one();
+ }
+ if (dictType == null) {
+ return Collections.emptyMap();
+ }
+ List dictDataList = dictDataService.listDictDataByTypeId(dictType.getId());
+ Map eventTypeNameMap = new LinkedHashMap();
+ for (DictData dictData : dictDataList) {
+ String id = trimToNull(dictData.getId());
+ String code = trimToNull(dictData.getCode());
+ if (id != null) {
+ eventTypeNameMap.put(id, defaultText(dictData.getName(), id));
+ }
+ if (code != null) {
+ eventTypeNameMap.put(code, defaultText(dictData.getName(), code));
+ }
+ }
+ return eventTypeNameMap;
+ }
+
+ private String translateEventType(String eventType, Map eventTypeNameMap) {
+ String normalizedEventType = trimToNull(eventType);
+ if (normalizedEventType == null) {
+ return EMPTY_TEXT;
+ }
+ String eventTypeName = eventTypeNameMap.get(normalizedEventType);
+ return eventTypeName == null ? normalizedEventType : eventTypeName;
+ }
+
private void validateFlag(Integer flag, String message) {
if (flag != null && flag != 0 && flag != 1) {
throw new BusinessException(CommonResponseEnum.FAIL, message);
@@ -283,4 +665,79 @@ public class EventListServiceImpl implements EventListService {
String trimmed = value.trim();
return trimmed.isEmpty() ? null : trimmed;
}
+
+ private static class WaveExportItem {
+
+ private String eventId;
+
+ private MpEventDetailPO eventDetail;
+
+ private AddLedgerLinePathVO linePath;
+
+ private EventListVO eventVO;
+
+ private EventWavePathResolver.WaveFilePath waveFilePath;
+
+ private String status = WAVE_EXPORT_FAIL;
+
+ private String failReason;
+
+ private String getEventId() {
+ return eventId;
+ }
+
+ private void setEventId(String eventId) {
+ this.eventId = eventId;
+ }
+
+ private MpEventDetailPO getEventDetail() {
+ return eventDetail;
+ }
+
+ private void setEventDetail(MpEventDetailPO eventDetail) {
+ this.eventDetail = eventDetail;
+ }
+
+ private AddLedgerLinePathVO getLinePath() {
+ return linePath;
+ }
+
+ private void setLinePath(AddLedgerLinePathVO linePath) {
+ this.linePath = linePath;
+ }
+
+ private EventListVO getEventVO() {
+ return eventVO;
+ }
+
+ private void setEventVO(EventListVO eventVO) {
+ this.eventVO = eventVO;
+ }
+
+ private EventWavePathResolver.WaveFilePath getWaveFilePath() {
+ return waveFilePath;
+ }
+
+ private void setWaveFilePath(EventWavePathResolver.WaveFilePath waveFilePath) {
+ this.waveFilePath = waveFilePath;
+ }
+
+ private String getStatus() {
+ return status;
+ }
+
+ private String getFailReason() {
+ return failReason;
+ }
+
+ private void success() {
+ this.status = WAVE_EXPORT_SUCCESS;
+ this.failReason = null;
+ }
+
+ private void fail(String failReason) {
+ this.status = WAVE_EXPORT_FAIL;
+ this.failReason = failReason;
+ }
+ }
}
diff --git a/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/impl/EventWavePathResolver.java b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/impl/EventWavePathResolver.java
new file mode 100644
index 0000000..7ba6414
--- /dev/null
+++ b/event/event-list/src/main/java/com/njcn/gather/event/eventlist/service/impl/EventWavePathResolver.java
@@ -0,0 +1,81 @@
+package com.njcn.gather.event.eventlist.service.impl;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * 暂态事件波形文件路径解析器。
+ */
+final class EventWavePathResolver {
+
+ private EventWavePathResolver() {
+ }
+
+ static WaveFilePath resolve(String storageRoot, String equipmentMac, String wavePath) {
+ String rootText = requireText(storageRoot, "波形存储路径未配置");
+ String mac = requireText(equipmentMac, "设备 MAC 为空");
+ String normalizedWavePath = normalizeWavePath(wavePath);
+
+ Path rootPath = Paths.get(rootText).normalize();
+ Path rawWavePath = Paths.get(normalizedWavePath).normalize();
+ Path eventBasePath;
+ if (rawWavePath.isAbsolute()) {
+ eventBasePath = rawWavePath;
+ } else if (startsWithSegment(rawWavePath, mac)) {
+ eventBasePath = rootPath.resolve(rawWavePath).normalize();
+ } else {
+ eventBasePath = rootPath.resolve(mac).resolve(rawWavePath).normalize();
+ }
+
+ if (!eventBasePath.startsWith(rootPath)) {
+ throw new IllegalArgumentException("波形路径非法");
+ }
+
+ String fileName = eventBasePath.getFileName().toString();
+ return new WaveFilePath(eventBasePath.resolveSibling(fileName + ".cfg"),
+ eventBasePath.resolveSibling(fileName + ".dat"));
+ }
+
+ private static String normalizeWavePath(String value) {
+ String wavePath = requireText(value, "事件 wave_path 为空").replace("\\", "/");
+ String lowerWavePath = wavePath.toLowerCase();
+ if (lowerWavePath.endsWith(".cfg") || lowerWavePath.endsWith(".dat")) {
+ wavePath = wavePath.substring(0, wavePath.length() - 4);
+ }
+ if (wavePath.contains("..")) {
+ throw new IllegalArgumentException("波形路径非法");
+ }
+ return wavePath;
+ }
+
+ private static boolean startsWithSegment(Path path, String segment) {
+ return path.getNameCount() > 0 && path.getName(0).toString().equalsIgnoreCase(segment);
+ }
+
+ private static String requireText(String value, String message) {
+ if (value == null || value.trim().isEmpty()) {
+ throw new IllegalArgumentException(message);
+ }
+ return value.trim();
+ }
+
+ static class WaveFilePath {
+
+ private final Path cfgPath;
+
+ private final Path datPath;
+
+ private WaveFilePath(Path cfgPath, Path datPath) {
+ this.cfgPath = cfgPath;
+ this.datPath = datPath;
+ }
+
+ Path getCfgPath() {
+ return cfgPath;
+ }
+
+ Path getDatPath() {
+ return datPath;
+ }
+ }
+}
diff --git a/event/event-list/src/test/java/com/njcn/gather/event/eventlist/service/impl/EventListTimeFormatTest.java b/event/event-list/src/test/java/com/njcn/gather/event/eventlist/service/impl/EventListTimeFormatTest.java
new file mode 100644
index 0000000..4e6f00b
--- /dev/null
+++ b/event/event-list/src/test/java/com/njcn/gather/event/eventlist/service/impl/EventListTimeFormatTest.java
@@ -0,0 +1,44 @@
+package com.njcn.gather.event.eventlist.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.njcn.gather.event.eventlist.pojo.param.EventListQueryParam;
+import com.njcn.gather.event.eventlist.pojo.vo.EventListVO;
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+import java.time.LocalDateTime;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class EventListTimeFormatTest {
+
+ @Test
+ public void startTimeJsonKeepsMilliseconds() throws Exception {
+ EventListVO vo = new EventListVO();
+ vo.setStartTime(LocalDateTime.of(2026, 5, 10, 13, 41, 17, 944000000));
+
+ String json = new ObjectMapper().writeValueAsString(vo);
+
+ assertTrue(json.contains("\"startTime\":\"2026-05-10 13:41:17.944\""));
+ }
+
+ @Test
+ public void queryTimeNormalizationKeepsMilliseconds() throws Exception {
+ EventListQueryParam param = new EventListQueryParam();
+ param.setStartTimeStart("2026-05-10 13:41:17.944");
+ param.setStartTimeEnd("2026-05-10 13:41:18.123");
+
+ normalizeQueryParam(param);
+
+ assertEquals("2026-05-10 13:41:17.944", param.getStartTimeStart());
+ assertEquals("2026-05-10 13:41:18.123", param.getStartTimeEnd());
+ }
+
+ private void normalizeQueryParam(EventListQueryParam param) throws Exception {
+ EventListServiceImpl service = new EventListServiceImpl(null, null, null, null, null, null);
+ Method method = EventListServiceImpl.class.getDeclaredMethod("normalizeQueryParam", EventListQueryParam.class);
+ method.setAccessible(true);
+ method.invoke(service, param);
+ }
+}
diff --git a/event/event-list/src/test/java/com/njcn/gather/event/eventlist/service/impl/EventWavePathResolverTest.java b/event/event-list/src/test/java/com/njcn/gather/event/eventlist/service/impl/EventWavePathResolverTest.java
new file mode 100644
index 0000000..3d4b7e5
--- /dev/null
+++ b/event/event-list/src/test/java/com/njcn/gather/event/eventlist/service/impl/EventWavePathResolverTest.java
@@ -0,0 +1,40 @@
+package com.njcn.gather.event.eventlist.service.impl;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class EventWavePathResolverTest {
+
+ public static void main(String[] args) {
+ resolvesAbsoluteWavePath();
+ resolvesRelativeWavePathWithMacPrefix();
+ resolvesRelativeWavePathAlreadyContainingMac();
+ }
+
+ private static void resolvesAbsoluteWavePath() {
+ EventWavePathResolver.WaveFilePath result = EventWavePathResolver.resolve("D:/", "AA-BB", "D:/wave/event-001.cfg");
+
+ assertPathEquals(Paths.get("D:/wave/event-001.cfg"), result.getCfgPath(), "absolute cfg");
+ assertPathEquals(Paths.get("D:/wave/event-001.dat"), result.getDatPath(), "absolute dat");
+ }
+
+ private static void resolvesRelativeWavePathWithMacPrefix() {
+ EventWavePathResolver.WaveFilePath result = EventWavePathResolver.resolve("D:/wave-root", "AA-BB", "event-001");
+
+ assertPathEquals(Paths.get("D:/wave-root/AA-BB/event-001.cfg"), result.getCfgPath(), "relative cfg");
+ assertPathEquals(Paths.get("D:/wave-root/AA-BB/event-001.dat"), result.getDatPath(), "relative dat");
+ }
+
+ private static void resolvesRelativeWavePathAlreadyContainingMac() {
+ EventWavePathResolver.WaveFilePath result = EventWavePathResolver.resolve("D:/wave-root", "AA-BB", "AA-BB/event-001.dat");
+
+ assertPathEquals(Paths.get("D:/wave-root/AA-BB/event-001.cfg"), result.getCfgPath(), "relative mac cfg");
+ assertPathEquals(Paths.get("D:/wave-root/AA-BB/event-001.dat"), result.getDatPath(), "relative mac dat");
+ }
+
+ private static void assertPathEquals(Path expected, Path actual, String label) {
+ if (!expected.normalize().equals(actual.normalize())) {
+ throw new AssertionError(label + " expected " + expected + " but got " + actual);
+ }
+ }
+}
diff --git a/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/component/SteadyTrendFieldResolver.java b/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/component/SteadyTrendFieldResolver.java
index 2fc1078..3437661 100644
--- a/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/component/SteadyTrendFieldResolver.java
+++ b/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/component/SteadyTrendFieldResolver.java
@@ -38,7 +38,6 @@ public class SteadyTrendFieldResolver {
validateBasicParam(param);
List lineIds = normalizeTextList(param.getLineIds());
List indicatorCodes = normalizeTextList(param.getIndicatorCodes());
- List requestPhases = normalizeUpperList(param.getPhases());
List statTypes = normalizeUpperList(param.getStatTypes());
if (statTypes.isEmpty()) {
statTypes.add("AVG");
@@ -47,7 +46,7 @@ public class SteadyTrendFieldResolver {
for (String lineId : lineIds) {
for (String indicatorCode : indicatorCodes) {
SteadyTrendIndicatorDefinitionBO indicator = requireIndicator(indicatorCode);
- List phases = resolvePhases(indicator, requestPhases);
+ List phases = resolvePhases(indicator);
for (String phase : phases) {
for (String statType : statTypes) {
validateStatType(indicator, statType);
@@ -57,7 +56,7 @@ public class SteadyTrendFieldResolver {
}
}
if (result.size() > MAX_SERIES_COUNT) {
- throw fail("趋势曲线数量不能超过 24 条,请缩小监测点、指标、相别或统计类型范围");
+ throw fail("趋势曲线数量不能超过 24 条,请缩小监测点、指标或统计类型范围");
}
return result;
}
@@ -165,23 +164,8 @@ public class SteadyTrendFieldResolver {
return indicator;
}
- private List resolvePhases(SteadyTrendIndicatorDefinitionBO indicator, List requestPhases) {
- if (requestPhases.isEmpty()) {
- return new ArrayList(indicator.getPhaseCodes());
- }
- List result = new ArrayList();
- for (String phase : requestPhases) {
- if (!"A".equals(phase) && !"B".equals(phase) && !"C".equals(phase) && !"T".equals(phase)) {
- throw fail("相别只能是 A、B、C、T");
- }
- if (indicator.getPhaseCodes().contains(phase) && !result.contains(phase)) {
- result.add(phase);
- }
- }
- if (result.isEmpty()) {
- throw fail("指标 " + indicator.getIndicatorCode() + " 不支持当前相别");
- }
- return result;
+ private List resolvePhases(SteadyTrendIndicatorDefinitionBO indicator) {
+ return new ArrayList(indicator.getPhaseCodes());
}
private void validateStatType(SteadyTrendIndicatorDefinitionBO indicator, String statType) {
diff --git a/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/controller/SteadyDataViewController.java b/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/controller/SteadyDataViewController.java
index 143d12b..dfdf11a 100644
--- a/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/controller/SteadyDataViewController.java
+++ b/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/controller/SteadyDataViewController.java
@@ -1,13 +1,11 @@
package com.njcn.gather.steady.datavie.controller;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.LogUtil;
import com.njcn.gather.steady.datavie.pojo.param.SteadyDataViewDetailParam;
-import com.njcn.gather.steady.datavie.pojo.param.SteadyDataViewQueryParam;
import com.njcn.gather.steady.datavie.pojo.vo.SteadyDataViewTemplateVO;
import com.njcn.gather.steady.datavie.pojo.vo.SteadyDataViewVO;
import com.njcn.gather.steady.datavie.service.SteadyDataViewService;
@@ -40,16 +38,6 @@ public class SteadyDataViewController extends BaseController {
/** 稳态数据查看服务。 */
private final SteadyDataViewService steadyDataViewService;
- @OperateInfo(info = LogEnum.BUSINESS_COMMON)
- @ApiOperation("分页查询稳态数据")
- @PostMapping("/page")
- public HttpResult> pageSteadyData(@RequestBody SteadyDataViewQueryParam param) {
- String methodDescribe = getMethodDescribe("pageSteadyData");
- LogUtil.njcnDebug(log, "{},开始分页查询稳态数据,param={}", methodDescribe, param);
- Page result = steadyDataViewService.pageSteadyData(param);
- return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
- }
-
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
@ApiOperation("查询稳态数据详情")
@PostMapping("/detail")
diff --git a/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/mapper/SteadyDataViewMapper.java b/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/mapper/SteadyDataViewMapper.java
index 9791876..4aac3d1 100644
--- a/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/mapper/SteadyDataViewMapper.java
+++ b/steady/steady-DataView/src/main/java/com/njcn/gather/steady/datavie/mapper/SteadyDataViewMapper.java
@@ -1,7 +1,5 @@
package com.njcn.gather.steady.datavie.mapper;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.njcn.gather.steady.datavie.pojo.param.SteadyDataViewQueryParam;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -12,11 +10,6 @@ import java.util.Map;
*/
public interface SteadyDataViewMapper {
- Page