Compare commits
7 Commits
2026-04
...
90219a3daf
| Author | SHA1 | Date | |
|---|---|---|---|
| 90219a3daf | |||
| 41c915d1df | |||
| 81d7b213b8 | |||
| a8a57e882f | |||
| b56116264c | |||
| 6f5d8dc45a | |||
| c3b074db26 |
@@ -27,6 +27,7 @@ CN_Tool 是一个基于 Spring Boot 的多模块后端聚合工程,当前仓
|
||||
|
||||
- `activate-tool`
|
||||
- `add-data`
|
||||
- `add-ledger`
|
||||
- `mms-mapping`
|
||||
- `wave-tool`
|
||||
|
||||
@@ -36,7 +37,7 @@ CN_Tool 是一个基于 Spring Boot 的多模块后端聚合工程,当前仓
|
||||
|
||||
- `entrance/src/main/java/com/njcn/gather/EntranceApplication.java`
|
||||
|
||||
`entrance` 模块聚合了 `system`、`disk-monitor`、`user`、`detection`、`activate-tool`、`add-data`、`wave-tool`、`mms-mapping`,是当前运行时主入口。
|
||||
`entrance` 模块聚合了 `system`、`disk-monitor`、`user`、`detection`、`activate-tool`、`add-data`、`add-ledger`、`wave-tool`、`mms-mapping`,是当前运行时主入口。
|
||||
|
||||
## 技术基线
|
||||
|
||||
@@ -85,6 +86,8 @@ P0 已补齐基线文档,建议按以下顺序阅读:
|
||||
- 负责激活码生成、激活码验证、许可证读取等能力
|
||||
- `tools/add-data`
|
||||
- 当前提供电能质量 13 张表批量补数、任务状态查询和模板规则查询能力
|
||||
- `tools/add-ledger`
|
||||
- 当前为数据台账工具预留空模块
|
||||
- `tools/mms-mapping`
|
||||
- 负责 ICD 文件解析与 MMS 映射数据生成能力
|
||||
- `tools/wave-tool`
|
||||
|
||||
@@ -0,0 +1,433 @@
|
||||
# steady-DataView 稳态历史趋势设计方案
|
||||
|
||||
## 目标
|
||||
|
||||
在 `steady/steady-DataView` 中新增稳态历史趋势查看能力,用于展示 InfluxDB 中的稳态数据历史趋势图。数据结构与 `tools/add-data` 中的 13 张 `data_*` 表字段保持一致,但查询数据源改为 InfluxDB 时序库。
|
||||
|
||||
本方案只设计后端接口、查询模型、页面交互和性能策略,不包含代码实现。
|
||||
|
||||
## 当前上下文
|
||||
|
||||
- `steady-DataView` 当前已有 `/steady/data-view/page`、`/detail`、`/templates`,主要面向 MySQL 稳态数据分页、详情和模板查询。
|
||||
- `tools/add-data` 已维护 13 张稳态数据表定义,字段包含基础字段 `TIMEID`、`LINEID`、`PHASIC_TYPE`、`QUALITYFLAG`,以及业务值字段和 `_MAX`、`_MIN`、`_CP95` 等统计字段。
|
||||
- `tools/add-ledger` 已提供台账树能力,层级固定为:工程 -> 项目 -> 设备 -> 监测点。
|
||||
- `tools/wave-tool` 已有趋势图点位返回结构,可参考 `points`、`sampled`、`displayPointCount` 等概念。
|
||||
|
||||
## 总体方案
|
||||
|
||||
新增趋势查看能力时,`steady-DataView` 负责统一编排:
|
||||
|
||||
1. 从 `add-ledger` 复用台账层级,生成趋势页面左侧监测点设备树。
|
||||
2. 从稳态指标目录生成指标树,指标范围覆盖电压、电流、频率、谐波、功率、闪变。
|
||||
3. 将页面选择的监测点、指标、相别、统计类型、时间范围转换成 InfluxDB 查询。
|
||||
4. 返回趋势图可直接消费的多序列点位数据。
|
||||
5. 按天和分桶粒度动态加载,避免大范围一次性返回明细点。
|
||||
|
||||
保留现有分页和详情接口,不在本次设计中移除。
|
||||
|
||||
## 左侧设备树
|
||||
|
||||
页面左侧展示台账监测点设备树,口径参照 `add-ledger`:
|
||||
|
||||
```text
|
||||
工程(设备数 / 监测点数)
|
||||
项目(设备数 / 监测点数)
|
||||
设备(监测点数)
|
||||
监测点
|
||||
```
|
||||
|
||||
数量统计口径:
|
||||
|
||||
- 台账节点:`cs_ledger.State = 1`
|
||||
- 设备:`cs_equipment_delivery.run_status <> 0`
|
||||
- 监测点:`cs_line.status = 1`
|
||||
- 设备数:当前节点下有效设备数量
|
||||
- 监测点数:当前节点下有效监测点数量
|
||||
|
||||
建议新增趋势专用接口:
|
||||
|
||||
```text
|
||||
GET /steady/data-view/ledger-tree
|
||||
```
|
||||
|
||||
返回字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "project-001",
|
||||
"parentId": "engineering-001",
|
||||
"name": "10kV一号站",
|
||||
"level": 1,
|
||||
"sort": 0,
|
||||
"deviceCount": 4,
|
||||
"lineCount": 28,
|
||||
"selectable": false,
|
||||
"children": []
|
||||
}
|
||||
```
|
||||
|
||||
节点选择规则:
|
||||
|
||||
- 监测点节点可直接作为趋势查询的 `lineId`。
|
||||
- 设备节点选中时,等价于选中其下全部有效监测点。
|
||||
- 工程、项目节点选中时,等价于选中其下全部有效监测点,但需要做数量限制。
|
||||
- 搜索设备名或监测点名时,应保留完整父级路径,避免返回孤立节点。
|
||||
|
||||
## 指标树
|
||||
|
||||
新增趋势指标树接口:
|
||||
|
||||
```text
|
||||
GET /steady/data-view/indicator-tree
|
||||
```
|
||||
|
||||
指标分组沿用用户提供的结构:
|
||||
|
||||
- 电压趋势
|
||||
- 电流趋势
|
||||
- 频率趋势
|
||||
- 谐波趋势
|
||||
- 功率趋势
|
||||
- 闪变趋势
|
||||
|
||||
后端不直接散落前端 JS 节点,而是维护统一指标目录。每个叶子指标建议包含:
|
||||
|
||||
```json
|
||||
{
|
||||
"indicatorCode": "V_RMS",
|
||||
"name": "相电压有效值",
|
||||
"groupCode": "VOLTAGE",
|
||||
"tableName": "data_v",
|
||||
"baseFields": ["RMS"],
|
||||
"phaseCodes": ["A", "B", "C"],
|
||||
"seriesFields": [
|
||||
{
|
||||
"field": "RMS",
|
||||
"name": "相电压有效值"
|
||||
}
|
||||
],
|
||||
"supportStats": ["AVG", "MAX", "MIN", "CP95"],
|
||||
"harmonic": false,
|
||||
"harmonicOrderStart": null,
|
||||
"harmonicOrderEnd": null,
|
||||
"unit": "V"
|
||||
}
|
||||
```
|
||||
|
||||
普通指标通过 `baseFields` 映射到 InfluxDB field。`phaseCodes` 用于约束 `PHASIC_TYPE` 查询条件,`seriesFields` 用于描述一个指标最终生成几条曲线。谐波指标通过 `fieldPrefix + harmonicOrder + statSuffix` 生成字段,如 `V_5`、`V_5_MAX`、`V_5_MIN`、`V_5_CP95`。
|
||||
|
||||
部分指标只支持 `T` 相,不能套用全局 A/B/C/T 相别选择。指标树只负责选择业务指标,相别选择由当前指标目录动态驱动:
|
||||
|
||||
- `phaseCodes = ["A", "B", "C"]` 的指标,页面展示 A/B/C 相别选择,默认可全选。
|
||||
- `phaseCodes = ["T"]` 的指标,页面固定为 T 相,可隐藏相别选择或显示为“总量/三相统计”。
|
||||
- 单监测点多指标查询时,每个指标按自己的 `phaseCodes` 生成曲线,不强制取多个指标的相别交集。
|
||||
- 多监测点单指标查询时,按该指标的 `phaseCodes` 展示相别选择。
|
||||
|
||||
`T` 相不一定只对应一条曲线。例如线电压有效值使用 `PHASIC_TYPE = 'T'` 过滤,但会展开 `RMSAB`、`RMSBC`、`RMSCA` 三条曲线:
|
||||
|
||||
```json
|
||||
{
|
||||
"indicatorCode": "V_LINE_RMS",
|
||||
"name": "线电压有效值",
|
||||
"tableName": "data_v",
|
||||
"phaseCodes": ["T"],
|
||||
"seriesFields": [
|
||||
{
|
||||
"field": "RMSAB",
|
||||
"name": "AB线电压"
|
||||
},
|
||||
{
|
||||
"field": "RMSBC",
|
||||
"name": "BC线电压"
|
||||
},
|
||||
{
|
||||
"field": "RMSCA",
|
||||
"name": "CA线电压"
|
||||
}
|
||||
],
|
||||
"supportStats": ["AVG", "MAX", "MIN", "CP95"],
|
||||
"unit": "V"
|
||||
}
|
||||
```
|
||||
|
||||
## InfluxDB 配置
|
||||
|
||||
InfluxDB 连接做成配置项,不在代码中写死。
|
||||
|
||||
```yaml
|
||||
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
|
||||
```
|
||||
|
||||
本地密码可配置为 `123456`,但不建议提交明文密码到仓库配置文件。
|
||||
|
||||
从截图判断当前更接近 InfluxDB 1.x 连接方式,查询方案优先按 InfluxQL 设计。如实际为 InfluxDB 2.x,需要将 `database` 改为 `bucket/org/token` 模型。
|
||||
|
||||
## InfluxDB 数据模型
|
||||
|
||||
建议保持与 `add-data` 表结构一致:
|
||||
|
||||
- measurement:沿用表名,如 `data_v`、`data_i`、`data_harmrate_v`
|
||||
- time:InfluxDB 内置时间,等价原 `TIMEID`
|
||||
- tag:`LINEID`、`PHASIC_TYPE`、`QUALITYFLAG`
|
||||
- field:沿用原业务字段,如 `RMS`、`RMS_MAX`、`RMS_MIN`、`RMS_CP95`
|
||||
|
||||
查询时必须使用 `AddDataTableRegistry` 或趋势指标目录做 measurement 和 field 白名单校验,禁止前端传任意表名或字段名直接拼接查询。
|
||||
|
||||
## 趋势查询接口
|
||||
|
||||
建议新增:
|
||||
|
||||
```text
|
||||
POST /steady/data-view/trend/query
|
||||
POST /steady/data-view/trend/day
|
||||
POST /steady/data-view/trend/summary
|
||||
```
|
||||
|
||||
`trend/query` 用于首次查询,返回图表元数据、首屏数据和可加载日期范围。
|
||||
|
||||
`trend/day` 用于按天动态加载。前端切换日期、拖动缩放或需要补齐某天数据时调用。
|
||||
|
||||
请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"lineIds": ["line-001"],
|
||||
"indicatorCodes": ["V_RMS", "FREQ"],
|
||||
"statTypes": ["AVG", "MAX", "MIN", "CP95"],
|
||||
"phases": ["A", "B", "C"],
|
||||
"timeStart": "2026-05-01 00:00:00",
|
||||
"timeEnd": "2026-05-01 23:59:59",
|
||||
"bucket": "10m",
|
||||
"qualityFlag": 1
|
||||
}
|
||||
```
|
||||
|
||||
返回示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"sampled": true,
|
||||
"bucket": "10m",
|
||||
"sourcePointCount": 86400,
|
||||
"displayPointCount": 144,
|
||||
"series": [
|
||||
{
|
||||
"seriesKey": "line-001|V_RMS|A|AVG",
|
||||
"lineId": "line-001",
|
||||
"lineName": "进线一",
|
||||
"indicatorCode": "V_RMS",
|
||||
"indicatorName": "相电压有效值",
|
||||
"phase": "A",
|
||||
"statType": "AVG",
|
||||
"unit": "V",
|
||||
"points": [
|
||||
{
|
||||
"time": "2026-05-01 00:00:00",
|
||||
"value": 220.1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`trend/summary` 返回当前查询范围或当前可视窗口内的统计值:
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"seriesKey": "line-001|V_RMS|A",
|
||||
"max": 232.1,
|
||||
"avg": 220.4,
|
||||
"min": 214.8,
|
||||
"cp95": 228.7
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 统计口径
|
||||
|
||||
统计类型包括:
|
||||
|
||||
- `MAX`:最大值
|
||||
- `AVG`:平均值
|
||||
- `MIN`:最小值
|
||||
- `CP95`:95% 概率大值
|
||||
|
||||
优先读取已有统计字段:
|
||||
|
||||
- `AVG` 读取基础字段,如 `RMS`、`FREQ`、`V_5`
|
||||
- `MAX` 读取 `_MAX` 字段
|
||||
- `MIN` 读取 `_MIN` 字段
|
||||
- `CP95` 读取 `_CP95` 字段
|
||||
|
||||
如果某些表没有独立统计字段,如部分闪变和波动字段,则接口应在指标目录中标明不支持的统计类型,前端禁用对应选项。仅在明确需要时才使用 InfluxDB 动态聚合兜底。
|
||||
|
||||
## 查询模式限制
|
||||
|
||||
支持两种主要查询模式:
|
||||
|
||||
1. 一个监测点,多指标
|
||||
2. 多个监测点,一个指标
|
||||
|
||||
为了保证图表可读性和查询效率,建议限制:
|
||||
|
||||
- 普通趋势:最多 8 个监测点或 8 个指标。
|
||||
- 多监测点查询时,默认只允许 1 个指标。
|
||||
- 单监测点查询时,可选择多个指标。
|
||||
- 多指标混查时,每个指标使用自己的相别配置,避免 A/B/C 指标与 T 相指标交集为空导致无法查询。
|
||||
- 单次序列数量建议不超过 24 条,超过时提示缩小监测点、指标、相别或统计类型范围。
|
||||
|
||||
## 谐波展示方案
|
||||
|
||||
谐波类包含 2~50 次谐波,不适合一次性全部画趋势线。建议拆成三种展示:
|
||||
|
||||
1. 趋势图模式
|
||||
- 用户选择谐波类型后,再选择 1 到 6 个谐波次数。
|
||||
- 只展示被选次数随时间变化。
|
||||
- 适合观察 3、5、7、11、13 次等重点谐波。
|
||||
|
||||
2. 谐波谱模式
|
||||
- 用户在趋势图上选中某个时间点。
|
||||
- 展示该时刻 2~50 次谐波柱状图。
|
||||
- 适合查看单个时刻的谐波分布。
|
||||
|
||||
3. TopN 模式
|
||||
- 后端按当前时间范围统计每个谐波次数的 `MAX` 或 `CP95`。
|
||||
- 默认返回 Top 10。
|
||||
- 适合快速定位主要谐波次数。
|
||||
|
||||
谐波趋势默认禁止直接加载 2~50 全部次数。必须指定 `harmonicOrders` 或使用 `topN`。
|
||||
|
||||
## 按天动态加载
|
||||
|
||||
前端首次查询时只加载当前可视范围或默认第一天数据。用户滚动、缩放、切换日期时按天请求。
|
||||
|
||||
后端按时间范围自动给出建议 bucket:
|
||||
|
||||
- 范围小于 6 小时:`1m`
|
||||
- 6 小时到 1 天:`5m` 或 `10m`
|
||||
- 1 天到 7 天:按天加载,每天 `10m` 或 `30m`
|
||||
- 大于 7 天:优先按天加载摘要,进入某天后再加载细节
|
||||
|
||||
接口返回 `sampled`、`sourcePointCount`、`displayPointCount`,前端可提示当前是否已下采样。
|
||||
|
||||
## 缓存策略
|
||||
|
||||
建议增加短期查询缓存,缓存 key 包含:
|
||||
|
||||
```text
|
||||
lineIds + indicatorCodes + phases + statTypes + day + bucket + qualityFlag
|
||||
```
|
||||
|
||||
缓存粒度以单日为主,避免一个大时间范围缓存过大。缓存只用于趋势点位,不缓存配置密码和连接对象以外的敏感信息。
|
||||
|
||||
## 页面布局
|
||||
|
||||
推荐布局:
|
||||
|
||||
```text
|
||||
顶部:时间范围 / 相别 / 统计类型 / 查询 / 重置
|
||||
|
||||
左侧:
|
||||
台账监测点树
|
||||
- 工程、项目、设备、监测点
|
||||
- 显示设备数、监测点数
|
||||
- 支持搜索与勾选
|
||||
|
||||
左侧下方或中左:
|
||||
稳态指标树
|
||||
- 电压趋势
|
||||
- 电流趋势
|
||||
- 频率趋势
|
||||
- 谐波趋势
|
||||
- 功率趋势
|
||||
- 闪变趋势
|
||||
|
||||
中间:
|
||||
趋势图
|
||||
- 折线图
|
||||
- 图例开关
|
||||
- tooltip
|
||||
- 缩放联动
|
||||
- 按天动态加载
|
||||
|
||||
右侧:
|
||||
当前范围统计
|
||||
- 最大值
|
||||
- 平均值
|
||||
- 最小值
|
||||
- CP95
|
||||
```
|
||||
|
||||
谐波类指标被选中时,趋势图上方增加:
|
||||
|
||||
- 谐波次数选择器
|
||||
- 趋势 / 谱图 / TopN 切换
|
||||
|
||||
## 后端模块划分
|
||||
|
||||
建议在 `steady-DataView` 中按职责拆分:
|
||||
|
||||
- `SteadyDataViewLedgerController`:趋势页面台账树
|
||||
- `SteadyDataViewIndicatorController`:指标树
|
||||
- `SteadyDataViewTrendController`:趋势查询、按天加载、统计摘要
|
||||
- `SteadyDataViewLedgerService`:复用 add-ledger 口径生成带数量的树
|
||||
- `SteadyDataViewIndicatorService`:维护指标目录和字段映射
|
||||
- `SteadyDataViewTrendService`:参数校验、查询编排、结果组装
|
||||
- `SteadyInfluxQueryComponent`:InfluxDB 查询封装
|
||||
- `SteadyTrendFieldResolver`:指标到 measurement/field 的白名单转换
|
||||
|
||||
保留现有 `SteadyDataViewController` 的分页、详情、模板职责,不继续把所有新接口堆到一个大 Controller。
|
||||
|
||||
## 验证方式
|
||||
|
||||
方案落地后,默认验证不执行 Maven 构建,除非用户明确要求。
|
||||
|
||||
建议检查:
|
||||
|
||||
1. 配置检查:InfluxDB 配置项可被 Spring Boot 读取,密码未硬编码提交。
|
||||
2. 指标映射检查:所有指标都能解析到合法 measurement 和 field。
|
||||
3. 台账树检查:设备数、监测点数与 add-ledger 有效数据口径一致。
|
||||
4. 查询限制检查:超出监测点、指标、谐波次数限制时返回明确提示。
|
||||
5. 查询语句检查:InfluxDB 查询必须带时间范围、`LINEID` 和必要 tag 条件。
|
||||
6. 趋势返回检查:返回 series、points、统计摘要结构稳定,前端可直接绘图。
|
||||
7. 谐波检查:趋势模式不默认返回 2~50 全部次数,谱图和 TopN 按独立接口或模式返回。
|
||||
|
||||
## 分期建议
|
||||
|
||||
第一期:
|
||||
|
||||
- InfluxDB 可配置连接
|
||||
- 台账监测点树,包含设备数和监测点数
|
||||
- 稳态指标树
|
||||
- 普通指标趋势查询
|
||||
- 最大值、平均值、最小值、CP95
|
||||
- 按天动态加载
|
||||
- 谐波趋势支持手动选择次数
|
||||
|
||||
第二期:
|
||||
|
||||
- 谐波谱图
|
||||
- 谐波 TopN
|
||||
- 查询缓存优化
|
||||
- 大范围摘要视图
|
||||
- 前端交互细节优化
|
||||
|
||||
## 待确认事项
|
||||
|
||||
1. InfluxDB 版本是否确定为 1.x。
|
||||
2. 生产环境 InfluxDB measurement 是否完全沿用 `data_*` 表名。
|
||||
3. `QUALITYFLAG` 在 InfluxDB 中是否作为 tag 保存。
|
||||
4. 谐波相角、间谐波等字段命名是否与 `add-data` 当前 SQL 完全一致。
|
||||
5. 前端是否已有可复用的 ECharts 趋势图组件,还是只参考 waveform 返回结构重新接入。
|
||||
@@ -53,6 +53,21 @@
|
||||
<artifactId>add-data</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>add-ledger</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>event-list</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>steady-DataView</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
317
event/event-list/API_DEBUG.md
Normal file
317
event/event-list/API_DEBUG.md
Normal file
@@ -0,0 +1,317 @@
|
||||
# event-list API 调试文档
|
||||
|
||||
## 1. 基础信息
|
||||
|
||||
- 模块:`event/event-list`
|
||||
- 控制器:`EventListController`
|
||||
- 接口前缀:`/event/list`
|
||||
- 本地默认地址:`http://localhost:18192`
|
||||
- Content-Type:`application/json`
|
||||
- 认证:除 `/admin/login`、`/admin/getPublicKey`、Swagger 资源外,请求需要携带登录后的 `Authorization` 头。
|
||||
|
||||
```text
|
||||
Authorization: Bearer <accessToken>
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `event-list` 当前提供暂态事件分页查询、详情查询和导出能力。
|
||||
- 事件数据来自 `r_mp_event_detail`。
|
||||
- 工程、项目、设备、监测点名称由 `tools/add-ledger` 内部服务按监测点 ID 批量补齐。
|
||||
- 本文示例中的业务数据为调试示例,实际值以数据库为准。
|
||||
|
||||
## 2. 通用响应
|
||||
|
||||
分页和详情接口统一返回 `HttpResult` 包装结果。外层字段由公共组件序列化,常见结构如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "000000",
|
||||
"message": "成功",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
调试时重点查看:
|
||||
|
||||
- `code`:业务响应码。
|
||||
- `message`:业务响应消息。
|
||||
- `data`:接口返回数据。
|
||||
|
||||
导出接口直接返回 Excel 文件流,不返回 `HttpResult` JSON。
|
||||
|
||||
## 3. 分页查询暂态事件列表
|
||||
|
||||
### 3.1 接口信息
|
||||
|
||||
- 路径:`POST /event/list/transient/page`
|
||||
- 完整地址:`http://localhost:18192/event/list/transient/page`
|
||||
- 控制器方法:`EventListController#pageTransientEvents`
|
||||
- 服务方法:`EventListService#pageTransientEvents`
|
||||
- 返回:`HttpResult<Page<EventListVO>>`
|
||||
- 默认排序:`start_time DESC, event_id DESC`
|
||||
|
||||
### 3.2 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"pageNum": 1,
|
||||
"pageSize": 10,
|
||||
"startTimeStart": "2026-05-01 00:00:00",
|
||||
"startTimeEnd": "2026-05-09 23:59:59",
|
||||
"eventType": "VOLTAGE_SAG",
|
||||
"phase": "A",
|
||||
"eventDescribe": "暂降",
|
||||
"durationMin": 0.02,
|
||||
"durationMax": 10,
|
||||
"featureAmplitudeMin": 10,
|
||||
"featureAmplitudeMax": 90,
|
||||
"fileFlag": 1,
|
||||
"dealFlag": 0,
|
||||
"lineIds": [
|
||||
"line-001"
|
||||
],
|
||||
"engineeringName": "示例工程",
|
||||
"projectName": "示例项目",
|
||||
"equipmentName": "示例设备",
|
||||
"lineName": "示例测点"
|
||||
}
|
||||
```
|
||||
|
||||
分页字段继承公共 `BaseParam`,调试时按项目现有分页参数约定传入。示例使用 `pageNum`、`pageSize`。
|
||||
|
||||
### 3.3 请求字段
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `pageNum` | Number | 否 | 页码,来自公共分页参数 |
|
||||
| `pageSize` | Number | 否 | 每页条数,来自公共分页参数 |
|
||||
| `startTimeStart` | String | 否 | 发生时刻开始,格式 `yyyy-MM-dd HH:mm:ss` |
|
||||
| `startTimeEnd` | String | 否 | 发生时刻结束,格式 `yyyy-MM-dd HH:mm:ss` |
|
||||
| `eventType` | String | 否 | 事件类型,对应 `r_mp_event_detail.event_type` |
|
||||
| `phase` | String | 否 | 相别,对应 `r_mp_event_detail.phase` |
|
||||
| `eventDescribe` | String | 否 | 事件描述关键字,按 `LIKE` 查询 |
|
||||
| `durationMin` | Number | 否 | 持续时间下限,单位秒 |
|
||||
| `durationMax` | Number | 否 | 持续时间上限,单位秒 |
|
||||
| `featureAmplitudeMin` | Number | 否 | 暂降/暂升幅值下限 |
|
||||
| `featureAmplitudeMax` | Number | 否 | 暂降/暂升幅值上限 |
|
||||
| `fileFlag` | Number | 否 | 波形文件状态:`0` 未招,`1` 已招 |
|
||||
| `dealFlag` | Number | 否 | 处理状态:`0` 未处理,`1` 已处理,`2` 已处理无结果,`3` 计算失败 |
|
||||
| `lineIds` | Array<String> | 否 | 监测点 ID 列表,最多 1000 个 |
|
||||
| `engineeringName` | String | 否 | 工程名称关键字,通过 `add-ledger` 反查监测点 |
|
||||
| `projectName` | String | 否 | 项目名称关键字,通过 `add-ledger` 反查监测点 |
|
||||
| `equipmentName` | String | 否 | 设备名称关键字,通过 `add-ledger` 反查监测点 |
|
||||
| `lineName` | String | 否 | 监测点名称关键字,通过 `add-ledger` 反查监测点 |
|
||||
|
||||
时间字段支持以下输入格式:
|
||||
|
||||
- `yyyy-MM-dd HH:mm:ss`
|
||||
- `yyyy-MM-dd HH:mm:ss.SSS`
|
||||
- `yyyy-MM-dd'T'HH:mm:ss`
|
||||
- `yyyy-MM-dd'T'HH:mm:ss.SSS`
|
||||
|
||||
如果不传 `startTimeStart`,后端默认取当前月 1 日 `00:00:00`。如果不传 `startTimeEnd`,后端默认取当前时间。
|
||||
|
||||
### 3.4 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "000000",
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"records": [
|
||||
{
|
||||
"eventId": "event-001",
|
||||
"measurementPointId": "line-001",
|
||||
"eventType": "VOLTAGE_SAG",
|
||||
"equipmentName": "示例设备",
|
||||
"engineeringName": "示例工程",
|
||||
"projectName": "示例项目",
|
||||
"startTime": "2026-05-09 10:20:30",
|
||||
"lineName": "示例测点",
|
||||
"eventDescribe": "电压暂降",
|
||||
"sagsource": "上游",
|
||||
"phase": "A",
|
||||
"duration": 0.12,
|
||||
"featureAmplitude": 65.5,
|
||||
"wavePath": "D:/wave/event-001.cfg",
|
||||
"fileFlag": 1,
|
||||
"dealFlag": 0,
|
||||
"createTime": "2026-05-09 10:21:00"
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"size": 10,
|
||||
"current": 1,
|
||||
"pages": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`Page` 对象可能包含 MyBatis-Plus 的其他分页字段,调试时主要关注 `records`、`total`、`size`、`current`、`pages`。
|
||||
|
||||
### 3.5 curl 示例
|
||||
|
||||
```powershell
|
||||
curl.exe -X POST "http://localhost:18192/event/list/transient/page" `
|
||||
-H "Content-Type: application/json" `
|
||||
-H "Authorization: Bearer <accessToken>" `
|
||||
-d "{\"pageNum\":1,\"pageSize\":10,\"startTimeStart\":\"2026-05-01 00:00:00\",\"startTimeEnd\":\"2026-05-09 23:59:59\",\"eventDescribe\":\"暂降\"}"
|
||||
```
|
||||
|
||||
## 4. 查询暂态事件详情
|
||||
|
||||
### 4.1 接口信息
|
||||
|
||||
- 路径:`GET /event/list/transient/{eventId}`
|
||||
- 完整地址:`http://localhost:18192/event/list/transient/{eventId}`
|
||||
- 控制器方法:`EventListController#getTransientEventDetail`
|
||||
- 服务方法:`EventListService#getTransientEventDetail`
|
||||
- 返回:`HttpResult<EventListVO>`
|
||||
|
||||
### 4.2 请求参数
|
||||
|
||||
| 参数 | 位置 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `eventId` | Path | String | 是 | 暂态事件 ID,对应 `r_mp_event_detail.event_id` |
|
||||
|
||||
### 4.3 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "000000",
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"eventId": "event-001",
|
||||
"measurementPointId": "line-001",
|
||||
"eventType": "VOLTAGE_SAG",
|
||||
"equipmentName": "示例设备",
|
||||
"engineeringName": "示例工程",
|
||||
"projectName": "示例项目",
|
||||
"startTime": "2026-05-09 10:20:30",
|
||||
"lineName": "示例测点",
|
||||
"eventDescribe": "电压暂降",
|
||||
"sagsource": "上游",
|
||||
"phase": "A",
|
||||
"duration": 0.12,
|
||||
"featureAmplitude": 65.5,
|
||||
"wavePath": "D:/wave/event-001.cfg",
|
||||
"fileFlag": 1,
|
||||
"dealFlag": 0,
|
||||
"createTime": "2026-05-09 10:21:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 curl 示例
|
||||
|
||||
```powershell
|
||||
curl.exe -X GET "http://localhost:18192/event/list/transient/event-001" `
|
||||
-H "Authorization: Bearer <accessToken>"
|
||||
```
|
||||
|
||||
## 5. 导出暂态事件列表
|
||||
|
||||
### 5.1 接口信息
|
||||
|
||||
- 路径:`POST /event/list/transient/export`
|
||||
- 完整地址:`http://localhost:18192/event/list/transient/export`
|
||||
- 控制器方法:`EventListController#exportTransientEvents`
|
||||
- 服务方法:`EventListService#exportTransientEvents`
|
||||
- 返回:Excel 文件流
|
||||
- 文件名:`暂态事件列表.xlsx`
|
||||
- Sheet 名称:`暂态事件列表`
|
||||
|
||||
导出复用分页查询的筛选条件,但不使用分页结果。当前同步导出最多允许 5000 条,超过时返回业务错误。
|
||||
|
||||
### 5.2 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"startTimeStart": "2026-05-01 00:00:00",
|
||||
"startTimeEnd": "2026-05-09 23:59:59",
|
||||
"eventDescribe": "暂降",
|
||||
"fileFlag": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 导出字段
|
||||
|
||||
| Excel 列名 | 响应字段 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 设备名称 | `equipmentName` | 由 `add-ledger` 按监测点补齐 |
|
||||
| 工程名称 | `engineeringName` | 由 `add-ledger` 按监测点补齐 |
|
||||
| 项目名称 | `projectName` | 由 `add-ledger` 按监测点补齐 |
|
||||
| 发生时刻 | `startTime` | 格式 `yyyy-MM-dd HH:mm:ss` |
|
||||
| 监测点名称 | `lineName` | 由 `add-ledger` 按监测点补齐 |
|
||||
| 事件描述 | `eventDescribe` | 为空时使用 `eventType` |
|
||||
| 事件发生位置 | `sagsource` | 为空时返回 `-` |
|
||||
| 相别 | `phase` | 为空时返回 `-` |
|
||||
| 持续时间(s) | `duration` | 单位秒 |
|
||||
| 暂降/暂升幅值(%) | `featureAmplitude` | 原值导出 |
|
||||
|
||||
### 5.4 curl 示例
|
||||
|
||||
```powershell
|
||||
curl.exe -X POST "http://localhost:18192/event/list/transient/export" `
|
||||
-H "Content-Type: application/json" `
|
||||
-H "Authorization: Bearer <accessToken>" `
|
||||
-d "{\"startTimeStart\":\"2026-05-01 00:00:00\",\"startTimeEnd\":\"2026-05-09 23:59:59\",\"eventDescribe\":\"暂降\"}" `
|
||||
-o "D:/temp/暂态事件列表.xlsx"
|
||||
```
|
||||
|
||||
## 6. 返回字段说明
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `eventId` | String | 事件 ID |
|
||||
| `measurementPointId` | String | 监测点 ID |
|
||||
| `eventType` | String | 事件类型 |
|
||||
| `equipmentName` | String | 设备名称,台账缺失时为 `-` |
|
||||
| `engineeringName` | String | 工程名称,台账缺失时为 `-` |
|
||||
| `projectName` | String | 项目名称,台账缺失时为 `-` |
|
||||
| `startTime` | String | 发生时刻,格式 `yyyy-MM-dd HH:mm:ss` |
|
||||
| `lineName` | String | 监测点名称,台账缺失时为 `-` |
|
||||
| `eventDescribe` | String | 事件描述,空值时返回 `eventType` |
|
||||
| `sagsource` | String | 事件发生位置,空值时为 `-` |
|
||||
| `phase` | String | 相别,空值时为 `-` |
|
||||
| `duration` | Number | 持续时间,单位秒 |
|
||||
| `featureAmplitude` | Number | 暂降/暂升幅值 |
|
||||
| `wavePath` | String | 波形文件路径 |
|
||||
| `fileFlag` | Number | 波形文件状态:`0` 未招,`1` 已招 |
|
||||
| `dealFlag` | Number | 处理状态:`0` 未处理,`1` 已处理,`2` 已处理无结果,`3` 计算失败 |
|
||||
| `createTime` | String | 创建时间,格式 `yyyy-MM-dd HH:mm:ss` |
|
||||
|
||||
## 7. 常见错误场景
|
||||
|
||||
| 场景 | 后端提示 |
|
||||
| --- | --- |
|
||||
| 详情接口 `eventId` 为空 | `事件 ID 不能为空` |
|
||||
| 详情数据不存在 | `暂态事件不存在` |
|
||||
| 开始时间大于结束时间 | `开始时间不能大于结束时间` |
|
||||
| 时间格式无法解析 | `时间格式不正确,仅支持 yyyy-MM-dd HH:mm:ss` |
|
||||
| 持续时间下限大于上限 | `持续时间下限不能大于上限` |
|
||||
| 幅值下限大于上限 | `幅值下限不能大于上限` |
|
||||
| `fileFlag` 不为 `0` 或 `1` | `波形文件状态只能是 0 或 1` |
|
||||
| `dealFlag` 不在 `0-3` 范围内 | `处理状态只能是 0、1、2、3` |
|
||||
| `lineIds` 超过 1000 个 | `监测点 ID 查询数量不能超过 1000 个` |
|
||||
| 台账关键字匹配监测点超过 1000 个 | `台账检索匹配监测点过多,请缩小查询条件` |
|
||||
| 导出超过 5000 条 | `导出数据超过 5000 条,请缩小查询条件` |
|
||||
|
||||
未携带有效 `Authorization` 时,全局认证过滤器会返回 token 解析相关错误。
|
||||
|
||||
## 8. 调试注意事项
|
||||
|
||||
- 先登录获取 `accessToken`,再调试 `event-list` 接口。
|
||||
- 分页查询不传时间范围时,后端默认查当前月 1 日到当前时间。
|
||||
- 台账关键字筛选会先通过 `add-ledger` 查询匹配监测点,再查询事件表。
|
||||
- 如果台账关键字命中范围过大,需要缩小工程、项目、设备或测点关键字。
|
||||
- 导出接口建议始终传入明确时间范围,避免超过 5000 条限制。
|
||||
- 如查询性能不稳定,可先检查是否已按需执行 `event/event-list/src/main/resources/sql/event-list/event-list-index.sql` 中的建议索引。
|
||||
|
||||
## 9. 当前限制
|
||||
|
||||
- 本文档只补充 API 调试说明,未改动业务代码。
|
||||
- 当前未执行 `mvn` 编译、打包、测试或真实接口联调。
|
||||
- 响应外层 `HttpResult` 字段以公共组件实际序列化结果为准。
|
||||
- 分页参数字段以公共 `BaseParam` 实际定义和前端现有调用约定为准。
|
||||
39
event/event-list/pom.xml
Normal file
39
event/event-list/pom.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>event</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>event-list</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>njcn-common</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>mybatis-plus</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>spingboot2.3.12</artifactId>
|
||||
<version>2.3.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>add-ledger</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.gather.event.eventlist.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 暂态事件时间字段按秒输出,避免接口响应携带毫秒。
|
||||
*/
|
||||
public class EventSecondTimeSerializer extends JsonSerializer<LocalDateTime> {
|
||||
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
if (value == null) {
|
||||
gen.writeNull();
|
||||
return;
|
||||
}
|
||||
gen.writeString(FORMATTER.format(value));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.njcn.gather.event.eventlist.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.njcn.common.pojo.annotation.OperateInfo;
|
||||
import com.njcn.common.pojo.constant.OperateType;
|
||||
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.event.eventlist.pojo.param.EventListQueryParam;
|
||||
import com.njcn.gather.event.eventlist.pojo.vo.EventListVO;
|
||||
import com.njcn.gather.event.eventlist.service.EventListService;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
import com.njcn.web.utils.HttpResultUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 事件列表接口预留入口。
|
||||
*/
|
||||
@Validated
|
||||
@Slf4j
|
||||
@Api(tags = "事件列表")
|
||||
@RestController
|
||||
@RequestMapping("/event/list")
|
||||
@RequiredArgsConstructor
|
||||
public class EventListController extends BaseController {
|
||||
|
||||
/** 事件列表服务。 */
|
||||
private final EventListService eventListService;
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("分页查询暂态事件列表")
|
||||
@PostMapping("/transient/page")
|
||||
public HttpResult<Page<EventListVO>> pageTransientEvents(@RequestBody EventListQueryParam param) {
|
||||
String methodDescribe = getMethodDescribe("pageTransientEvents");
|
||||
LogUtil.njcnDebug(log, "{},开始分页查询暂态事件列表,param={}", methodDescribe, param);
|
||||
Page<EventListVO> result = eventListService.pageTransientEvents(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询暂态事件详情")
|
||||
@GetMapping("/transient/{eventId}")
|
||||
public HttpResult<EventListVO> getTransientEventDetail(@PathVariable("eventId") String eventId) {
|
||||
String methodDescribe = getMethodDescribe("getTransientEventDetail");
|
||||
LogUtil.njcnDebug(log, "{},开始查询暂态事件详情,eventId={}", methodDescribe, eventId);
|
||||
EventListVO result = eventListService.getTransientEventDetail(eventId);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.DOWNLOAD)
|
||||
@ApiOperation("导出暂态事件列表")
|
||||
@PostMapping("/transient/export")
|
||||
public void exportTransientEvents(@RequestBody EventListQueryParam param) {
|
||||
eventListService.exportTransientEvents(param);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.njcn.gather.event.eventlist.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.njcn.gather.event.eventlist.pojo.param.EventListQueryParam;
|
||||
import com.njcn.gather.event.eventlist.pojo.po.MpEventDetailPO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 暂态事件列表 Mapper。
|
||||
*/
|
||||
public interface EventListMapper extends BaseMapper<MpEventDetailPO> {
|
||||
|
||||
Page<MpEventDetailPO> selectTransientPage(Page<MpEventDetailPO> page, @Param("param") EventListQueryParam param);
|
||||
|
||||
List<MpEventDetailPO> selectTransientExportList(@Param("param") EventListQueryParam param, @Param("limit") Integer limit);
|
||||
|
||||
MpEventDetailPO selectTransientDetail(@Param("eventId") String eventId);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.njcn.gather.event.eventlist.mapper.EventListMapper">
|
||||
|
||||
<sql id="EventDetailColumns">
|
||||
event_id,
|
||||
measurement_point_id,
|
||||
start_time,
|
||||
event_type,
|
||||
advance_reason,
|
||||
advance_type,
|
||||
feature_amplitude,
|
||||
duration,
|
||||
eventass_index,
|
||||
dq_time,
|
||||
deal_time,
|
||||
num,
|
||||
file_flag,
|
||||
deal_flag,
|
||||
first_time,
|
||||
first_type,
|
||||
first_ms,
|
||||
energy,
|
||||
severity,
|
||||
sagsource,
|
||||
phase,
|
||||
event_describe,
|
||||
wave_path,
|
||||
create_time,
|
||||
transient_value,
|
||||
verify_reason,
|
||||
verify_reason_detail
|
||||
</sql>
|
||||
|
||||
<sql id="TransientWhere">
|
||||
<where>
|
||||
<if test="param.startTimeStart != null and param.startTimeStart != ''">
|
||||
AND start_time >= #{param.startTimeStart}
|
||||
</if>
|
||||
<if test="param.startTimeEnd != null and param.startTimeEnd != ''">
|
||||
AND start_time <= #{param.startTimeEnd}
|
||||
</if>
|
||||
<if test="param.eventType != null and param.eventType != ''">
|
||||
AND event_type = #{param.eventType}
|
||||
</if>
|
||||
<if test="param.phase != null and param.phase != ''">
|
||||
AND phase = #{param.phase}
|
||||
</if>
|
||||
<if test="param.eventDescribe != null and param.eventDescribe != ''">
|
||||
AND event_describe LIKE CONCAT('%', #{param.eventDescribe}, '%')
|
||||
</if>
|
||||
<if test="param.durationMin != null">
|
||||
AND duration >= #{param.durationMin}
|
||||
</if>
|
||||
<if test="param.durationMax != null">
|
||||
AND duration <= #{param.durationMax}
|
||||
</if>
|
||||
<if test="param.featureAmplitudeMin != null">
|
||||
AND feature_amplitude >= #{param.featureAmplitudeMin}
|
||||
</if>
|
||||
<if test="param.featureAmplitudeMax != null">
|
||||
AND feature_amplitude <= #{param.featureAmplitudeMax}
|
||||
</if>
|
||||
<if test="param.fileFlag != null">
|
||||
AND file_flag = #{param.fileFlag}
|
||||
</if>
|
||||
<if test="param.dealFlag != null">
|
||||
AND deal_flag = #{param.dealFlag}
|
||||
</if>
|
||||
<if test="param.lineIds != null and param.lineIds.size() > 0">
|
||||
AND measurement_point_id IN
|
||||
<foreach collection="param.lineIds" item="lineId" open="(" separator="," close=")">
|
||||
#{lineId}
|
||||
</foreach>
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<select id="selectTransientPage" resultType="com.njcn.gather.event.eventlist.pojo.po.MpEventDetailPO">
|
||||
SELECT
|
||||
<include refid="EventDetailColumns"/>
|
||||
FROM r_mp_event_detail
|
||||
<include refid="TransientWhere"/>
|
||||
ORDER BY start_time DESC, event_id DESC
|
||||
</select>
|
||||
|
||||
<select id="selectTransientExportList" resultType="com.njcn.gather.event.eventlist.pojo.po.MpEventDetailPO">
|
||||
SELECT
|
||||
<include refid="EventDetailColumns"/>
|
||||
FROM r_mp_event_detail
|
||||
<include refid="TransientWhere"/>
|
||||
ORDER BY start_time DESC, event_id DESC
|
||||
LIMIT #{limit}
|
||||
</select>
|
||||
|
||||
<select id="selectTransientDetail" resultType="com.njcn.gather.event.eventlist.pojo.po.MpEventDetailPO">
|
||||
SELECT
|
||||
<include refid="EventDetailColumns"/>
|
||||
FROM r_mp_event_detail
|
||||
WHERE event_id = #{eventId}
|
||||
LIMIT 1
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.njcn.gather.event.eventlist.pojo.param;
|
||||
|
||||
import com.njcn.web.pojo.param.BaseParam;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 暂态事件列表查询参数。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ApiModel("暂态事件列表查询参数")
|
||||
public class EventListQueryParam extends BaseParam {
|
||||
|
||||
@ApiModelProperty("发生时刻开始,格式 yyyy-MM-dd HH:mm:ss")
|
||||
private String startTimeStart;
|
||||
|
||||
@ApiModelProperty("发生时刻结束,格式 yyyy-MM-dd HH:mm:ss")
|
||||
private String startTimeEnd;
|
||||
|
||||
@ApiModelProperty("事件类型")
|
||||
private String eventType;
|
||||
|
||||
@ApiModelProperty("相别")
|
||||
private String phase;
|
||||
|
||||
@ApiModelProperty("事件描述关键字")
|
||||
private String eventDescribe;
|
||||
|
||||
@ApiModelProperty("持续时间下限,单位秒")
|
||||
private BigDecimal durationMin;
|
||||
|
||||
@ApiModelProperty("持续时间上限,单位秒")
|
||||
private BigDecimal durationMax;
|
||||
|
||||
@ApiModelProperty("暂降/暂升幅值下限")
|
||||
private BigDecimal featureAmplitudeMin;
|
||||
|
||||
@ApiModelProperty("暂降/暂升幅值上限")
|
||||
private BigDecimal featureAmplitudeMax;
|
||||
|
||||
@ApiModelProperty("波形文件状态:0 未招,1 已招")
|
||||
private Integer fileFlag;
|
||||
|
||||
@ApiModelProperty("处理状态:0 未处理,1 已处理,2 已处理无结果,3 计算失败")
|
||||
private Integer dealFlag;
|
||||
|
||||
@ApiModelProperty("监测点 ID 列表")
|
||||
private List<String> lineIds = new ArrayList<String>();
|
||||
|
||||
@ApiModelProperty("工程名称关键字")
|
||||
private String engineeringName;
|
||||
|
||||
@ApiModelProperty("项目名称关键字")
|
||||
private String projectName;
|
||||
|
||||
@ApiModelProperty("设备名称关键字")
|
||||
private String equipmentName;
|
||||
|
||||
@ApiModelProperty("监测点名称关键字")
|
||||
private String lineName;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.njcn.gather.event.eventlist.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
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 lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 暂态事件明细。
|
||||
*/
|
||||
@Data
|
||||
@TableName("r_mp_event_detail")
|
||||
public class MpEventDetailPO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId("event_id")
|
||||
private String eventId;
|
||||
|
||||
private String measurementPointId;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
private LocalDateTime startTime;
|
||||
|
||||
private String eventType;
|
||||
|
||||
private String advanceReason;
|
||||
|
||||
private String advanceType;
|
||||
|
||||
private BigDecimal featureAmplitude;
|
||||
|
||||
private BigDecimal duration;
|
||||
|
||||
private String eventassIndex;
|
||||
|
||||
private Double dqTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
private LocalDateTime dealTime;
|
||||
|
||||
private Integer num;
|
||||
|
||||
private Integer fileFlag;
|
||||
|
||||
private Integer dealFlag;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
private LocalDateTime firstTime;
|
||||
|
||||
private String firstType;
|
||||
|
||||
private BigDecimal firstMs;
|
||||
|
||||
private Double energy;
|
||||
|
||||
private Double severity;
|
||||
|
||||
private String sagsource;
|
||||
|
||||
private String phase;
|
||||
|
||||
private String eventDescribe;
|
||||
|
||||
private String wavePath;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private Double transientValue;
|
||||
|
||||
private String verifyReason;
|
||||
|
||||
private String verifyReasonDetail;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
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.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 lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 暂态事件列表展示对象。
|
||||
*/
|
||||
@Data
|
||||
public class EventListVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String eventId;
|
||||
|
||||
private String measurementPointId;
|
||||
|
||||
private String eventType;
|
||||
|
||||
@Excel(name = "设备名称", width = 25)
|
||||
private String equipmentName;
|
||||
|
||||
@Excel(name = "工程名称", width = 25)
|
||||
private String engineeringName;
|
||||
|
||||
@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 lineName;
|
||||
|
||||
@Excel(name = "事件描述", width = 25)
|
||||
private String eventDescribe;
|
||||
|
||||
@Excel(name = "事件发生位置", width = 18)
|
||||
private String sagsource;
|
||||
|
||||
@Excel(name = "相别", width = 15)
|
||||
private String phase;
|
||||
|
||||
@Excel(name = "持续时间(s)", width = 18)
|
||||
private BigDecimal duration;
|
||||
|
||||
@Excel(name = "暂降/暂升幅值(%)", width = 20)
|
||||
private BigDecimal featureAmplitude;
|
||||
|
||||
private String wavePath;
|
||||
|
||||
private Integer fileFlag;
|
||||
|
||||
private Integer dealFlag;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
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.vo.EventListVO;
|
||||
|
||||
/**
|
||||
* 事件列表服务。
|
||||
*/
|
||||
public interface EventListService {
|
||||
|
||||
Page<EventListVO> pageTransientEvents(EventListQueryParam param);
|
||||
|
||||
EventListVO getTransientEventDetail(String eventId);
|
||||
|
||||
void exportTransientEvents(EventListQueryParam param);
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
package com.njcn.gather.event.eventlist.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
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.po.MpEventDetailPO;
|
||||
import com.njcn.gather.event.eventlist.pojo.vo.EventListVO;
|
||||
import com.njcn.gather.event.eventlist.service.EventListService;
|
||||
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.web.factory.PageFactory;
|
||||
import com.njcn.web.utils.ExcelUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 事件列表服务实现。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
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 String EMPTY_TEXT = "-";
|
||||
private static final DateTimeFormatter OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
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"),
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"),
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
|
||||
};
|
||||
|
||||
private final EventListMapper eventListMapper;
|
||||
private final AddLedgerService addLedgerService;
|
||||
|
||||
@Override
|
||||
public Page<EventListVO> pageTransientEvents(EventListQueryParam param) {
|
||||
EventListQueryParam queryParam = normalizeQueryParam(param);
|
||||
if (!resolveLineFilter(queryParam)) {
|
||||
return emptyPage(queryParam);
|
||||
}
|
||||
Page<MpEventDetailPO> eventPage = eventListMapper.selectTransientPage(
|
||||
new Page<MpEventDetailPO>(PageFactory.getPageNum(queryParam), PageFactory.getPageSize(queryParam)),
|
||||
queryParam);
|
||||
List<EventListVO> records = buildEventList(eventPage.getRecords());
|
||||
Page<EventListVO> resultPage = new Page<EventListVO>(eventPage.getCurrent(), eventPage.getSize(), eventPage.getTotal());
|
||||
resultPage.setRecords(records);
|
||||
return resultPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventListVO getTransientEventDetail(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, "暂态事件不存在");
|
||||
}
|
||||
List<MpEventDetailPO> eventDetails = new ArrayList<MpEventDetailPO>();
|
||||
eventDetails.add(eventDetail);
|
||||
return buildEventList(eventDetails).get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportTransientEvents(EventListQueryParam param) {
|
||||
EventListQueryParam queryParam = normalizeQueryParam(param);
|
||||
List<EventListVO> exportRecords;
|
||||
if (resolveLineFilter(queryParam)) {
|
||||
List<MpEventDetailPO> eventDetails = eventListMapper.selectTransientExportList(queryParam, EXPORT_LIMIT + 1);
|
||||
if (eventDetails.size() > EXPORT_LIMIT) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "导出数据超过 5000 条,请缩小查询条件");
|
||||
}
|
||||
exportRecords = buildEventList(eventDetails);
|
||||
} else {
|
||||
exportRecords = Collections.emptyList();
|
||||
}
|
||||
ExcelUtil.exportExcel("暂态事件列表.xlsx", "暂态事件列表", EventListVO.class, exportRecords);
|
||||
}
|
||||
|
||||
private List<EventListVO> buildEventList(List<MpEventDetailPO> eventDetails) {
|
||||
if (eventDetails == null || eventDetails.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> lineIds = new ArrayList<String>();
|
||||
for (MpEventDetailPO eventDetail : eventDetails) {
|
||||
String lineId = trimToNull(eventDetail.getMeasurementPointId());
|
||||
if (lineId != null && !lineIds.contains(lineId)) {
|
||||
lineIds.add(lineId);
|
||||
}
|
||||
}
|
||||
Map<String, AddLedgerLinePathVO> linePathMap = addLedgerService.listLinePathByLineIds(lineIds);
|
||||
List<EventListVO> result = new ArrayList<EventListVO>();
|
||||
for (MpEventDetailPO eventDetail : eventDetails) {
|
||||
AddLedgerLinePathVO linePath = linePathMap.get(eventDetail.getMeasurementPointId());
|
||||
result.add(buildEventVO(eventDetail, linePath));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private EventListVO buildEventVO(MpEventDetailPO eventDetail, AddLedgerLinePathVO linePath) {
|
||||
EventListVO vo = new EventListVO();
|
||||
vo.setEventId(eventDetail.getEventId());
|
||||
vo.setMeasurementPointId(eventDetail.getMeasurementPointId());
|
||||
vo.setEventType(eventDetail.getEventType());
|
||||
vo.setEquipmentName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getEquipmentName()));
|
||||
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.setSagsource(defaultText(eventDetail.getSagsource()));
|
||||
vo.setPhase(defaultText(eventDetail.getPhase()));
|
||||
vo.setDuration(eventDetail.getDuration());
|
||||
vo.setFeatureAmplitude(eventDetail.getFeatureAmplitude());
|
||||
vo.setWavePath(eventDetail.getWavePath());
|
||||
vo.setFileFlag(eventDetail.getFileFlag());
|
||||
vo.setDealFlag(eventDetail.getDealFlag());
|
||||
vo.setCreateTime(eventDetail.getCreateTime());
|
||||
return vo;
|
||||
}
|
||||
|
||||
private EventListQueryParam normalizeQueryParam(EventListQueryParam param) {
|
||||
EventListQueryParam queryParam = param == null ? new EventListQueryParam() : param;
|
||||
LocalDateTime startTime = parseDateTime(queryParam.getStartTimeStart());
|
||||
LocalDateTime endTime = parseDateTime(queryParam.getStartTimeEnd());
|
||||
if (startTime == null) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
startTime = LocalDateTime.of(now.getYear(), now.getMonth(), 1, 0, 0, 0);
|
||||
}
|
||||
if (endTime == null) {
|
||||
endTime = LocalDateTime.now();
|
||||
}
|
||||
if (startTime.isAfter(endTime)) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "开始时间不能大于结束时间");
|
||||
}
|
||||
validateRange(queryParam.getDurationMin(), queryParam.getDurationMax(), "持续时间下限不能大于上限");
|
||||
validateRange(queryParam.getFeatureAmplitudeMin(), queryParam.getFeatureAmplitudeMax(), "幅值下限不能大于上限");
|
||||
validateFlag(queryParam.getFileFlag(), "波形文件状态只能是 0 或 1");
|
||||
validateDealFlag(queryParam.getDealFlag());
|
||||
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()));
|
||||
queryParam.setLineName(trimToNull(queryParam.getLineName()));
|
||||
List<String> lineIds = normalizeIds(queryParam.getLineIds());
|
||||
if (lineIds.size() > EVENT_LINE_ID_QUERY_LIMIT) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "监测点 ID 查询数量不能超过 1000 个");
|
||||
}
|
||||
queryParam.setLineIds(lineIds);
|
||||
return queryParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* 台账关键字先转成测点 ID,避免在事件模块直接联查台账表。
|
||||
*/
|
||||
private boolean resolveLineFilter(EventListQueryParam queryParam) {
|
||||
if (!hasLedgerKeyword(queryParam)) {
|
||||
return true;
|
||||
}
|
||||
AddLedgerLinePathQueryParam linePathQueryParam = new AddLedgerLinePathQueryParam();
|
||||
linePathQueryParam.setEngineeringName(queryParam.getEngineeringName());
|
||||
linePathQueryParam.setProjectName(queryParam.getProjectName());
|
||||
linePathQueryParam.setEquipmentName(queryParam.getEquipmentName());
|
||||
linePathQueryParam.setLineName(queryParam.getLineName());
|
||||
linePathQueryParam.setLimit(LEDGER_LINE_QUERY_LIMIT + 1);
|
||||
List<String> ledgerLineIds = addLedgerService.listLineIdsByPathQuery(linePathQueryParam);
|
||||
if (ledgerLineIds.size() > LEDGER_LINE_QUERY_LIMIT) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "台账检索匹配监测点过多,请缩小查询条件");
|
||||
}
|
||||
if (ledgerLineIds.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
List<String> explicitLineIds = normalizeIds(queryParam.getLineIds());
|
||||
if (explicitLineIds.isEmpty()) {
|
||||
queryParam.setLineIds(ledgerLineIds);
|
||||
return true;
|
||||
}
|
||||
List<String> intersectLineIds = new ArrayList<String>();
|
||||
for (String lineId : explicitLineIds) {
|
||||
if (ledgerLineIds.contains(lineId)) {
|
||||
intersectLineIds.add(lineId);
|
||||
}
|
||||
}
|
||||
queryParam.setLineIds(intersectLineIds);
|
||||
return !intersectLineIds.isEmpty();
|
||||
}
|
||||
|
||||
private Page<EventListVO> emptyPage(EventListQueryParam queryParam) {
|
||||
Page<EventListVO> page = new Page<EventListVO>(PageFactory.getPageNum(queryParam), PageFactory.getPageSize(queryParam), 0);
|
||||
page.setRecords(Collections.<EventListVO>emptyList());
|
||||
return page;
|
||||
}
|
||||
|
||||
private LocalDateTime parseDateTime(String value) {
|
||||
String text = trimToNull(value);
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
for (DateTimeFormatter formatter : INPUT_FORMATTERS) {
|
||||
try {
|
||||
return LocalDateTime.parse(text, formatter);
|
||||
} catch (DateTimeParseException ignored) {
|
||||
// 尝试下一个前端可能传入的时间格式。
|
||||
}
|
||||
}
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "时间格式不正确,仅支持 yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
private List<String> normalizeIds(List<String> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> normalizedIds = new ArrayList<String>();
|
||||
for (String id : ids) {
|
||||
String normalizedId = trimToNull(id);
|
||||
if (normalizedId != null && !normalizedIds.contains(normalizedId)) {
|
||||
normalizedIds.add(normalizedId);
|
||||
}
|
||||
}
|
||||
return normalizedIds;
|
||||
}
|
||||
|
||||
private boolean hasLedgerKeyword(EventListQueryParam queryParam) {
|
||||
return trimToNull(queryParam.getEngineeringName()) != null
|
||||
|| trimToNull(queryParam.getProjectName()) != null
|
||||
|| trimToNull(queryParam.getEquipmentName()) != null
|
||||
|| trimToNull(queryParam.getLineName()) != null;
|
||||
}
|
||||
|
||||
private void validateRange(BigDecimal min, BigDecimal max, String message) {
|
||||
if (min != null && max != null && min.compareTo(max) > 0) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, message);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateFlag(Integer flag, String message) {
|
||||
if (flag != null && flag != 0 && flag != 1) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, message);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateDealFlag(Integer dealFlag) {
|
||||
if (dealFlag != null && (dealFlag < 0 || dealFlag > 3)) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "处理状态只能是 0、1、2、3");
|
||||
}
|
||||
}
|
||||
|
||||
private String defaultText(String value) {
|
||||
return defaultText(value, EMPTY_TEXT);
|
||||
}
|
||||
|
||||
private String defaultText(String value, String defaultValue) {
|
||||
String text = trimToNull(value);
|
||||
return text == null ? defaultValue : text;
|
||||
}
|
||||
|
||||
private String trimToNull(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.isEmpty() ? null : trimmed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
-- 暂态事件列表查询建议索引。
|
||||
-- 本脚本不自动执行,请按数据库现状审阅后单独执行。
|
||||
|
||||
CREATE INDEX idx_event_start_id
|
||||
ON r_mp_event_detail (start_time, event_id);
|
||||
|
||||
CREATE INDEX idx_event_mp_time_id
|
||||
ON r_mp_event_detail (measurement_point_id, start_time, event_id);
|
||||
|
||||
CREATE INDEX idx_event_type_time_id
|
||||
ON r_mp_event_detail (event_type, start_time, event_id);
|
||||
|
||||
CREATE INDEX idx_event_phase_time_id
|
||||
ON r_mp_event_detail (phase, start_time, event_id);
|
||||
25
event/pom.xml
Normal file
25
event/pom.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>CN_Tool</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>event</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>event-list</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
2
pom.xml
2
pom.xml
@@ -16,6 +16,8 @@
|
||||
<module>user</module>
|
||||
<module>detection</module>
|
||||
<module>tools</module>
|
||||
<module>event</module>
|
||||
<module>steady</module>
|
||||
</modules>
|
||||
|
||||
<distributionManagement>
|
||||
|
||||
24
steady/pom.xml
Normal file
24
steady/pom.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>CN_Tool</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>steady</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>steady-DataView</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</project>
|
||||
239
steady/steady-DataView/API_DEBUG.md
Normal file
239
steady/steady-DataView/API_DEBUG.md
Normal file
@@ -0,0 +1,239 @@
|
||||
# steady-DataView API 调试文档
|
||||
|
||||
## 1. 基础信息
|
||||
|
||||
- 模块:`steady/steady-DataView`
|
||||
- 控制器:`SteadyDataViewController`
|
||||
- 接口前缀:`/steady/data-view`
|
||||
- 本地默认地址:`http://localhost:18192`
|
||||
- Content-Type:`application/json`
|
||||
- 认证:除登录和 Swagger 资源外,请求需要携带登录后的 `Authorization` 头。
|
||||
|
||||
## 2. 分页查询稳态数据
|
||||
|
||||
- 路径:`POST /steady/data-view/page`
|
||||
- 返回:`HttpResult<Page<SteadyDataViewVO>>`
|
||||
- 默认表:`data_v`
|
||||
- 默认时间范围:当前月 1 日 `00:00:00` 到当前时间
|
||||
- 默认排序:`TIMEID DESC, LINEID ASC, PHASIC_TYPE ASC`
|
||||
|
||||
请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"pageNum": 1,
|
||||
"pageSize": 10,
|
||||
"tableName": "data_v",
|
||||
"timeStart": "2026-05-01 00:00:00",
|
||||
"timeEnd": "2026-05-09 23:59:59",
|
||||
"phasicType": "A",
|
||||
"qualityFlag": 1,
|
||||
"lineIds": [
|
||||
"line-001"
|
||||
],
|
||||
"engineeringName": "示例工程",
|
||||
"projectName": "示例项目",
|
||||
"equipmentName": "示例设备",
|
||||
"lineName": "示例测点"
|
||||
}
|
||||
```
|
||||
|
||||
`tableName` 只允许 `tools/add-data` 已注册的 13 张 `data_*` 表;台账关键字会先通过 `add-ledger` 转换为监测点 ID,再查询稳态数据表。
|
||||
|
||||
## 3. 查询稳态数据详情
|
||||
|
||||
- 路径:`POST /steady/data-view/detail`
|
||||
- 返回:`HttpResult<SteadyDataViewVO>`
|
||||
|
||||
请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"tableName": "data_v",
|
||||
"lineId": "line-001",
|
||||
"timeId": "2026-05-09 10:20:30",
|
||||
"phasicType": "A"
|
||||
}
|
||||
```
|
||||
|
||||
详情使用 `LINEID + TIMEID + PHASIC_TYPE` 定位单条数据。
|
||||
|
||||
## 4. 查询稳态数据模板
|
||||
|
||||
- 路径:`GET /steady/data-view/templates`
|
||||
- 返回:`HttpResult<List<SteadyDataViewTemplateVO>>`
|
||||
|
||||
模板来自 `tools/add-data` 的前端展示模板,返回参数名称、表名、相别和当前表可展示值字段。
|
||||
|
||||
## 5. 查询趋势台账树
|
||||
|
||||
- 路径:`GET /steady/data-view/ledger-tree`
|
||||
- 返回:`HttpResult<List<SteadyDataViewLedgerNodeVO>>`
|
||||
- 查询参数:`keyword`,可选,按台账节点名称搜索并保留父级路径。
|
||||
|
||||
节点字段:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `id` | 台账节点 ID |
|
||||
| `parentId` | 父节点 ID |
|
||||
| `name` | 节点名称 |
|
||||
| `level` | 层级:0 工程,1 项目,2 设备,3 监测点 |
|
||||
| `deviceCount` | 当前节点下有效设备数 |
|
||||
| `lineCount` | 当前节点下有效监测点数 |
|
||||
| `selectable` | 是否可直接选择 |
|
||||
| `children` | 子节点 |
|
||||
|
||||
## 6. 查询趋势指标树
|
||||
|
||||
- 路径:`GET /steady/data-view/indicator-tree`
|
||||
- 返回:`HttpResult<List<SteadyDataViewIndicatorNodeVO>>`
|
||||
|
||||
当前指标目录覆盖:
|
||||
|
||||
- 电压趋势:`V_RMS`、`V_LINE_RMS`
|
||||
- 电流趋势:`I_RMS`
|
||||
- 频率趋势:`FREQ`
|
||||
- 谐波趋势:`V_THD`、`I_THD`、`V_HARMONIC`、`I_HARMONIC`、`V_HARMONIC_RATE`、`I_HARMONIC_RATE`、`I_INTER_HARMONIC`、`P_HARMONIC_POWER`、`Q_HARMONIC_POWER`、`S_HARMONIC_POWER`
|
||||
- 闪变趋势:`FLUC`、`PST`、`PLT`
|
||||
|
||||
叶子节点会返回 `tableName`、`phaseCodes`、`seriesFields`、`supportStats`、`harmonicOrderStart`、`harmonicOrderEnd`、`unit`,前端按这些字段驱动相别、统计类型和谐波次数选择。
|
||||
|
||||
## 7. 查询趋势数据
|
||||
|
||||
- 路径:`POST /steady/data-view/trend/query`
|
||||
- 返回:`HttpResult<SteadyTrendQueryVO>`
|
||||
|
||||
请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"lineIds": ["line-001"],
|
||||
"indicatorCodes": ["V_RMS"],
|
||||
"statTypes": ["AVG", "MAX", "MIN", "CP95"],
|
||||
"phases": ["A", "B", "C"],
|
||||
"timeStart": "2026-05-01 00:00:00",
|
||||
"timeEnd": "2026-05-01 23:59:59",
|
||||
"bucket": "10m",
|
||||
"qualityFlag": 1
|
||||
}
|
||||
```
|
||||
|
||||
返回示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"sampled": true,
|
||||
"bucket": "10m",
|
||||
"sourcePointCount": 144,
|
||||
"displayPointCount": 144,
|
||||
"loadableDays": ["2026-05-01"],
|
||||
"series": [
|
||||
{
|
||||
"seriesKey": "line-001|V_RMS|A|AVG|RMS",
|
||||
"lineId": "line-001",
|
||||
"lineName": "进线一",
|
||||
"indicatorCode": "V_RMS",
|
||||
"indicatorName": "相电压有效值",
|
||||
"seriesName": "相电压有效值",
|
||||
"phase": "A",
|
||||
"statType": "AVG",
|
||||
"unit": "V",
|
||||
"points": [
|
||||
{
|
||||
"time": "2026-05-01 00:00:00",
|
||||
"value": 220.1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
谐波请求必须指定 `harmonicOrders`,最多 6 个:
|
||||
|
||||
```json
|
||||
{
|
||||
"lineIds": ["line-001"],
|
||||
"indicatorCodes": ["V_HARMONIC"],
|
||||
"statTypes": ["MAX"],
|
||||
"phases": ["A"],
|
||||
"harmonicOrders": [3, 5, 7],
|
||||
"timeStart": "2026-05-01 00:00:00",
|
||||
"timeEnd": "2026-05-01 23:59:59",
|
||||
"bucket": "10m",
|
||||
"qualityFlag": 1
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 按天查询趋势数据
|
||||
|
||||
- 路径:`POST /steady/data-view/trend/day`
|
||||
- 返回:`HttpResult<SteadyTrendQueryVO>`
|
||||
|
||||
请求体与 `/trend/query` 一致。前端切换日期或加载某一天数据时,将 `timeStart`、`timeEnd` 控制在当天范围即可。
|
||||
|
||||
## 9. 查询趋势统计摘要
|
||||
|
||||
- 路径:`POST /steady/data-view/trend/summary`
|
||||
- 返回:`HttpResult<SteadyTrendSummaryVO>`
|
||||
|
||||
请求体与 `/trend/query` 一致。后端按当前查询范围返回每条曲线的 `max`、`avg`、`min`、`cp95`。
|
||||
|
||||
## 10. InfluxDB 配置
|
||||
|
||||
配置项前缀:`steady.influxdb`。
|
||||
|
||||
```yaml
|
||||
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
|
||||
```
|
||||
|
||||
接口按 InfluxDB 1.x InfluxQL `/query` 方式访问。代码不会提交明文密码;本地密码请通过环境变量或本地覆盖配置提供。
|
||||
|
||||
## 11. 返回字段说明
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `tableName` | 数据表名 |
|
||||
| `lineId` | 监测点 ID |
|
||||
| `timeId` | 数据时间 |
|
||||
| `phasicType` | 相别 |
|
||||
| `qualityFlag` | 质量标识 |
|
||||
| `equipmentName` | 设备名称,台账缺失时为 `-` |
|
||||
| `engineeringName` | 工程名称,台账缺失时为 `-` |
|
||||
| `projectName` | 项目名称,台账缺失时为 `-` |
|
||||
| `lineName` | 监测点名称,台账缺失时为 `-` |
|
||||
| `values` | 动态指标字段,字段名与目标 `data_*` 表保持一致 |
|
||||
|
||||
## 12. 常见错误场景
|
||||
|
||||
| 场景 | 后端提示 |
|
||||
| --- | --- |
|
||||
| 表名不在 add-data 注册表范围内 | `稳态数据表不支持:xxx` |
|
||||
| 开始时间大于结束时间 | `开始时间不能大于结束时间` |
|
||||
| 时间格式无法解析 | `时间格式不正确,仅支持 yyyy-MM-dd HH:mm:ss` |
|
||||
| 相别不为 `A/B/C/T` | `相别只能是 A、B、C、T` |
|
||||
| 质量标识不为 `0/1` | `质量标识只能是 0 或 1` |
|
||||
| `lineIds` 超过 1000 个 | `监测点 ID 查询数量不能超过 1000 个` |
|
||||
| 台账关键字匹配监测点超过 1000 个 | `台账检索匹配监测点过多,请缩小查询条件` |
|
||||
| 趋势监测点为空 | `监测点 ID 不能为空` |
|
||||
| 趋势指标为空 | `指标不能为空` |
|
||||
| 多监测点同时多指标查询 | `多监测点查询时只能选择 1 个指标` |
|
||||
| 趋势曲线超过 24 条 | `趋势曲线数量不能超过 24 条,请缩小监测点、指标、相别或统计类型范围` |
|
||||
| 谐波指标未传次数 | `谐波次数不能为空` |
|
||||
| 谐波次数超过 6 个 | `谐波次数最多选择 6 个` |
|
||||
| InfluxDB 未配置地址 | `InfluxDB 地址未配置` |
|
||||
|
||||
## 13. 当前限制
|
||||
|
||||
- 当前仅提供分页、详情和模板查询,未提供动态 Excel 导出。
|
||||
- 趋势接口已提供后端结构和 InfluxQL 查询封装,未做真实 InfluxDB 联调。
|
||||
- `sourcePointCount` 当前与实际返回点数一致,未额外发 InfluxDB `count` 查询。
|
||||
51
steady/steady-DataView/pom.xml
Normal file
51
steady/steady-DataView/pom.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>steady</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>steady-DataView</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>njcn-common</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>mybatis-plus</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>spingboot2.3.12</artifactId>
|
||||
<version>2.3.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>add-ledger</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>add-data</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.njcn.gather.steady.datavie.component;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.gather.steady.datavie.config.SteadyInfluxDbProperties;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendPointVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势 InfluxDB 查询组件。
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SteadyInfluxQueryComponent {
|
||||
|
||||
private static final DateTimeFormatter INFLUX_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
private static final DateTimeFormatter OUTPUT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private final SteadyInfluxDbProperties properties;
|
||||
|
||||
public List<SteadyTrendPointVO> queryTrendPoints(SteadyTrendResolvedFieldBO field, LocalDateTime startTime,
|
||||
LocalDateTime endTime, String bucket, Integer qualityFlag) {
|
||||
validateConfig();
|
||||
String query = buildTrendQuery(field, startTime, endTime, bucket, qualityFlag);
|
||||
String body = executeQuery(query);
|
||||
return parseTrendPoints(body);
|
||||
}
|
||||
|
||||
public String buildTrendQuery(SteadyTrendResolvedFieldBO field, LocalDateTime startTime, LocalDateTime endTime,
|
||||
String bucket, Integer qualityFlag) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
if (bucket == null || bucket.trim().isEmpty()) {
|
||||
sql.append("SELECT \"").append(field.getField()).append("\" AS \"value\"");
|
||||
} else {
|
||||
sql.append("SELECT mean(\"").append(field.getField()).append("\") AS \"value\"");
|
||||
}
|
||||
sql.append(" FROM \"").append(field.getMeasurement()).append("\"");
|
||||
sql.append(" WHERE time >= '").append(INFLUX_TIME_FORMATTER.format(startTime)).append("'");
|
||||
sql.append(" AND time <= '").append(INFLUX_TIME_FORMATTER.format(endTime)).append("'");
|
||||
sql.append(" AND \"LINEID\" = '").append(escapeTagValue(field.getLineId())).append("'");
|
||||
sql.append(" AND \"PHASIC_TYPE\" = '").append(escapeTagValue(field.getPhase())).append("'");
|
||||
if (qualityFlag != null) {
|
||||
sql.append(" AND \"QUALITYFLAG\" = '").append(qualityFlag).append("'");
|
||||
}
|
||||
if (bucket != null && !bucket.trim().isEmpty()) {
|
||||
sql.append(" GROUP BY time(").append(bucket.trim()).append(") fill(none)");
|
||||
} else {
|
||||
sql.append(" ORDER BY time ASC");
|
||||
}
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
private String executeQuery(String query) {
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
URL url = new URL(buildQueryUrl(query));
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setConnectTimeout(properties.getConnectTimeoutMs());
|
||||
connection.setReadTimeout(properties.getReadTimeoutMs());
|
||||
int status = connection.getResponseCode();
|
||||
InputStream stream = status >= 200 && status < 300 ? connection.getInputStream() : connection.getErrorStream();
|
||||
String body = readBody(stream);
|
||||
if (status < 200 || status >= 300) {
|
||||
throw fail("InfluxDB 查询失败:" + body);
|
||||
}
|
||||
return body;
|
||||
} catch (IOException ex) {
|
||||
throw fail("InfluxDB 查询异常:" + ex.getMessage());
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String buildQueryUrl(String query) throws IOException {
|
||||
StringBuilder url = new StringBuilder(trimRightSlash(properties.getUrl())).append("/query?");
|
||||
url.append("db=").append(encode(properties.getDatabase()));
|
||||
if (properties.getUsername() != null && !properties.getUsername().trim().isEmpty()) {
|
||||
url.append("&u=").append(encode(properties.getUsername().trim()));
|
||||
}
|
||||
if (properties.getPassword() != null && !properties.getPassword().trim().isEmpty()) {
|
||||
url.append("&p=").append(encode(properties.getPassword()));
|
||||
}
|
||||
url.append("&q=").append(encode(query));
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
private List<SteadyTrendPointVO> parseTrendPoints(String body) {
|
||||
try {
|
||||
JsonNode root = OBJECT_MAPPER.readTree(body);
|
||||
JsonNode series = root.path("results").path(0).path("series").path(0);
|
||||
JsonNode values = series.path("values");
|
||||
if (!values.isArray()) {
|
||||
return new ArrayList<SteadyTrendPointVO>();
|
||||
}
|
||||
List<SteadyTrendPointVO> result = new ArrayList<SteadyTrendPointVO>();
|
||||
for (JsonNode value : values) {
|
||||
if (value.size() < 2 || value.get(1).isNull()) {
|
||||
continue;
|
||||
}
|
||||
String time = formatInfluxTime(value.get(0).asText());
|
||||
BigDecimal pointValue = value.get(1).decimalValue();
|
||||
result.add(new SteadyTrendPointVO(time, pointValue));
|
||||
}
|
||||
return result;
|
||||
} catch (IOException ex) {
|
||||
throw fail("InfluxDB 返回结果解析失败:" + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String formatInfluxTime(String value) {
|
||||
try {
|
||||
return OUTPUT_TIME_FORMATTER.format(OffsetDateTime.parse(value).withOffsetSameInstant(ZoneOffset.UTC).toLocalDateTime());
|
||||
} catch (RuntimeException ex) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateConfig() {
|
||||
if (properties.getUrl() == null || properties.getUrl().trim().isEmpty()) {
|
||||
throw fail("InfluxDB 地址未配置");
|
||||
}
|
||||
if (properties.getDatabase() == null || properties.getDatabase().trim().isEmpty()) {
|
||||
throw fail("InfluxDB database 未配置");
|
||||
}
|
||||
}
|
||||
|
||||
private String readBody(InputStream stream) throws IOException {
|
||||
if (stream == null) {
|
||||
return "";
|
||||
}
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8));
|
||||
StringBuilder body = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
body.append(line);
|
||||
}
|
||||
return body.toString();
|
||||
}
|
||||
|
||||
private String escapeTagValue(String value) {
|
||||
return value == null ? "" : value.replace("\\", "\\\\").replace("'", "\\'");
|
||||
}
|
||||
|
||||
private String trimRightSlash(String value) {
|
||||
String text = value.trim();
|
||||
while (text.endsWith("/")) {
|
||||
text = text.substring(0, text.length() - 1);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private String encode(String value) throws IOException {
|
||||
return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
|
||||
}
|
||||
|
||||
private BusinessException fail(String message) {
|
||||
return new BusinessException(CommonResponseEnum.FAIL, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
package com.njcn.gather.steady.datavie.component;
|
||||
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendIndicatorDefinitionBO;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendSeriesFieldBO;
|
||||
import com.njcn.gather.steady.datavie.pojo.param.SteadyTrendQueryParam;
|
||||
import com.njcn.gather.tool.adddata.component.AddDataTableRegistry;
|
||||
import com.njcn.gather.tool.adddata.pojo.bo.AddDataTableDefinition;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
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.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势字段白名单解析器。
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SteadyTrendFieldResolver {
|
||||
|
||||
private static final int MAX_LINE_COUNT = 8;
|
||||
private static final int MAX_INDICATOR_COUNT = 8;
|
||||
private static final int MAX_SERIES_COUNT = 24;
|
||||
private static final int MAX_HARMONIC_ORDER_COUNT = 6;
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private final SteadyTrendIndicatorCatalog indicatorCatalog;
|
||||
private final AddDataTableRegistry addDataTableRegistry;
|
||||
|
||||
public List<SteadyTrendResolvedFieldBO> resolveFields(SteadyTrendQueryParam param) {
|
||||
validateBasicParam(param);
|
||||
List<String> lineIds = normalizeTextList(param.getLineIds());
|
||||
List<String> indicatorCodes = normalizeTextList(param.getIndicatorCodes());
|
||||
List<String> requestPhases = normalizeUpperList(param.getPhases());
|
||||
List<String> statTypes = normalizeUpperList(param.getStatTypes());
|
||||
if (statTypes.isEmpty()) {
|
||||
statTypes.add("AVG");
|
||||
}
|
||||
List<SteadyTrendResolvedFieldBO> result = new ArrayList<SteadyTrendResolvedFieldBO>();
|
||||
for (String lineId : lineIds) {
|
||||
for (String indicatorCode : indicatorCodes) {
|
||||
SteadyTrendIndicatorDefinitionBO indicator = requireIndicator(indicatorCode);
|
||||
List<String> phases = resolvePhases(indicator, requestPhases);
|
||||
for (String phase : phases) {
|
||||
for (String statType : statTypes) {
|
||||
validateStatType(indicator, statType);
|
||||
result.addAll(resolveIndicatorFields(lineId, indicator, phase, statType, param.getHarmonicOrders()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.size() > MAX_SERIES_COUNT) {
|
||||
throw fail("趋势曲线数量不能超过 24 条,请缩小监测点、指标、相别或统计类型范围");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public LocalDateTime parseRequiredTime(String time, String emptyMessage) {
|
||||
String text = trimToNull(time);
|
||||
if (text == null) {
|
||||
throw fail(emptyMessage);
|
||||
}
|
||||
try {
|
||||
return LocalDateTime.parse(text, TIME_FORMATTER);
|
||||
} catch (DateTimeParseException ex) {
|
||||
throw fail("时间格式不正确,仅支持 yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
}
|
||||
|
||||
private List<SteadyTrendResolvedFieldBO> resolveIndicatorFields(String lineId, SteadyTrendIndicatorDefinitionBO indicator,
|
||||
String phase, String statType, List<Integer> harmonicOrders) {
|
||||
if (Boolean.TRUE.equals(indicator.getHarmonic())) {
|
||||
return resolveHarmonicFields(lineId, indicator, phase, statType, harmonicOrders);
|
||||
}
|
||||
List<SteadyTrendResolvedFieldBO> result = new ArrayList<SteadyTrendResolvedFieldBO>();
|
||||
for (SteadyTrendSeriesFieldBO seriesField : indicator.getSeriesFields()) {
|
||||
String field = resolveStatField(seriesField.getField(), statType);
|
||||
validateColumn(indicator.getTableName(), field);
|
||||
result.add(buildResolvedField(lineId, indicator, phase, statType, field, seriesField.getName()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<SteadyTrendResolvedFieldBO> resolveHarmonicFields(String lineId, SteadyTrendIndicatorDefinitionBO indicator,
|
||||
String phase, String statType, List<Integer> harmonicOrders) {
|
||||
List<Integer> orders = normalizeOrders(harmonicOrders);
|
||||
if (orders.isEmpty()) {
|
||||
throw fail("谐波次数不能为空");
|
||||
}
|
||||
if (orders.size() > MAX_HARMONIC_ORDER_COUNT) {
|
||||
throw fail("谐波次数最多选择 6 个");
|
||||
}
|
||||
List<SteadyTrendResolvedFieldBO> result = new ArrayList<SteadyTrendResolvedFieldBO>();
|
||||
for (Integer order : orders) {
|
||||
if (order < indicator.getHarmonicOrderStart() || order > indicator.getHarmonicOrderEnd()) {
|
||||
throw fail("谐波次数只能在 " + indicator.getHarmonicOrderStart() + " 到 " + indicator.getHarmonicOrderEnd() + " 之间");
|
||||
}
|
||||
String baseField = indicator.getHarmonicFieldPrefix() + "_" + order;
|
||||
String field = resolveStatField(baseField, statType);
|
||||
validateColumn(indicator.getTableName(), field);
|
||||
result.add(buildResolvedField(lineId, indicator, phase, statType, field, order + "次" + indicator.getName()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private SteadyTrendResolvedFieldBO buildResolvedField(String lineId, SteadyTrendIndicatorDefinitionBO indicator,
|
||||
String phase, String statType, String field, String seriesName) {
|
||||
SteadyTrendResolvedFieldBO resolved = new SteadyTrendResolvedFieldBO();
|
||||
resolved.setMeasurement(indicator.getTableName());
|
||||
resolved.setField(field);
|
||||
resolved.setLineId(lineId);
|
||||
resolved.setIndicatorCode(indicator.getIndicatorCode());
|
||||
resolved.setIndicatorName(indicator.getName());
|
||||
resolved.setSeriesName(seriesName);
|
||||
resolved.setPhase(phase);
|
||||
resolved.setStatType(statType);
|
||||
resolved.setUnit(indicator.getUnit());
|
||||
resolved.setSeriesKey(lineId + "|" + indicator.getIndicatorCode() + "|" + phase + "|" + statType + "|" + field);
|
||||
return resolved;
|
||||
}
|
||||
|
||||
private void validateBasicParam(SteadyTrendQueryParam param) {
|
||||
if (param == null) {
|
||||
throw fail("趋势查询参数不能为空");
|
||||
}
|
||||
List<String> lineIds = normalizeTextList(param.getLineIds());
|
||||
List<String> indicatorCodes = normalizeTextList(param.getIndicatorCodes());
|
||||
if (lineIds.isEmpty()) {
|
||||
throw fail("监测点 ID 不能为空");
|
||||
}
|
||||
if (indicatorCodes.isEmpty()) {
|
||||
throw fail("指标不能为空");
|
||||
}
|
||||
if (lineIds.size() > MAX_LINE_COUNT) {
|
||||
throw fail("监测点数量不能超过 8 个");
|
||||
}
|
||||
if (indicatorCodes.size() > MAX_INDICATOR_COUNT) {
|
||||
throw fail("指标数量不能超过 8 个");
|
||||
}
|
||||
if (lineIds.size() > 1 && indicatorCodes.size() > 1) {
|
||||
throw fail("多监测点查询时只能选择 1 个指标");
|
||||
}
|
||||
LocalDateTime startTime = parseRequiredTime(param.getTimeStart(), "开始时间不能为空");
|
||||
LocalDateTime endTime = parseRequiredTime(param.getTimeEnd(), "结束时间不能为空");
|
||||
if (startTime.isAfter(endTime)) {
|
||||
throw fail("开始时间不能大于结束时间");
|
||||
}
|
||||
if (param.getQualityFlag() != null && param.getQualityFlag() != 0 && param.getQualityFlag() != 1) {
|
||||
throw fail("质量标识只能是 0 或 1");
|
||||
}
|
||||
}
|
||||
|
||||
private SteadyTrendIndicatorDefinitionBO requireIndicator(String indicatorCode) {
|
||||
SteadyTrendIndicatorDefinitionBO indicator = indicatorCatalog.getIndicator(indicatorCode);
|
||||
if (indicator == null) {
|
||||
throw fail("稳态趋势指标不支持:" + indicatorCode);
|
||||
}
|
||||
return indicator;
|
||||
}
|
||||
|
||||
private List<String> resolvePhases(SteadyTrendIndicatorDefinitionBO indicator, List<String> requestPhases) {
|
||||
if (requestPhases.isEmpty()) {
|
||||
return new ArrayList<String>(indicator.getPhaseCodes());
|
||||
}
|
||||
List<String> result = new ArrayList<String>();
|
||||
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 void validateStatType(SteadyTrendIndicatorDefinitionBO indicator, String statType) {
|
||||
if (!"AVG".equals(statType) && !"MAX".equals(statType) && !"MIN".equals(statType) && !"CP95".equals(statType)) {
|
||||
throw fail("统计类型只能是 AVG、MAX、MIN、CP95");
|
||||
}
|
||||
if (!indicator.getSupportStats().contains(statType)) {
|
||||
throw fail("指标 " + indicator.getIndicatorCode() + " 不支持统计类型:" + statType);
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveStatField(String baseField, String statType) {
|
||||
if ("AVG".equals(statType)) {
|
||||
return baseField;
|
||||
}
|
||||
return baseField + "_" + statType;
|
||||
}
|
||||
|
||||
private void validateColumn(String tableName, String field) {
|
||||
AddDataTableDefinition definition;
|
||||
try {
|
||||
definition = addDataTableRegistry.getDefinition(tableName);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw fail("稳态数据表不支持:" + tableName);
|
||||
}
|
||||
if (!definition.getColumns().contains(field)) {
|
||||
throw fail("稳态趋势字段不支持:" + tableName + "." + field);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> normalizeTextList(List<String> values) {
|
||||
if (values == null || values.isEmpty()) {
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (String value : values) {
|
||||
String text = trimToNull(value);
|
||||
if (text != null && !result.contains(text)) {
|
||||
result.add(text);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<String> normalizeUpperList(List<String> values) {
|
||||
List<String> result = normalizeTextList(values);
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
result.set(i, result.get(i).toUpperCase());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Integer> normalizeOrders(List<Integer> orders) {
|
||||
if (orders == null || orders.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Integer> result = new ArrayList<Integer>();
|
||||
for (Integer order : orders) {
|
||||
if (order != null && !result.contains(order)) {
|
||||
result.add(order);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String trimToNull(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.isEmpty() ? null : trimmed;
|
||||
}
|
||||
|
||||
private BusinessException fail(String message) {
|
||||
return new BusinessException(CommonResponseEnum.FAIL, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.njcn.gather.steady.datavie.component;
|
||||
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendIndicatorDefinitionBO;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendSeriesFieldBO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 稳态趋势指标目录。
|
||||
*/
|
||||
@Component
|
||||
public class SteadyTrendIndicatorCatalog {
|
||||
|
||||
private static final List<String> FULL_STATS = Collections.unmodifiableList(Arrays.asList("AVG", "MAX", "MIN", "CP95"));
|
||||
private static final List<String> AVG_ONLY = Collections.unmodifiableList(Collections.singletonList("AVG"));
|
||||
private static final List<String> ABC_PHASES = Collections.unmodifiableList(Arrays.asList("A", "B", "C"));
|
||||
private static final List<String> T_PHASE = Collections.unmodifiableList(Collections.singletonList("T"));
|
||||
|
||||
private final List<SteadyTrendIndicatorDefinitionBO> indicators;
|
||||
private final Map<String, SteadyTrendIndicatorDefinitionBO> indicatorMap;
|
||||
|
||||
public SteadyTrendIndicatorCatalog() {
|
||||
List<SteadyTrendIndicatorDefinitionBO> result = new ArrayList<SteadyTrendIndicatorDefinitionBO>();
|
||||
result.add(indicator("V_RMS", "相电压有效值", "VOLTAGE", "电压趋势", "data_v", ABC_PHASES,
|
||||
fields(field("RMS", "相电压有效值")), FULL_STATS, "V"));
|
||||
result.add(indicator("V_LINE_RMS", "线电压有效值", "VOLTAGE", "电压趋势", "data_v", T_PHASE,
|
||||
fields(field("RMSAB", "AB线电压"), field("RMSBC", "BC线电压"), field("RMSCA", "CA线电压")),
|
||||
FULL_STATS, "V"));
|
||||
result.add(indicator("FREQ", "频率", "FREQUENCY", "频率趋势", "data_v", T_PHASE,
|
||||
fields(field("FREQ", "频率")), FULL_STATS, "Hz"));
|
||||
result.add(indicator("V_THD", "电压总谐波畸变率", "HARMONIC", "谐波趋势", "data_v", ABC_PHASES,
|
||||
fields(field("V_THD", "电压总谐波畸变率")), FULL_STATS, "%"));
|
||||
result.add(indicator("I_RMS", "电流有效值", "CURRENT", "电流趋势", "data_i", ABC_PHASES,
|
||||
fields(field("RMS", "电流有效值")), FULL_STATS, "A"));
|
||||
result.add(indicator("I_THD", "电流总谐波畸变率", "HARMONIC", "谐波趋势", "data_i", ABC_PHASES,
|
||||
fields(field("I_THD", "电流总谐波畸变率")), FULL_STATS, "%"));
|
||||
result.add(harmonic("V_HARMONIC", "电压谐波幅值", "data_harmphasic_v", "V", "V"));
|
||||
result.add(harmonic("I_HARMONIC", "电流谐波幅值", "data_harmphasic_i", "I", "A"));
|
||||
result.add(harmonic("V_HARMONIC_RATE", "电压谐波含有率", "data_harmrate_v", "V", "%"));
|
||||
result.add(harmonic("I_HARMONIC_RATE", "电流谐波含有率", "data_harmrate_i", "I", "%"));
|
||||
result.add(harmonic("I_INTER_HARMONIC", "间谐波电流", "data_inharm_i", "I", "A"));
|
||||
result.add(harmonicPower("P_HARMONIC_POWER", "有功谐波功率", "data_harmpower_p", "P", "kW"));
|
||||
result.add(harmonicPower("Q_HARMONIC_POWER", "无功谐波功率", "data_harmpower_q", "Q", "kvar"));
|
||||
result.add(harmonicPower("S_HARMONIC_POWER", "视在谐波功率", "data_harmpower_s", "S", "kVA"));
|
||||
result.add(indicator("FLUC", "电压波动", "FLICKER", "闪变趋势", "data_fluc", T_PHASE,
|
||||
fields(field("FLUC", "电压波动")), AVG_ONLY, "%"));
|
||||
result.add(indicator("PST", "短时闪变", "FLICKER", "闪变趋势", "data_flicker", T_PHASE,
|
||||
fields(field("PST", "短时闪变")), AVG_ONLY, ""));
|
||||
result.add(indicator("PLT", "长时闪变", "FLICKER", "闪变趋势", "data_plt", T_PHASE,
|
||||
fields(field("PLT", "长时闪变")), AVG_ONLY, ""));
|
||||
indicators = Collections.unmodifiableList(result);
|
||||
|
||||
Map<String, SteadyTrendIndicatorDefinitionBO> map = new LinkedHashMap<String, SteadyTrendIndicatorDefinitionBO>();
|
||||
for (SteadyTrendIndicatorDefinitionBO indicator : indicators) {
|
||||
map.put(indicator.getIndicatorCode(), indicator);
|
||||
}
|
||||
indicatorMap = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
public List<SteadyTrendIndicatorDefinitionBO> listIndicators() {
|
||||
return indicators;
|
||||
}
|
||||
|
||||
public SteadyTrendIndicatorDefinitionBO getIndicator(String indicatorCode) {
|
||||
return indicatorMap.get(indicatorCode);
|
||||
}
|
||||
|
||||
private SteadyTrendIndicatorDefinitionBO harmonic(String code, String name, String tableName, String prefix, String unit) {
|
||||
SteadyTrendIndicatorDefinitionBO indicator = indicator(code, name, "HARMONIC", "谐波趋势", tableName, ABC_PHASES,
|
||||
new ArrayList<SteadyTrendSeriesFieldBO>(), FULL_STATS, unit);
|
||||
indicator.setHarmonic(true);
|
||||
indicator.setHarmonicFieldPrefix(prefix);
|
||||
indicator.setHarmonicOrderStart(2);
|
||||
indicator.setHarmonicOrderEnd(50);
|
||||
return indicator;
|
||||
}
|
||||
|
||||
private SteadyTrendIndicatorDefinitionBO harmonicPower(String code, String name, String tableName, String prefix, String unit) {
|
||||
return harmonic(code, name, tableName, prefix, unit);
|
||||
}
|
||||
|
||||
private SteadyTrendIndicatorDefinitionBO indicator(String code, String name, String groupCode, String groupName,
|
||||
String tableName, List<String> phaseCodes,
|
||||
List<SteadyTrendSeriesFieldBO> seriesFields,
|
||||
List<String> supportStats, String unit) {
|
||||
SteadyTrendIndicatorDefinitionBO indicator = new SteadyTrendIndicatorDefinitionBO();
|
||||
indicator.setIndicatorCode(code);
|
||||
indicator.setName(name);
|
||||
indicator.setGroupCode(groupCode);
|
||||
indicator.setGroupName(groupName);
|
||||
indicator.setTableName(tableName);
|
||||
indicator.setPhaseCodes(new ArrayList<String>(phaseCodes));
|
||||
indicator.setSeriesFields(new ArrayList<SteadyTrendSeriesFieldBO>(seriesFields));
|
||||
indicator.setSupportStats(new ArrayList<String>(supportStats));
|
||||
indicator.setUnit(unit);
|
||||
return indicator;
|
||||
}
|
||||
|
||||
private List<SteadyTrendSeriesFieldBO> fields(SteadyTrendSeriesFieldBO... fields) {
|
||||
return new ArrayList<SteadyTrendSeriesFieldBO>(Arrays.asList(fields));
|
||||
}
|
||||
|
||||
private SteadyTrendSeriesFieldBO field(String field, String name) {
|
||||
return new SteadyTrendSeriesFieldBO(field, name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.njcn.gather.steady.datavie.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 稳态趋势 InfluxDB 配置。
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "steady.influxdb")
|
||||
public class SteadyInfluxDbProperties {
|
||||
|
||||
private String url;
|
||||
|
||||
private String database;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private Boolean ssl = false;
|
||||
|
||||
private Integer connectTimeoutMs = 5000;
|
||||
|
||||
private Integer readTimeoutMs = 30000;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.gather.steady.datavie.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 稳态数据时间字段按秒输出,避免接口响应携带毫秒。
|
||||
*/
|
||||
public class SteadySecondTimeSerializer extends JsonSerializer<LocalDateTime> {
|
||||
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
if (value == null) {
|
||||
gen.writeNull();
|
||||
return;
|
||||
}
|
||||
gen.writeString(FORMATTER.format(value));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
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;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
import com.njcn.web.utils.HttpResultUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态数据查看接口。
|
||||
*/
|
||||
@Validated
|
||||
@Slf4j
|
||||
@Api(tags = "稳态数据查看")
|
||||
@RestController
|
||||
@RequestMapping("/steady/data-view")
|
||||
@RequiredArgsConstructor
|
||||
public class SteadyDataViewController extends BaseController {
|
||||
|
||||
/** 稳态数据查看服务。 */
|
||||
private final SteadyDataViewService steadyDataViewService;
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("分页查询稳态数据")
|
||||
@PostMapping("/page")
|
||||
public HttpResult<Page<SteadyDataViewVO>> pageSteadyData(@RequestBody SteadyDataViewQueryParam param) {
|
||||
String methodDescribe = getMethodDescribe("pageSteadyData");
|
||||
LogUtil.njcnDebug(log, "{},开始分页查询稳态数据,param={}", methodDescribe, param);
|
||||
Page<SteadyDataViewVO> result = steadyDataViewService.pageSteadyData(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询稳态数据详情")
|
||||
@PostMapping("/detail")
|
||||
public HttpResult<SteadyDataViewVO> getSteadyDataDetail(@RequestBody SteadyDataViewDetailParam param) {
|
||||
String methodDescribe = getMethodDescribe("getSteadyDataDetail");
|
||||
LogUtil.njcnDebug(log, "{},开始查询稳态数据详情,param={}", methodDescribe, param);
|
||||
SteadyDataViewVO result = steadyDataViewService.getSteadyDataDetail(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询稳态数据模板")
|
||||
@GetMapping("/templates")
|
||||
public HttpResult<List<SteadyDataViewTemplateVO>> listTemplates() {
|
||||
String methodDescribe = getMethodDescribe("listTemplates");
|
||||
LogUtil.njcnDebug(log, "{},开始查询稳态数据模板", methodDescribe);
|
||||
List<SteadyDataViewTemplateVO> result = steadyDataViewService.listTemplates();
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.njcn.gather.steady.datavie.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.steady.datavie.pojo.vo.SteadyDataViewIndicatorNodeVO;
|
||||
import com.njcn.gather.steady.datavie.service.SteadyDataViewIndicatorService;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
import com.njcn.web.utils.HttpResultUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势指标接口。
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "稳态趋势指标")
|
||||
@RestController
|
||||
@RequestMapping("/steady/data-view")
|
||||
@RequiredArgsConstructor
|
||||
public class SteadyDataViewIndicatorController extends BaseController {
|
||||
|
||||
private final SteadyDataViewIndicatorService indicatorService;
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询稳态趋势指标树")
|
||||
@GetMapping("/indicator-tree")
|
||||
public HttpResult<List<SteadyDataViewIndicatorNodeVO>> listIndicatorTree() {
|
||||
String methodDescribe = getMethodDescribe("listIndicatorTree");
|
||||
LogUtil.njcnDebug(log, "{},开始查询稳态趋势指标树", methodDescribe);
|
||||
List<SteadyDataViewIndicatorNodeVO> result = indicatorService.listIndicatorTree();
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.njcn.gather.steady.datavie.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.steady.datavie.pojo.vo.SteadyDataViewLedgerNodeVO;
|
||||
import com.njcn.gather.steady.datavie.service.SteadyDataViewLedgerService;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
import com.njcn.web.utils.HttpResultUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势台账树接口。
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "稳态趋势台账树")
|
||||
@RestController
|
||||
@RequestMapping("/steady/data-view")
|
||||
@RequiredArgsConstructor
|
||||
public class SteadyDataViewLedgerController extends BaseController {
|
||||
|
||||
private final SteadyDataViewLedgerService ledgerService;
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询稳态趋势台账树")
|
||||
@GetMapping("/ledger-tree")
|
||||
public HttpResult<List<SteadyDataViewLedgerNodeVO>> listLedgerTree(@RequestParam(value = "keyword", required = false) String keyword) {
|
||||
String methodDescribe = getMethodDescribe("listLedgerTree");
|
||||
LogUtil.njcnDebug(log, "{},开始查询稳态趋势台账树,keyword={}", methodDescribe, keyword);
|
||||
List<SteadyDataViewLedgerNodeVO> result = ledgerService.listLedgerTree(keyword);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.njcn.gather.steady.datavie.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.steady.datavie.pojo.param.SteadyTrendQueryParam;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendQueryVO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendSummaryVO;
|
||||
import com.njcn.gather.steady.datavie.service.SteadyDataViewTrendService;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
import com.njcn.web.utils.HttpResultUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
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("/steady/data-view/trend")
|
||||
@RequiredArgsConstructor
|
||||
public class SteadyDataViewTrendController extends BaseController {
|
||||
|
||||
private final SteadyDataViewTrendService trendService;
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询稳态趋势")
|
||||
@PostMapping("/query")
|
||||
public HttpResult<SteadyTrendQueryVO> queryTrend(@RequestBody SteadyTrendQueryParam param) {
|
||||
String methodDescribe = getMethodDescribe("queryTrend");
|
||||
LogUtil.njcnDebug(log, "{},开始查询稳态趋势,param={}", methodDescribe, param);
|
||||
SteadyTrendQueryVO result = trendService.queryTrend(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("按天查询稳态趋势")
|
||||
@PostMapping("/day")
|
||||
public HttpResult<SteadyTrendQueryVO> queryTrendDay(@RequestBody SteadyTrendQueryParam param) {
|
||||
String methodDescribe = getMethodDescribe("queryTrendDay");
|
||||
LogUtil.njcnDebug(log, "{},开始按天查询稳态趋势,param={}", methodDescribe, param);
|
||||
SteadyTrendQueryVO result = trendService.queryTrendDay(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询稳态趋势统计摘要")
|
||||
@PostMapping("/summary")
|
||||
public HttpResult<SteadyTrendSummaryVO> summarizeTrend(@RequestBody SteadyTrendQueryParam param) {
|
||||
String methodDescribe = getMethodDescribe("summarizeTrend");
|
||||
LogUtil.njcnDebug(log, "{},开始查询稳态趋势统计摘要,param={}", methodDescribe, param);
|
||||
SteadyTrendSummaryVO result = trendService.summarizeTrend(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.njcn.gather.steady.datavie.mapper;
|
||||
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyDataViewLedgerRowBO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势台账树 Mapper。
|
||||
*/
|
||||
public interface SteadyDataViewLedgerMapper {
|
||||
|
||||
List<SteadyDataViewLedgerRowBO> selectLedgerTree(@Param("keyword") String keyword);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
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;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 稳态数据查看 Mapper。
|
||||
*/
|
||||
public interface SteadyDataViewMapper {
|
||||
|
||||
Page<Map<String, Object>> selectSteadyPage(Page<Map<String, Object>> page,
|
||||
@Param("tableName") String tableName,
|
||||
@Param("columns") List<String> columns,
|
||||
@Param("param") SteadyDataViewQueryParam param);
|
||||
|
||||
Map<String, Object> selectSteadyDetail(@Param("tableName") String tableName,
|
||||
@Param("columns") List<String> columns,
|
||||
@Param("lineId") String lineId,
|
||||
@Param("timeId") String timeId,
|
||||
@Param("phasicType") String phasicType);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.njcn.gather.steady.datavie.mapper.SteadyDataViewLedgerMapper">
|
||||
|
||||
<select id="selectLedgerTree" resultType="com.njcn.gather.steady.datavie.pojo.bo.SteadyDataViewLedgerRowBO">
|
||||
SELECT ledger.Id AS id,
|
||||
ledger.Pid AS parentId,
|
||||
ledger.Name AS name,
|
||||
ledger.Level AS level,
|
||||
ledger.Sort AS sort,
|
||||
(
|
||||
SELECT COUNT(DISTINCT equipment.id)
|
||||
FROM cs_ledger equipment_ledger
|
||||
INNER JOIN cs_equipment_delivery equipment ON equipment.id = equipment_ledger.Id
|
||||
WHERE equipment_ledger.State = 1
|
||||
AND equipment_ledger.Level = 2
|
||||
AND equipment.run_status <> 0
|
||||
AND (equipment_ledger.Id = ledger.Id OR FIND_IN_SET(ledger.Id, equipment_ledger.Pids) > 0)
|
||||
) AS deviceCount,
|
||||
(
|
||||
SELECT COUNT(DISTINCT line.line_id)
|
||||
FROM cs_ledger line_ledger
|
||||
INNER JOIN cs_line line ON line.line_id = line_ledger.Id
|
||||
INNER JOIN cs_equipment_delivery equipment ON equipment.id = line.device_id
|
||||
WHERE line_ledger.State = 1
|
||||
AND line_ledger.Level = 3
|
||||
AND line.status = 1
|
||||
AND equipment.run_status <> 0
|
||||
AND (line_ledger.Id = ledger.Id OR FIND_IN_SET(ledger.Id, line_ledger.Pids) > 0)
|
||||
) AS lineCount
|
||||
FROM cs_ledger ledger
|
||||
WHERE ledger.State = 1
|
||||
<if test="keyword != null and keyword != ''">
|
||||
AND (
|
||||
ledger.Name LIKE CONCAT('%', #{keyword}, '%')
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM cs_ledger child
|
||||
WHERE child.State = 1
|
||||
AND FIND_IN_SET(ledger.Id, child.Pids) > 0
|
||||
AND child.Name LIKE CONCAT('%', #{keyword}, '%')
|
||||
)
|
||||
)
|
||||
</if>
|
||||
ORDER BY ledger.Level ASC, ledger.Sort ASC, ledger.Name ASC
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.njcn.gather.steady.datavie.mapper.SteadyDataViewMapper">
|
||||
|
||||
<sql id="SteadyDataWhere">
|
||||
<where>
|
||||
<if test="param.timeStart != null and param.timeStart != ''">
|
||||
AND TIMEID >= #{param.timeStart}
|
||||
</if>
|
||||
<if test="param.timeEnd != null and param.timeEnd != ''">
|
||||
AND TIMEID <= #{param.timeEnd}
|
||||
</if>
|
||||
<if test="param.phasicType != null and param.phasicType != ''">
|
||||
AND PHASIC_TYPE = #{param.phasicType}
|
||||
</if>
|
||||
<if test="param.qualityFlag != null">
|
||||
AND QUALITYFLAG = #{param.qualityFlag}
|
||||
</if>
|
||||
<if test="param.lineIds != null and param.lineIds.size() > 0">
|
||||
AND LINEID IN
|
||||
<foreach collection="param.lineIds" item="lineId" open="(" separator="," close=")">
|
||||
#{lineId}
|
||||
</foreach>
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<select id="selectSteadyPage" resultType="java.util.LinkedHashMap">
|
||||
SELECT
|
||||
<foreach collection="columns" item="column" separator=",">
|
||||
`${column}`
|
||||
</foreach>
|
||||
FROM `${tableName}`
|
||||
<include refid="SteadyDataWhere"/>
|
||||
ORDER BY TIMEID DESC, LINEID ASC, PHASIC_TYPE ASC
|
||||
</select>
|
||||
|
||||
<select id="selectSteadyDetail" resultType="java.util.LinkedHashMap">
|
||||
SELECT
|
||||
<foreach collection="columns" item="column" separator=",">
|
||||
`${column}`
|
||||
</foreach>
|
||||
FROM `${tableName}`
|
||||
WHERE LINEID = #{lineId}
|
||||
AND TIMEID = #{timeId}
|
||||
AND PHASIC_TYPE = #{phasicType}
|
||||
LIMIT 1
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 稳态趋势台账树查询行。
|
||||
*/
|
||||
@Data
|
||||
public class SteadyDataViewLedgerRowBO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
|
||||
private String parentId;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer level;
|
||||
|
||||
private Integer sort;
|
||||
|
||||
private Integer deviceCount;
|
||||
|
||||
private Integer lineCount;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势指标定义。
|
||||
*/
|
||||
@Data
|
||||
public class SteadyTrendIndicatorDefinitionBO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String indicatorCode;
|
||||
|
||||
private String name;
|
||||
|
||||
private String groupCode;
|
||||
|
||||
private String groupName;
|
||||
|
||||
private String tableName;
|
||||
|
||||
private List<String> phaseCodes = new ArrayList<String>();
|
||||
|
||||
private List<SteadyTrendSeriesFieldBO> seriesFields = new ArrayList<SteadyTrendSeriesFieldBO>();
|
||||
|
||||
private List<String> supportStats = new ArrayList<String>();
|
||||
|
||||
private Boolean harmonic = false;
|
||||
|
||||
private String harmonicFieldPrefix;
|
||||
|
||||
private Integer harmonicOrderStart;
|
||||
|
||||
private Integer harmonicOrderEnd;
|
||||
|
||||
private String unit;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 稳态趋势查询字段解析结果。
|
||||
*/
|
||||
@Data
|
||||
public class SteadyTrendResolvedFieldBO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String measurement;
|
||||
|
||||
private String field;
|
||||
|
||||
private String lineId;
|
||||
|
||||
private String lineName;
|
||||
|
||||
private String indicatorCode;
|
||||
|
||||
private String indicatorName;
|
||||
|
||||
private String seriesName;
|
||||
|
||||
private String phase;
|
||||
|
||||
private String statType;
|
||||
|
||||
private String unit;
|
||||
|
||||
private String seriesKey;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.bo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 稳态趋势指标曲线字段。
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SteadyTrendSeriesFieldBO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** InfluxDB field 基础名。 */
|
||||
private String field;
|
||||
|
||||
/** 曲线展示名称。 */
|
||||
private String name;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.param;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 稳态数据详情查询参数。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("稳态数据详情查询参数")
|
||||
public class SteadyDataViewDetailParam {
|
||||
|
||||
@ApiModelProperty("表名,对应 add-data 模板表名")
|
||||
private String tableName;
|
||||
|
||||
@ApiModelProperty("监测点 ID")
|
||||
private String lineId;
|
||||
|
||||
@ApiModelProperty("时间,格式 yyyy-MM-dd HH:mm:ss")
|
||||
private String timeId;
|
||||
|
||||
@ApiModelProperty("相别:A/B/C/T")
|
||||
private String phasicType;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.param;
|
||||
|
||||
import com.njcn.web.pojo.param.BaseParam;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态数据查看查询参数。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ApiModel("稳态数据查看查询参数")
|
||||
public class SteadyDataViewQueryParam extends BaseParam {
|
||||
|
||||
@ApiModelProperty("表名,对应 add-data 模板表名")
|
||||
private String tableName;
|
||||
|
||||
@ApiModelProperty("时间开始,格式 yyyy-MM-dd HH:mm:ss")
|
||||
private String timeStart;
|
||||
|
||||
@ApiModelProperty("时间结束,格式 yyyy-MM-dd HH:mm:ss")
|
||||
private String timeEnd;
|
||||
|
||||
@ApiModelProperty("相别:A/B/C/T")
|
||||
private String phasicType;
|
||||
|
||||
@ApiModelProperty("质量标识")
|
||||
private Integer qualityFlag;
|
||||
|
||||
@ApiModelProperty("监测点 ID 列表")
|
||||
private List<String> lineIds = new ArrayList<String>();
|
||||
|
||||
@ApiModelProperty("工程名称关键字")
|
||||
private String engineeringName;
|
||||
|
||||
@ApiModelProperty("项目名称关键字")
|
||||
private String projectName;
|
||||
|
||||
@ApiModelProperty("设备名称关键字")
|
||||
private String equipmentName;
|
||||
|
||||
@ApiModelProperty("监测点名称关键字")
|
||||
private String lineName;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.njcn.gather.steady.datavie.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 SteadyTrendQueryParam {
|
||||
|
||||
@ApiModelProperty("监测点 ID 列表")
|
||||
private List<String> lineIds = new ArrayList<String>();
|
||||
|
||||
@ApiModelProperty("指标编码列表")
|
||||
private List<String> indicatorCodes = new ArrayList<String>();
|
||||
|
||||
@ApiModelProperty("统计类型:AVG/MAX/MIN/CP95")
|
||||
private List<String> statTypes = new ArrayList<String>();
|
||||
|
||||
@ApiModelProperty("相别:A/B/C/T")
|
||||
private List<String> phases = new ArrayList<String>();
|
||||
|
||||
@ApiModelProperty("开始时间,格式 yyyy-MM-dd HH:mm:ss")
|
||||
private String timeStart;
|
||||
|
||||
@ApiModelProperty("结束时间,格式 yyyy-MM-dd HH:mm:ss")
|
||||
private String timeEnd;
|
||||
|
||||
@ApiModelProperty("分桶粒度,如 1m、5m、10m、30m、1h")
|
||||
private String bucket;
|
||||
|
||||
@ApiModelProperty("质量标识")
|
||||
private Integer qualityFlag;
|
||||
|
||||
@ApiModelProperty("谐波次数,谐波指标必填,最多 6 个")
|
||||
private List<Integer> harmonicOrders = new ArrayList<Integer>();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.vo;
|
||||
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendSeriesFieldBO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势指标树节点。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("稳态趋势指标树节点")
|
||||
public class SteadyDataViewIndicatorNodeVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
|
||||
private String parentId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String groupCode;
|
||||
|
||||
private String indicatorCode;
|
||||
|
||||
private String tableName;
|
||||
|
||||
private List<String> phaseCodes = new ArrayList<String>();
|
||||
|
||||
private List<SteadyTrendSeriesFieldBO> seriesFields = new ArrayList<SteadyTrendSeriesFieldBO>();
|
||||
|
||||
private List<String> supportStats = new ArrayList<String>();
|
||||
|
||||
private Boolean harmonic = false;
|
||||
|
||||
private Integer harmonicOrderStart;
|
||||
|
||||
private Integer harmonicOrderEnd;
|
||||
|
||||
private String unit;
|
||||
|
||||
@ApiModelProperty("是否可选")
|
||||
private Boolean selectable = false;
|
||||
|
||||
private List<SteadyDataViewIndicatorNodeVO> children = new ArrayList<SteadyDataViewIndicatorNodeVO>();
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势台账树节点。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("稳态趋势台账树节点")
|
||||
public class SteadyDataViewLedgerNodeVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
|
||||
private String parentId;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer level;
|
||||
|
||||
private Integer sort;
|
||||
|
||||
private Integer deviceCount;
|
||||
|
||||
private Integer lineCount;
|
||||
|
||||
private Boolean selectable;
|
||||
|
||||
private List<SteadyDataViewLedgerNodeVO> children = new ArrayList<SteadyDataViewLedgerNodeVO>();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态数据查看模板。
|
||||
*/
|
||||
@Data
|
||||
public class SteadyDataViewTemplateVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String parameterName;
|
||||
|
||||
private String tableName;
|
||||
|
||||
private String phaseDisplay;
|
||||
|
||||
private List<String> phaseCodes = new ArrayList<String>();
|
||||
|
||||
private List<String> valueColumns = new ArrayList<String>();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.njcn.gather.steady.datavie.config.SteadySecondTimeSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 稳态数据查看展示对象。
|
||||
*/
|
||||
@Data
|
||||
public class SteadyDataViewVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String tableName;
|
||||
|
||||
private String lineId;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = SteadySecondTimeSerializer.class)
|
||||
private LocalDateTime timeId;
|
||||
|
||||
private String phasicType;
|
||||
|
||||
private Integer qualityFlag;
|
||||
|
||||
private String equipmentName;
|
||||
|
||||
private String engineeringName;
|
||||
|
||||
private String projectName;
|
||||
|
||||
private String lineName;
|
||||
|
||||
private Map<String, Object> values = new LinkedHashMap<String, Object>();
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 稳态趋势点位。
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ApiModel("稳态趋势点位")
|
||||
public class SteadyTrendPointVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("时间,格式 yyyy-MM-dd HH:mm:ss")
|
||||
private String time;
|
||||
|
||||
@ApiModelProperty("点位值")
|
||||
private BigDecimal value;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势查询结果。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("稳态趋势查询结果")
|
||||
public class SteadyTrendQueryVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Boolean sampled;
|
||||
|
||||
private String bucket;
|
||||
|
||||
private Integer sourcePointCount;
|
||||
|
||||
private Integer displayPointCount;
|
||||
|
||||
private List<String> loadableDays = new ArrayList<String>();
|
||||
|
||||
private List<SteadyTrendSeriesVO> series = new ArrayList<SteadyTrendSeriesVO>();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势曲线。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("稳态趋势曲线")
|
||||
public class SteadyTrendSeriesVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String seriesKey;
|
||||
|
||||
private String lineId;
|
||||
|
||||
private String lineName;
|
||||
|
||||
private String indicatorCode;
|
||||
|
||||
private String indicatorName;
|
||||
|
||||
private String seriesName;
|
||||
|
||||
private String phase;
|
||||
|
||||
private String statType;
|
||||
|
||||
private String unit;
|
||||
|
||||
private List<SteadyTrendPointVO> points = new ArrayList<SteadyTrendPointVO>();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 稳态趋势统计项。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("稳态趋势统计项")
|
||||
public class SteadyTrendSummaryItemVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String seriesKey;
|
||||
|
||||
private BigDecimal max;
|
||||
|
||||
private BigDecimal avg;
|
||||
|
||||
private BigDecimal min;
|
||||
|
||||
private BigDecimal cp95;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.njcn.gather.steady.datavie.pojo.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势统计结果。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("稳态趋势统计结果")
|
||||
public class SteadyTrendSummaryVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private List<SteadyTrendSummaryItemVO> items = new ArrayList<SteadyTrendSummaryItemVO>();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.njcn.gather.steady.datavie.service;
|
||||
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyDataViewIndicatorNodeVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势指标服务。
|
||||
*/
|
||||
public interface SteadyDataViewIndicatorService {
|
||||
|
||||
List<SteadyDataViewIndicatorNodeVO> listIndicatorTree();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.njcn.gather.steady.datavie.service;
|
||||
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyDataViewLedgerNodeVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势台账树服务。
|
||||
*/
|
||||
public interface SteadyDataViewLedgerService {
|
||||
|
||||
List<SteadyDataViewLedgerNodeVO> listLedgerTree(String keyword);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.njcn.gather.steady.datavie.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
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 java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态数据查看服务。
|
||||
*/
|
||||
public interface SteadyDataViewService {
|
||||
|
||||
Page<SteadyDataViewVO> pageSteadyData(SteadyDataViewQueryParam param);
|
||||
|
||||
SteadyDataViewVO getSteadyDataDetail(SteadyDataViewDetailParam param);
|
||||
|
||||
List<SteadyDataViewTemplateVO> listTemplates();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.njcn.gather.steady.datavie.service;
|
||||
|
||||
import com.njcn.gather.steady.datavie.pojo.param.SteadyTrendQueryParam;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendQueryVO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendSummaryVO;
|
||||
|
||||
/**
|
||||
* 稳态趋势查询服务。
|
||||
*/
|
||||
public interface SteadyDataViewTrendService {
|
||||
|
||||
SteadyTrendQueryVO queryTrend(SteadyTrendQueryParam param);
|
||||
|
||||
SteadyTrendQueryVO queryTrendDay(SteadyTrendQueryParam param);
|
||||
|
||||
SteadyTrendSummaryVO summarizeTrend(SteadyTrendQueryParam param);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.njcn.gather.steady.datavie.service.impl;
|
||||
|
||||
import com.njcn.gather.steady.datavie.component.SteadyTrendIndicatorCatalog;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendIndicatorDefinitionBO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyDataViewIndicatorNodeVO;
|
||||
import com.njcn.gather.steady.datavie.service.SteadyDataViewIndicatorService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 稳态趋势指标服务实现。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SteadyDataViewIndicatorServiceImpl implements SteadyDataViewIndicatorService {
|
||||
|
||||
private final SteadyTrendIndicatorCatalog indicatorCatalog;
|
||||
|
||||
@Override
|
||||
public List<SteadyDataViewIndicatorNodeVO> listIndicatorTree() {
|
||||
Map<String, SteadyDataViewIndicatorNodeVO> groupMap = new LinkedHashMap<String, SteadyDataViewIndicatorNodeVO>();
|
||||
for (SteadyTrendIndicatorDefinitionBO indicator : indicatorCatalog.listIndicators()) {
|
||||
SteadyDataViewIndicatorNodeVO groupNode = groupMap.get(indicator.getGroupCode());
|
||||
if (groupNode == null) {
|
||||
groupNode = new SteadyDataViewIndicatorNodeVO();
|
||||
groupNode.setId(indicator.getGroupCode());
|
||||
groupNode.setName(indicator.getGroupName());
|
||||
groupNode.setGroupCode(indicator.getGroupCode());
|
||||
groupNode.setSelectable(false);
|
||||
groupMap.put(indicator.getGroupCode(), groupNode);
|
||||
}
|
||||
groupNode.getChildren().add(buildIndicatorNode(indicator, groupNode.getId()));
|
||||
}
|
||||
return new ArrayList<SteadyDataViewIndicatorNodeVO>(groupMap.values());
|
||||
}
|
||||
|
||||
private SteadyDataViewIndicatorNodeVO buildIndicatorNode(SteadyTrendIndicatorDefinitionBO indicator, String parentId) {
|
||||
SteadyDataViewIndicatorNodeVO node = new SteadyDataViewIndicatorNodeVO();
|
||||
node.setId(indicator.getIndicatorCode());
|
||||
node.setParentId(parentId);
|
||||
node.setName(indicator.getName());
|
||||
node.setGroupCode(indicator.getGroupCode());
|
||||
node.setIndicatorCode(indicator.getIndicatorCode());
|
||||
node.setTableName(indicator.getTableName());
|
||||
node.setPhaseCodes(new ArrayList<String>(indicator.getPhaseCodes()));
|
||||
node.setSeriesFields(new ArrayList<com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendSeriesFieldBO>(indicator.getSeriesFields()));
|
||||
node.setSupportStats(new ArrayList<String>(indicator.getSupportStats()));
|
||||
node.setHarmonic(indicator.getHarmonic());
|
||||
node.setHarmonicOrderStart(indicator.getHarmonicOrderStart());
|
||||
node.setHarmonicOrderEnd(indicator.getHarmonicOrderEnd());
|
||||
node.setUnit(indicator.getUnit());
|
||||
node.setSelectable(true);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.njcn.gather.steady.datavie.service.impl;
|
||||
|
||||
import com.njcn.gather.steady.datavie.mapper.SteadyDataViewLedgerMapper;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyDataViewLedgerRowBO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyDataViewLedgerNodeVO;
|
||||
import com.njcn.gather.steady.datavie.service.SteadyDataViewLedgerService;
|
||||
import com.njcn.gather.tool.addledger.pojo.constant.AddLedgerConst;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 稳态趋势台账树服务实现。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SteadyDataViewLedgerServiceImpl implements SteadyDataViewLedgerService {
|
||||
|
||||
private final SteadyDataViewLedgerMapper ledgerMapper;
|
||||
|
||||
@Override
|
||||
public List<SteadyDataViewLedgerNodeVO> listLedgerTree(String keyword) {
|
||||
List<SteadyDataViewLedgerRowBO> rows = ledgerMapper.selectLedgerTree(trimToNull(keyword));
|
||||
Map<String, SteadyDataViewLedgerNodeVO> nodeMap = new LinkedHashMap<String, SteadyDataViewLedgerNodeVO>();
|
||||
for (SteadyDataViewLedgerRowBO row : rows) {
|
||||
SteadyDataViewLedgerNodeVO node = new SteadyDataViewLedgerNodeVO();
|
||||
node.setId(row.getId());
|
||||
node.setParentId(row.getParentId());
|
||||
node.setName(row.getName());
|
||||
node.setLevel(row.getLevel());
|
||||
node.setSort(row.getSort());
|
||||
node.setDeviceCount(row.getDeviceCount() == null ? 0 : row.getDeviceCount());
|
||||
node.setLineCount(row.getLineCount() == null ? 0 : row.getLineCount());
|
||||
node.setSelectable(AddLedgerConst.LEVEL_EQUIPMENT == row.getLevel() || AddLedgerConst.LEVEL_LINE == row.getLevel());
|
||||
nodeMap.put(node.getId(), node);
|
||||
}
|
||||
List<SteadyDataViewLedgerNodeVO> roots = new ArrayList<SteadyDataViewLedgerNodeVO>();
|
||||
for (SteadyDataViewLedgerNodeVO node : nodeMap.values()) {
|
||||
SteadyDataViewLedgerNodeVO parent = nodeMap.get(node.getParentId());
|
||||
if (parent == null || AddLedgerConst.ROOT_PARENT_ID.equals(node.getParentId())) {
|
||||
roots.add(node);
|
||||
} else {
|
||||
parent.getChildren().add(node);
|
||||
}
|
||||
}
|
||||
sortTree(roots);
|
||||
return roots;
|
||||
}
|
||||
|
||||
private void sortTree(List<SteadyDataViewLedgerNodeVO> nodes) {
|
||||
nodes.sort(Comparator.comparing(SteadyDataViewLedgerNodeVO::getSort, Comparator.nullsLast(Integer::compareTo))
|
||||
.thenComparing(SteadyDataViewLedgerNodeVO::getName, Comparator.nullsLast(String::compareTo)));
|
||||
for (SteadyDataViewLedgerNodeVO node : nodes) {
|
||||
sortTree(node.getChildren());
|
||||
}
|
||||
}
|
||||
|
||||
private String trimToNull(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.isEmpty() ? null : trimmed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
package com.njcn.gather.steady.datavie.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.gather.steady.datavie.mapper.SteadyDataViewMapper;
|
||||
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;
|
||||
import com.njcn.gather.tool.adddata.component.AddDataTableRegistry;
|
||||
import com.njcn.gather.tool.adddata.component.AddDataTemplateRegistry;
|
||||
import com.njcn.gather.tool.adddata.pojo.bo.AddDataTableDefinition;
|
||||
import com.njcn.gather.tool.adddata.pojo.vo.AddDataTemplateVO;
|
||||
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.web.factory.PageFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 稳态数据查看服务实现。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SteadyDataViewServiceImpl implements SteadyDataViewService {
|
||||
|
||||
private static final int LEDGER_LINE_QUERY_LIMIT = 1000;
|
||||
private static final int STEADY_LINE_ID_QUERY_LIMIT = 1000;
|
||||
private static final String DEFAULT_TABLE_NAME = "data_v";
|
||||
private static final String EMPTY_TEXT = "-";
|
||||
private static final DateTimeFormatter OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
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"),
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"),
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
|
||||
};
|
||||
|
||||
private final SteadyDataViewMapper steadyDataViewMapper;
|
||||
private final AddLedgerService addLedgerService;
|
||||
private final AddDataTableRegistry addDataTableRegistry;
|
||||
private final AddDataTemplateRegistry addDataTemplateRegistry;
|
||||
|
||||
@Override
|
||||
public Page<SteadyDataViewVO> pageSteadyData(SteadyDataViewQueryParam param) {
|
||||
SteadyDataViewQueryParam queryParam = normalizeQueryParam(param);
|
||||
AddDataTableDefinition definition = resolveTableDefinition(queryParam.getTableName());
|
||||
if (!resolveLineFilter(queryParam)) {
|
||||
return emptyPage(queryParam);
|
||||
}
|
||||
Page<Map<String, Object>> steadyPage = steadyDataViewMapper.selectSteadyPage(
|
||||
new Page<Map<String, Object>>(PageFactory.getPageNum(queryParam), PageFactory.getPageSize(queryParam)),
|
||||
definition.getTableName(), definition.getColumns(), queryParam);
|
||||
List<SteadyDataViewVO> records = buildSteadyDataList(definition.getTableName(), definition.getColumns(), steadyPage.getRecords());
|
||||
Page<SteadyDataViewVO> resultPage = new Page<SteadyDataViewVO>(steadyPage.getCurrent(), steadyPage.getSize(), steadyPage.getTotal());
|
||||
resultPage.setRecords(records);
|
||||
return resultPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SteadyDataViewVO getSteadyDataDetail(SteadyDataViewDetailParam param) {
|
||||
if (param == null) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "详情查询参数不能为空");
|
||||
}
|
||||
String tableName = normalizeTableName(param.getTableName());
|
||||
String lineId = trimToNull(param.getLineId());
|
||||
String timeId = normalizeRequiredTime(param.getTimeId(), "时间不能为空");
|
||||
String phasicType = normalizePhasicType(param.getPhasicType());
|
||||
if (lineId == null) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "监测点 ID 不能为空");
|
||||
}
|
||||
if (phasicType == null) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "相别不能为空");
|
||||
}
|
||||
AddDataTableDefinition definition = resolveTableDefinition(tableName);
|
||||
Map<String, Object> row = steadyDataViewMapper.selectSteadyDetail(definition.getTableName(), definition.getColumns(),
|
||||
lineId, timeId, phasicType);
|
||||
if (row == null || row.isEmpty()) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "稳态数据不存在");
|
||||
}
|
||||
List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
|
||||
rows.add(row);
|
||||
return buildSteadyDataList(definition.getTableName(), definition.getColumns(), rows).get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SteadyDataViewTemplateVO> listTemplates() {
|
||||
List<SteadyDataViewTemplateVO> result = new ArrayList<SteadyDataViewTemplateVO>();
|
||||
for (AddDataTemplateVO template : addDataTemplateRegistry.getTemplates()) {
|
||||
AddDataTableDefinition definition = resolveTableDefinition(template.getTableName());
|
||||
SteadyDataViewTemplateVO vo = new SteadyDataViewTemplateVO();
|
||||
vo.setParameterName(template.getParameterName());
|
||||
vo.setTableName(template.getTableName());
|
||||
vo.setPhaseDisplay(template.getPhaseDisplay());
|
||||
vo.setPhaseCodes(template.getPhaseCodes());
|
||||
vo.setValueColumns(resolveValueColumns(definition.getColumns()));
|
||||
result.add(vo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<SteadyDataViewVO> buildSteadyDataList(String tableName, List<String> columns, List<Map<String, Object>> rows) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> lineIds = new ArrayList<String>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
String lineId = trimToNull(toStringValue(row.get("LINEID")));
|
||||
if (lineId != null && !lineIds.contains(lineId)) {
|
||||
lineIds.add(lineId);
|
||||
}
|
||||
}
|
||||
Map<String, AddLedgerLinePathVO> linePathMap = addLedgerService.listLinePathByLineIds(lineIds);
|
||||
List<SteadyDataViewVO> result = new ArrayList<SteadyDataViewVO>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
String lineId = trimToNull(toStringValue(row.get("LINEID")));
|
||||
AddLedgerLinePathVO linePath = linePathMap.get(lineId);
|
||||
result.add(buildSteadyDataVO(tableName, columns, row, linePath));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private SteadyDataViewVO buildSteadyDataVO(String tableName, List<String> columns, Map<String, Object> row, AddLedgerLinePathVO linePath) {
|
||||
SteadyDataViewVO vo = new SteadyDataViewVO();
|
||||
vo.setTableName(tableName);
|
||||
vo.setLineId(toStringValue(row.get("LINEID")));
|
||||
vo.setTimeId(toLocalDateTime(row.get("TIMEID")));
|
||||
vo.setPhasicType(toStringValue(row.get("PHASIC_TYPE")));
|
||||
vo.setQualityFlag(toInteger(row.get("QUALITYFLAG")));
|
||||
vo.setEquipmentName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getEquipmentName()));
|
||||
vo.setEngineeringName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getEngineeringName()));
|
||||
vo.setProjectName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getProjectName()));
|
||||
vo.setLineName(linePath == null ? EMPTY_TEXT : defaultText(linePath.getLineName()));
|
||||
Map<String, Object> values = new LinkedHashMap<String, Object>();
|
||||
for (String column : columns) {
|
||||
if (!isInfrastructureColumn(column)) {
|
||||
values.put(column, row.get(column));
|
||||
}
|
||||
}
|
||||
vo.setValues(values);
|
||||
return vo;
|
||||
}
|
||||
|
||||
private SteadyDataViewQueryParam normalizeQueryParam(SteadyDataViewQueryParam param) {
|
||||
SteadyDataViewQueryParam queryParam = param == null ? new SteadyDataViewQueryParam() : param;
|
||||
queryParam.setTableName(normalizeTableName(queryParam.getTableName()));
|
||||
LocalDateTime startTime = parseDateTime(queryParam.getTimeStart());
|
||||
LocalDateTime endTime = parseDateTime(queryParam.getTimeEnd());
|
||||
if (startTime == null) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
startTime = LocalDateTime.of(now.getYear(), now.getMonth(), 1, 0, 0, 0);
|
||||
}
|
||||
if (endTime == null) {
|
||||
endTime = LocalDateTime.now();
|
||||
}
|
||||
if (startTime.isAfter(endTime)) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "开始时间不能大于结束时间");
|
||||
}
|
||||
queryParam.setTimeStart(OUTPUT_FORMATTER.format(startTime));
|
||||
queryParam.setTimeEnd(OUTPUT_FORMATTER.format(endTime));
|
||||
queryParam.setPhasicType(normalizePhasicType(queryParam.getPhasicType()));
|
||||
validateQualityFlag(queryParam.getQualityFlag());
|
||||
queryParam.setEngineeringName(trimToNull(queryParam.getEngineeringName()));
|
||||
queryParam.setProjectName(trimToNull(queryParam.getProjectName()));
|
||||
queryParam.setEquipmentName(trimToNull(queryParam.getEquipmentName()));
|
||||
queryParam.setLineName(trimToNull(queryParam.getLineName()));
|
||||
List<String> lineIds = normalizeIds(queryParam.getLineIds());
|
||||
if (lineIds.size() > STEADY_LINE_ID_QUERY_LIMIT) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "监测点 ID 查询数量不能超过 1000 个");
|
||||
}
|
||||
queryParam.setLineIds(lineIds);
|
||||
return queryParam;
|
||||
}
|
||||
|
||||
private boolean resolveLineFilter(SteadyDataViewQueryParam queryParam) {
|
||||
if (!hasLedgerKeyword(queryParam)) {
|
||||
return true;
|
||||
}
|
||||
AddLedgerLinePathQueryParam linePathQueryParam = new AddLedgerLinePathQueryParam();
|
||||
linePathQueryParam.setEngineeringName(queryParam.getEngineeringName());
|
||||
linePathQueryParam.setProjectName(queryParam.getProjectName());
|
||||
linePathQueryParam.setEquipmentName(queryParam.getEquipmentName());
|
||||
linePathQueryParam.setLineName(queryParam.getLineName());
|
||||
linePathQueryParam.setLimit(LEDGER_LINE_QUERY_LIMIT + 1);
|
||||
List<String> ledgerLineIds = addLedgerService.listLineIdsByPathQuery(linePathQueryParam);
|
||||
if (ledgerLineIds.size() > LEDGER_LINE_QUERY_LIMIT) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "台账检索匹配监测点过多,请缩小查询条件");
|
||||
}
|
||||
if (ledgerLineIds.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
List<String> explicitLineIds = normalizeIds(queryParam.getLineIds());
|
||||
if (explicitLineIds.isEmpty()) {
|
||||
queryParam.setLineIds(ledgerLineIds);
|
||||
return true;
|
||||
}
|
||||
List<String> intersectLineIds = new ArrayList<String>();
|
||||
for (String lineId : explicitLineIds) {
|
||||
if (ledgerLineIds.contains(lineId)) {
|
||||
intersectLineIds.add(lineId);
|
||||
}
|
||||
}
|
||||
queryParam.setLineIds(intersectLineIds);
|
||||
return !intersectLineIds.isEmpty();
|
||||
}
|
||||
|
||||
private AddDataTableDefinition resolveTableDefinition(String tableName) {
|
||||
try {
|
||||
return addDataTableRegistry.getDefinition(tableName);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "稳态数据表不支持:" + tableName);
|
||||
}
|
||||
}
|
||||
|
||||
private String normalizeTableName(String tableName) {
|
||||
String normalizedTableName = trimToNull(tableName);
|
||||
return normalizedTableName == null ? DEFAULT_TABLE_NAME : normalizedTableName;
|
||||
}
|
||||
|
||||
private String normalizeRequiredTime(String value, String emptyMessage) {
|
||||
LocalDateTime dateTime = parseDateTime(value);
|
||||
if (dateTime == null) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, emptyMessage);
|
||||
}
|
||||
return OUTPUT_FORMATTER.format(dateTime);
|
||||
}
|
||||
|
||||
private LocalDateTime parseDateTime(String value) {
|
||||
String text = trimToNull(value);
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
for (DateTimeFormatter formatter : INPUT_FORMATTERS) {
|
||||
try {
|
||||
return LocalDateTime.parse(text, formatter);
|
||||
} catch (DateTimeParseException ignored) {
|
||||
// 尝试下一个前端可能传入的时间格式。
|
||||
}
|
||||
}
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "时间格式不正确,仅支持 yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
private String normalizePhasicType(String phasicType) {
|
||||
String text = trimToNull(phasicType);
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
String normalized = text.toUpperCase();
|
||||
if (!"A".equals(normalized) && !"B".equals(normalized) && !"C".equals(normalized) && !"T".equals(normalized)) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "相别只能是 A、B、C、T");
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private void validateQualityFlag(Integer qualityFlag) {
|
||||
if (qualityFlag != null && qualityFlag != 0 && qualityFlag != 1) {
|
||||
throw new BusinessException(CommonResponseEnum.FAIL, "质量标识只能是 0 或 1");
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> normalizeIds(List<String> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> normalizedIds = new ArrayList<String>();
|
||||
for (String id : ids) {
|
||||
String normalizedId = trimToNull(id);
|
||||
if (normalizedId != null && !normalizedIds.contains(normalizedId)) {
|
||||
normalizedIds.add(normalizedId);
|
||||
}
|
||||
}
|
||||
return normalizedIds;
|
||||
}
|
||||
|
||||
private boolean hasLedgerKeyword(SteadyDataViewQueryParam queryParam) {
|
||||
return trimToNull(queryParam.getEngineeringName()) != null
|
||||
|| trimToNull(queryParam.getProjectName()) != null
|
||||
|| trimToNull(queryParam.getEquipmentName()) != null
|
||||
|| trimToNull(queryParam.getLineName()) != null;
|
||||
}
|
||||
|
||||
private Page<SteadyDataViewVO> emptyPage(SteadyDataViewQueryParam queryParam) {
|
||||
Page<SteadyDataViewVO> page = new Page<SteadyDataViewVO>(PageFactory.getPageNum(queryParam), PageFactory.getPageSize(queryParam), 0);
|
||||
page.setRecords(Collections.<SteadyDataViewVO>emptyList());
|
||||
return page;
|
||||
}
|
||||
|
||||
private List<String> resolveValueColumns(List<String> columns) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
for (String column : columns) {
|
||||
if (!isInfrastructureColumn(column)) {
|
||||
result.add(column);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isInfrastructureColumn(String column) {
|
||||
return "TIMEID".equals(column) || "LINEID".equals(column) || "PHASIC_TYPE".equals(column) || "QUALITYFLAG".equals(column);
|
||||
}
|
||||
|
||||
private LocalDateTime toLocalDateTime(Object value) {
|
||||
if (value instanceof LocalDateTime) {
|
||||
return (LocalDateTime) value;
|
||||
}
|
||||
if (value instanceof Timestamp) {
|
||||
return ((Timestamp) value).toLocalDateTime();
|
||||
}
|
||||
String text = trimToNull(toStringValue(value));
|
||||
return text == null ? null : parseDateTime(text);
|
||||
}
|
||||
|
||||
private Integer toInteger(Object value) {
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
String text = trimToNull(toStringValue(value));
|
||||
return text == null ? null : Integer.valueOf(text);
|
||||
}
|
||||
|
||||
private String toStringValue(Object value) {
|
||||
return value == null ? null : String.valueOf(value);
|
||||
}
|
||||
|
||||
private String defaultText(String value) {
|
||||
String text = trimToNull(value);
|
||||
return text == null ? EMPTY_TEXT : text;
|
||||
}
|
||||
|
||||
private String trimToNull(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.isEmpty() ? null : trimmed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package com.njcn.gather.steady.datavie.service.impl;
|
||||
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.gather.steady.datavie.component.SteadyInfluxQueryComponent;
|
||||
import com.njcn.gather.steady.datavie.component.SteadyTrendFieldResolver;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
||||
import com.njcn.gather.steady.datavie.pojo.param.SteadyTrendQueryParam;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendPointVO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendQueryVO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendSeriesVO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendSummaryItemVO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendSummaryVO;
|
||||
import com.njcn.gather.steady.datavie.service.SteadyDataViewTrendService;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
|
||||
import com.njcn.gather.tool.addledger.service.AddLedgerService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 稳态趋势查询服务实现。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SteadyDataViewTrendServiceImpl implements SteadyDataViewTrendService {
|
||||
|
||||
private static final String EMPTY_TEXT = "-";
|
||||
|
||||
private final SteadyTrendFieldResolver fieldResolver;
|
||||
private final SteadyInfluxQueryComponent influxQueryComponent;
|
||||
private final AddLedgerService addLedgerService;
|
||||
|
||||
@Override
|
||||
public SteadyTrendQueryVO queryTrend(SteadyTrendQueryParam param) {
|
||||
return queryTrendInternal(param, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SteadyTrendQueryVO queryTrendDay(SteadyTrendQueryParam param) {
|
||||
return queryTrendInternal(param, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SteadyTrendSummaryVO summarizeTrend(SteadyTrendQueryParam param) {
|
||||
SteadyTrendQueryParam summaryParam = copyParam(param);
|
||||
summaryParam.setBucket(null);
|
||||
SteadyTrendQueryVO trend = queryTrendInternal(summaryParam, false);
|
||||
SteadyTrendSummaryVO result = new SteadyTrendSummaryVO();
|
||||
for (SteadyTrendSeriesVO series : trend.getSeries()) {
|
||||
result.getItems().add(buildSummaryItem(series));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private SteadyTrendQueryVO queryTrendInternal(SteadyTrendQueryParam param, boolean autoBucket) {
|
||||
LocalDateTime startTime = fieldResolver.parseRequiredTime(param == null ? null : param.getTimeStart(), "开始时间不能为空");
|
||||
LocalDateTime endTime = fieldResolver.parseRequiredTime(param == null ? null : param.getTimeEnd(), "结束时间不能为空");
|
||||
List<SteadyTrendResolvedFieldBO> fields = fieldResolver.resolveFields(param);
|
||||
enrichLineNames(fields);
|
||||
String bucket = autoBucket ? resolveBucket(param.getBucket(), startTime, endTime) : null;
|
||||
|
||||
SteadyTrendQueryVO result = new SteadyTrendQueryVO();
|
||||
result.setBucket(bucket);
|
||||
result.setSampled(bucket != null);
|
||||
result.setLoadableDays(resolveLoadableDays(startTime, endTime));
|
||||
int displayPointCount = 0;
|
||||
for (SteadyTrendResolvedFieldBO field : fields) {
|
||||
List<SteadyTrendPointVO> points = influxQueryComponent.queryTrendPoints(field, startTime, endTime, bucket, param.getQualityFlag());
|
||||
displayPointCount += points.size();
|
||||
result.getSeries().add(buildSeries(field, points));
|
||||
}
|
||||
/*
|
||||
* 当前 Influx 查询按曲线独立执行,未额外发 count 查询;sourcePointCount 保持与实际返回点数一致。
|
||||
* 后续如需要精确原始点数,可单独增加 count(field) 查询。
|
||||
*/
|
||||
result.setDisplayPointCount(displayPointCount);
|
||||
result.setSourcePointCount(displayPointCount);
|
||||
return result;
|
||||
}
|
||||
|
||||
private SteadyTrendSeriesVO buildSeries(SteadyTrendResolvedFieldBO field, List<SteadyTrendPointVO> points) {
|
||||
SteadyTrendSeriesVO series = new SteadyTrendSeriesVO();
|
||||
series.setSeriesKey(field.getSeriesKey());
|
||||
series.setLineId(field.getLineId());
|
||||
series.setLineName(field.getLineName());
|
||||
series.setIndicatorCode(field.getIndicatorCode());
|
||||
series.setIndicatorName(field.getIndicatorName());
|
||||
series.setSeriesName(field.getSeriesName());
|
||||
series.setPhase(field.getPhase());
|
||||
series.setStatType(field.getStatType());
|
||||
series.setUnit(field.getUnit());
|
||||
series.setPoints(points);
|
||||
return series;
|
||||
}
|
||||
|
||||
private void enrichLineNames(List<SteadyTrendResolvedFieldBO> fields) {
|
||||
List<String> lineIds = new ArrayList<String>();
|
||||
for (SteadyTrendResolvedFieldBO field : fields) {
|
||||
if (!lineIds.contains(field.getLineId())) {
|
||||
lineIds.add(field.getLineId());
|
||||
}
|
||||
}
|
||||
Map<String, AddLedgerLinePathVO> linePathMap = addLedgerService.listLinePathByLineIds(lineIds);
|
||||
for (SteadyTrendResolvedFieldBO field : fields) {
|
||||
AddLedgerLinePathVO linePath = linePathMap.get(field.getLineId());
|
||||
field.setLineName(linePath == null || trimToNull(linePath.getLineName()) == null ? EMPTY_TEXT : linePath.getLineName());
|
||||
}
|
||||
}
|
||||
|
||||
private SteadyTrendSummaryItemVO buildSummaryItem(SteadyTrendSeriesVO series) {
|
||||
SteadyTrendSummaryItemVO item = new SteadyTrendSummaryItemVO();
|
||||
item.setSeriesKey(series.getSeriesKey());
|
||||
List<BigDecimal> values = new ArrayList<BigDecimal>();
|
||||
for (SteadyTrendPointVO point : series.getPoints()) {
|
||||
if (point.getValue() != null) {
|
||||
values.add(point.getValue());
|
||||
}
|
||||
}
|
||||
if (values.isEmpty()) {
|
||||
return item;
|
||||
}
|
||||
values.sort(Comparator.naturalOrder());
|
||||
BigDecimal sum = BigDecimal.ZERO;
|
||||
for (BigDecimal value : values) {
|
||||
sum = sum.add(value);
|
||||
}
|
||||
item.setMin(values.get(0));
|
||||
item.setMax(values.get(values.size() - 1));
|
||||
item.setAvg(sum.divide(new BigDecimal(values.size()), 6, RoundingMode.HALF_UP));
|
||||
int cp95Index = Math.max(0, (int) Math.ceil(values.size() * 0.95D) - 1);
|
||||
item.setCp95(values.get(cp95Index));
|
||||
return item;
|
||||
}
|
||||
|
||||
private String resolveBucket(String requestBucket, LocalDateTime startTime, LocalDateTime endTime) {
|
||||
String bucket = trimToNull(requestBucket);
|
||||
if (bucket != null) {
|
||||
if (!bucket.matches("^[1-9][0-9]*(m|h|d)$")) {
|
||||
throw fail("分桶粒度仅支持 m、h、d,例如 10m、1h");
|
||||
}
|
||||
return bucket;
|
||||
}
|
||||
long hours = ChronoUnit.HOURS.between(startTime, endTime);
|
||||
if (hours < 6) {
|
||||
return "1m";
|
||||
}
|
||||
if (hours <= 24) {
|
||||
return "10m";
|
||||
}
|
||||
if (hours <= 24 * 7) {
|
||||
return "30m";
|
||||
}
|
||||
return "1h";
|
||||
}
|
||||
|
||||
private List<String> resolveLoadableDays(LocalDateTime startTime, LocalDateTime endTime) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
LocalDate date = startTime.toLocalDate();
|
||||
LocalDate endDate = endTime.toLocalDate();
|
||||
while (!date.isAfter(endDate)) {
|
||||
result.add(date.toString());
|
||||
date = date.plusDays(1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private SteadyTrendQueryParam copyParam(SteadyTrendQueryParam source) {
|
||||
SteadyTrendQueryParam target = new SteadyTrendQueryParam();
|
||||
if (source == null) {
|
||||
return target;
|
||||
}
|
||||
target.setLineIds(copyList(source.getLineIds()));
|
||||
target.setIndicatorCodes(copyList(source.getIndicatorCodes()));
|
||||
target.setStatTypes(copyList(source.getStatTypes()));
|
||||
target.setPhases(copyList(source.getPhases()));
|
||||
target.setTimeStart(source.getTimeStart());
|
||||
target.setTimeEnd(source.getTimeEnd());
|
||||
target.setBucket(source.getBucket());
|
||||
target.setQualityFlag(source.getQualityFlag());
|
||||
target.setHarmonicOrders(source.getHarmonicOrders() == null ? Collections.<Integer>emptyList() : new ArrayList<Integer>(source.getHarmonicOrders()));
|
||||
return target;
|
||||
}
|
||||
|
||||
private List<String> copyList(List<String> source) {
|
||||
return source == null ? new ArrayList<String>() : new ArrayList<String>(source);
|
||||
}
|
||||
|
||||
private String trimToNull(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.isEmpty() ? null : trimmed;
|
||||
}
|
||||
|
||||
private BusinessException fail(String message) {
|
||||
return new BusinessException(CommonResponseEnum.FAIL, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.njcn.gather.steady.datavie.component;
|
||||
|
||||
import com.njcn.gather.steady.datavie.config.SteadyInfluxDbProperties;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* InfluxQL 查询语句生成测试。
|
||||
*/
|
||||
class SteadyInfluxQueryComponentTest {
|
||||
|
||||
@Test
|
||||
void shouldBuildBucketedTrendQueryWithRequiredTags() {
|
||||
SteadyInfluxQueryComponent component = new SteadyInfluxQueryComponent(new SteadyInfluxDbProperties());
|
||||
SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
|
||||
field.setMeasurement("data_v");
|
||||
field.setField("RMS_CP95");
|
||||
field.setLineId("line-001");
|
||||
field.setPhase("A");
|
||||
|
||||
String query = component.buildTrendQuery(field,
|
||||
LocalDateTime.of(2026, 5, 1, 0, 0, 0),
|
||||
LocalDateTime.of(2026, 5, 1, 1, 0, 0),
|
||||
"10m",
|
||||
1);
|
||||
|
||||
Assertions.assertEquals("SELECT mean(\"RMS_CP95\") AS \"value\" FROM \"data_v\" WHERE time >= '2026-05-01T00:00:00Z' AND time <= '2026-05-01T01:00:00Z' AND \"LINEID\" = 'line-001' AND \"PHASIC_TYPE\" = 'A' AND \"QUALITYFLAG\" = '1' GROUP BY time(10m) fill(none)", query);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldEscapeTagValuesInTrendQuery() {
|
||||
SteadyInfluxQueryComponent component = new SteadyInfluxQueryComponent(new SteadyInfluxDbProperties());
|
||||
SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
|
||||
field.setMeasurement("data_v");
|
||||
field.setField("RMS");
|
||||
field.setLineId("line'001");
|
||||
field.setPhase("A");
|
||||
|
||||
String query = component.buildTrendQuery(field,
|
||||
LocalDateTime.of(2026, 5, 1, 0, 0, 0),
|
||||
LocalDateTime.of(2026, 5, 1, 1, 0, 0),
|
||||
null,
|
||||
null);
|
||||
|
||||
Assertions.assertTrue(query.contains("\"LINEID\" = 'line\\'001'"));
|
||||
Assertions.assertFalse(query.contains("GROUP BY time"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.njcn.gather.steady.datavie.component;
|
||||
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
||||
import com.njcn.gather.steady.datavie.pojo.param.SteadyTrendQueryParam;
|
||||
import com.njcn.gather.tool.adddata.component.AddDataTableRegistry;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势字段解析测试。
|
||||
*/
|
||||
class SteadyTrendFieldResolverTest {
|
||||
|
||||
private SteadyTrendFieldResolver resolver;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
AddDataTableRegistry tableRegistry = new AddDataTableRegistry();
|
||||
tableRegistry.afterPropertiesSet();
|
||||
resolver = new SteadyTrendFieldResolver(new SteadyTrendIndicatorCatalog(), tableRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveVoltageRmsAverageAndCp95Fields() {
|
||||
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
||||
param.setLineIds(Arrays.asList("line-001"));
|
||||
param.setIndicatorCodes(Arrays.asList("V_RMS"));
|
||||
param.setPhases(Arrays.asList("A"));
|
||||
param.setStatTypes(Arrays.asList("AVG", "CP95"));
|
||||
param.setTimeStart("2026-05-01 00:00:00");
|
||||
param.setTimeEnd("2026-05-01 01:00:00");
|
||||
|
||||
List<SteadyTrendResolvedFieldBO> fields = resolver.resolveFields(param);
|
||||
|
||||
Assertions.assertEquals(2, fields.size());
|
||||
Assertions.assertEquals("data_v", fields.get(0).getMeasurement());
|
||||
Assertions.assertEquals("RMS", fields.get(0).getField());
|
||||
Assertions.assertEquals("AVG", fields.get(0).getStatType());
|
||||
Assertions.assertEquals("RMS_CP95", fields.get(1).getField());
|
||||
Assertions.assertEquals("V", fields.get(1).getUnit());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExpandLineVoltageTotalPhaseToThreeSeries() {
|
||||
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
||||
param.setLineIds(Arrays.asList("line-001"));
|
||||
param.setIndicatorCodes(Arrays.asList("V_LINE_RMS"));
|
||||
param.setPhases(Arrays.asList("T"));
|
||||
param.setStatTypes(Arrays.asList("AVG"));
|
||||
param.setTimeStart("2026-05-01 00:00:00");
|
||||
param.setTimeEnd("2026-05-01 01:00:00");
|
||||
|
||||
List<SteadyTrendResolvedFieldBO> fields = resolver.resolveFields(param);
|
||||
|
||||
Assertions.assertEquals(3, fields.size());
|
||||
Assertions.assertEquals("RMSAB", fields.get(0).getField());
|
||||
Assertions.assertEquals("RMSBC", fields.get(1).getField());
|
||||
Assertions.assertEquals("RMSCA", fields.get(2).getField());
|
||||
Assertions.assertEquals("T", fields.get(0).getPhase());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectHarmonicTrendWithoutOrders() {
|
||||
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
||||
param.setLineIds(Arrays.asList("line-001"));
|
||||
param.setIndicatorCodes(Arrays.asList("V_HARMONIC"));
|
||||
param.setPhases(Arrays.asList("A"));
|
||||
param.setStatTypes(Arrays.asList("AVG"));
|
||||
param.setTimeStart("2026-05-01 00:00:00");
|
||||
param.setTimeEnd("2026-05-01 01:00:00");
|
||||
|
||||
BusinessException exception = Assertions.assertThrows(BusinessException.class, () -> resolver.resolveFields(param));
|
||||
|
||||
Assertions.assertTrue(exception.getMessage().contains("谐波次数不能为空"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveSelectedHarmonicOrdersOnly() {
|
||||
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
||||
param.setLineIds(Arrays.asList("line-001"));
|
||||
param.setIndicatorCodes(Arrays.asList("V_HARMONIC"));
|
||||
param.setPhases(Arrays.asList("A"));
|
||||
param.setStatTypes(Arrays.asList("MAX"));
|
||||
param.setHarmonicOrders(Arrays.asList(3, 5));
|
||||
param.setTimeStart("2026-05-01 00:00:00");
|
||||
param.setTimeEnd("2026-05-01 01:00:00");
|
||||
|
||||
List<SteadyTrendResolvedFieldBO> fields = resolver.resolveFields(param);
|
||||
|
||||
Assertions.assertEquals(2, fields.size());
|
||||
Assertions.assertEquals("V_3_MAX", fields.get(0).getField());
|
||||
Assertions.assertEquals("V_5_MAX", fields.get(1).getField());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.njcn.gather.steady.datavie.service.impl;
|
||||
|
||||
import com.njcn.gather.steady.datavie.component.SteadyTrendIndicatorCatalog;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyDataViewIndicatorNodeVO;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 稳态趋势指标服务测试。
|
||||
*/
|
||||
class SteadyDataViewIndicatorServiceImplTest {
|
||||
|
||||
@Test
|
||||
void shouldGroupIndicatorsByCategory() {
|
||||
SteadyDataViewIndicatorServiceImpl service = new SteadyDataViewIndicatorServiceImpl(new SteadyTrendIndicatorCatalog());
|
||||
|
||||
List<SteadyDataViewIndicatorNodeVO> tree = service.listIndicatorTree();
|
||||
|
||||
Assertions.assertEquals(5, tree.size());
|
||||
Assertions.assertEquals("VOLTAGE", tree.get(0).getGroupCode());
|
||||
Assertions.assertTrue(tree.get(0).getChildren().size() >= 2);
|
||||
Assertions.assertEquals("V_RMS", tree.get(0).getChildren().get(0).getIndicatorCode());
|
||||
Assertions.assertTrue(tree.get(0).getChildren().get(0).getSelectable());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.njcn.gather.steady.datavie.service.impl;
|
||||
|
||||
import com.njcn.gather.steady.datavie.component.SteadyInfluxQueryComponent;
|
||||
import com.njcn.gather.steady.datavie.component.SteadyTrendFieldResolver;
|
||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
||||
import com.njcn.gather.steady.datavie.pojo.param.SteadyTrendQueryParam;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendPointVO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendQueryVO;
|
||||
import com.njcn.gather.steady.datavie.pojo.vo.SteadyTrendSummaryVO;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
|
||||
import com.njcn.gather.tool.addledger.service.AddLedgerService;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 稳态趋势服务编排测试。
|
||||
*/
|
||||
class SteadyDataViewTrendServiceImplTest {
|
||||
|
||||
@Test
|
||||
void shouldBuildTrendQueryWithDefaultBucketAndLineName() {
|
||||
SteadyTrendFieldResolver fieldResolver = Mockito.mock(SteadyTrendFieldResolver.class);
|
||||
SteadyInfluxQueryComponent influxQueryComponent = Mockito.mock(SteadyInfluxQueryComponent.class);
|
||||
AddLedgerService addLedgerService = Mockito.mock(AddLedgerService.class);
|
||||
|
||||
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
||||
param.setLineIds(Arrays.asList("line-001"));
|
||||
param.setIndicatorCodes(Arrays.asList("V_RMS"));
|
||||
param.setPhases(Arrays.asList("A"));
|
||||
param.setStatTypes(Arrays.asList("AVG"));
|
||||
param.setTimeStart("2026-05-01 00:00:00");
|
||||
param.setTimeEnd("2026-05-01 05:59:59");
|
||||
|
||||
SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
|
||||
field.setMeasurement("data_v");
|
||||
field.setField("RMS");
|
||||
field.setLineId("line-001");
|
||||
field.setIndicatorCode("V_RMS");
|
||||
field.setIndicatorName("相电压有效值");
|
||||
field.setSeriesName("相电压有效值");
|
||||
field.setPhase("A");
|
||||
field.setStatType("AVG");
|
||||
field.setUnit("V");
|
||||
field.setSeriesKey("line-001|V_RMS|A|AVG|RMS");
|
||||
|
||||
Mockito.when(fieldResolver.parseRequiredTime("2026-05-01 00:00:00", "开始时间不能为空"))
|
||||
.thenReturn(LocalDateTime.of(2026, 5, 1, 0, 0, 0));
|
||||
Mockito.when(fieldResolver.parseRequiredTime("2026-05-01 05:59:59", "结束时间不能为空"))
|
||||
.thenReturn(LocalDateTime.of(2026, 5, 1, 5, 59, 59));
|
||||
Mockito.when(fieldResolver.resolveFields(Mockito.any())).thenReturn(Collections.singletonList(field));
|
||||
Mockito.when(addLedgerService.listLinePathByLineIds(Collections.singletonList("line-001")))
|
||||
.thenReturn(Collections.singletonMap("line-001", buildLinePath("进线一")));
|
||||
Mockito.when(influxQueryComponent.queryTrendPoints(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.eq("1m"), Mockito.isNull()))
|
||||
.thenReturn(Collections.singletonList(new SteadyTrendPointVO("2026-05-01 00:00:00", new BigDecimal("1.2"))));
|
||||
|
||||
SteadyDataViewTrendServiceImpl service = new SteadyDataViewTrendServiceImpl(fieldResolver, influxQueryComponent, addLedgerService);
|
||||
SteadyTrendQueryVO result = service.queryTrend(param);
|
||||
|
||||
Assertions.assertEquals("1m", result.getBucket());
|
||||
Assertions.assertTrue(result.getSampled());
|
||||
Assertions.assertEquals("进线一", result.getSeries().get(0).getLineName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCalculateTrendSummaryFromSeriesPoints() {
|
||||
SteadyTrendFieldResolver fieldResolver = Mockito.mock(SteadyTrendFieldResolver.class);
|
||||
SteadyInfluxQueryComponent influxQueryComponent = Mockito.mock(SteadyInfluxQueryComponent.class);
|
||||
AddLedgerService addLedgerService = Mockito.mock(AddLedgerService.class);
|
||||
|
||||
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
||||
param.setLineIds(Arrays.asList("line-001"));
|
||||
param.setIndicatorCodes(Arrays.asList("V_RMS"));
|
||||
param.setPhases(Arrays.asList("A"));
|
||||
param.setStatTypes(Arrays.asList("AVG"));
|
||||
param.setTimeStart("2026-05-01 00:00:00");
|
||||
param.setTimeEnd("2026-05-01 05:59:59");
|
||||
|
||||
SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
|
||||
field.setMeasurement("data_v");
|
||||
field.setField("RMS");
|
||||
field.setLineId("line-001");
|
||||
field.setIndicatorCode("V_RMS");
|
||||
field.setIndicatorName("相电压有效值");
|
||||
field.setSeriesName("相电压有效值");
|
||||
field.setPhase("A");
|
||||
field.setStatType("AVG");
|
||||
field.setUnit("V");
|
||||
field.setSeriesKey("line-001|V_RMS|A|AVG|RMS");
|
||||
|
||||
Mockito.when(fieldResolver.parseRequiredTime(Mockito.anyString(), Mockito.anyString()))
|
||||
.thenReturn(LocalDateTime.of(2026, 5, 1, 0, 0, 0))
|
||||
.thenReturn(LocalDateTime.of(2026, 5, 1, 5, 59, 59));
|
||||
Mockito.when(fieldResolver.resolveFields(param)).thenReturn(Collections.singletonList(field));
|
||||
Mockito.when(addLedgerService.listLinePathByLineIds(Collections.singletonList("line-001")))
|
||||
.thenReturn(Collections.<String, AddLedgerLinePathVO>emptyMap());
|
||||
Mockito.when(influxQueryComponent.queryTrendPoints(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.isNull(), Mockito.isNull()))
|
||||
.thenReturn(Arrays.asList(
|
||||
new SteadyTrendPointVO("2026-05-01 00:00:00", new BigDecimal("1")),
|
||||
new SteadyTrendPointVO("2026-05-01 01:00:00", new BigDecimal("3")),
|
||||
new SteadyTrendPointVO("2026-05-01 02:00:00", new BigDecimal("2"))
|
||||
));
|
||||
|
||||
SteadyDataViewTrendServiceImpl service = new SteadyDataViewTrendServiceImpl(fieldResolver, influxQueryComponent, addLedgerService);
|
||||
SteadyTrendSummaryVO summary = service.summarizeTrend(param);
|
||||
|
||||
Assertions.assertEquals(new BigDecimal("3"), summary.getItems().get(0).getMax());
|
||||
Assertions.assertEquals(new BigDecimal("1"), summary.getItems().get(0).getMin());
|
||||
Assertions.assertEquals(new BigDecimal("2.000000"), summary.getItems().get(0).getAvg());
|
||||
Assertions.assertEquals(new BigDecimal("3"), summary.getItems().get(0).getCp95());
|
||||
}
|
||||
|
||||
private AddLedgerLinePathVO buildLinePath(String lineName) {
|
||||
AddLedgerLinePathVO linePathVO = new AddLedgerLinePathVO();
|
||||
linePathVO.setLineName(lineName);
|
||||
return linePathVO;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,10 @@ package com.njcn.gather.system.dictionary.pojo.enums;
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import static com.njcn.gather.system.pojo.constant.DictConst.REG_RES_CONTRAST_CODE;
|
||||
import static com.njcn.gather.system.pojo.constant.DictConst.REG_RES_DIGITAL_CODE;
|
||||
import static com.njcn.gather.system.pojo.constant.DictConst.REG_RES_SIMULATE_CODE;
|
||||
|
||||
/**
|
||||
* @author caozehui
|
||||
* @data 2024-12-12
|
||||
@@ -14,9 +18,9 @@ public enum DictDataEnum {
|
||||
* Key cleanup point: only keep registration-related platform capability
|
||||
* types that are still referenced by the retained activation flow.
|
||||
*/
|
||||
DIGITAL("数字式", "Digital"),
|
||||
SIMULATE("模拟式", "Simulate"),
|
||||
CONTRAST("比对式", "Contrast");
|
||||
DIGITAL("数字式", REG_RES_DIGITAL_CODE),
|
||||
SIMULATE("模拟式", REG_RES_SIMULATE_CODE),
|
||||
CONTRAST("比对式", REG_RES_CONTRAST_CODE);
|
||||
|
||||
private final String name;
|
||||
private final String code;
|
||||
|
||||
@@ -18,4 +18,24 @@ public interface DictConst {
|
||||
* 顶层父类的pid
|
||||
*/
|
||||
String FATHER_ID = "0";
|
||||
|
||||
/**
|
||||
* 注册资源字典数据编码:数字式
|
||||
*/
|
||||
String REG_RES_DIGITAL_CODE = "Digital";
|
||||
|
||||
/**
|
||||
* 注册资源字典数据编码:模拟式
|
||||
*/
|
||||
String REG_RES_SIMULATE_CODE = "Simulate";
|
||||
|
||||
/**
|
||||
* 注册资源字典数据编码:比对式
|
||||
*/
|
||||
String REG_RES_CONTRAST_CODE = "Contrast";
|
||||
|
||||
/**
|
||||
* 注册资源字典数据 ID:比对式
|
||||
*/
|
||||
String REG_RES_CONTRAST_ID = "7cd65363a6bf675ae408f28a281b77d4";
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.njcn.gather.system.cfg.service.ISysTestConfigService;
|
||||
import com.njcn.gather.system.dictionary.pojo.enums.DictDataEnum;
|
||||
import com.njcn.gather.system.dictionary.pojo.po.DictData;
|
||||
import com.njcn.gather.system.dictionary.service.IDictDataService;
|
||||
import com.njcn.gather.system.pojo.constant.DictConst;
|
||||
import com.njcn.gather.system.pojo.enums.SystemResponseEnum;
|
||||
import com.njcn.gather.system.reg.mapper.SysRegResMapper;
|
||||
import com.njcn.gather.system.reg.pojo.dto.RegInfoData;
|
||||
@@ -214,7 +215,7 @@ public class SysRegResServiceImpl extends ServiceImpl<SysRegResMapper, SysRegRes
|
||||
|
||||
@Override
|
||||
public SysRegRes getContrastRegRes() {
|
||||
return this.getRegResByType("7cd65363a6bf675ae408f28a281b77d4");
|
||||
return this.getRegResByType(DictConst.REG_RES_CONTRAST_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
|
||||
- `activate-tool`
|
||||
- `add-data`
|
||||
- `add-ledger`
|
||||
- `mms-mapping`
|
||||
- `wave-tool`
|
||||
|
||||
因此,`tools` 现阶段仍然是聚合模块,但当前已实际承载激活工具、电能质量数据补录工具、ICD/MMS 映射工具和波形查看工具四个子模块。
|
||||
因此,`tools` 现阶段仍然是聚合模块,但当前已实际承载激活工具、电能质量数据补录工具、数据台账工具空模块、ICD/MMS 映射工具和波形查看工具五个子模块。
|
||||
|
||||
## 当前结构
|
||||
|
||||
@@ -19,6 +20,7 @@
|
||||
tools/
|
||||
├── activate-tool/
|
||||
├── add-data/
|
||||
├── add-ledger/
|
||||
├── mms-mapping/
|
||||
└── wave-tool/
|
||||
```
|
||||
@@ -37,6 +39,12 @@ tools/
|
||||
|
||||
模块内部已按职责拆分 `controller`、`service`、`service/impl`、`component`、`pojo`、`config` 和 `util`,并通过 `JdbcTemplate + INSERT IGNORE` 执行批量补数。
|
||||
|
||||
## add-ledger 的职责
|
||||
|
||||
`add-ledger` 当前仅完成 Maven 空模块接入,后续用于承载数据台账相关能力。
|
||||
|
||||
当前未提供业务接口、Java 分层骨架、配置项或持久化逻辑。目录中的 `ledger.sql` 仅作为原始脚本保留,暂未接入运行时资源解析。
|
||||
|
||||
## activate-tool 的职责
|
||||
|
||||
`activate-tool` 当前提供的能力主要围绕设备授权与许可证:
|
||||
@@ -90,7 +98,7 @@ tools/
|
||||
|
||||
## 依赖关系
|
||||
|
||||
`tools/activate-tool`、`tools/add-data`、`tools/mms-mapping` 与 `tools/wave-tool` 当前主要依赖:
|
||||
`tools/activate-tool`、`tools/add-data`、`tools/add-ledger`、`tools/mms-mapping` 与 `tools/wave-tool` 当前主要依赖:
|
||||
|
||||
- `com.njcn:njcn-common`
|
||||
- `com.njcn:spingboot2.3.12`
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
- 独立任务持久化表
|
||||
- 前端页面代码
|
||||
|
||||
目录中保留历史 SQL 脚本 `DATA_FLICKER.sql`,并同步复制到 `src/main/resources/sql/add-data` 供运行时解析表字段元数据。
|
||||
SQL 元数据脚本位于 `src/main/resources/sql/add-data/DATA_FLICKER.sql`,供运行时解析表字段元数据。
|
||||
|
||||
## 当前结构
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
add-data/
|
||||
├── pom.xml
|
||||
├── README.md
|
||||
├── DATA_FLICKER.sql
|
||||
└── src/main/java/com/njcn/gather/tool/adddata/
|
||||
├── component/
|
||||
├── config/
|
||||
|
||||
2279
tools/add-data/src/main/resources/sql/add-data/DATA_FLICKER.sql
Normal file
2279
tools/add-data/src/main/resources/sql/add-data/DATA_FLICKER.sql
Normal file
File diff suppressed because it is too large
Load Diff
67
tools/add-ledger/README.md
Normal file
67
tools/add-ledger/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# add-ledger 模块说明
|
||||
|
||||
## 模块定位
|
||||
|
||||
`add-ledger` 是 `tools` 下的数据台账配置工具模块,当前基于 `ledger.sql` 中的工程、项目、设备、监测点和台账树表结构,提供后端配置接口。
|
||||
|
||||
本次范围不包含:
|
||||
|
||||
- 前端真实页面代码
|
||||
- 自动执行 SQL 初始化
|
||||
- 自动数据库迁移
|
||||
- 设备通信、WebSocket 或 Netty 链路改造
|
||||
|
||||
目录中的 `ledger.sql` 仅作为原始表结构脚本保留,当前模块不加载、不解析该脚本。
|
||||
|
||||
## 当前结构
|
||||
|
||||
```text
|
||||
add-ledger/
|
||||
├── ledger.sql
|
||||
├── pom.xml
|
||||
├── README.md
|
||||
├── src/main/java/com/njcn/gather/tool/addledger/
|
||||
│ ├── component/
|
||||
│ ├── config/
|
||||
│ ├── controller/
|
||||
│ ├── mapper/
|
||||
│ ├── pojo/
|
||||
│ ├── service/
|
||||
│ └── util/
|
||||
└── src/main/resources/sql/add-ledger/
|
||||
```
|
||||
|
||||
## 当前接口
|
||||
|
||||
完整调试说明见 [API_DEBUG.md](./API_DEBUG.md)。
|
||||
|
||||
- `GET /addLedger/tree`
|
||||
- 查询台账树,支持按节点名称关键字过滤。
|
||||
- `GET /addLedger/detail`
|
||||
- 根据 `id` 和 `level` 查询工程、项目、设备或测点详情。
|
||||
- `POST /addLedger/engineering/save`
|
||||
- 新增或保存工程,并同步 `cs_ledger` 工程节点。
|
||||
- `POST /addLedger/project/save`
|
||||
- 新增或保存项目,并同步 `cs_ledger` 项目节点。
|
||||
- `POST /addLedger/equipment/save`
|
||||
- 新增或保存设备,并同步 `cs_ledger` 设备节点。
|
||||
- `POST /addLedger/line/save`
|
||||
- 新增或保存测点,并同步 `cs_ledger` 测点节点。
|
||||
- `GET /addLedger/line/availableLineNos`
|
||||
- 查询设备下 `1-20` 中可用的线路号。
|
||||
- `DELETE /addLedger/node`
|
||||
- 软删除指定节点,父节点会级联软删除下级业务数据和台账节点。
|
||||
|
||||
## 实现说明
|
||||
|
||||
- 台账层级固定为:工程 -> 项目 -> 设备 -> 监测点。
|
||||
- 新增时绑定父级节点;编辑时只更新当前业务数据和台账节点名称,不搬迁节点。
|
||||
- 保存业务表和 `cs_ledger` 在同一事务内完成。
|
||||
- 设备保存时同步 `associated_engineering` 和 `associated_project`。
|
||||
- 测点新增时生成 32 位 UUID 作为 `line_id`。
|
||||
- 测点 `line_no` 后端限制为 `1-20`,且同设备下正常测点不可重复。
|
||||
- 删除采用软删除:工程、项目、测点更新 `status=0`,设备更新 `run_status=0`,台账节点更新 `State=0`。
|
||||
|
||||
## 后续扩展约束
|
||||
|
||||
后续如果新增更多台账能力,应沿当前 `controller -> service -> mapper -> XML` 职责边界扩展,不回退为单一大类承载全部接口。
|
||||
39
tools/add-ledger/pom.xml
Normal file
39
tools/add-ledger/pom.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.njcn.gather</groupId>
|
||||
<artifactId>tools</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>add-ledger</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>njcn-common</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>mybatis-plus</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.njcn</groupId>
|
||||
<artifactId>spingboot2.3.12</artifactId>
|
||||
<version>2.3.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.njcn.gather.tool.addledger.component;
|
||||
|
||||
import com.njcn.gather.tool.addledger.pojo.constant.AddLedgerConst;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerLedgerPO;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerTreeNodeVO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据台账树组装器。
|
||||
*/
|
||||
@Component
|
||||
public class AddLedgerTreeBuilder {
|
||||
|
||||
public List<AddLedgerTreeNodeVO> buildTree(List<AddLedgerLedgerPO> ledgers) {
|
||||
Map<String, AddLedgerTreeNodeVO> nodeMap = new LinkedHashMap<String, AddLedgerTreeNodeVO>();
|
||||
if (ledgers == null || ledgers.isEmpty()) {
|
||||
return new ArrayList<AddLedgerTreeNodeVO>();
|
||||
}
|
||||
for (AddLedgerLedgerPO ledger : ledgers) {
|
||||
AddLedgerTreeNodeVO node = new AddLedgerTreeNodeVO();
|
||||
node.setId(ledger.getId());
|
||||
node.setParentId(ledger.getPid());
|
||||
node.setParentIds(ledger.getPids());
|
||||
node.setName(ledger.getName());
|
||||
node.setLevel(ledger.getLevel());
|
||||
node.setSort(ledger.getSort());
|
||||
nodeMap.put(node.getId(), node);
|
||||
}
|
||||
List<AddLedgerTreeNodeVO> roots = new ArrayList<AddLedgerTreeNodeVO>();
|
||||
for (AddLedgerTreeNodeVO node : nodeMap.values()) {
|
||||
AddLedgerTreeNodeVO parent = nodeMap.get(node.getParentId());
|
||||
if (parent == null || AddLedgerConst.ROOT_PARENT_ID.equals(node.getParentId())) {
|
||||
roots.add(node);
|
||||
} else {
|
||||
parent.getChildren().add(node);
|
||||
}
|
||||
}
|
||||
sortTree(roots);
|
||||
return roots;
|
||||
}
|
||||
|
||||
private void sortTree(List<AddLedgerTreeNodeVO> nodes) {
|
||||
nodes.sort(Comparator.comparing(AddLedgerTreeNodeVO::getSort, Comparator.nullsLast(Integer::compareTo))
|
||||
.thenComparing(AddLedgerTreeNodeVO::getName, Comparator.nullsLast(String::compareTo)));
|
||||
for (AddLedgerTreeNodeVO node : nodes) {
|
||||
sortTree(node.getChildren());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.njcn.gather.tool.addledger.config;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 数据台账 Mapper 扫描配置。
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan("com.njcn.gather.tool.addledger.mapper")
|
||||
public class AddLedgerMapperConfig {
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.njcn.gather.tool.addledger.controller;
|
||||
|
||||
import com.njcn.common.pojo.annotation.OperateInfo;
|
||||
import com.njcn.common.pojo.constant.OperateType;
|
||||
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.addledger.pojo.param.AddLedgerEngineeringSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEquipmentSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLineSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerProjectSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerDetailVO;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerTreeNodeVO;
|
||||
import com.njcn.gather.tool.addledger.service.AddLedgerService;
|
||||
import com.njcn.web.controller.BaseController;
|
||||
import com.njcn.web.utils.HttpResultUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 数据台账配置接口。
|
||||
*/
|
||||
@Validated
|
||||
@Slf4j
|
||||
@Api(tags = "数据台账配置")
|
||||
@RestController
|
||||
@RequestMapping("/addLedger")
|
||||
@RequiredArgsConstructor
|
||||
public class AddLedgerController extends BaseController {
|
||||
|
||||
private final AddLedgerService addLedgerService;
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询台账树")
|
||||
@GetMapping("/tree")
|
||||
public HttpResult<List<AddLedgerTreeNodeVO>> tree(@RequestParam(value = "keyword", required = false) String keyword) {
|
||||
String methodDescribe = getMethodDescribe("tree");
|
||||
LogUtil.njcnDebug(log, "{},开始查询台账树,keyword={}", methodDescribe, keyword);
|
||||
List<AddLedgerTreeNodeVO> result = addLedgerService.tree(keyword);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询台账节点详情")
|
||||
@GetMapping("/detail")
|
||||
public HttpResult<AddLedgerDetailVO> detail(@RequestParam("id") String id, @RequestParam("level") Integer level) {
|
||||
String methodDescribe = getMethodDescribe("detail");
|
||||
LogUtil.njcnDebug(log, "{},开始查询台账节点详情,id={}, level={}", methodDescribe, id, level);
|
||||
AddLedgerDetailVO result = addLedgerService.detail(id, level);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.ADD)
|
||||
@ApiOperation("新增或保存工程")
|
||||
@PostMapping("/engineering/save")
|
||||
public HttpResult<AddLedgerDetailVO> saveEngineering(@RequestBody @Validated AddLedgerEngineeringSaveParam param) {
|
||||
String methodDescribe = getMethodDescribe("saveEngineering");
|
||||
LogUtil.njcnDebug(log, "{},开始保存工程,id={}", methodDescribe, param.getId());
|
||||
AddLedgerDetailVO result = addLedgerService.saveEngineering(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.ADD)
|
||||
@ApiOperation("新增或保存项目")
|
||||
@PostMapping("/project/save")
|
||||
public HttpResult<AddLedgerDetailVO> saveProject(@RequestBody @Validated AddLedgerProjectSaveParam param) {
|
||||
String methodDescribe = getMethodDescribe("saveProject");
|
||||
LogUtil.njcnDebug(log, "{},开始保存项目,id={}", methodDescribe, param.getId());
|
||||
AddLedgerDetailVO result = addLedgerService.saveProject(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.ADD)
|
||||
@ApiOperation("新增或保存设备")
|
||||
@PostMapping("/equipment/save")
|
||||
public HttpResult<AddLedgerDetailVO> saveEquipment(@RequestBody @Validated AddLedgerEquipmentSaveParam param) {
|
||||
String methodDescribe = getMethodDescribe("saveEquipment");
|
||||
LogUtil.njcnDebug(log, "{},开始保存设备,id={}", methodDescribe, param.getId());
|
||||
AddLedgerDetailVO result = addLedgerService.saveEquipment(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.ADD)
|
||||
@ApiOperation("新增或保存测点")
|
||||
@PostMapping("/line/save")
|
||||
public HttpResult<AddLedgerDetailVO> saveLine(@RequestBody @Validated AddLedgerLineSaveParam param) {
|
||||
String methodDescribe = getMethodDescribe("saveLine");
|
||||
LogUtil.njcnDebug(log, "{},开始保存测点,lineId={}", methodDescribe, param.getLineId());
|
||||
AddLedgerDetailVO result = addLedgerService.saveLine(param);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON)
|
||||
@ApiOperation("查询设备可用线路号")
|
||||
@GetMapping("/line/availableLineNos")
|
||||
public HttpResult<List<Integer>> availableLineNos(@RequestParam("deviceId") String deviceId,
|
||||
@RequestParam(value = "lineId", required = false) String lineId) {
|
||||
String methodDescribe = getMethodDescribe("availableLineNos");
|
||||
LogUtil.njcnDebug(log, "{},开始查询可用线路号,deviceId={}, lineId={}", methodDescribe, deviceId, lineId);
|
||||
List<Integer> result = addLedgerService.availableLineNos(deviceId, lineId);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
|
||||
@OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.DELETE)
|
||||
@ApiOperation("删除台账节点")
|
||||
@DeleteMapping("/node")
|
||||
public HttpResult<Boolean> deleteNode(@RequestParam("id") String id, @RequestParam("level") Integer level) {
|
||||
String methodDescribe = getMethodDescribe("deleteNode");
|
||||
LogUtil.njcnDebug(log, "{},开始删除台账节点,id={}, level={}", methodDescribe, id, level);
|
||||
boolean result = addLedgerService.deleteNode(id, level);
|
||||
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, result, methodDescribe);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.njcn.gather.tool.addledger.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerEngineeringPO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工程信息 Mapper。
|
||||
*/
|
||||
public interface AddLedgerEngineeringMapper extends BaseMapper<AddLedgerEngineeringPO> {
|
||||
|
||||
int softDeleteByIds(@Param("ids") List<String> ids, @Param("updateBy") String updateBy);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.njcn.gather.tool.addledger.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerEquipmentPO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 设备信息 Mapper。
|
||||
*/
|
||||
public interface AddLedgerEquipmentMapper extends BaseMapper<AddLedgerEquipmentPO> {
|
||||
|
||||
int softDeleteByIds(@Param("ids") List<String> ids, @Param("updateBy") String updateBy);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.njcn.gather.tool.addledger.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerLedgerPO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 台账树 Mapper。
|
||||
*/
|
||||
public interface AddLedgerLedgerMapper extends BaseMapper<AddLedgerLedgerPO> {
|
||||
|
||||
List<AddLedgerLedgerPO> selectTree(@Param("keyword") String keyword);
|
||||
|
||||
AddLedgerLedgerPO selectActiveNode(@Param("id") String id, @Param("level") Integer level);
|
||||
|
||||
List<AddLedgerLedgerPO> selectActiveSubtree(@Param("id") String id);
|
||||
|
||||
int softDeleteByIds(@Param("ids") List<String> ids, @Param("updateBy") String updateBy);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.njcn.gather.tool.addledger.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLinePathQueryParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerLinePO;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 监测点 Mapper。
|
||||
*/
|
||||
public interface AddLedgerLineMapper extends BaseMapper<AddLedgerLinePO> {
|
||||
|
||||
List<Integer> selectUsedLineNos(@Param("deviceId") String deviceId, @Param("lineId") String lineId);
|
||||
|
||||
int countActiveLineNo(@Param("deviceId") String deviceId,
|
||||
@Param("lineNo") Integer lineNo,
|
||||
@Param("lineId") String lineId);
|
||||
|
||||
List<AddLedgerLinePathVO> selectLinePathByLineIds(@Param("lineIds") List<String> lineIds);
|
||||
|
||||
List<AddLedgerLinePathVO> selectLinePathByQuery(@Param("param") AddLedgerLinePathQueryParam param);
|
||||
|
||||
int softDeleteByIds(@Param("ids") List<String> ids, @Param("updateBy") String updateBy);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.njcn.gather.tool.addledger.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerProjectPO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 项目信息 Mapper。
|
||||
*/
|
||||
public interface AddLedgerProjectMapper extends BaseMapper<AddLedgerProjectPO> {
|
||||
|
||||
int softDeleteByIds(@Param("ids") List<String> ids, @Param("updateBy") String updateBy);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.njcn.gather.tool.addledger.mapper.AddLedgerEngineeringMapper">
|
||||
|
||||
<update id="softDeleteByIds">
|
||||
UPDATE cs_engineering
|
||||
SET status = 0,
|
||||
update_by = #{updateBy},
|
||||
update_time = NOW()
|
||||
WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.njcn.gather.tool.addledger.mapper.AddLedgerEquipmentMapper">
|
||||
|
||||
<update id="softDeleteByIds">
|
||||
UPDATE cs_equipment_delivery
|
||||
SET run_status = 0,
|
||||
update_by = #{updateBy},
|
||||
update_time = NOW()
|
||||
WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.njcn.gather.tool.addledger.mapper.AddLedgerLedgerMapper">
|
||||
|
||||
<select id="selectTree" resultType="com.njcn.gather.tool.addledger.pojo.po.AddLedgerLedgerPO">
|
||||
SELECT Id AS id,
|
||||
Pid AS pid,
|
||||
Pids AS pids,
|
||||
Name AS name,
|
||||
Level AS level,
|
||||
Sort AS sort,
|
||||
Remark AS remark,
|
||||
State AS state
|
||||
FROM cs_ledger
|
||||
WHERE State = 1
|
||||
<if test="keyword != null and keyword != ''">
|
||||
AND Name LIKE CONCAT('%', #{keyword}, '%')
|
||||
</if>
|
||||
ORDER BY Level ASC, Sort ASC, Name ASC
|
||||
</select>
|
||||
|
||||
<select id="selectActiveNode" resultType="com.njcn.gather.tool.addledger.pojo.po.AddLedgerLedgerPO">
|
||||
SELECT Id AS id,
|
||||
Pid AS pid,
|
||||
Pids AS pids,
|
||||
Name AS name,
|
||||
Level AS level,
|
||||
Sort AS sort,
|
||||
Remark AS remark,
|
||||
State AS state
|
||||
FROM cs_ledger
|
||||
WHERE Id = #{id}
|
||||
AND Level = #{level}
|
||||
AND State = 1
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<select id="selectActiveSubtree" resultType="com.njcn.gather.tool.addledger.pojo.po.AddLedgerLedgerPO">
|
||||
SELECT Id AS id,
|
||||
Pid AS pid,
|
||||
Pids AS pids,
|
||||
Name AS name,
|
||||
Level AS level,
|
||||
Sort AS sort,
|
||||
Remark AS remark,
|
||||
State AS state
|
||||
FROM cs_ledger
|
||||
WHERE State = 1
|
||||
AND (Id = #{id} OR FIND_IN_SET(#{id}, Pids) > 0)
|
||||
ORDER BY Level DESC
|
||||
</select>
|
||||
|
||||
<update id="softDeleteByIds">
|
||||
UPDATE cs_ledger
|
||||
SET State = 0,
|
||||
Update_By = #{updateBy},
|
||||
Update_Time = NOW()
|
||||
WHERE Id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
AND State = 1
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.njcn.gather.tool.addledger.mapper.AddLedgerLineMapper">
|
||||
|
||||
<select id="selectUsedLineNos" resultType="java.lang.Integer">
|
||||
SELECT line_no
|
||||
FROM cs_line
|
||||
WHERE device_id = #{deviceId}
|
||||
AND status = 1
|
||||
<if test="lineId != null and lineId != ''">
|
||||
AND line_id <> #{lineId}
|
||||
</if>
|
||||
AND line_no BETWEEN 1 AND 20
|
||||
</select>
|
||||
|
||||
<select id="countActiveLineNo" resultType="java.lang.Integer">
|
||||
SELECT COUNT(1)
|
||||
FROM cs_line
|
||||
WHERE device_id = #{deviceId}
|
||||
AND line_no = #{lineNo}
|
||||
AND status = 1
|
||||
<if test="lineId != null and lineId != ''">
|
||||
AND line_id <> #{lineId}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="selectLinePathByLineIds" resultType="com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO">
|
||||
SELECT engineering.id AS engineeringId,
|
||||
engineering.name AS engineeringName,
|
||||
project.id AS projectId,
|
||||
project.name AS projectName,
|
||||
equipment.id AS equipmentId,
|
||||
equipment.name AS equipmentName,
|
||||
line.line_id AS lineId,
|
||||
line.name AS lineName
|
||||
FROM cs_line line
|
||||
INNER JOIN cs_equipment_delivery equipment ON equipment.id = line.device_id
|
||||
INNER JOIN cs_project project ON project.id = equipment.associated_project
|
||||
INNER JOIN cs_engineering engineering ON engineering.id = equipment.associated_engineering
|
||||
WHERE line.status = 1
|
||||
AND equipment.run_status <> 0
|
||||
AND project.status = 1
|
||||
AND engineering.status = 1
|
||||
AND line.line_id IN
|
||||
<foreach collection="lineIds" item="lineId" open="(" separator="," close=")">
|
||||
#{lineId}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<select id="selectLinePathByQuery" resultType="com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO">
|
||||
SELECT engineering.id AS engineeringId,
|
||||
engineering.name AS engineeringName,
|
||||
project.id AS projectId,
|
||||
project.name AS projectName,
|
||||
equipment.id AS equipmentId,
|
||||
equipment.name AS equipmentName,
|
||||
line.line_id AS lineId,
|
||||
line.name AS lineName
|
||||
FROM cs_line line
|
||||
INNER JOIN cs_equipment_delivery equipment ON equipment.id = line.device_id
|
||||
INNER JOIN cs_project project ON project.id = equipment.associated_project
|
||||
INNER JOIN cs_engineering engineering ON engineering.id = equipment.associated_engineering
|
||||
WHERE line.status = 1
|
||||
AND equipment.run_status <> 0
|
||||
AND project.status = 1
|
||||
AND engineering.status = 1
|
||||
<if test="param.engineeringName != null and param.engineeringName != ''">
|
||||
AND engineering.name LIKE CONCAT('%', #{param.engineeringName}, '%')
|
||||
</if>
|
||||
<if test="param.projectName != null and param.projectName != ''">
|
||||
AND project.name LIKE CONCAT('%', #{param.projectName}, '%')
|
||||
</if>
|
||||
<if test="param.equipmentName != null and param.equipmentName != ''">
|
||||
AND equipment.name LIKE CONCAT('%', #{param.equipmentName}, '%')
|
||||
</if>
|
||||
<if test="param.lineName != null and param.lineName != ''">
|
||||
AND line.name LIKE CONCAT('%', #{param.lineName}, '%')
|
||||
</if>
|
||||
ORDER BY engineering.name ASC, project.name ASC, equipment.name ASC, line.name ASC
|
||||
LIMIT #{param.limit}
|
||||
</select>
|
||||
|
||||
<update id="softDeleteByIds">
|
||||
UPDATE cs_line
|
||||
SET status = 0,
|
||||
update_by = #{updateBy},
|
||||
update_time = NOW()
|
||||
WHERE line_id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.njcn.gather.tool.addledger.mapper.AddLedgerProjectMapper">
|
||||
|
||||
<update id="softDeleteByIds">
|
||||
UPDATE cs_project
|
||||
SET status = 0,
|
||||
update_by = #{updateBy},
|
||||
update_time = NOW()
|
||||
WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.constant;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 数据台账常量。
|
||||
*/
|
||||
public final class AddLedgerConst {
|
||||
|
||||
private AddLedgerConst() {
|
||||
}
|
||||
|
||||
public static final String ROOT_PARENT_ID = "0";
|
||||
|
||||
public static final int LEVEL_ENGINEERING = 0;
|
||||
public static final int LEVEL_PROJECT = 1;
|
||||
public static final int LEVEL_EQUIPMENT = 2;
|
||||
public static final int LEVEL_LINE = 3;
|
||||
|
||||
public static final int STATE_DELETED = 0;
|
||||
public static final int STATE_NORMAL = 1;
|
||||
|
||||
public static final int EQUIPMENT_RUN_STATUS_DELETED = 0;
|
||||
public static final int EQUIPMENT_RUN_STATUS_OFFLINE = 1;
|
||||
public static final int EQUIPMENT_STATUS_UNREGISTERED = 1;
|
||||
public static final int EQUIPMENT_PROCESS_RUNNING = 4;
|
||||
public static final int ENABLE = 1;
|
||||
public static final int DISABLE = 0;
|
||||
|
||||
public static final int LINE_RUN_STATUS_RUNNING = 0;
|
||||
public static final int LINE_INTERVAL_DEFAULT = 1;
|
||||
public static final String LOG_LEVEL_WARN = "WARN";
|
||||
|
||||
public static final int MIN_LINE_NO = 1;
|
||||
public static final int MAX_LINE_NO = 20;
|
||||
|
||||
public static final Set<Integer> CON_TYPES = new LinkedHashSet<Integer>(Arrays.asList(0, 1, 2));
|
||||
|
||||
public static final Set<BigDecimal> VOL_GRADES = new LinkedHashSet<BigDecimal>(Arrays.asList(
|
||||
new BigDecimal("0.38"),
|
||||
new BigDecimal("10"),
|
||||
new BigDecimal("35"),
|
||||
new BigDecimal("110"),
|
||||
new BigDecimal("220"),
|
||||
new BigDecimal("500")
|
||||
));
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.param;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 工程保存参数。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("工程保存参数")
|
||||
public class AddLedgerEngineeringSaveParam {
|
||||
|
||||
@ApiModelProperty("工程ID")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(value = "工程名称", required = true)
|
||||
@NotBlank(message = "工程名称不能为空")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("省")
|
||||
private String province;
|
||||
|
||||
@ApiModelProperty("市")
|
||||
private String city;
|
||||
|
||||
@ApiModelProperty("描述")
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.param;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 设备保存参数。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("设备保存参数")
|
||||
public class AddLedgerEquipmentSaveParam {
|
||||
|
||||
@ApiModelProperty("设备ID")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty("父级项目ID")
|
||||
private String projectId;
|
||||
|
||||
@ApiModelProperty(value = "装置名称", required = true)
|
||||
@NotBlank(message = "设备名称不能为空")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "网络设备ID", required = true)
|
||||
@NotBlank(message = "设备 ndid 不能为空")
|
||||
private String ndid;
|
||||
|
||||
@ApiModelProperty(value = "装置 MAC 地址", required = true)
|
||||
@NotBlank(message = "设备 mac 不能为空")
|
||||
private String mac;
|
||||
|
||||
@ApiModelProperty("装置类型")
|
||||
private String devType;
|
||||
|
||||
@ApiModelProperty(value = "装置型号", required = true)
|
||||
@NotBlank(message = "设备 dev_model 不能为空")
|
||||
private String devModel;
|
||||
|
||||
@ApiModelProperty("装置接入方式")
|
||||
private String devAccessMethod;
|
||||
|
||||
@ApiModelProperty("前置服务器IP")
|
||||
private String nodeId;
|
||||
|
||||
@ApiModelProperty("前置进程号")
|
||||
private Integer nodeProcess;
|
||||
|
||||
@ApiModelProperty("是否支持升级")
|
||||
private Integer upgrade;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.param;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 监测点台账链路检索参数。
|
||||
*/
|
||||
@Data
|
||||
public class AddLedgerLinePathQueryParam {
|
||||
|
||||
@ApiModelProperty("工程名称关键字")
|
||||
private String engineeringName;
|
||||
|
||||
@ApiModelProperty("项目名称关键字")
|
||||
private String projectName;
|
||||
|
||||
@ApiModelProperty("设备名称关键字")
|
||||
private String equipmentName;
|
||||
|
||||
@ApiModelProperty("监测点名称关键字")
|
||||
private String lineName;
|
||||
|
||||
@ApiModelProperty("最大返回监测点数量")
|
||||
private Integer limit;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.param;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.DecimalMin;
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 测点保存参数。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("测点保存参数")
|
||||
public class AddLedgerLineSaveParam {
|
||||
|
||||
@ApiModelProperty("测点ID")
|
||||
private String lineId;
|
||||
|
||||
@ApiModelProperty("父级设备ID")
|
||||
private String deviceId;
|
||||
|
||||
@ApiModelProperty(value = "监测点名", required = true)
|
||||
@NotBlank(message = "测点名称不能为空")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "线路号", required = true)
|
||||
@NotNull(message = "line_no 不能为空")
|
||||
@Min(value = 1, message = "line_no 必须在 1-20 之间")
|
||||
@Max(value = 20, message = "line_no 必须在 1-20 之间")
|
||||
private Integer lineNo;
|
||||
|
||||
@ApiModelProperty(value = "接线方式", required = true)
|
||||
@NotNull(message = "conType 不能为空")
|
||||
private Integer conType;
|
||||
|
||||
@ApiModelProperty(value = "电压等级", required = true)
|
||||
@NotNull(message = "vol_grade 不能为空")
|
||||
private BigDecimal volGrade;
|
||||
|
||||
@ApiModelProperty("安装位置")
|
||||
private String position;
|
||||
|
||||
@ApiModelProperty(value = "CT 一次额定值", required = true)
|
||||
@NotNull(message = "ct_ratio 不能为空")
|
||||
@DecimalMin(value = "0", inclusive = true, message = "ct_ratio 不能为负数")
|
||||
private BigDecimal ctRatio;
|
||||
|
||||
@ApiModelProperty(value = "CT 二次额定值", required = true)
|
||||
@NotNull(message = "ct2_ratio 不能为空")
|
||||
@DecimalMin(value = "0", inclusive = true, message = "ct2_ratio 不能为负数")
|
||||
private BigDecimal ct2Ratio;
|
||||
|
||||
@ApiModelProperty(value = "PT 一次额定值", required = true)
|
||||
@NotNull(message = "pt_ratio 不能为空")
|
||||
@DecimalMin(value = "0", inclusive = true, message = "pt_ratio 不能为负数")
|
||||
private BigDecimal ptRatio;
|
||||
|
||||
@ApiModelProperty(value = "PT 二次额定值", required = true)
|
||||
@NotNull(message = "pt2_ratio 不能为空")
|
||||
@DecimalMin(value = "0", inclusive = true, message = "pt2_ratio 不能为负数")
|
||||
private BigDecimal pt2Ratio;
|
||||
|
||||
@ApiModelProperty("最小短路容量(MVA)")
|
||||
@DecimalMin(value = "0", inclusive = true, message = "short_circuit_capacity 不能为负数")
|
||||
private BigDecimal shortCircuitCapacity;
|
||||
|
||||
@ApiModelProperty("供电设备容量(MVA)")
|
||||
@DecimalMin(value = "0", inclusive = true, message = "dev_capacity 不能为负数")
|
||||
private BigDecimal devCapacity;
|
||||
|
||||
@ApiModelProperty("基准短路容量(MVA)")
|
||||
@DecimalMin(value = "0", inclusive = true, message = "basic_capacity 不能为负数")
|
||||
private BigDecimal basicCapacity;
|
||||
|
||||
@ApiModelProperty("用户协议容量(MVA)")
|
||||
@DecimalMin(value = "0", inclusive = true, message = "protocol_capacity 不能为负数")
|
||||
private BigDecimal protocolCapacity;
|
||||
|
||||
@ApiModelProperty("监测对象类型")
|
||||
private String monitorObj;
|
||||
|
||||
@ApiModelProperty("是否治理")
|
||||
private Integer isGovern;
|
||||
|
||||
@ApiModelProperty("敏感用户")
|
||||
private String monitorUser;
|
||||
|
||||
@ApiModelProperty("是否主要监测点")
|
||||
private Integer isImportant;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.param;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 项目保存参数。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("项目保存参数")
|
||||
public class AddLedgerProjectSaveParam {
|
||||
|
||||
@ApiModelProperty("项目ID")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty("父级工程ID")
|
||||
private String engineeringId;
|
||||
|
||||
@ApiModelProperty(value = "项目名称", required = true)
|
||||
@NotBlank(message = "项目名称不能为空")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("相对位置")
|
||||
private String area;
|
||||
|
||||
@ApiModelProperty("项目描述")
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.njcn.db.mybatisplus.bo.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 工程信息。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("cs_engineering")
|
||||
public class AddLedgerEngineeringPO extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String province;
|
||||
|
||||
private String city;
|
||||
|
||||
private String description;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Integer sort;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.njcn.db.mybatisplus.bo.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 设备出厂信息。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("cs_equipment_delivery")
|
||||
public class AddLedgerEquipmentPO extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String ndid;
|
||||
|
||||
private String mac;
|
||||
|
||||
private String devType;
|
||||
|
||||
private String devModel;
|
||||
|
||||
private String cntractNo;
|
||||
|
||||
private Integer runStatus;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String devAccessMethod;
|
||||
|
||||
private String softinfoId;
|
||||
|
||||
private Integer moduleNumber;
|
||||
|
||||
private Integer process;
|
||||
|
||||
private String qrPath;
|
||||
|
||||
private Integer usageStatus;
|
||||
|
||||
private Integer sort;
|
||||
|
||||
private String nodeId;
|
||||
|
||||
private Integer nodeProcess;
|
||||
|
||||
private String devLogLevel;
|
||||
|
||||
private String associatedEngineering;
|
||||
|
||||
private String associatedProject;
|
||||
|
||||
private String icd;
|
||||
|
||||
private Integer upgrade;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.njcn.db.mybatisplus.bo.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 台账树节点。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("cs_ledger")
|
||||
public class AddLedgerLedgerPO extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId("Id")
|
||||
private String id;
|
||||
|
||||
@TableField("Pid")
|
||||
private String pid;
|
||||
|
||||
@TableField("Pids")
|
||||
private String pids;
|
||||
|
||||
@TableField("Name")
|
||||
private String name;
|
||||
|
||||
@TableField("Level")
|
||||
private Integer level;
|
||||
|
||||
@TableField("Sort")
|
||||
private Integer sort;
|
||||
|
||||
@TableField("Remark")
|
||||
private String remark;
|
||||
|
||||
@TableField("State")
|
||||
private Integer state;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.njcn.db.mybatisplus.bo.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 监测点信息。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("cs_line")
|
||||
public class AddLedgerLinePO extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId("line_id")
|
||||
private String lineId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String deviceId;
|
||||
|
||||
private String dataSetId;
|
||||
|
||||
private String dataModelId;
|
||||
|
||||
private String position;
|
||||
|
||||
private BigDecimal volGrade;
|
||||
|
||||
private Integer runStatus;
|
||||
|
||||
@TableField("conType")
|
||||
private Integer conType;
|
||||
|
||||
private BigDecimal ptRatio;
|
||||
|
||||
private BigDecimal pt2Ratio;
|
||||
|
||||
private BigDecimal ctRatio;
|
||||
|
||||
private BigDecimal ct2Ratio;
|
||||
|
||||
private Integer status;
|
||||
|
||||
@TableField("clDid")
|
||||
private Integer clDid;
|
||||
|
||||
private Integer lineInterval;
|
||||
|
||||
private Integer lineNo;
|
||||
|
||||
private BigDecimal shortCircuitCapacity;
|
||||
|
||||
private BigDecimal devCapacity;
|
||||
|
||||
private BigDecimal basicCapacity;
|
||||
|
||||
private BigDecimal protocolCapacity;
|
||||
|
||||
private String monitorObj;
|
||||
|
||||
private Integer isGovern;
|
||||
|
||||
private String monitorUser;
|
||||
|
||||
private String reportFilePath;
|
||||
|
||||
private String lineLogLevel;
|
||||
|
||||
private Integer isImportant;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.njcn.db.mybatisplus.bo.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 项目信息。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("cs_project")
|
||||
public class AddLedgerProjectPO extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String area;
|
||||
|
||||
private String description;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Integer sort;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 台账节点详情。
|
||||
*/
|
||||
@Data
|
||||
public class AddLedgerDetailVO {
|
||||
|
||||
private String id;
|
||||
|
||||
private Integer level;
|
||||
|
||||
private String parentId;
|
||||
|
||||
private String parentIds;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer sort;
|
||||
|
||||
private String province;
|
||||
|
||||
private String city;
|
||||
|
||||
private String description;
|
||||
|
||||
private String area;
|
||||
|
||||
private String ndid;
|
||||
|
||||
private String mac;
|
||||
|
||||
private String devType;
|
||||
|
||||
private String devModel;
|
||||
|
||||
private String devAccessMethod;
|
||||
|
||||
private String nodeId;
|
||||
|
||||
private Integer nodeProcess;
|
||||
|
||||
private Integer upgrade;
|
||||
|
||||
private String position;
|
||||
|
||||
private Integer lineNo;
|
||||
|
||||
private Integer conType;
|
||||
|
||||
private BigDecimal volGrade;
|
||||
|
||||
private BigDecimal ctRatio;
|
||||
|
||||
private BigDecimal ct2Ratio;
|
||||
|
||||
private BigDecimal ptRatio;
|
||||
|
||||
private BigDecimal pt2Ratio;
|
||||
|
||||
private BigDecimal shortCircuitCapacity;
|
||||
|
||||
private BigDecimal devCapacity;
|
||||
|
||||
private BigDecimal basicCapacity;
|
||||
|
||||
private BigDecimal protocolCapacity;
|
||||
|
||||
private String monitorObj;
|
||||
|
||||
private Integer isGovern;
|
||||
|
||||
private String monitorUser;
|
||||
|
||||
private Integer isImportant;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 监测点所属台账链路。
|
||||
*/
|
||||
@Data
|
||||
public class AddLedgerLinePathVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String engineeringId;
|
||||
|
||||
private String engineeringName;
|
||||
|
||||
private String projectId;
|
||||
|
||||
private String projectName;
|
||||
|
||||
private String equipmentId;
|
||||
|
||||
private String equipmentName;
|
||||
|
||||
private String lineId;
|
||||
|
||||
private String lineName;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.njcn.gather.tool.addledger.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 台账树节点。
|
||||
*/
|
||||
@Data
|
||||
public class AddLedgerTreeNodeVO {
|
||||
|
||||
private String id;
|
||||
|
||||
private String parentId;
|
||||
|
||||
private String parentIds;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer level;
|
||||
|
||||
private Integer sort;
|
||||
|
||||
private List<AddLedgerTreeNodeVO> children = new ArrayList<AddLedgerTreeNodeVO>();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.njcn.gather.tool.addledger.service;
|
||||
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEngineeringSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEquipmentSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLinePathQueryParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLineSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerProjectSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerDetailVO;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerTreeNodeVO;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据台账服务。
|
||||
*/
|
||||
public interface AddLedgerService {
|
||||
|
||||
List<AddLedgerTreeNodeVO> tree(String keyword);
|
||||
|
||||
AddLedgerDetailVO detail(String id, Integer level);
|
||||
|
||||
AddLedgerDetailVO saveEngineering(AddLedgerEngineeringSaveParam param);
|
||||
|
||||
AddLedgerDetailVO saveProject(AddLedgerProjectSaveParam param);
|
||||
|
||||
AddLedgerDetailVO saveEquipment(AddLedgerEquipmentSaveParam param);
|
||||
|
||||
AddLedgerDetailVO saveLine(AddLedgerLineSaveParam param);
|
||||
|
||||
List<Integer> availableLineNos(String deviceId, String lineId);
|
||||
|
||||
Map<String, AddLedgerLinePathVO> listLinePathByLineIds(List<String> lineIds);
|
||||
|
||||
List<String> listLineIdsByPathQuery(AddLedgerLinePathQueryParam param);
|
||||
|
||||
boolean deleteNode(String id, Integer level);
|
||||
}
|
||||
@@ -0,0 +1,572 @@
|
||||
package com.njcn.gather.tool.addledger.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.njcn.gather.tool.addledger.component.AddLedgerTreeBuilder;
|
||||
import com.njcn.gather.tool.addledger.mapper.AddLedgerEngineeringMapper;
|
||||
import com.njcn.gather.tool.addledger.mapper.AddLedgerEquipmentMapper;
|
||||
import com.njcn.gather.tool.addledger.mapper.AddLedgerLedgerMapper;
|
||||
import com.njcn.gather.tool.addledger.mapper.AddLedgerLineMapper;
|
||||
import com.njcn.gather.tool.addledger.mapper.AddLedgerProjectMapper;
|
||||
import com.njcn.gather.tool.addledger.pojo.constant.AddLedgerConst;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEngineeringSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerEquipmentSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLinePathQueryParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerLineSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.param.AddLedgerProjectSaveParam;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerEngineeringPO;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerEquipmentPO;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerLedgerPO;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerLinePO;
|
||||
import com.njcn.gather.tool.addledger.pojo.po.AddLedgerProjectPO;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerDetailVO;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
|
||||
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerTreeNodeVO;
|
||||
import com.njcn.gather.tool.addledger.service.AddLedgerService;
|
||||
import com.njcn.gather.tool.addledger.util.AddLedgerIdUtil;
|
||||
import com.njcn.gather.tool.addledger.util.AddLedgerLineNoUtil;
|
||||
import com.njcn.web.utils.RequestUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据台账服务实现。
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AddLedgerServiceImpl implements AddLedgerService {
|
||||
|
||||
private static final int DEFAULT_LINE_PATH_QUERY_LIMIT = 1000;
|
||||
private static final int MAX_LINE_PATH_QUERY_LIMIT = 5000;
|
||||
|
||||
private final AddLedgerEngineeringMapper engineeringMapper;
|
||||
private final AddLedgerProjectMapper projectMapper;
|
||||
private final AddLedgerEquipmentMapper equipmentMapper;
|
||||
private final AddLedgerLineMapper lineMapper;
|
||||
private final AddLedgerLedgerMapper ledgerMapper;
|
||||
private final AddLedgerTreeBuilder treeBuilder;
|
||||
|
||||
@Override
|
||||
public List<AddLedgerTreeNodeVO> tree(String keyword) {
|
||||
return treeBuilder.buildTree(ledgerMapper.selectTree(trimToNull(keyword)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddLedgerDetailVO detail(String id, Integer level) {
|
||||
AddLedgerLedgerPO ledger = requireLedger(id, level);
|
||||
if (AddLedgerConst.LEVEL_ENGINEERING == level) {
|
||||
return buildEngineeringDetail(ledger, requireEngineering(id));
|
||||
}
|
||||
if (AddLedgerConst.LEVEL_PROJECT == level) {
|
||||
return buildProjectDetail(ledger, requireProject(id));
|
||||
}
|
||||
if (AddLedgerConst.LEVEL_EQUIPMENT == level) {
|
||||
return buildEquipmentDetail(ledger, requireEquipment(id));
|
||||
}
|
||||
if (AddLedgerConst.LEVEL_LINE == level) {
|
||||
return buildLineDetail(ledger, requireLine(id));
|
||||
}
|
||||
throw new IllegalArgumentException("不支持的台账层级");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public AddLedgerDetailVO saveEngineering(AddLedgerEngineeringSaveParam param) {
|
||||
String name = requireText(param == null ? null : param.getName(), "工程名称不能为空");
|
||||
boolean create = isBlank(param.getId());
|
||||
String id = create ? AddLedgerIdUtil.nextId() : param.getId().trim();
|
||||
|
||||
AddLedgerEngineeringPO engineering = create ? new AddLedgerEngineeringPO() : requireEngineering(id);
|
||||
engineering.setId(id);
|
||||
engineering.setName(name);
|
||||
engineering.setProvince(trimToNull(param.getProvince()));
|
||||
engineering.setCity(trimToNull(param.getCity()));
|
||||
engineering.setDescription(trimToNull(param.getDescription()));
|
||||
if (create) {
|
||||
engineering.setStatus(AddLedgerConst.STATE_NORMAL);
|
||||
engineering.setSort(0);
|
||||
engineeringMapper.insert(engineering);
|
||||
saveLedger(id, AddLedgerConst.ROOT_PARENT_ID, AddLedgerConst.ROOT_PARENT_ID, name, AddLedgerConst.LEVEL_ENGINEERING);
|
||||
} else {
|
||||
engineeringMapper.updateById(engineering);
|
||||
updateLedgerName(id, AddLedgerConst.LEVEL_ENGINEERING, name);
|
||||
}
|
||||
return detail(id, AddLedgerConst.LEVEL_ENGINEERING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public AddLedgerDetailVO saveProject(AddLedgerProjectSaveParam param) {
|
||||
String name = requireText(param == null ? null : param.getName(), "项目名称不能为空");
|
||||
boolean create = isBlank(param.getId());
|
||||
String id = create ? AddLedgerIdUtil.nextId() : param.getId().trim();
|
||||
AddLedgerLedgerPO parentLedger;
|
||||
if (create) {
|
||||
parentLedger = requireLedger(param.getEngineeringId(), AddLedgerConst.LEVEL_ENGINEERING);
|
||||
} else {
|
||||
parentLedger = requireLedger(requireLedger(id, AddLedgerConst.LEVEL_PROJECT).getPid(), AddLedgerConst.LEVEL_ENGINEERING);
|
||||
}
|
||||
|
||||
AddLedgerProjectPO project = create ? new AddLedgerProjectPO() : requireProject(id);
|
||||
project.setId(id);
|
||||
project.setName(name);
|
||||
project.setArea(trimToNull(param.getArea()));
|
||||
project.setDescription(trimToNull(param.getDescription()));
|
||||
if (create) {
|
||||
project.setStatus(AddLedgerConst.STATE_NORMAL);
|
||||
project.setSort(0);
|
||||
projectMapper.insert(project);
|
||||
saveLedger(id, parentLedger.getId(), buildChildPids(parentLedger), name, AddLedgerConst.LEVEL_PROJECT);
|
||||
} else {
|
||||
projectMapper.updateById(project);
|
||||
updateLedgerName(id, AddLedgerConst.LEVEL_PROJECT, name);
|
||||
}
|
||||
return detail(id, AddLedgerConst.LEVEL_PROJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public AddLedgerDetailVO saveEquipment(AddLedgerEquipmentSaveParam param) {
|
||||
validateEquipmentParam(param);
|
||||
boolean create = isBlank(param.getId());
|
||||
String id = create ? AddLedgerIdUtil.nextId() : param.getId().trim();
|
||||
AddLedgerLedgerPO projectLedger;
|
||||
if (create) {
|
||||
projectLedger = requireLedger(param.getProjectId(), AddLedgerConst.LEVEL_PROJECT);
|
||||
} else {
|
||||
projectLedger = requireLedger(requireLedger(id, AddLedgerConst.LEVEL_EQUIPMENT).getPid(), AddLedgerConst.LEVEL_PROJECT);
|
||||
}
|
||||
AddLedgerLedgerPO engineeringLedger = requireLedger(projectLedger.getPid(), AddLedgerConst.LEVEL_ENGINEERING);
|
||||
|
||||
AddLedgerEquipmentPO equipment = create ? new AddLedgerEquipmentPO() : requireEquipment(id);
|
||||
equipment.setId(id);
|
||||
equipment.setName(param.getName().trim());
|
||||
equipment.setNdid(param.getNdid().trim());
|
||||
equipment.setMac(param.getMac().trim());
|
||||
equipment.setDevType(trimToNull(param.getDevType()));
|
||||
equipment.setDevModel(param.getDevModel().trim());
|
||||
equipment.setDevAccessMethod(trimToNull(param.getDevAccessMethod()));
|
||||
equipment.setNodeId(trimToNull(param.getNodeId()));
|
||||
equipment.setNodeProcess(param.getNodeProcess());
|
||||
equipment.setUpgrade(param.getUpgrade() == null ? AddLedgerConst.DISABLE : param.getUpgrade());
|
||||
equipment.setAssociatedEngineering(engineeringLedger.getId());
|
||||
equipment.setAssociatedProject(projectLedger.getId());
|
||||
if (create) {
|
||||
equipment.setRunStatus(AddLedgerConst.EQUIPMENT_RUN_STATUS_OFFLINE);
|
||||
equipment.setStatus(AddLedgerConst.EQUIPMENT_STATUS_UNREGISTERED);
|
||||
equipment.setProcess(AddLedgerConst.EQUIPMENT_PROCESS_RUNNING);
|
||||
equipment.setUsageStatus(AddLedgerConst.ENABLE);
|
||||
equipment.setSort(0);
|
||||
equipmentMapper.insert(equipment);
|
||||
saveLedger(id, projectLedger.getId(), buildChildPids(projectLedger), equipment.getName(), AddLedgerConst.LEVEL_EQUIPMENT);
|
||||
} else {
|
||||
equipmentMapper.updateById(equipment);
|
||||
updateLedgerName(id, AddLedgerConst.LEVEL_EQUIPMENT, equipment.getName());
|
||||
}
|
||||
return detail(id, AddLedgerConst.LEVEL_EQUIPMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public AddLedgerDetailVO saveLine(AddLedgerLineSaveParam param) {
|
||||
validateLineParam(param);
|
||||
boolean create = isBlank(param.getLineId());
|
||||
String id = create ? AddLedgerIdUtil.nextId() : param.getLineId().trim();
|
||||
AddLedgerLedgerPO equipmentLedger;
|
||||
if (create) {
|
||||
equipmentLedger = requireLedger(param.getDeviceId(), AddLedgerConst.LEVEL_EQUIPMENT);
|
||||
} else {
|
||||
equipmentLedger = requireLedger(requireLedger(id, AddLedgerConst.LEVEL_LINE).getPid(), AddLedgerConst.LEVEL_EQUIPMENT);
|
||||
}
|
||||
assertLineNoUnique(equipmentLedger.getId(), param.getLineNo(), create ? null : id);
|
||||
|
||||
AddLedgerLinePO line = create ? new AddLedgerLinePO() : requireLine(id);
|
||||
line.setLineId(id);
|
||||
line.setName(param.getName().trim());
|
||||
line.setDeviceId(equipmentLedger.getId());
|
||||
line.setLineNo(param.getLineNo());
|
||||
line.setConType(param.getConType());
|
||||
line.setVolGrade(param.getVolGrade());
|
||||
line.setPosition(trimToNull(param.getPosition()));
|
||||
line.setCtRatio(param.getCtRatio());
|
||||
line.setCt2Ratio(param.getCt2Ratio());
|
||||
line.setPtRatio(param.getPtRatio());
|
||||
line.setPt2Ratio(param.getPt2Ratio());
|
||||
line.setShortCircuitCapacity(param.getShortCircuitCapacity());
|
||||
line.setDevCapacity(param.getDevCapacity());
|
||||
line.setBasicCapacity(param.getBasicCapacity());
|
||||
line.setProtocolCapacity(param.getProtocolCapacity());
|
||||
line.setMonitorObj(trimToNull(param.getMonitorObj()));
|
||||
line.setIsGovern(param.getIsGovern() == null ? AddLedgerConst.DISABLE : param.getIsGovern());
|
||||
line.setMonitorUser(trimToNull(param.getMonitorUser()));
|
||||
line.setIsImportant(param.getIsImportant() == null ? AddLedgerConst.DISABLE : param.getIsImportant());
|
||||
if (create) {
|
||||
line.setStatus(AddLedgerConst.STATE_NORMAL);
|
||||
line.setRunStatus(AddLedgerConst.LINE_RUN_STATUS_RUNNING);
|
||||
line.setLineInterval(AddLedgerConst.LINE_INTERVAL_DEFAULT);
|
||||
line.setLineLogLevel(AddLedgerConst.LOG_LEVEL_WARN);
|
||||
lineMapper.insert(line);
|
||||
saveLedger(id, equipmentLedger.getId(), buildChildPids(equipmentLedger), line.getName(), AddLedgerConst.LEVEL_LINE);
|
||||
} else {
|
||||
lineMapper.updateById(line);
|
||||
updateLedgerName(id, AddLedgerConst.LEVEL_LINE, line.getName());
|
||||
}
|
||||
return detail(id, AddLedgerConst.LEVEL_LINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> availableLineNos(String deviceId, String lineId) {
|
||||
AddLedgerLedgerPO equipmentLedger = requireLedger(deviceId, AddLedgerConst.LEVEL_EQUIPMENT);
|
||||
List<Integer> usedLineNos = lineMapper.selectUsedLineNos(equipmentLedger.getId(), trimToNull(lineId));
|
||||
return AddLedgerLineNoUtil.resolveAvailableLineNos(usedLineNos, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, AddLedgerLinePathVO> listLinePathByLineIds(List<String> lineIds) {
|
||||
List<String> normalizedLineIds = normalizeIds(lineIds);
|
||||
if (normalizedLineIds.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
List<AddLedgerLinePathVO> linePaths = lineMapper.selectLinePathByLineIds(normalizedLineIds);
|
||||
Map<String, AddLedgerLinePathVO> result = new LinkedHashMap<String, AddLedgerLinePathVO>();
|
||||
for (AddLedgerLinePathVO linePath : linePaths) {
|
||||
if (linePath != null && !isBlank(linePath.getLineId())) {
|
||||
result.put(linePath.getLineId(), linePath);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listLineIdsByPathQuery(AddLedgerLinePathQueryParam param) {
|
||||
if (!hasPathKeyword(param)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
AddLedgerLinePathQueryParam queryParam = new AddLedgerLinePathQueryParam();
|
||||
queryParam.setEngineeringName(trimToNull(param.getEngineeringName()));
|
||||
queryParam.setProjectName(trimToNull(param.getProjectName()));
|
||||
queryParam.setEquipmentName(trimToNull(param.getEquipmentName()));
|
||||
queryParam.setLineName(trimToNull(param.getLineName()));
|
||||
queryParam.setLimit(normalizeLimit(param.getLimit()));
|
||||
List<AddLedgerLinePathVO> linePaths = lineMapper.selectLinePathByQuery(queryParam);
|
||||
List<String> lineIds = new ArrayList<String>();
|
||||
for (AddLedgerLinePathVO linePath : linePaths) {
|
||||
if (linePath != null && !isBlank(linePath.getLineId())) {
|
||||
lineIds.add(linePath.getLineId());
|
||||
}
|
||||
}
|
||||
return lineIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean deleteNode(String id, Integer level) {
|
||||
requireLedger(id, level);
|
||||
List<AddLedgerLedgerPO> subtree = ledgerMapper.selectActiveSubtree(id);
|
||||
if (subtree.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
List<String> engineeringIds = new ArrayList<String>();
|
||||
List<String> projectIds = new ArrayList<String>();
|
||||
List<String> equipmentIds = new ArrayList<String>();
|
||||
List<String> lineIds = new ArrayList<String>();
|
||||
List<String> ledgerIds = new ArrayList<String>();
|
||||
for (AddLedgerLedgerPO node : subtree) {
|
||||
ledgerIds.add(node.getId());
|
||||
if (AddLedgerConst.LEVEL_ENGINEERING == node.getLevel()) {
|
||||
engineeringIds.add(node.getId());
|
||||
} else if (AddLedgerConst.LEVEL_PROJECT == node.getLevel()) {
|
||||
projectIds.add(node.getId());
|
||||
} else if (AddLedgerConst.LEVEL_EQUIPMENT == node.getLevel()) {
|
||||
equipmentIds.add(node.getId());
|
||||
} else if (AddLedgerConst.LEVEL_LINE == node.getLevel()) {
|
||||
lineIds.add(node.getId());
|
||||
}
|
||||
}
|
||||
String updateBy = currentUserId();
|
||||
if (!lineIds.isEmpty()) {
|
||||
lineMapper.softDeleteByIds(lineIds, updateBy);
|
||||
}
|
||||
if (!equipmentIds.isEmpty()) {
|
||||
equipmentMapper.softDeleteByIds(equipmentIds, updateBy);
|
||||
}
|
||||
if (!projectIds.isEmpty()) {
|
||||
projectMapper.softDeleteByIds(projectIds, updateBy);
|
||||
}
|
||||
if (!engineeringIds.isEmpty()) {
|
||||
engineeringMapper.softDeleteByIds(engineeringIds, updateBy);
|
||||
}
|
||||
ledgerMapper.softDeleteByIds(ledgerIds, updateBy);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void validateEquipmentParam(AddLedgerEquipmentSaveParam param) {
|
||||
if (param == null) {
|
||||
throw new IllegalArgumentException("设备参数不能为空");
|
||||
}
|
||||
requireText(param.getName(), "设备名称不能为空");
|
||||
requireText(param.getNdid(), "设备 ndid 不能为空");
|
||||
requireText(param.getMac(), "设备 mac 不能为空");
|
||||
requireText(param.getDevModel(), "设备 dev_model 不能为空");
|
||||
}
|
||||
|
||||
private void validateLineParam(AddLedgerLineSaveParam param) {
|
||||
if (param == null) {
|
||||
throw new IllegalArgumentException("测点参数不能为空");
|
||||
}
|
||||
requireText(param.getName(), "测点名称不能为空");
|
||||
if (param.getLineNo() == null
|
||||
|| param.getLineNo() < AddLedgerConst.MIN_LINE_NO
|
||||
|| param.getLineNo() > AddLedgerConst.MAX_LINE_NO) {
|
||||
throw new IllegalArgumentException("line_no 必须在 1-20 之间");
|
||||
}
|
||||
if (!AddLedgerConst.CON_TYPES.contains(param.getConType())) {
|
||||
throw new IllegalArgumentException("conType 只能是 0、1、2");
|
||||
}
|
||||
if (!containsVolGrade(param.getVolGrade())) {
|
||||
throw new IllegalArgumentException("vol_grade 只能是 0.38、10、35、110、220、500");
|
||||
}
|
||||
requireNonNegative(param.getCtRatio(), "ct_ratio 不能为空且不能为负数");
|
||||
requireNonNegative(param.getCt2Ratio(), "ct2_ratio 不能为空且不能为负数");
|
||||
requireNonNegative(param.getPtRatio(), "pt_ratio 不能为空且不能为负数");
|
||||
requireNonNegative(param.getPt2Ratio(), "pt2_ratio 不能为空且不能为负数");
|
||||
requireNonNegativeIfPresent(param.getShortCircuitCapacity(), "short_circuit_capacity 不能为负数");
|
||||
requireNonNegativeIfPresent(param.getDevCapacity(), "dev_capacity 不能为负数");
|
||||
requireNonNegativeIfPresent(param.getBasicCapacity(), "basic_capacity 不能为负数");
|
||||
requireNonNegativeIfPresent(param.getProtocolCapacity(), "protocol_capacity 不能为负数");
|
||||
}
|
||||
|
||||
private void assertLineNoUnique(String deviceId, Integer lineNo, String lineId) {
|
||||
int count = lineMapper.countActiveLineNo(deviceId, lineNo, lineId);
|
||||
if (count > 0) {
|
||||
throw new IllegalArgumentException("同设备下 line_no 不可重复");
|
||||
}
|
||||
}
|
||||
|
||||
private AddLedgerLedgerPO requireLedger(String id, Integer level) {
|
||||
String nodeId = requireText(id, "台账节点 ID 不能为空");
|
||||
if (level == null) {
|
||||
throw new IllegalArgumentException("台账节点层级不能为空");
|
||||
}
|
||||
AddLedgerLedgerPO ledger = ledgerMapper.selectActiveNode(nodeId, level);
|
||||
if (ledger == null) {
|
||||
throw new IllegalArgumentException("台账节点不存在或已删除");
|
||||
}
|
||||
return ledger;
|
||||
}
|
||||
|
||||
private AddLedgerEngineeringPO requireEngineering(String id) {
|
||||
AddLedgerEngineeringPO engineering = engineeringMapper.selectOne(new LambdaQueryWrapper<AddLedgerEngineeringPO>()
|
||||
.eq(AddLedgerEngineeringPO::getId, id)
|
||||
.eq(AddLedgerEngineeringPO::getStatus, AddLedgerConst.STATE_NORMAL));
|
||||
if (engineering == null) {
|
||||
throw new IllegalArgumentException("工程不存在或已删除");
|
||||
}
|
||||
return engineering;
|
||||
}
|
||||
|
||||
private AddLedgerProjectPO requireProject(String id) {
|
||||
AddLedgerProjectPO project = projectMapper.selectOne(new LambdaQueryWrapper<AddLedgerProjectPO>()
|
||||
.eq(AddLedgerProjectPO::getId, id)
|
||||
.eq(AddLedgerProjectPO::getStatus, AddLedgerConst.STATE_NORMAL));
|
||||
if (project == null) {
|
||||
throw new IllegalArgumentException("项目不存在或已删除");
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
private AddLedgerEquipmentPO requireEquipment(String id) {
|
||||
AddLedgerEquipmentPO equipment = equipmentMapper.selectOne(new LambdaQueryWrapper<AddLedgerEquipmentPO>()
|
||||
.eq(AddLedgerEquipmentPO::getId, id)
|
||||
.ne(AddLedgerEquipmentPO::getRunStatus, AddLedgerConst.EQUIPMENT_RUN_STATUS_DELETED));
|
||||
if (equipment == null) {
|
||||
throw new IllegalArgumentException("设备不存在或已删除");
|
||||
}
|
||||
return equipment;
|
||||
}
|
||||
|
||||
private AddLedgerLinePO requireLine(String id) {
|
||||
AddLedgerLinePO line = lineMapper.selectOne(new LambdaQueryWrapper<AddLedgerLinePO>()
|
||||
.eq(AddLedgerLinePO::getLineId, id)
|
||||
.eq(AddLedgerLinePO::getStatus, AddLedgerConst.STATE_NORMAL));
|
||||
if (line == null) {
|
||||
throw new IllegalArgumentException("测点不存在或已删除");
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private void saveLedger(String id, String pid, String pids, String name, Integer level) {
|
||||
AddLedgerLedgerPO ledger = new AddLedgerLedgerPO();
|
||||
ledger.setId(id);
|
||||
ledger.setPid(pid);
|
||||
ledger.setPids(pids);
|
||||
ledger.setName(name);
|
||||
ledger.setLevel(level);
|
||||
ledger.setSort(0);
|
||||
ledger.setState(AddLedgerConst.STATE_NORMAL);
|
||||
ledgerMapper.insert(ledger);
|
||||
}
|
||||
|
||||
private void updateLedgerName(String id, Integer level, String name) {
|
||||
AddLedgerLedgerPO ledger = requireLedger(id, level);
|
||||
ledger.setName(name);
|
||||
ledgerMapper.updateById(ledger);
|
||||
}
|
||||
|
||||
private String buildChildPids(AddLedgerLedgerPO parent) {
|
||||
return parent.getPids() + "," + parent.getId();
|
||||
}
|
||||
|
||||
private AddLedgerDetailVO buildEngineeringDetail(AddLedgerLedgerPO ledger, AddLedgerEngineeringPO engineering) {
|
||||
AddLedgerDetailVO detail = buildBaseDetail(ledger);
|
||||
detail.setName(engineering.getName());
|
||||
detail.setProvince(engineering.getProvince());
|
||||
detail.setCity(engineering.getCity());
|
||||
detail.setDescription(engineering.getDescription());
|
||||
return detail;
|
||||
}
|
||||
|
||||
private AddLedgerDetailVO buildProjectDetail(AddLedgerLedgerPO ledger, AddLedgerProjectPO project) {
|
||||
AddLedgerDetailVO detail = buildBaseDetail(ledger);
|
||||
detail.setName(project.getName());
|
||||
detail.setArea(project.getArea());
|
||||
detail.setDescription(project.getDescription());
|
||||
return detail;
|
||||
}
|
||||
|
||||
private AddLedgerDetailVO buildEquipmentDetail(AddLedgerLedgerPO ledger, AddLedgerEquipmentPO equipment) {
|
||||
AddLedgerDetailVO detail = buildBaseDetail(ledger);
|
||||
detail.setName(equipment.getName());
|
||||
detail.setNdid(equipment.getNdid());
|
||||
detail.setMac(equipment.getMac());
|
||||
detail.setDevType(equipment.getDevType());
|
||||
detail.setDevModel(equipment.getDevModel());
|
||||
detail.setDevAccessMethod(equipment.getDevAccessMethod());
|
||||
detail.setNodeId(equipment.getNodeId());
|
||||
detail.setNodeProcess(equipment.getNodeProcess());
|
||||
detail.setUpgrade(equipment.getUpgrade());
|
||||
return detail;
|
||||
}
|
||||
|
||||
private AddLedgerDetailVO buildLineDetail(AddLedgerLedgerPO ledger, AddLedgerLinePO line) {
|
||||
AddLedgerDetailVO detail = buildBaseDetail(ledger);
|
||||
detail.setName(line.getName());
|
||||
detail.setLineNo(line.getLineNo());
|
||||
detail.setConType(line.getConType());
|
||||
detail.setVolGrade(line.getVolGrade());
|
||||
detail.setPosition(line.getPosition());
|
||||
detail.setCtRatio(line.getCtRatio());
|
||||
detail.setCt2Ratio(line.getCt2Ratio());
|
||||
detail.setPtRatio(line.getPtRatio());
|
||||
detail.setPt2Ratio(line.getPt2Ratio());
|
||||
detail.setShortCircuitCapacity(line.getShortCircuitCapacity());
|
||||
detail.setDevCapacity(line.getDevCapacity());
|
||||
detail.setBasicCapacity(line.getBasicCapacity());
|
||||
detail.setProtocolCapacity(line.getProtocolCapacity());
|
||||
detail.setMonitorObj(line.getMonitorObj());
|
||||
detail.setIsGovern(line.getIsGovern());
|
||||
detail.setMonitorUser(line.getMonitorUser());
|
||||
detail.setIsImportant(line.getIsImportant());
|
||||
return detail;
|
||||
}
|
||||
|
||||
private AddLedgerDetailVO buildBaseDetail(AddLedgerLedgerPO ledger) {
|
||||
AddLedgerDetailVO detail = new AddLedgerDetailVO();
|
||||
detail.setId(ledger.getId());
|
||||
detail.setLevel(ledger.getLevel());
|
||||
detail.setParentId(ledger.getPid());
|
||||
detail.setParentIds(ledger.getPids());
|
||||
detail.setSort(ledger.getSort());
|
||||
detail.setName(ledger.getName());
|
||||
return detail;
|
||||
}
|
||||
|
||||
private boolean containsVolGrade(BigDecimal volGrade) {
|
||||
if (volGrade == null) {
|
||||
return false;
|
||||
}
|
||||
for (BigDecimal supported : AddLedgerConst.VOL_GRADES) {
|
||||
if (supported.compareTo(volGrade) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void requireNonNegative(BigDecimal value, String message) {
|
||||
if (value == null || value.compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void requireNonNegativeIfPresent(BigDecimal value, String message) {
|
||||
if (value != null && value.compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
private String requireText(String value, String message) {
|
||||
String text = trimToNull(value);
|
||||
if (text == null) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private String trimToNull(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.isEmpty() ? null : trimmed;
|
||||
}
|
||||
|
||||
private boolean isBlank(String value) {
|
||||
return trimToNull(value) == null;
|
||||
}
|
||||
|
||||
private List<String> normalizeIds(List<String> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> normalizedIds = new ArrayList<String>();
|
||||
for (String id : ids) {
|
||||
String normalizedId = trimToNull(id);
|
||||
if (normalizedId != null && !normalizedIds.contains(normalizedId)) {
|
||||
normalizedIds.add(normalizedId);
|
||||
}
|
||||
}
|
||||
return normalizedIds;
|
||||
}
|
||||
|
||||
private boolean hasPathKeyword(AddLedgerLinePathQueryParam param) {
|
||||
return param != null
|
||||
&& (trimToNull(param.getEngineeringName()) != null
|
||||
|| trimToNull(param.getProjectName()) != null
|
||||
|| trimToNull(param.getEquipmentName()) != null
|
||||
|| trimToNull(param.getLineName()) != null);
|
||||
}
|
||||
|
||||
private int normalizeLimit(Integer limit) {
|
||||
if (limit == null || limit <= 0) {
|
||||
return DEFAULT_LINE_PATH_QUERY_LIMIT;
|
||||
}
|
||||
return Math.min(limit, MAX_LINE_PATH_QUERY_LIMIT);
|
||||
}
|
||||
|
||||
private String currentUserId() {
|
||||
try {
|
||||
String userId = RequestUtil.getUserId();
|
||||
return isBlank(userId) ? "未知用户" : userId;
|
||||
} catch (Exception e) {
|
||||
return "未知用户";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.njcn.gather.tool.addledger.util;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 数据台账 ID 工具。
|
||||
*/
|
||||
public final class AddLedgerIdUtil {
|
||||
|
||||
private AddLedgerIdUtil() {
|
||||
}
|
||||
|
||||
public static String nextId() {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.gather.tool.addledger.util;
|
||||
|
||||
import com.njcn.gather.tool.addledger.pojo.constant.AddLedgerConst;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 数据台账测点线路号工具。
|
||||
*/
|
||||
public final class AddLedgerLineNoUtil {
|
||||
|
||||
private AddLedgerLineNoUtil() {
|
||||
}
|
||||
|
||||
public static List<Integer> resolveAvailableLineNos(List<Integer> usedLineNos, Integer currentLineNo) {
|
||||
Set<Integer> usedSet = new HashSet<Integer>();
|
||||
if (usedLineNos != null) {
|
||||
usedSet.addAll(usedLineNos);
|
||||
}
|
||||
List<Integer> result = new ArrayList<Integer>();
|
||||
for (int lineNo = AddLedgerConst.MIN_LINE_NO; lineNo <= AddLedgerConst.MAX_LINE_NO; lineNo++) {
|
||||
if (!usedSet.contains(lineNo) || Integer.valueOf(lineNo).equals(currentLineNo)) {
|
||||
result.add(lineNo);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user