refactor: 流量系统重构 — 增量累加算法 + 日粒度缓冲 + 旧详单清理
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m16s

核心改造:
- 增量算法:流量计算从覆盖式改为增量累加(gateway - lastReading),支持上游运营商重置检测
- 日流量缓冲:insertDataUsageRecord 改为 Redis INCRBYFLOAT,每日凌晨落盘到 tb_card_daily_usage
- 运营商:新增 data_reset_day 字段(联通=27,其余=1)
- IoT卡:新增 last_gateway_reading_mb 字段存储上次网关读数
- 查询层:新建 TrafficQueryService 合并 Redis(今日)+ DB(历史)数据源
- 清理:删除 DataUsageRecord model/store,移除 polling_handler 旧引用

迁移:000094-000097(carrier字段、iot_card字段、数据初始化、日流量表)
This commit is contained in:
2026-03-30 09:59:30 +08:00
parent f5dd2ce4ab
commit cebcada950
44 changed files with 1149 additions and 1613 deletions

View File

@@ -1,151 +1,16 @@
# carrier Specification
## MODIFIED Requirements
## Purpose
管理运营商(Carrier)实体,支持四大固定运营商(中国移动、中国联通、中国电信、广电)的 CRUD 操作
### Requirement: 运营商上游流量重置日配置
`tb_carrier` SHALL 包含 `data_reset_day` 字段INT, 1-28表示该运营商每月上游流量重置日即上游运营商清零网关计数器的日期。创建/编辑运营商时 SHALL 支持设置此字段
## Requirements
注意:此字段与套餐级别的 `data_reset_cycle`daily/monthly/yearly是**完全独立的两个维度**。`data_reset_day` 用于检测上游网关值下降是否为正常重置,`data_reset_cycle` 用于我们系统套餐的已用量定时归零。
### Requirement: 运营商实体定义
系统 SHALL 定义运营商(Carrier)实体,管理四大固定运营商(中国移动、中国联通、中国电信、广电)。
**四大运营商固定枚举**
- **CMCC**:中国移动
- **CUCC**:中国联通
- **CTCC**:中国电信
- **CBN**:广电
**实体字段**
- `id`:运营商 ID主键BIGINT
- `carrier_code`运营商编码VARCHAR(50),唯一约束)
- `carrier_name`运营商名称VARCHAR(100),如"中国移动"
- `carrier_type`运营商类型VARCHAR(20),枚举值:"CMCC" | "CUCC" | "CTCC" | "CBN"
- `description`运营商描述VARCHAR(500),可选)
- `status`状态INT1-启用 0-禁用)
- `creator`:创建人 IDBIGINT
- `updater`:更新人 IDBIGINT
- `created_at`创建时间TIMESTAMP自动填充
- `updated_at`更新时间TIMESTAMP自动填充
- `deleted_at`删除时间TIMESTAMP可空软删除
**唯一约束**`carrier_code``deleted_at IS NULL` 条件下唯一
---
### Requirement: 创建运营商
系统 SHALL 允许管理员创建新的运营商记录。创建时必须指定 carrier_code唯一编码、carrier_name显示名称、carrier_type运营商类型枚举值。description 为选填字段。创建成功后默认状态为启用status=1
#### Scenario: 成功创建运营商
- **WHEN** 管理员提交有效的创建请求carrier_code 不重复carrier_type 为有效枚举值
- **THEN** 系统创建运营商记录,返回完整的运营商信息
#### Scenario: carrier_code 重复
- **WHEN** 管理员提交的 carrier_code 已存在
- **THEN** 系统返回错误"运营商编码已存在"
#### Scenario: carrier_type 无效
- **WHEN** 管理员提交的 carrier_type 不是 CMCC/CUCC/CTCC/CBN 之一
- **THEN** 系统返回参数校验错误
---
### Requirement: 查询运营商列表
系统 SHALL 提供分页查询运营商列表的接口,支持按 carrier_type、status、carrier_name模糊搜索筛选。
#### Scenario: 无筛选条件查询
- **WHEN** 管理员请求列表,不带筛选条件
- **THEN** 系统返回所有运营商的分页列表,按 ID 降序排列
#### Scenario: 按运营商类型筛选
- **WHEN** 管理员指定 carrier_type=CMCC
- **THEN** 系统仅返回 carrier_type 为 CMCC 的记录
#### Scenario: 按名称模糊搜索
- **WHEN** 管理员指定 carrier_name=移动
- **THEN** 系统返回 carrier_name 包含"移动"的记录
---
### Requirement: 获取运营商详情
系统 SHALL 允许管理员通过 ID 获取单个运营商的详细信息。
#### Scenario: 成功获取详情
- **WHEN** 管理员请求存在的运营商 ID
- **THEN** 系统返回该运营商的完整信息
#### Scenario: 运营商不存在
- **WHEN** 管理员请求不存在的运营商 ID
- **THEN** 系统返回错误"运营商不存在"
---
### Requirement: 更新运营商
系统 SHALL 允许管理员更新运营商的 carrier_name 和 description 字段。carrier_code 和 carrier_type 创建后不可修改。
#### Scenario: 成功更新运营商
- **WHEN** 管理员提交有效的更新请求
- **THEN** 系统更新运营商信息,返回更新后的完整信息
#### Scenario: 尝试修改 carrier_code
- **WHEN** 管理员尝试修改 carrier_code
- **THEN** 系统忽略该字段(不报错,但不修改)
---
### Requirement: 删除运营商
系统 SHALL 允许管理员软删除运营商记录。
#### Scenario: 成功删除运营商
- **WHEN** 管理员请求删除存在的运营商
- **THEN** 系统软删除该记录(设置 deleted_at
#### Scenario: 删除不存在的运营商
- **WHEN** 管理员请求删除不存在的运营商 ID
- **THEN** 系统返回错误"运营商不存在"
---
### Requirement: 更新运营商状态
系统 SHALL 允许管理员启用或禁用运营商。状态值1=启用0=禁用。
#### Scenario: 启用运营商
- **WHEN** 管理员将状态设置为 1
- **THEN** 系统更新运营商状态为启用
#### Scenario: 禁用运营商
- **WHEN** 管理员将状态设置为 0
- **THEN** 系统更新运营商状态为禁用
#### Scenario: 无效状态值
- **WHEN** 管理员提交的状态值不是 0 或 1
- **THEN** 系统返回参数校验错误
---
### Requirement: 运营商数据校验
系统 SHALL 对运营商数据进行校验,确保数据完整性和一致性。
**校验规则**
- `carrier_type`:必填,枚举值 "CMCC" | "CUCC" | "CTCC" | "CBN"
- `carrier_name`:必填,长度 1-100 字符
- `carrier_code`:必填,长度 1-50 字符
- `description`:可选,长度 0-500 字符
- `status`:必填,枚举值 0 或 1
#### Scenario: 创建运营商时 carrier_type 无效
- **WHEN** 创建运营商,`carrier_type` 为 "INVALID"
- **THEN** 系统拒绝创建,返回错误信息"运营商类型无效"
#### Scenario: 创建运营商时 carrier_name 为空
- **WHEN** 创建运营商,`carrier_name` 为空
- **THEN** 系统拒绝创建,返回错误信息"运营商名称不能为空"
#### Scenario: 创建运营商时指定重置日
- **WHEN** 管理员创建运营商,指定 `data_reset_day = 27`
- **THEN** 该运营商记录的 `data_reset_day` SHALL 为 27
#### Scenario: 轮询时读取重置日判断上游重置
- **WHEN** 轮询系统检测到网关流量值下降(`increment < 0`
- **THEN** 系统 SHALL 读取该卡对应运营商的 `data_reset_day`
- **AND** 使用 `isResetWindow(now, resetDay)` 判断是否在重置日窗口内(重置日当天 + 前一天容错)
- **AND** 窗口内视为正常上游重置,窗口外记录 Warn 日志并丢弃异常值