fix: 卡日流量查询改用卡日快照 tb_card_flow_day
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 12m2s

tb_card_daily_usage 为已停用旧表(测试库为空,且列名与模型不一致),
卡日流量列表与索引改用采集链路写入的 tb_card_flow_day,当日用量取 settled_mb。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
邹进
2026-11-05 18:59:30 +09:00
parent 94cbf2adab
commit 7e0e37933e
7 changed files with 26 additions and 20 deletions

View File

@@ -103,18 +103,22 @@ type TrafficCollectionFailureListResponse struct {
type CardDailyUsageListRequest struct {
RecordDateRangeQuery
CarrierID *uint `query:"carrier_id" validate:"omitempty,min=1" description:"运营商账户ID"`
MinUsageMB *float64 `query:"min_usage_mb" validate:"omitempty,min=0" description:"单日用量下限(MB),用于排查异常大流量"`
MinUsageMB *float64 `query:"min_usage_mb" validate:"omitempty,min=0" description:"当日已结算增量下限(MB),用于排查异常大流量"`
}
// CardDailyUsageItem 卡日流量。
// CardDailyUsageItem 卡日流量(卡日快照 tb_card_flow_day)。
type CardDailyUsageItem struct {
ID uint `json:"id" description:"记录ID"`
IotCardID uint `json:"iot_card_id" description:"卡ID"`
ICCID string `json:"iccid" description:"ICCID"`
CarrierID uint `json:"carrier_id" description:"运营商账户ID"`
Date string `json:"date" description:"日期"`
UsageMB float64 `json:"usage_mb" description:"当日流量(MB)"`
UpdatedAt time.Time `json:"updated_at" description:"更新时间"`
ID uint `json:"id" description:"记录ID"`
IotCardID uint `json:"iot_card_id" description:"卡ID"`
ICCID string `json:"iccid" description:"ICCID"`
CarrierID uint `json:"carrier_id" description:"运营商账户ID"`
Date string `json:"date" description:"日期(上海)"`
SettledMB float64 `json:"settled_mb" description:"当日已结算增量合计(MB),即当日用量"`
MonthUsedMB float64 `json:"month_used_mb" description:"当日结束时的本月自然月累计(MB)"`
VendorUsedMB float64 `json:"vendor_used_mb" description:"当天最后一次写入的运营商原始读数(MB)"`
StaleGuarded bool `json:"stale_guarded" description:"当天是否触发重置日防旧值"`
ObsCount int `json:"obs_count" description:"当天写入次数"`
UpdatedAt time.Time `json:"updated_at" description:"更新时间"`
}
// CardDailyUsageListResponse 卡日流量分页结果。

View File

@@ -25,7 +25,7 @@ func registerRecordQueryRoutes(router fiber.Router, asset *admin.AssetHandler, r
})
Register(router, doc, basePath, "GET", "/card-daily-usages", asset.ListCardDailyUsages, RouteSpec{
Summary: "卡日流量记录",
Description: recordQueryDescription + "按日期范围(含首尾)查询;min_usage_mb 可筛异常大流量。",
Description: recordQueryDescription + "数据来自卡日快照(每卡每天一条);按日期范围(含首尾)查询;min_usage_mb 按当日已结算增量筛异常大流量。",
Tags: []string{"记录查询"}, Input: new(dto.CardDailyUsageListRequest), Output: new(dto.CardDailyUsageListResponse), Auth: true,
})
Register(router, doc, basePath, "GET", "/package-usage-daily-records", asset.ListPackageUsageDailyRecords, RouteSpec{

View File

@@ -237,13 +237,13 @@ func (s *Service) ListCardDailyUsages(ctx context.Context, req *dto.CardDailyUsa
return resp, err
}
type row struct {
model.CardDailyUsage
model.CardFlowDay
ICCID string
CarrierID uint
}
query := s.db.WithContext(ctx).Table("tb_card_daily_usage AS u").
query := s.db.WithContext(ctx).Table("tb_card_flow_day AS u").
Select("u.*, c.iccid, c.carrier_id").Joins("LEFT JOIN tb_iot_card c ON c.id = u.iot_card_id").
Where("u.date >= ? AND u.date <= ?", from.Format(recordDateLayout), to.Format(recordDateLayout))
Where("u.flow_date >= ? AND u.flow_date <= ?", from.Format(recordDateLayout), to.Format(recordDateLayout))
if !scope.all {
query = query.Where("u.iot_card_id IN ?", scope.cardIDs)
}
@@ -251,16 +251,17 @@ func (s *Service) ListCardDailyUsages(ctx context.Context, req *dto.CardDailyUsa
query = query.Where("c.carrier_id = ?", *req.CarrierID)
}
if req.MinUsageMB != nil {
query = query.Where("u.usage_mb >= ?", *req.MinUsageMB)
query = query.Where("u.settled_mb >= ?", *req.MinUsageMB)
}
rows, total, err := pageQuery[row](query, "u.date DESC, u.id DESC", page, size)
rows, total, err := pageQuery[row](query, "u.flow_date DESC, u.id DESC", page, size)
if err != nil {
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询卡日流量失败")
}
for _, item := range rows {
resp.Items = append(resp.Items, dto.CardDailyUsageItem{
ID: item.ID, IotCardID: item.IotCardID, ICCID: item.ICCID, CarrierID: item.CarrierID,
Date: item.Date.Format(recordDateLayout), UsageMB: item.UsageMB, UpdatedAt: item.UpdatedAt,
Date: item.FlowDate.Format(recordDateLayout), SettledMB: item.SettledMB, MonthUsedMB: item.MonthUsedMB,
VendorUsedMB: item.VendorUsedMB, StaleGuarded: item.StaleGuarded, ObsCount: item.ObsCount, UpdatedAt: item.UpdatedAt,
})
}
resp.Total = total

View File

@@ -1,6 +1,6 @@
DROP INDEX IF EXISTS idx_package_usage_adjustment_time;
DROP INDEX IF EXISTS idx_package_usage_daily_record_day;
DROP INDEX IF EXISTS idx_card_daily_usage_date_usage;
DROP INDEX IF EXISTS idx_card_flow_day_date_settled;
DROP INDEX IF EXISTS idx_card_stop_resume_record_command;
DROP INDEX IF EXISTS idx_card_stop_resume_record_scene;
DROP INDEX IF EXISTS idx_card_stop_resume_record_time;

View File

@@ -6,7 +6,8 @@ CREATE INDEX IF NOT EXISTS idx_card_stop_resume_record_time ON tb_card_stop_resu
CREATE INDEX IF NOT EXISTS idx_card_stop_resume_record_scene ON tb_card_stop_resume_record (scene, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_card_stop_resume_record_command ON tb_card_stop_resume_record (command_id);
CREATE INDEX IF NOT EXISTS idx_card_daily_usage_date_usage ON tb_card_daily_usage (date, usage_mb DESC);
-- 卡日流量取采集链路写入的卡日快照 tb_card_flow_day(tb_card_daily_usage 为已停用旧表)。
CREATE INDEX IF NOT EXISTS idx_card_flow_day_date_settled ON tb_card_flow_day (flow_date, settled_mb DESC);
CREATE INDEX IF NOT EXISTS idx_package_usage_daily_record_day ON tb_package_usage_daily_record (date);

View File

@@ -214,7 +214,7 @@
| 采集成功表 | `(observed_at DESC)`、`(carrier_id, observed_at DESC)`、`(decision, observed_at DESC)`,保留现有 `(iot_card_id, observed_at DESC)` |
| 采集失败表 | `(iot_card_id, observed_at DESC)`、`(observed_at DESC)`、`(carrier_id, observed_at DESC)`、`(error_category, observed_at DESC)`、`(observation_id)` |
| 停复机记录 | 现有三个升序索引保留(B-tree 可反向扫描,直接支持倒序分页);新增 `(created_at DESC)`、`(scene, created_at DESC)`、`(command_id)` |
| 卡日流量 | 新增 `(date, usage_mb DESC)` |
| 卡日流量(卡日快照 `tb_card_flow_day`;`tb_card_daily_usage` 为已停用旧表) | 新增 `(flow_date, settled_mb DESC)` |
| 套餐日流量详单 | 新增 `(package_usage_id, date DESC)`、`(date)` |
| 冲正流水 | 新增 `(iot_card_id, created_at DESC)`、`(created_at DESC)` |
| 退款后处理尝试 | `(refund_id, created_at DESC)`、`(created_at DESC)`、`(result, created_at DESC)`、`(error_code, created_at DESC)` |

View File

@@ -88,7 +88,7 @@
| 记录 | 筛选条件 |
|---|---|
| 套餐日流量详单 | 资产标识、套餐使用记录、套餐、运营商账户、日期范围 |
| 卡日流量 | 资产标识、运营商账户、日期范围、用量下限 |
| 卡日流量(卡日快照) | 资产标识、运营商账户、日期范围、当日已结算增量下限 |
| 套餐流量冲正流水 | 资产标识、套餐使用记录、操作人、调整方向(补扣或退回)、时间范围 |
现有套餐日流量详单接口 SHALL 增加分页。现有单套餐冲正流水接口 SHALL 增加时间范围筛选。