feat(event): 添加暂态事件波形查看与导出功能
- 新增 getTransientEventWave 接口用于查看暂态事件波形 - 新增 exportTransientEventWaves 接口用于批量导出暂态事件波形 - 添加 EventWaveExportParam 参数类支持波形导出 - 在 EventListMapper 中增加 selectTransientDetailsByIds 查询方法 - 更新事件列表查询参数支持毫秒级时间格式 - 移除事件描述模糊查询条件优化查询性能 - 添加波形导出相关的常量和工具类集成
This commit is contained in:
@@ -196,7 +196,7 @@ curl.exe -X POST "http://localhost:8080/api/mms-mapping/get-icd-mms-json" `
|
||||
说明:
|
||||
|
||||
- `mappingJson` 是字符串字段,字段值本身也是一段 JSON 文本。
|
||||
- 当 `saveToDisk=true` 时,响应中还会返回 `savedPath`。
|
||||
- 当 `saveToDisk=true` 时,响应中还会返回 `savedPath`,落盘文件名按统一规则追加 `_yyyyMMdd`。
|
||||
|
||||
### 5.3 FAILED
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.njcn.gather.icd.mapping.component;
|
||||
|
||||
import com.njcn.gather.icd.mapping.utils.GeneratedFileNameUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
@@ -26,7 +27,7 @@ public class FileStorageService {
|
||||
if (!dir.isDirectory()) {
|
||||
throw new IllegalStateException("输出路径不是目录:" + dir.getAbsolutePath());
|
||||
}
|
||||
File target = new File(dir, fileName);
|
||||
File target = new File(dir, GeneratedFileNameUtil.appendToday(fileName));
|
||||
try (FileOutputStream fos = new FileOutputStream(target)) {
|
||||
fos.write(content.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.njcn.gather.icd.mapping.pojo.vo.IndexCandidateReportItemResponse;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.IndexCandidateResponse;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.MappingDocumentResponse;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.XmlFileResponse;
|
||||
import com.njcn.gather.icd.mapping.utils.GeneratedFileNameUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@@ -90,13 +91,13 @@ public class IcdToXmlResponseConverter {
|
||||
private String resolveXmlFileName(IcdToXmlGenerateResult result) {
|
||||
String iedName = result.getIedName();
|
||||
if (iedName == null || iedName.trim().isEmpty()) {
|
||||
return DEFAULT_XML_FILE_NAME;
|
||||
return GeneratedFileNameUtil.appendToday(DEFAULT_XML_FILE_NAME);
|
||||
}
|
||||
|
||||
String safeName = iedName.replaceAll("[\\\\/:*?\"<>|]+", "_").trim();
|
||||
if (safeName.isEmpty()) {
|
||||
return DEFAULT_XML_FILE_NAME;
|
||||
return GeneratedFileNameUtil.appendToday(DEFAULT_XML_FILE_NAME);
|
||||
}
|
||||
return safeName + ".xml";
|
||||
return GeneratedFileNameUtil.appendToday(safeName + ".xml");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.njcn.gather.icd.mapping.pojo.param.*;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.*;
|
||||
import com.njcn.gather.icd.mapping.pojo.enums.GenerateStatus;
|
||||
import com.njcn.gather.icd.mapping.pojo.bo.mapping.MappingDocument;
|
||||
import com.njcn.gather.icd.mapping.utils.GeneratedFileNameUtil;
|
||||
import lombok.var;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -17,6 +18,8 @@ import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -57,8 +60,9 @@ public class JsonToXmlConversionService {
|
||||
String xmlContent = buildXmlContentFromJson(mappingJson, templateStream, ruleStreams, indexMapping);
|
||||
|
||||
// 3. 保存为临时文件
|
||||
Path tempPath = Files.createTempFile("converted_", ".xml");
|
||||
Files.write(tempPath, xmlContent.getBytes(StandardCharsets.UTF_8));
|
||||
Path tempPath = Paths.get(System.getProperty("java.io.tmpdir"),
|
||||
GeneratedFileNameUtil.appendToday("converted_" + java.util.UUID.randomUUID().toString().replace("-", "") + ".xml"));
|
||||
Files.write(tempPath, xmlContent.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE_NEW);
|
||||
|
||||
return tempPath.toString();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -20,6 +22,7 @@ import com.njcn.gather.icd.mapping.pojo.bo.*;
|
||||
import com.njcn.gather.icd.mapping.pojo.param.*;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.*;
|
||||
import com.njcn.gather.icd.mapping.pojo.enums.GenerateStatus;
|
||||
import com.njcn.gather.icd.mapping.utils.GeneratedFileNameUtil;
|
||||
@Component
|
||||
public class RuleBasedXmlMappingService {
|
||||
|
||||
@@ -104,8 +107,9 @@ public class RuleBasedXmlMappingService {
|
||||
|
||||
xmlContent = applyRulesToXml(xmlContent, applicableRules);
|
||||
|
||||
Path tempPath = Files.createTempFile("rule_mapped_", ".xml");
|
||||
Files.write(tempPath, xmlContent.getBytes(StandardCharsets.UTF_8));
|
||||
Path tempPath = Paths.get(System.getProperty("java.io.tmpdir"),
|
||||
GeneratedFileNameUtil.appendToday("rule_mapped_" + UUID.randomUUID().toString().replace("-", "") + ".xml"));
|
||||
Files.write(tempPath, xmlContent.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE_NEW);
|
||||
return tempPath.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.njcn.gather.icd.mapping.utils;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 生成文件名处理工具。
|
||||
*/
|
||||
public final class GeneratedFileNameUtil {
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
private GeneratedFileNameUtil() {
|
||||
}
|
||||
|
||||
public static String appendToday(String fileName) {
|
||||
return appendDate(fileName, LocalDate.now());
|
||||
}
|
||||
|
||||
public static String appendDate(String fileName, LocalDate date) {
|
||||
if (fileName == null || date == null) {
|
||||
return fileName;
|
||||
}
|
||||
String dateText = DATE_FORMATTER.format(date);
|
||||
int separatorIndex = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
|
||||
int dotIndex = fileName.lastIndexOf('.');
|
||||
if (dotIndex > separatorIndex) {
|
||||
return fileName.substring(0, dotIndex) + "_" + dateText + fileName.substring(dotIndex);
|
||||
}
|
||||
return fileName + "_" + dateText;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
package com.njcn.gather.icd.mapping.debug;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.njcn.gather.icd.mapping.component.MappingResponseConverter;
|
||||
import com.njcn.gather.icd.mapping.pojo.dto.GenerateFromIcdCommand;
|
||||
import com.njcn.gather.icd.mapping.pojo.dto.IndexBindingCommand;
|
||||
import com.njcn.gather.icd.mapping.pojo.dto.IndexSelectionGroupCommand;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.IndexCandidateReportItemResponse;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.IndexCandidateResponse;
|
||||
import com.njcn.gather.icd.mapping.pojo.vo.MappingTaskResponse;
|
||||
import com.njcn.gather.icd.mapping.service.MappingTaskService;
|
||||
import org.springframework.boot.Banner;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* `getIcdMmsJson` 本地调试入口。
|
||||
*
|
||||
* 使用方式:
|
||||
* 1. 先修改 ICD_FILE_PATH 指向本地真实 ICD/SCD 文件。
|
||||
* 2. 直接运行 main,先观察第一次调试返回的 indexCandidates。
|
||||
* 3. 按第一次返回结果补齐 buildSecondStepSelection() 中的绑定关系。
|
||||
* 4. 把 RUN_SECOND_STEP 改成 true,再次运行 main 获取最终 mappingJson。
|
||||
*/
|
||||
public class GetIcdMmsJsonDebugRunner {
|
||||
|
||||
/** 本地 ICD/SCD 文件路径,运行前请改成真实文件。 */
|
||||
private static final String ICD_FILE_PATH = "D:\\Work\\工作资料\\1灿能项目资料\\01自研\\01灿能\\09灿能C端功能\\01需求文档\\灿能工具箱开发\\icd\\PQS882_VX_BJ_1(V111).icd";
|
||||
|
||||
/** 调试时可固定版本号,便于对比输出。 */
|
||||
private static final String VERSION = "20260421";
|
||||
|
||||
/** 调试作者标识。 */
|
||||
private static final String AUTHOR = "debug-user";
|
||||
|
||||
/** 是否输出格式化 JSON,便于人工查看。 */
|
||||
private static final boolean PRETTY_JSON = true;
|
||||
|
||||
/** 是否把生成结果写入磁盘。 */
|
||||
private static final boolean SAVE_TO_DISK = false;
|
||||
|
||||
/** saveToDisk=true 时使用的输出目录。 */
|
||||
private static final String OUTPUT_DIR = "D:/temp/mms-output";
|
||||
|
||||
/**
|
||||
* 第二次正式生成开关。
|
||||
* 默认先只跑第一次,确认 groupKey/reportName/dataSetName/lnInst 候选值后再打开。
|
||||
*/
|
||||
private static final boolean RUN_SECOND_STEP = false;
|
||||
|
||||
public static void main(String[] args) {
|
||||
try (ConfigurableApplicationContext context = new SpringApplicationBuilder(DebugApplication.class)
|
||||
.web(WebApplicationType.NONE)
|
||||
.bannerMode(Banner.Mode.OFF)
|
||||
.logStartupInfo(false)
|
||||
.run(args)) {
|
||||
MappingTaskService mappingTaskService = context.getBean(MappingTaskService.class);
|
||||
MappingResponseConverter responseConverter = context.getBean(MappingResponseConverter.class);
|
||||
ObjectMapper objectMapper = createObjectMapper();
|
||||
|
||||
MappingTaskResponse firstResponse = debugNeedIndexSelection(mappingTaskService, responseConverter);
|
||||
printResponse("第一次调试:获取索引候选", firstResponse, objectMapper);
|
||||
printIndexCandidatesJson(firstResponse, objectMapper);
|
||||
printIndexCandidateSummary(firstResponse);
|
||||
|
||||
if (!RUN_SECOND_STEP) {
|
||||
System.out.println("第二次调试未开启。请先根据第一次返回结果补齐 buildSecondStepSelection(),再把 RUN_SECOND_STEP 改成 true。");
|
||||
return;
|
||||
}
|
||||
|
||||
MappingTaskResponse secondResponse = debugGenerateMapping(mappingTaskService, responseConverter);
|
||||
printResponse("第二次调试:生成 MMS JSON", secondResponse, objectMapper);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("getIcdMmsJson 调试失败:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 第一次调试:不传 indexSelection,只获取 icdDocument 和 indexCandidates。
|
||||
*/
|
||||
private static MappingTaskResponse debugNeedIndexSelection(MappingTaskService mappingTaskService,
|
||||
MappingResponseConverter responseConverter) {
|
||||
GenerateFromIcdCommand command = buildBaseCommand();
|
||||
return responseConverter.fromSubmitResult(mappingTaskService.getIcdMmsJson(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 第二次调试:补齐 indexSelection 后直接生成最终 mappingJson。
|
||||
*/
|
||||
private static MappingTaskResponse debugGenerateMapping(MappingTaskService mappingTaskService,
|
||||
MappingResponseConverter responseConverter) {
|
||||
List<IndexSelectionGroupCommand> selectionGroups = buildSecondStepSelection();
|
||||
if (selectionGroups.isEmpty()) {
|
||||
throw new IllegalArgumentException("第二次调试缺少 indexSelection,请先补齐 buildSecondStepSelection()");
|
||||
}
|
||||
|
||||
GenerateFromIcdCommand command = buildBaseCommand();
|
||||
command.getIndexSelection().addAll(selectionGroups);
|
||||
return responseConverter.fromSubmitResult(mappingTaskService.getIcdMmsJson(command));
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装调试用基础命令,等价于接口中的 request 基础参数。
|
||||
*/
|
||||
private static GenerateFromIcdCommand buildBaseCommand() {
|
||||
Path icdPath = Paths.get(ICD_FILE_PATH);
|
||||
if (!Files.exists(icdPath)) {
|
||||
throw new IllegalArgumentException("ICD 文件不存在:" + icdPath.toAbsolutePath());
|
||||
}
|
||||
|
||||
try {
|
||||
GenerateFromIcdCommand command = new GenerateFromIcdCommand();
|
||||
command.setFileName(icdPath.getFileName().toString());
|
||||
command.setFileBytes(Files.readAllBytes(icdPath));
|
||||
command.setVersion(VERSION);
|
||||
command.setAuthor(AUTHOR);
|
||||
command.setPrettyJson(PRETTY_JSON);
|
||||
command.setSaveToDisk(SAVE_TO_DISK);
|
||||
command.setOutputDir(OUTPUT_DIR);
|
||||
return command;
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalArgumentException("读取 ICD 文件失败:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 第二次调试的索引绑定示例。
|
||||
*
|
||||
* 注意:
|
||||
* 1. groupKey/groupDesc/reportName/dataSetName/lnInst 必须使用第一次返回的真实值。
|
||||
* 2. 下面示例仅作占位,默认不参与运行。
|
||||
*/
|
||||
private static List<IndexSelectionGroupCommand> buildSecondStepSelection() {
|
||||
List<IndexSelectionGroupCommand> groups = new ArrayList<IndexSelectionGroupCommand>();
|
||||
|
||||
// 示例:
|
||||
// IndexSelectionGroupCommand group = createSelectionGroup("HARM__DSSTHARM", "谐波数据");
|
||||
// group.getBindings().add(createBinding("brcbStHarm", "dsStHarm", "A相", "1"));
|
||||
// group.getBindings().add(createBinding("brcbStHarm", "dsStHarm", "B相", "2"));
|
||||
// group.getBindings().add(createBinding("brcbStHarm", "dsStHarm", "C相", "3"));
|
||||
// groups.add(group);
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
private static IndexSelectionGroupCommand createSelectionGroup(String groupKey, String groupDesc) {
|
||||
IndexSelectionGroupCommand group = new IndexSelectionGroupCommand();
|
||||
group.setGroupKey(groupKey);
|
||||
group.setGroupDesc(groupDesc);
|
||||
return group;
|
||||
}
|
||||
|
||||
private static IndexBindingCommand createBinding(String reportName,
|
||||
String dataSetName,
|
||||
String label,
|
||||
String lnInst) {
|
||||
IndexBindingCommand binding = new IndexBindingCommand();
|
||||
binding.setReportName(reportName);
|
||||
binding.setDataSetName(dataSetName);
|
||||
binding.setLabel(label);
|
||||
binding.setLnInst(lnInst);
|
||||
return binding;
|
||||
}
|
||||
|
||||
/**
|
||||
* 控制台输出候选摘要,方便把第一次返回值填回第二次调试配置。
|
||||
*/
|
||||
private static void printIndexCandidateSummary(MappingTaskResponse response) {
|
||||
if (response == null || response.getIndexCandidates() == null || response.getIndexCandidates().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("===== 索引候选摘要 =====");
|
||||
for (IndexCandidateResponse candidate : response.getIndexCandidates()) {
|
||||
System.out.println("groupKey=" + candidate.getGroupKey() + ", groupDesc=" + candidate.getGroupDesc());
|
||||
if (candidate.getReports() == null) {
|
||||
continue;
|
||||
}
|
||||
for (IndexCandidateReportItemResponse report : candidate.getReports()) {
|
||||
System.out.println(" reportName=" + report.getReportName()
|
||||
+ ", dataSetName=" + report.getDataSetName()
|
||||
+ ", availableLnInstValues=" + report.getAvailableLnInstValues());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单独输出 indexCandidates 的 JSON,便于直接复制做第二次调试绑定。
|
||||
*/
|
||||
private static void printIndexCandidatesJson(MappingTaskResponse response, ObjectMapper objectMapper) {
|
||||
try {
|
||||
System.out.println();
|
||||
System.out.println("===== indexCandidates JSON =====");
|
||||
if (response == null) {
|
||||
System.out.println("null");
|
||||
return;
|
||||
}
|
||||
System.out.println(objectMapper.writeValueAsString(response.getIndexCandidates()));
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalArgumentException("print indexCandidates JSON failed: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void printResponse(String title, MappingTaskResponse response, ObjectMapper objectMapper) {
|
||||
try {
|
||||
System.out.println();
|
||||
System.out.println("===== " + title + " =====");
|
||||
System.out.println(objectMapper.writeValueAsString(response));
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalArgumentException("打印调试响应失败:" + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static ObjectMapper createObjectMapper() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
@SpringBootApplication(scanBasePackages = "com.njcn.gather.icd.mapping")
|
||||
public static class DebugApplication {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user