# 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 返回结构重新接入。
