From a9432d45345558444949f904d4e91e116fd6a0ff Mon Sep 17 00:00:00 2001
From: yexb <553699424@qq.com>
Date: Wed, 15 Apr 2026 11:48:33 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B4=AA=E5=9C=A3=E6=96=87=E4=BD=A0=E6=98=AF?=
=?UTF-8?q?=E5=A4=A7=E5=82=BB=E9=80=BC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
AGENTS.md | 11 +
README.md | 8 +-
entrance/pom.xml | 5 +
tools/README.md | 21 +-
tools/pom.xml | 5 +-
tools/wave-tool/pom.xml | 28 +++
.../tool/wave/controller/WaveController.java | 42 ++++
.../tool/wave/param/WaveParseParam.java | 36 +++
.../gather/tool/wave/service/WaveService.java | 15 ++
.../wave/service/impl/WaveServiceImpl.java | 214 ++++++++++++++++++
.../tool/wave/vo/WaveParseResultVO.java | 46 ++++
.../njcn/gather/tool/wave/vo/WavePointVO.java | 22 ++
12 files changed, 445 insertions(+), 8 deletions(-)
create mode 100644 tools/wave-tool/pom.xml
create mode 100644 tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/controller/WaveController.java
create mode 100644 tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/param/WaveParseParam.java
create mode 100644 tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/WaveService.java
create mode 100644 tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/impl/WaveServiceImpl.java
create mode 100644 tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/vo/WaveParseResultVO.java
create mode 100644 tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/vo/WavePointVO.java
diff --git a/AGENTS.md b/AGENTS.md
index 7fda346..1488a3c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -34,6 +34,17 @@ Java 源码位于 `src/main/java`,配置文件位于 `src/main/resources`,My
## 代码风格与命名规范
保持现有 Java 风格:4 空格缩进、UTF-8 文件编码、基础包名使用 `com.njcn.gather`。命名沿用分层后缀,如 `*Controller`、`*Service`、`*ServiceImpl`、`*Mapper`、`*Param`、`*PO`、`*VO`。优先复用现有 Lombok 注解,如 `@Data`、`@RequiredArgsConstructor`、`@Slf4j`。Mapper XML 文件名应与接口名保持一致。业务代码中,关键流程、分支判断、状态流转或容易误解的节点需要补充简洁的中文注释,但不要添加无信息量的注释。
+## 数据与 SQL 约束
+- 新增业务表的 DO 优先复用当前 `BaseDO` / 审计字段风格;除非表本身明确不需要逻辑删除,不要再引入另一套审计基类。
+- 不要假设运行时存在自动数据库迁移;如果代码依赖新表、新字段或新索引,必须同步补齐对应 SQL 与文档说明。
+- SQL 脚本应放在目标模块的 `src/main/resources/sql/...` 下,并保持可审阅、可单独执行、语义清晰。
+- 变更缓存、日志、审计相关逻辑时,优先沿用现有机制,不要绕开现有登录上下文、缓存约定和审计字段填充方式。
+
+## 注释与编码
+- 新增或修改代码时,关键字段、关键分支、关键约束和非直观实现应补充简洁中文注释。
+- 不要为了省事删除原有有效注释,也不要添加无信息量的注释。
+- 写入中文内容时必须保持 UTF-8 编码,并自行检查中文显示是否正常;不要用“改成英文”规避乱码问题。
+
## 提交与合并请求规范
当前 `main` 分支尚无可参考的提交历史,仓库内也没有既有提交规范。建议使用“模块前缀 + 动词短句”的提交格式,例如 `user: 优化登录会话校验`、`system: 增加字典参数校验`。提交 PR 时应说明影响模块、配置或数据结构变更、人工验证步骤;若接口行为有变化,附上请求与响应示例。
diff --git a/README.md b/README.md
index a01a9bf..841e864 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@ CN_Tool 是一个基于 Spring Boot 的多模块后端聚合工程,当前仓
- 系统字典、日志、系统配置、注册资源管理
- WebSocket / Netty 通信基础设施
- 激活码与许可证能力
+- 波形文本解析与查看数据组装能力
## 当前真实模块
@@ -17,9 +18,10 @@ CN_Tool 是一个基于 Spring Boot 的多模块后端聚合工程,当前仓
- `detection`
- `tools`
-其中 `tools` 当前仅保留:
+其中 `tools` 当前包含:
- `activate-tool`
+- `wave-tool`
## 启动入口
@@ -27,7 +29,7 @@ CN_Tool 是一个基于 Spring Boot 的多模块后端聚合工程,当前仓
- `entrance/src/main/java/com/njcn/gather/EntranceApplication.java`
-`entrance` 模块聚合了 `system`、`user`、`detection`、`activate-tool`,是当前运行时主入口。
+`entrance` 模块聚合了 `system`、`user`、`detection`、`activate-tool`、`wave-tool`,是当前运行时主入口。
## 技术基线
@@ -72,6 +74,8 @@ P0 已补齐基线文档,建议按以下顺序阅读:
- 当前以通信基础设施为主,包含 WebSocket / Netty 相关组件
- `tools/activate-tool`
- 负责激活码生成、激活码验证、许可证读取等能力
+- `tools/wave-tool`
+ - 负责波形文本解析与查看数据组装能力
## 文档使用规则
diff --git a/entrance/pom.xml b/entrance/pom.xml
index 9f044dc..ad56706 100644
--- a/entrance/pom.xml
+++ b/entrance/pom.xml
@@ -33,6 +33,11 @@
activate-tool
1.0.0
+
+ com.njcn.gather
+ wave-tool
+ 1.0.0
+
diff --git a/tools/README.md b/tools/README.md
index 97fdf20..54bcf15 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -4,17 +4,19 @@
`tools` 当前是工具能力聚合模块,但在本仓库内已经完成一次收口。
-当前真实保留的子模块只有:
+当前真实保留的子模块有:
- `activate-tool`
+- `wave-tool`
-因此,`tools` 现阶段不是一个包含多个通用工具的完整工具市场,而是一个仅保留激活能力的聚合模块。
+因此,`tools` 现阶段仍然是聚合模块,但当前已实际承载激活工具和波形查看工具两个子模块。
## 当前结构
```text
tools/
-└── activate-tool/
+├── activate-tool/
+└── wave-tool/
```
## activate-tool 的职责
@@ -28,6 +30,17 @@ tools/
从接口层看,当前主要围绕 `/activate/*` 路径提供能力。
+## wave-tool 的职责
+
+`wave-tool` 当前提供的能力主要围绕波形文本解析与查看数据组装:
+
+- 解析单列幅值波形文本
+- 解析双列时间/幅值波形文本
+- 统计点位范围、均值、点数等摘要信息
+- 按查看场景输出下采样后的点位集合
+
+从接口层看,当前主要围绕 `/wave/*` 路径提供能力。
+
## 模块定位
当前 `activate-tool` 更适合作为平台级基础能力模块,而不是业务检测模块的一部分。
@@ -40,7 +53,7 @@ tools/
## 依赖关系
-`tools/activate-tool` 当前主要依赖:
+`tools/activate-tool` 与 `tools/wave-tool` 当前主要依赖:
- `com.njcn:njcn-common`
- `com.njcn:spingboot2.3.12`
diff --git a/tools/pom.xml b/tools/pom.xml
index 06a07e1..c6245c9 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -16,9 +16,10 @@
Retained utility aggregator for platform capabilities.
-
+
activate-tool
+ wave-tool
diff --git a/tools/wave-tool/pom.xml b/tools/wave-tool/pom.xml
new file mode 100644
index 0000000..4a8f6fe
--- /dev/null
+++ b/tools/wave-tool/pom.xml
@@ -0,0 +1,28 @@
+
+
+ 4.0.0
+
+
+ com.njcn.gather
+ tools
+ 1.0.0
+
+
+ wave-tool
+
+
+
+ com.njcn
+ njcn-common
+ 0.0.1
+
+
+
+ com.njcn
+ spingboot2.3.12
+ 2.3.12
+
+
+
diff --git a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/controller/WaveController.java b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/controller/WaveController.java
new file mode 100644
index 0000000..b9d36e3
--- /dev/null
+++ b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/controller/WaveController.java
@@ -0,0 +1,42 @@
+package com.njcn.gather.tool.wave.controller;
+
+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.tool.wave.param.WaveParseParam;
+import com.njcn.gather.tool.wave.service.WaveService;
+import com.njcn.gather.tool.wave.vo.WaveParseResultVO;
+import com.njcn.web.controller.BaseController;
+import com.njcn.web.utils.HttpResultUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@Api(tags = "波形查看")
+@RestController
+@RequestMapping("/wave")
+@RequiredArgsConstructor
+public class WaveController extends BaseController {
+
+ private final WaveService waveService;
+
+ @OperateInfo(info = LogEnum.BUSINESS_COMMON)
+ @ApiOperation("解析波形文本")
+ @ApiImplicitParam(name = "param", value = "波形解析参数", required = true, dataType = "WaveParseParam")
+ @PostMapping("/parse")
+ public HttpResult parse(@RequestBody WaveParseParam param) {
+ String methodDescribe = getMethodDescribe("parse");
+ LogUtil.njcnDebug(log, "{},开始解析波形文本", methodDescribe);
+ WaveParseResultVO result = waveService.parse(param);
+ return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
+ }
+}
diff --git a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/param/WaveParseParam.java b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/param/WaveParseParam.java
new file mode 100644
index 0000000..47b2157
--- /dev/null
+++ b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/param/WaveParseParam.java
@@ -0,0 +1,36 @@
+package com.njcn.gather.tool.wave.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@ApiModel("波形解析参数")
+public class WaveParseParam {
+
+ @ApiModelProperty(value = "波形文本内容,支持单列幅值、单行多值或双列时间/幅值数据", required = true)
+ private String waveformText;
+
+ @ApiModelProperty(value = "分隔符,默认 AUTO 自动识别,支持直接传入具体字符,也支持 TAB 或 SPACE")
+ private String separator;
+
+ @ApiModelProperty(value = "是否包含 X 轴列,true 表示文本中显式传入时间列")
+ private Boolean containsXAxis;
+
+ @ApiModelProperty(value = "X 轴列下标,默认 0")
+ private Integer xColumnIndex;
+
+ @ApiModelProperty(value = "Y 轴列下标,单列波形默认 0,双列波形默认 1")
+ private Integer yColumnIndex;
+
+ @ApiModelProperty(value = "跳过的表头行数,默认 0")
+ private Integer skipHeaderLines;
+
+ @ApiModelProperty(value = "单列波形的采样间隔,默认 1")
+ private BigDecimal samplingInterval;
+
+ @ApiModelProperty(value = "返回的最大点位数,超过时自动下采样,默认 2000")
+ private Integer maxPointCount;
+}
diff --git a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/WaveService.java b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/WaveService.java
new file mode 100644
index 0000000..c08fbbe
--- /dev/null
+++ b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/WaveService.java
@@ -0,0 +1,15 @@
+package com.njcn.gather.tool.wave.service;
+
+import com.njcn.gather.tool.wave.param.WaveParseParam;
+import com.njcn.gather.tool.wave.vo.WaveParseResultVO;
+
+public interface WaveService {
+
+ /**
+ * 解析波形文本并输出适合查看的点位结果。
+ *
+ * @param param 波形解析参数
+ * @return 波形查看结果
+ */
+ WaveParseResultVO parse(WaveParseParam param);
+}
diff --git a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/impl/WaveServiceImpl.java b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/impl/WaveServiceImpl.java
new file mode 100644
index 0000000..cdea739
--- /dev/null
+++ b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/service/impl/WaveServiceImpl.java
@@ -0,0 +1,214 @@
+package com.njcn.gather.tool.wave.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.njcn.common.pojo.enums.response.CommonResponseEnum;
+import com.njcn.common.pojo.exception.BusinessException;
+import com.njcn.gather.tool.wave.param.WaveParseParam;
+import com.njcn.gather.tool.wave.service.WaveService;
+import com.njcn.gather.tool.wave.vo.WaveParseResultVO;
+import com.njcn.gather.tool.wave.vo.WavePointVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+@Slf4j
+@Service
+public class WaveServiceImpl implements WaveService {
+
+ private static final int DEFAULT_MAX_POINT_COUNT = 2000;
+ private static final String AUTO_SEPARATOR = "AUTO";
+
+ @Override
+ public WaveParseResultVO parse(WaveParseParam param) {
+ if (param == null || StrUtil.isBlank(param.getWaveformText())) {
+ throw new BusinessException(CommonResponseEnum.FAIL, "波形文本不能为空");
+ }
+
+ boolean containsXAxis = Boolean.TRUE.equals(param.getContainsXAxis());
+ int skipHeaderLines = sanitizeSkipHeaderLines(param.getSkipHeaderLines());
+ int maxPointCount = sanitizeMaxPointCount(param.getMaxPointCount());
+ BigDecimal samplingInterval = sanitizeSamplingInterval(param.getSamplingInterval());
+ int xColumnIndex = sanitizeColumnIndex(param.getXColumnIndex(), 0);
+ int yColumnIndex = sanitizeColumnIndex(param.getYColumnIndex(), containsXAxis ? 1 : 0);
+
+ List sourcePoints = new ArrayList<>();
+ int ignoredLineCount = 0;
+ int nonBlankLineIndex = 0;
+ String[] lines = param.getWaveformText().split("\\r?\\n");
+ for (String line : lines) {
+ if (StrUtil.isBlank(line)) {
+ continue;
+ }
+ if (nonBlankLineIndex++ < skipHeaderLines) {
+ continue;
+ }
+ String[] columns = splitColumns(line, param.getSeparator());
+ if (columns.length == 0) {
+ ignoredLineCount++;
+ continue;
+ }
+ try {
+ if (containsXAxis) {
+ WavePointVO point = buildPoint(columns, xColumnIndex, yColumnIndex);
+ sourcePoints.add(point);
+ } else {
+ sourcePoints.addAll(buildSingleColumnPoints(columns, samplingInterval, sourcePoints.size()));
+ }
+ } catch (Exception ex) {
+ ignoredLineCount++;
+ log.debug("波形行解析失败,line={}, reason={}", line, ex.getMessage());
+ }
+ }
+
+ if (sourcePoints.isEmpty()) {
+ throw new BusinessException(CommonResponseEnum.FAIL, "未解析到有效波形点位");
+ }
+
+ List displayPoints = downSample(sourcePoints, maxPointCount);
+ return buildResult(sourcePoints, displayPoints, ignoredLineCount, containsXAxis);
+ }
+
+ private WavePointVO buildPoint(String[] columns, int xColumnIndex, int yColumnIndex) {
+ BigDecimal yValue = parseNumber(readColumn(columns, yColumnIndex));
+ BigDecimal xValue = parseNumber(readColumn(columns, xColumnIndex));
+ return new WavePointVO(xValue, yValue);
+ }
+
+ private List buildSingleColumnPoints(String[] columns, BigDecimal samplingInterval, int startIndex) {
+ List points = new ArrayList<>();
+ for (int i = 0; i < columns.length; i++) {
+ BigDecimal yValue = parseNumber(columns[i]);
+ // 单列波形默认按采样间隔自动补齐 X 轴,便于前端直接绘制。
+ BigDecimal xValue = samplingInterval.multiply(BigDecimal.valueOf(startIndex + i));
+ points.add(new WavePointVO(xValue, yValue));
+ }
+ return points;
+ }
+
+ private String readColumn(String[] columns, int columnIndex) {
+ if (columnIndex < 0 || columnIndex >= columns.length) {
+ throw new IllegalArgumentException("列下标超出范围");
+ }
+ return columns[columnIndex];
+ }
+
+ private BigDecimal parseNumber(String value) {
+ if (StrUtil.isBlank(value)) {
+ throw new IllegalArgumentException("数值为空");
+ }
+ return new BigDecimal(value.trim());
+ }
+
+ private String[] splitColumns(String line, String separator) {
+ String trimmedLine = line.trim();
+ if (StrUtil.isBlank(trimmedLine)) {
+ return new String[0];
+ }
+ String[] parts;
+ if (StrUtil.isBlank(separator) || AUTO_SEPARATOR.equalsIgnoreCase(separator)) {
+ parts = trimmedLine.split("[,;\\s]+");
+ } else if ("TAB".equalsIgnoreCase(separator)) {
+ parts = trimmedLine.split("\\t+");
+ } else if ("SPACE".equalsIgnoreCase(separator)) {
+ parts = trimmedLine.split("\\s+");
+ } else {
+ parts = trimmedLine.split(Pattern.quote(separator));
+ }
+ return Arrays.stream(parts)
+ .map(String::trim)
+ .filter(StrUtil::isNotBlank)
+ .toArray(String[]::new);
+ }
+
+ private List downSample(List sourcePoints, int maxPointCount) {
+ if (sourcePoints.size() <= maxPointCount) {
+ return sourcePoints;
+ }
+
+ List result = new ArrayList<>();
+ int step = (int) Math.ceil((double) sourcePoints.size() / maxPointCount);
+ for (int i = 0; i < sourcePoints.size(); i += step) {
+ result.add(sourcePoints.get(i));
+ }
+ WavePointVO lastPoint = sourcePoints.get(sourcePoints.size() - 1);
+ if (!result.contains(lastPoint) && result.size() < maxPointCount) {
+ result.add(lastPoint);
+ } else if (!result.isEmpty()) {
+ result.set(result.size() - 1, lastPoint);
+ }
+ return result;
+ }
+
+ private WaveParseResultVO buildResult(List sourcePoints, List displayPoints,
+ int ignoredLineCount, boolean containsXAxis) {
+ BigDecimal minX = sourcePoints.get(0).getX();
+ BigDecimal maxX = sourcePoints.get(0).getX();
+ BigDecimal minY = sourcePoints.get(0).getY();
+ BigDecimal maxY = sourcePoints.get(0).getY();
+ BigDecimal sumY = BigDecimal.ZERO;
+
+ for (WavePointVO point : sourcePoints) {
+ if (point.getX().compareTo(minX) < 0) {
+ minX = point.getX();
+ }
+ if (point.getX().compareTo(maxX) > 0) {
+ maxX = point.getX();
+ }
+ if (point.getY().compareTo(minY) < 0) {
+ minY = point.getY();
+ }
+ if (point.getY().compareTo(maxY) > 0) {
+ maxY = point.getY();
+ }
+ sumY = sumY.add(point.getY());
+ }
+
+ WaveParseResultVO result = new WaveParseResultVO();
+ result.setContainsXAxis(containsXAxis);
+ result.setSourcePointCount(sourcePoints.size());
+ result.setDisplayPointCount(displayPoints.size());
+ result.setIgnoredLineCount(ignoredLineCount);
+ result.setSampled(sourcePoints.size() != displayPoints.size());
+ result.setMinX(minX);
+ result.setMaxX(maxX);
+ result.setMinY(minY);
+ result.setMaxY(maxY);
+ result.setAverageY(sumY.divide(BigDecimal.valueOf(sourcePoints.size()), 6, RoundingMode.HALF_UP));
+ result.setPoints(displayPoints);
+ return result;
+ }
+
+ private int sanitizeSkipHeaderLines(Integer skipHeaderLines) {
+ if (skipHeaderLines == null || skipHeaderLines < 0) {
+ return 0;
+ }
+ return skipHeaderLines;
+ }
+
+ private int sanitizeMaxPointCount(Integer maxPointCount) {
+ if (maxPointCount == null || maxPointCount <= 0) {
+ return DEFAULT_MAX_POINT_COUNT;
+ }
+ return maxPointCount;
+ }
+
+ private int sanitizeColumnIndex(Integer columnIndex, int defaultValue) {
+ if (columnIndex == null || columnIndex < 0) {
+ return defaultValue;
+ }
+ return columnIndex;
+ }
+
+ private BigDecimal sanitizeSamplingInterval(BigDecimal samplingInterval) {
+ if (samplingInterval == null || samplingInterval.compareTo(BigDecimal.ZERO) <= 0) {
+ return BigDecimal.ONE;
+ }
+ return samplingInterval;
+ }
+}
diff --git a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/vo/WaveParseResultVO.java b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/vo/WaveParseResultVO.java
new file mode 100644
index 0000000..8c81748
--- /dev/null
+++ b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/vo/WaveParseResultVO.java
@@ -0,0 +1,46 @@
+package com.njcn.gather.tool.wave.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+@ApiModel("波形解析结果")
+public class WaveParseResultVO {
+
+ @ApiModelProperty("是否包含显式 X 轴")
+ private Boolean containsXAxis;
+
+ @ApiModelProperty("原始有效点位数")
+ private Integer sourcePointCount;
+
+ @ApiModelProperty("返回的显示点位数")
+ private Integer displayPointCount;
+
+ @ApiModelProperty("被忽略的无效行数")
+ private Integer ignoredLineCount;
+
+ @ApiModelProperty("是否发生下采样")
+ private Boolean sampled;
+
+ @ApiModelProperty("X 轴最小值")
+ private BigDecimal minX;
+
+ @ApiModelProperty("X 轴最大值")
+ private BigDecimal maxX;
+
+ @ApiModelProperty("Y 轴最小值")
+ private BigDecimal minY;
+
+ @ApiModelProperty("Y 轴最大值")
+ private BigDecimal maxY;
+
+ @ApiModelProperty("Y 轴平均值")
+ private BigDecimal averageY;
+
+ @ApiModelProperty("用于查看的波形点位")
+ private List points;
+}
diff --git a/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/vo/WavePointVO.java b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/vo/WavePointVO.java
new file mode 100644
index 0000000..74258e9
--- /dev/null
+++ b/tools/wave-tool/src/main/java/com/njcn/gather/tool/wave/vo/WavePointVO.java
@@ -0,0 +1,22 @@
+package com.njcn.gather.tool.wave.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel("波形点位")
+public class WavePointVO {
+
+ @ApiModelProperty("X 轴值")
+ private BigDecimal x;
+
+ @ApiModelProperty("Y 轴值")
+ private BigDecimal y;
+}