fix: 卡日流量查询改用卡日快照 tb_card_flow_day
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 12m2s
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:
@@ -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 卡日流量分页结果。
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)` |
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
| 记录 | 筛选条件 |
|
||||
|---|---|
|
||||
| 套餐日流量详单 | 资产标识、套餐使用记录、套餐、运营商账户、日期范围 |
|
||||
| 卡日流量 | 资产标识、运营商账户、日期范围、用量下限 |
|
||||
| 卡日流量(卡日快照) | 资产标识、运营商账户、日期范围、当日已结算增量下限 |
|
||||
| 套餐流量冲正流水 | 资产标识、套餐使用记录、操作人、调整方向(补扣或退回)、时间范围 |
|
||||
|
||||
现有套餐日流量详单接口 SHALL 增加分页。现有单套餐冲正流水接口 SHALL 增加时间范围筛选。
|
||||
|
||||
Reference in New Issue
Block a user